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
72 73 74 75 76 77 78 79 80 81 |
# File 'lib/right_support/net/address_helper.rb', line 72 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
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
# File 'lib/right_support/net/address_helper.rb', line 43 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
117 118 119 120 121 122 123 |
# File 'lib/right_support/net/address_helper.rb', line 117 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
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/right_support/net/address_helper.rb', line 91 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 |