Class: OpenASN::Result
- Inherits:
-
Object
- Object
- OpenASN::Result
- 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
- LABELS =
Short human-readable names for every verdict — what you'd print in an admin table or a log line a human reads. Deliberately neutral wording (no "suspicious", no "risky"): the label states what the network IS; what to do about it is your app's policy. Keys follow the VERDICTS append-only contract.
{ residential_isp: "Residential ISP", mobile: "Mobile carrier", business: "Business", hosting: "Hosting / datacenter", vpn: "VPN", tor_exit: "Tor exit", relay: "Privacy relay", enterprise_gateway: "Corporate gateway", education: "University / research", government: "Government", cgnat: "Carrier NAT", private: "Private IP", unknown: "Unknown" }.freeze
Instance Attribute Summary collapse
-
#as_org ⇒ Object
readonly
Returns the value of attribute as_org.
-
#asn ⇒ Object
readonly
Returns the value of attribute asn.
-
#category ⇒ Object
readonly
Returns the value of attribute category.
-
#context_flags ⇒ Object
readonly
Returns the value of attribute context_flags.
-
#flag_names ⇒ Object
readonly
Returns the value of attribute flag_names.
-
#flags ⇒ Object
readonly
Returns the value of attribute flags.
-
#ip ⇒ Object
readonly
Returns the value of attribute ip.
-
#network_role ⇒ Object
readonly
Returns the value of attribute network_role.
-
#provider ⇒ Object
readonly
Returns the value of attribute provider.
-
#sources ⇒ Object
readonly
Returns the value of attribute sources.
-
#verdict ⇒ Object
readonly
Returns the value of attribute verdict.
Instance Method Summary collapse
-
#bad_asn? ⇒ Boolean
The ASN appears in brianhama/bad-asn-list — a curated catalog of hosting/cloud/colo ASNs.
- #cgnat? ⇒ Boolean
-
#flag?(name) ⇒ Boolean
Named ASN-level flag check: flag?(:bad_asn), flag?(:cdn), … (the full vocabulary is BinaryFormat::FLAG_NAMES.values / the README table).
- #hosting? ⇒ Boolean
- #infrastructure? ⇒ Boolean
-
#initialize(ip:, verdict:, asn: nil, as_org: nil, category: nil, network_role: nil, provider: nil, sources: [], flags: 0, context_flags: [], unrouted: false) ⇒ Result
constructor
A new instance of Result.
- #inspect ⇒ Object (also: #to_s)
-
#label ⇒ Object
The verdict as a short human-readable string ("Residential ISP", "Hosting / datacenter") — for admin tables, tooltips, log lines.
- #likely_human? ⇒ Boolean
- #mobile? ⇒ Boolean
- #private? ⇒ Boolean
- #relay? ⇒ Boolean
-
#to_h ⇒ Object
Everything, for logging and shadow mode.
- #tor? ⇒ Boolean
-
#unrouted? ⇒ Boolean
True when no ASN announces this IP (unallocated/unrouted space).
- #vpn? ⇒ Boolean
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.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/openasn/result.rb', line 60 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 # The raw u16 is a wire detail; apps want names. Decoded once here so # nobody downstream needs BinaryFormat bit knowledge. @flag_names = BinaryFormat.flag_names(flags).freeze @context_flags = context_flags.freeze @unrouted = unrouted freeze end |
Instance Attribute Details
#as_org ⇒ Object (readonly)
Returns the value of attribute as_org.
57 58 59 |
# File 'lib/openasn/result.rb', line 57 def as_org @as_org end |
#asn ⇒ Object (readonly)
Returns the value of attribute asn.
57 58 59 |
# File 'lib/openasn/result.rb', line 57 def asn @asn end |
#category ⇒ Object (readonly)
Returns the value of attribute category.
57 58 59 |
# File 'lib/openasn/result.rb', line 57 def category @category end |
#context_flags ⇒ Object (readonly)
Returns the value of attribute context_flags.
57 58 59 |
# File 'lib/openasn/result.rb', line 57 def context_flags @context_flags end |
#flag_names ⇒ Object (readonly)
Returns the value of attribute flag_names.
57 58 59 |
# File 'lib/openasn/result.rb', line 57 def flag_names @flag_names end |
#flags ⇒ Object (readonly)
Returns the value of attribute flags.
57 58 59 |
# File 'lib/openasn/result.rb', line 57 def flags @flags end |
#ip ⇒ Object (readonly)
Returns the value of attribute ip.
57 58 59 |
# File 'lib/openasn/result.rb', line 57 def ip @ip end |
#network_role ⇒ Object (readonly)
Returns the value of attribute network_role.
57 58 59 |
# File 'lib/openasn/result.rb', line 57 def network_role @network_role end |
#provider ⇒ Object (readonly)
Returns the value of attribute provider.
57 58 59 |
# File 'lib/openasn/result.rb', line 57 def provider @provider end |
#sources ⇒ Object (readonly)
Returns the value of attribute sources.
57 58 59 |
# File 'lib/openasn/result.rb', line 57 def sources @sources end |
#verdict ⇒ Object (readonly)
Returns the value of attribute verdict.
57 58 59 |
# File 'lib/openasn/result.rb', line 57 def verdict @verdict end |
Instance Method Details
#bad_asn? ⇒ Boolean
The ASN appears in brianhama/bad-asn-list — a curated catalog of hosting/cloud/colo ASNs. An infrastructure signal worth an admin's glance, NOT a verdict override and NOT a claim of abuse.
94 |
# File 'lib/openasn/result.rb', line 94 def bad_asn? = flag?(:bad_asn) |
#cgnat? ⇒ Boolean
102 |
# File 'lib/openasn/result.rb', line 102 def cgnat? = verdict == :cgnat |
#flag?(name) ⇒ Boolean
Named ASN-level flag check: flag?(:bad_asn), flag?(:cdn), … (the full vocabulary is BinaryFormat::FLAG_NAMES.values / the README table).
89 |
# File 'lib/openasn/result.rb', line 89 def flag?(name) = flag_names.include?(name) |
#hosting? ⇒ Boolean
97 |
# File 'lib/openasn/result.rb', line 97 def hosting? = verdict == :hosting |
#infrastructure? ⇒ Boolean
84 |
# File 'lib/openasn/result.rb', line 84 def infrastructure? = INFRASTRUCTURE_VERDICTS.include?(verdict) |
#inspect ⇒ Object Also known as: to_s
129 130 131 |
# File 'lib/openasn/result.rb', line 129 def inspect "#<OpenASN::Result #{ip} verdict=#{verdict}#{asn ? " AS#{asn}" : ''}#{as_org ? " (#{as_org})" : ''} sources=#{sources.inspect}>" end |
#label ⇒ Object
The verdict as a short human-readable string ("Residential ISP", "Hosting / datacenter") — for admin tables, tooltips, log lines.
82 |
# File 'lib/openasn/result.rb', line 82 def label = LABELS.fetch(verdict) |
#likely_human? ⇒ Boolean
85 |
# File 'lib/openasn/result.rb', line 85 def likely_human? = LIKELY_HUMAN_VERDICTS.include?(verdict) |
#mobile? ⇒ Boolean
100 |
# File 'lib/openasn/result.rb', line 100 def mobile? = verdict == :mobile |
#private? ⇒ Boolean
101 |
# File 'lib/openasn/result.rb', line 101 def private? = verdict == :private |
#relay? ⇒ Boolean
99 |
# File 'lib/openasn/result.rb', line 99 def relay? = verdict == :relay |
#to_h ⇒ Object
Everything, for logging and shadow mode. Stable keys — CarHey-style shadow analyses depend on this shape staying append-only. (flag_names added in 0.3.0: the raw bitfield is useless in a log line.)
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/openasn/result.rb', line 110 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, flag_names: flag_names, context_flags: context_flags, unrouted: unrouted? } end |
#tor? ⇒ Boolean
98 |
# File 'lib/openasn/result.rb', line 98 def tor? = verdict == :tor_exit |
#unrouted? ⇒ Boolean
True when no ASN announces this IP (unallocated/unrouted space).
105 |
# File 'lib/openasn/result.rb', line 105 def unrouted? = @unrouted |
#vpn? ⇒ Boolean
96 |
# File 'lib/openasn/result.rb', line 96 def vpn? = verdict == :vpn |