Class: Otto::Privacy::AsnResolver

Inherits:
Object
  • Object
show all
Defined in:
lib/otto/privacy/asn_resolver.rb

Overview

Autonomous System Number (ASN) resolution for IP addresses

Provides the network operator an address belongs to, as a privacy-safe label a downstream allow/deny rule can compare directly. Resolution is database-only and operates on Otto’s already-MASKED IP, exactly as GeoResolver’s database fallback does — the unmasked address never reaches this resolver.

Resolution order (first hit wins), when a privacy Config is supplied: 1. Local MMDB lookup, masked before lookup (Config#asn_db_reader) 2. ‘**’ (unknown)

Resolution is honest: when no database resolves an ASN, the answer is ‘’ — never a guess. A caller can therefore distinguish three states: nil (ASN resolution is switched off), ‘’ (on, but no answer), and a real label.

Why database-only

Unlike country, no CDN publishes a client-ASN header with meaningful deployment, so there is no header tier to trust. Staying database-only also keeps ASN clear of the geo_header/trusted_proxy_depth boot conflict (Security::Config::GEO_HEADER_DEPTH_CONFLICT_MESSAGE): there is no header to be silently ignored under count-based proxy trust.

Masking and accuracy

IPv4 BGP routes are not announced longer than /24, so a /24-masked address lands in the same announced prefix — and therefore the same ASN — as the real one. That equivalence is what makes a masked lookup honest here, and it is weaker than it looks for IPv6: at +octet_precision: 1+ Otto zeroes the last 80 bits (a /48), which is coarser than many IPv6 announcements. Treat IPv6 ASN as best-effort.

Examples:

Configuring

otto.configure_ip_privacy(asn: true, asn_db_path: 'data/GeoLite2-ASN.mmdb')

Reading

req.asn                       # => 'AS15169' | '**' | nil
env['otto.privacy.asn']

Constant Summary collapse

UNKNOWN =

Returned when ASN resolution is enabled but nothing resolved. Shared spelling with GeoResolver::UNKNOWN so consumers can treat every privacy label the same way.

'**'
RESERVED =

Reserved ASNs that carry no operator meaning: 0 is “reserved by the IANA” (RFC 7607) and 23456 is the AS_TRANS placeholder a 2-byte-only speaker substitutes for a 4-byte ASN (RFC 6793). A database that returns either has told us nothing, so both resolve to UNKNOWN rather than being dressed up as an answer.

[0, 23_456].freeze
MAX_ASN =

Highest assignable ASN; 4_294_967_295 is reserved (RFC 7300).

4_294_967_294

Class Method Summary collapse

Class Method Details

.resolve(ip, config = nil) ⇒ String

Resolve an ASN label for an IP address.

Parameters:

  • ip (String)

    the ALREADY-MASKED client IP

  • config (Otto::Privacy::Config, nil) (defaults to: nil)

    privacy configuration

Returns:



70
71
72
73
74
# File 'lib/otto/privacy/asn_resolver.rb', line 70

def resolve(ip, config = nil)
  return UNKNOWN if ip.nil? || ip.empty?

  check_asn_database(ip, config) || UNKNOWN
end