Module: PrivateAddressCheck

Defined in:
lib/private_address_check.rb,
lib/private_address_check/version.rb,
lib/private_address_check/tcpsocket_ext.rb

Constant Summary collapse

IPV4_CIDRS =
[
  IPAddr.new("127.0.0.0/8"),     # Loopback
  IPAddr.new("0.0.0.0/8"),       # Current network (only valid as source address)
  IPAddr.new("169.254.0.0/16"),  # Link-local
  IPAddr.new("10.0.0.0/8"),      # Private network
  IPAddr.new("100.64.0.0/10"),   # Shared Address Space
  IPAddr.new("172.16.0.0/12"),   # Private network
  IPAddr.new("192.0.0.0/24"),    # IETF Protocol Assignments
  IPAddr.new("192.0.2.0/24"),    # TEST-NET-1, documentation and examples
  IPAddr.new("192.88.99.0/24"),  # IPv6 to IPv4 relay anycast (RFC 7526, deprecated)
  IPAddr.new("192.168.0.0/16"),  # Private network
  IPAddr.new("198.18.0.0/15"),   # Network benchmark tests
  IPAddr.new("198.51.100.0/24"), # TEST-NET-2, documentation and examples
  IPAddr.new("203.0.113.0/24"),  # TEST-NET-3, documentation and examples
  IPAddr.new("224.0.0.0/4"),     # IP multicast (former Class D network)
  IPAddr.new("240.0.0.0/4")      # Reserved (former Class E network, covers 255.255.255.255)
].freeze
IPV6_CIDRS =
[
  IPAddr.new("::/128"),          # Unspecified address (RFC 4291)
  IPAddr.new("::1/128"),         # Loopback
  IPAddr.new("64:ff9b:1::/48"),  # IPv4/IPv6 translation, local use (RFC 8215)
  IPAddr.new("100::/64"),        # Discard prefix (RFC 6666)
  IPAddr.new("100:0:0:1::/64"),  # Dummy IPv6 Prefix (RFC 9780)
  IPAddr.new("2001::/32"),       # Teredo tunneling
  IPAddr.new("2001:2::/48"),     # Benchmarking (RFC 5180)
  IPAddr.new("2001:10::/28"),    # Deprecated (previously ORCHID)
  IPAddr.new("2001:20::/28"),    # ORCHIDv2
  IPAddr.new("2001:db8::/32"),   # Addresses used in documentation and example source code
  IPAddr.new("3fff::/20"),       # Documentation (RFC 9637)
  IPAddr.new("5f00::/16"),       # Segment Routing (SRv6) SIDs (RFC 9602)
  IPAddr.new("fc00::/7"),        # Unique local address
  IPAddr.new("fe80::/10"),       # Link-local address
  IPAddr.new("ff00::/8")         # Multicast
].freeze
IPV4_MAPPED_CIDRS =

Embedded IPv4 representations in IPv6, generated from IPV4_CIDRS so that addresses like ::ffff:10.0.0.1 cannot bypass the private-address check.

IPV4_CIDRS.flat_map do |cidr|
  prefix = cidr.prefix + 96
  ip = cidr.to_s
  octets = ip.split(".").map(&:to_i)
  v4_hex = format("%<high>04x:%<low>04x", high: (octets[0] << 8) | octets[1], low: (octets[2] << 8) | octets[3])
  [
    IPAddr.new("::#{ip}/#{prefix}"),                       # IPv4-compatible (deprecated)
    IPAddr.new("::ffff:#{ip}/#{prefix}"),                  # IPv4-mapped (RFC 4291)
    IPAddr.new("::ffff:0:#{ip}/#{prefix}"),                # IPv4-translated (RFC 2765)
    IPAddr.new("64:ff9b::#{ip}/#{prefix}"),                # NAT64 well-known prefix (RFC 6052)
    IPAddr.new("2002:#{v4_hex}::/#{cidr.prefix + 16}")     # 6to4 (RFC 3056)
  ]
end.freeze
CIDR_LIST =
(IPV4_CIDRS + IPV6_CIDRS + IPV4_MAPPED_CIDRS).freeze
VERSION =
"0.8.0".freeze
PrivateConnectionAttemptedError =
Class.new(StandardError)

Class Method Summary collapse

Class Method Details

.only_public_connectionsObject



8
9
10
11
12
13
# File 'lib/private_address_check/tcpsocket_ext.rb', line 8

def only_public_connections
  Thread.current[:private_address_check] = true
  yield
ensure
  Thread.current[:private_address_check] = false
end

.private_address?(address) ⇒ Boolean

Returns:

  • (Boolean)


65
66
67
68
69
# File 'lib/private_address_check.rb', line 65

def private_address?(address)
  CIDR_LIST.any? do |cidr|
    cidr.include?(address)
  end
end

.resolves_to_private_address?(hostname) ⇒ Boolean

Returns:

  • (Boolean)


71
72
73
74
75
76
77
78
# File 'lib/private_address_check.rb', line 71

def resolves_to_private_address?(hostname)
  ips = Socket.getaddrinfo(hostname, nil).map { |info| IPAddr.new(info[3]) }
  return true if ips.empty?

  ips.any? do |ip|
    private_address?(ip)
  end
end