Module: RightSupport::Net::AddressHelper
- Included in:
- RightSupport::Net
- Defined in:
- lib/right_support/net/address_helper.rb
Overview
A helper module that provides some useful methods for querying the local machine about its network addresses.
This module is automatically included into the eigenclass of RightSupport::Net for convenience. Any of the methods available in this module can be called as RightSupport::Net.foo without needing to include this module.
Defined Under Namespace
Classes: NoSuitableInterface
Constant Summary collapse
- PRIVATE_IP_REGEX =
/^(10\.|192\.168\.|172\.(1[6789]|2[0-9]|3[01]))/
- LOOPBACK_IP_REGEX =
/^(127\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})/
Instance Method Summary collapse
-
#local_hostname_addresses(address_family) ⇒ Object
Determine all network addresses of the local machine that are resolvable using either the machine’s hostname or “localhost”.
-
#local_routable_address(address_family) ⇒ Object
Determine the network address of some local interface that has a route to the public Internet.
-
#my_ipv4_address(flavor = :private) ⇒ Object
Determine an IPv4 address of the local machine that falls into the given range of IP address space (public, private or loopback).
-
#my_ipv4_addresses(flavor = :private) ⇒ Object
Determine all IPv4 addresses of the local machine that fall into the given range of IP address space (public, private or loopback).
Instance Method Details
#local_hostname_addresses(address_family) ⇒ Object
Determine all network addresses of the local machine that are resolvable using either the machine’s hostname or “localhost”. Typically this allows us to discover the local IP addresses of “interesting” network interfaces without relying on OS-specific tools such as ifconfig/ipconfig.
Parameters
- address_family(Integer)
-
Socket::AF_INET or Socket::AF_INET6
Return
- addresses(Array)
-
a list of IP addresses in dotted-quad notation
84 85 86 87 88 89 90 91 92 93 |
# File 'lib/right_support/net/address_helper.rb', line 84 def local_hostname_addresses(address_family) loopback = Socket.getaddrinfo('localhost', 1, address_family, Socket::SOCK_STREAM, nil, nil).collect { |x| x[3] } real = Socket.getaddrinfo(Socket.gethostname, 1, address_family, Socket::SOCK_STREAM, nil, nil).collect { |x| x[3] } (loopback + real).uniq end |
#local_routable_address(address_family) ⇒ Object
Determine the network address of some local interface that has a route to the public Internet.
On some systems, Socket.getaddrinfo(Socket.gethostname, …) does not return any IP addresses, for instance because the local hostname cannot be resolved by DNS. This method can be used to detect “my IP address” in such cases.
This code does NOT make a connection or send any packets (to 64.233.187.99 which is google). Since UDP is a stateless protocol, connect() merely makes a system call which figures out how to route the packets based on the address and what interface (and therefore IP address) it should bind to. addr() returns an array containing the family (AF_INET), local port, and local address (which is what we want) of the socket.
Parameters
- address_family(Integer)
-
Socket::AF_INET or Socket::AF_INET6
Return
- address(String)
-
a single IP address in dotted-quad notation
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/right_support/net/address_helper.rb', line 55 def local_routable_address(address_family) case address_family when Socket::AF_INET remote_address = '64.233.187.99' when Socket::AF_INET6 remote_address = '2607:f8b0:4003:c00::68' else raise ArgumentError, "Routable address discovery only works for AF_INET or AF_INET6" end # turn off reverse DNS resolution temporarily orig, Socket.do_not_reverse_lookup = Socket.do_not_reverse_lookup, true UDPSocket.open(address_family) do |s| s.connect remote_address, 1 s.addr.last end ensure Socket.do_not_reverse_lookup = orig end |
#my_ipv4_address(flavor = :private) ⇒ Object
Determine an IPv4 address of the local machine that falls into the given range of IP address space (public, private or loopback). If multiple suitable addresses are found, the same address will be consistently returned but there is no way to influence which address that will be.
Parameters
- flavor(Symbol)
-
One of :public, :private or :loopback
Return
- addresses(Array)
-
a list of IP addresses in dotted-quad notation
129 130 131 132 133 134 135 |
# File 'lib/right_support/net/address_helper.rb', line 129 def my_ipv4_address(flavor=:private) candidates = my_ipv4_addresses(flavor) raise NoSuitableInterface, "No interface had a #{flavor} IPv4 address" if candidates.empty? #Ensure we consistently the same interface by doing a lexical sort return candidates.sort.first end |
#my_ipv4_addresses(flavor = :private) ⇒ Object
Determine all IPv4 addresses of the local machine that fall into the given range of IP address space (public, private or loopback).
Parameters
- flavor(Symbol)
-
One of :public, :private or :loopback
Return
- addresses(Array)
-
a list of IP addresses in dotted-quad notation
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/right_support/net/address_helper.rb', line 103 def my_ipv4_addresses(flavor=:private) all = local_hostname_addresses(Socket::AF_INET) all << local_routable_address(Socket::AF_INET) all.uniq! case flavor when :public return all.select { |ip| ip !~ PRIVATE_IP_REGEX && ip !~ LOOPBACK_IP_REGEX } when :private return all.select { |ip| ip =~ PRIVATE_IP_REGEX } when :loopback return all.select { |ip| ip =~ LOOPBACK_IP_REGEX } else raise ArgumentError, "flavor must be :public, :private or :loopback" end end |