Search code examples
rubysocketsip-address

Identify all relevant ip addresses from ruby Socket.ip_address_list


When using rubies Socket.ip_address_list, it will return an array of addr_info (https://ruby-doc.org/stdlib-2.0.0/libdoc/socket/rdoc/Addrinfo.html)

Example:

require 'socket'

addr_infos = Socket.ip_address_list

This array could be iterated and listed by all defined ip_addresses and attributes like

addr_infos.each do |addr_info|
  puts "#{addr_info.ip_address} 
         #{addr_info.ipv4? ? 'ipv4? ' : ''}" + 
        "#{addr_info.ipv4_loopback? ? 'ipv4_loopback? ' : ''}" +
        "#{addr_info.ipv4_private? ? 'ipv4_private? ' : ''}" +
        "#{addr_info.ipv4_multicast? ? 'ipv4_multicast? ' : ''}" +
        "#{addr_info.ipv6? ? 'ipv6? ' : '' }" +
        "#{addr_info.ipv6_loopback? ? 'ipv6_loopback? ' : ''}" +
        "#{addr_info.ipv6_linklocal? ? 'ipv6_linklocal? ' : ''}" +
        "#{addr_info.ipv6_multicast? ? 'ipv6_multicast? ' : ''}" +
        "#{addr_info.ipv6_sitelocal? ? 'ipv6_sitelocal? ' : ''}" +
        "#{addr_info.ipv6_unique_local? ? 'ipv6_unique_local? ' : ''}" +
        "#{addr_info.ipv6_mc_global? ? 'ipv6_mc_global? ' : ''}" +
        "#{addr_info.ipv6_unspecified? ? 'ipv6_unspecified? ' : ''}"
end

The result will look like

127.0.0.1
       ipv4? ipv4_loopback? 
192.168.178.33
       ipv4? ipv4_private? 
1.2.4.5
       ipv4?
::1
       ipv6? ipv6_loopback?
fe80::1%lo0
       ipv6? ipv6_linklocal? 
fe80::aede:48ff:fe00:1122%en5
       ipv6? ipv6_linklocal? 
fe80::68:e785:4cfb:41e6%en0
       ipv6? ipv6_linklocal? 
fe80::50fc:46ff:fe4c:c2b4%awdl0
       ipv6? ipv6_linklocal? 
fe80::3203:d609:ff08:151d%utun0
       ipv6? ipv6_linklocal?
fd00::ffff:aaaa:bbbb:7005
       ipv6? ipv6_unique_local?
2003:ffff:4723:aaaa:bbbb:8888:269a:42a4
       ipv6?

Q: How to identify "correct" ip-addresses to bind listening services to?

IMHO it would be easy to identify the IPv4 addresses like:

IPv4 = ipv4? && (ipv4_loopback? || ipv4_private? || !(ipv4_loopback? || ipv4_private? || ipv4_multicast?))

But in case of those many ipv6_? attributes I wondering what to to check to identify the IPv6 addresses.

Is this the correct suggestion?

It is an IPv6 address when:

a. ipv6? is true and no other ipv6_...? attribute is true
b. ipv6? and ipv6_loopback? are true
c. ipv6? and ipv6_unique_local are true

Do I miss something from IPv6 addresses?


Solution

  • This is my current solution in addition to this question. Maybe some may add a comment or vote to make sure that this goes the right direction

    ip_addresses_for_host = []
    Socket.ip_address_list.each do |a|
    # test for all local valid ipv4 and ipv6 ip_addresses
    # check question on stackoverflow for details
    # https://stackoverflow.com/questions/59770803/identify-all-relevant-ip-addresses-from-ruby-socket-ip-address-list
    ip_addresses_for_host << a.ip_address if \
      (a.ipv4? &&
        (a.ipv4_loopback? || a.ipv4_private? ||
         !(a.ipv4_loopback? || a.ipv4_private? || a.ipv4_multicast?)
        )
      ) ||
      (a.ipv6? &&
        (a.ipv6_loopback? || a.ipv6_unique_local? ||
         !(a.ipv6_loopback? || a.ipv6_unique_local? || a.ipv6_linklocal? || a.ipv6_multicast? || a.ipv6_sitelocal? ||
           a.ipv6_mc_global? || a.ipv6_mc_linklocal? || a.ipv6_mc_nodelocal? || a.ipv6_mc_orglocal? || a.ipv6_mc_sitelocal? ||
           a.ipv6_v4compat? || a.ipv6_v4mapped? || a.ipv6_unspecified?)
        )
      )
    end
    

    This will resolve for IPv4:

    a. 127.0.0.1
    b. private addresses like 192.168./16, 10./8, ...
    c. other ipv4 addresses like 1.2.3.4

    and for IPv6:

    a. ::1
    b. fc00::
    c. abcd::

    Appreciate if someone would add more knowledge.