Class: OpenASN::Result

Inherits:
Object
  • Object
show all
Defined in:
lib/openasn/result.rb

Overview

The answer to "where is this IP really coming from?". Immutable.

Verdict-first design: verdict is the closed enum; the predicates are sugar. There is deliberately NO suspicious? — that's a policy word, and drawing that line belongs to your application, not this gem.

STABILITY CONTRACT (README "API stability contract" is the canonical text; keep in sync): VERDICTS is append-only — never remove, rename, or redefine an entry; additions land in minor versions with a loud CHANGELOG note. Verdicts are compiled code, never data: a data refresh cannot introduce one. to_h keys are append-only. The same contract binds every future client (openasn-js, …) — the enum is the project's cross-language API, defined in the data repo's DECISIONS.md.

Constant Summary collapse

VERDICTS =
%i[
  residential_isp mobile business hosting vpn tor_exit relay
  enterprise_gateway education government cgnat private unknown
].freeze
INFRASTRUCTURE_VERDICTS =

High-confidence "this is infrastructure, not an eyeball connection".

%i[hosting vpn tor_exit].freeze
LIKELY_HUMAN_VERDICTS =

"Very likely a human being on the other end" — including the classes people wrongly block: relay users are paying iCloud+ customers, CGNAT/mobile IPs are hundreds of people each, enterprise gateways are entire offices. Note the deliberate asymmetry: business/education/ government/unknown are NEITHER infrastructure nor likely_human — your app decides those.

%i[residential_isp mobile relay cgnat enterprise_gateway].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ip:, verdict:, asn: nil, as_org: nil, category: nil, network_role: nil, provider: nil, sources: [], flags: 0, context_flags: [], unrouted: false) ⇒ Result

Returns a new instance of Result.



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# File 'lib/openasn/result.rb', line 37

def initialize(ip:, verdict:, asn: nil, as_org: nil, category: nil,
               network_role: nil, provider: nil, sources: [], flags: 0,
               context_flags: [], unrouted: false)
  @ip = ip
  @verdict = verdict
  @asn = asn
  @as_org = as_org
  @category = category
  @network_role = network_role
  @provider = provider
  @sources = sources.freeze
  @flags = flags
  @context_flags = context_flags.freeze
  @unrouted = unrouted
  freeze
end

Instance Attribute Details

#as_orgObject (readonly)

Returns the value of attribute as_org.



34
35
36
# File 'lib/openasn/result.rb', line 34

def as_org
  @as_org
end

#asnObject (readonly)

Returns the value of attribute asn.



34
35
36
# File 'lib/openasn/result.rb', line 34

def asn
  @asn
end

#categoryObject (readonly)

Returns the value of attribute category.



34
35
36
# File 'lib/openasn/result.rb', line 34

def category
  @category
end

#context_flagsObject (readonly)

Returns the value of attribute context_flags.



34
35
36
# File 'lib/openasn/result.rb', line 34

def context_flags
  @context_flags
end

#flagsObject (readonly)

Returns the value of attribute flags.



34
35
36
# File 'lib/openasn/result.rb', line 34

def flags
  @flags
end

#ipObject (readonly)

Returns the value of attribute ip.



34
35
36
# File 'lib/openasn/result.rb', line 34

def ip
  @ip
end

#network_roleObject (readonly)

Returns the value of attribute network_role.



34
35
36
# File 'lib/openasn/result.rb', line 34

def network_role
  @network_role
end

#providerObject (readonly)

Returns the value of attribute provider.



34
35
36
# File 'lib/openasn/result.rb', line 34

def provider
  @provider
end

#sourcesObject (readonly)

Returns the value of attribute sources.



34
35
36
# File 'lib/openasn/result.rb', line 34

def sources
  @sources
end

#verdictObject (readonly)

Returns the value of attribute verdict.



34
35
36
# File 'lib/openasn/result.rb', line 34

def verdict
  @verdict
end

Instance Method Details

#cgnat?Boolean

Returns:

  • (Boolean)


63
# File 'lib/openasn/result.rb', line 63

def cgnat?   = verdict == :cgnat

#hosting?Boolean

Returns:

  • (Boolean)


58
# File 'lib/openasn/result.rb', line 58

def hosting? = verdict == :hosting

#infrastructure?Boolean

Returns:

  • (Boolean)


54
# File 'lib/openasn/result.rb', line 54

def infrastructure? = INFRASTRUCTURE_VERDICTS.include?(verdict)

#inspectObject Also known as: to_s



88
89
90
# File 'lib/openasn/result.rb', line 88

def inspect
  "#<OpenASN::Result #{ip} verdict=#{verdict}#{asn ? " AS#{asn}" : ''}#{as_org ? " (#{as_org})" : ''} sources=#{sources.inspect}>"
end

#likely_human?Boolean

Returns:

  • (Boolean)


55
# File 'lib/openasn/result.rb', line 55

def likely_human?   = LIKELY_HUMAN_VERDICTS.include?(verdict)

#mobile?Boolean

Returns:

  • (Boolean)


61
# File 'lib/openasn/result.rb', line 61

def mobile?  = verdict == :mobile

#private?Boolean

Returns:

  • (Boolean)


62
# File 'lib/openasn/result.rb', line 62

def private? = verdict == :private

#relay?Boolean

Returns:

  • (Boolean)


60
# File 'lib/openasn/result.rb', line 60

def relay?   = verdict == :relay

#to_hObject

Everything, for logging and shadow mode. Stable keys — CarHey-style shadow analyses depend on this shape staying append-only.



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/openasn/result.rb', line 70

def to_h
  {
    ip: ip,
    verdict: verdict,
    infrastructure: infrastructure?,
    likely_human: likely_human?,
    asn: asn,
    as_org: as_org,
    category: category,
    network_role: network_role,
    provider: provider,
    sources: sources,
    flags: flags,
    context_flags: context_flags,
    unrouted: unrouted?
  }
end

#tor?Boolean

Returns:

  • (Boolean)


59
# File 'lib/openasn/result.rb', line 59

def tor?     = verdict == :tor_exit

#unrouted?Boolean

True when no ASN announces this IP (unallocated/unrouted space).

Returns:

  • (Boolean)


66
# File 'lib/openasn/result.rb', line 66

def unrouted? = @unrouted

#vpn?Boolean

Returns:

  • (Boolean)


57
# File 'lib/openasn/result.rb', line 57

def vpn?     = verdict == :vpn