Search code examples
rubyip-address

Ruby IPAddr: find address mask


I have an application where I process a lot of IP addresses (analysing Checkpoint firewall rule sets). At one point I want to check if a particular address object is a /32 or a 'network'.

Currently I am doing it like this:

next unless ip.inspect.match(/\/255\.255\.255\.255/)

it works but seems a bit inefficient but I can't see any method that extracts the mask from the address object.


Solution

  • Some parts of the Ruby core library are sometimes just sketched in, and IPAddr appears to be one of those that is, unfortunately, a little bit incomplete.

    Not to worry. You can fix this with a simple monkey-patch:

    class IPAddr
      def cidr_mask
        case (@family)
        when Socket::AF_INET
          32 - Math.log2((1<<32) - @mask_addr).to_i
        when Socket::AF_INET6
          128 - Math.log2((1<<128) - @mask_addr).to_i
        else
          raise AddressFamilyError, "unsupported address family"
        end
      end
    end
    

    That should handle IPv4 and IPv6 addresses:

    IPAddr.new('151.101.65.69').cidr_mask
    # => 32
    
    IPAddr.new('151.101.65.69/26').cidr_mask
    # => 26
    
    IPAddr.new('151.101.65.69/255.255.255.0').cidr_mask
    # => 24
    
    IPAddr.new('2607:f8b0:4006:800::200e').cidr_mask
    # => 128
    
    IPAddr.new('2607:f8b0:4006:800::200e/100').cidr_mask
    # => 100
    

    It's not necessarily the best solution here, but it works.