Netmask to CIDR in ruby

前端 未结 7 879
灰色年华
灰色年华 2020-12-29 11:13

I\'ve been using the ip-address gem and it doesn\'t seem to have the ability to convert from a netmask of the form

255.255.255.0 

into the

相关标签:
7条回答
  • 2020-12-29 11:34

    Here is a way to do it without the IPAddr gem

    (('1'*cidr)+('0'*(32-cidr))).scan(/.{8}/m).map{|e|e.to_i(2)}.join('.')
    
    0 讨论(0)
  • 2020-12-29 11:36
    require 'ipaddr'
    
    def serialize_ipaddr(address)
      mask = address.instance_variable_get(:@mask_addr).to_s(2).count('1')
      "#{address}/#{mask}"
    end
    
    serialize_ipaddr(IPAddr.new('192.168.0.1/24')) # => "192.168.0.0/24"
    

    The code achieves the masking by accessing private instance variable *@mask_addr) of IPAddr instance (address, passed into serialize_ipaddr). This is not recommended way (as the instance variables are not part of the classes public API but here it's better than parsing the string from #inspect in my opinion.

    So the process is as follows:

    1. Get the instance variable @mask_addr that represents netmask
    2. Get its binary representation e.g. 255.255.255.0 -> 4294967040 -> 11111111111111111111111100000000
    3. Count the 1-s in the base-2 number to get CIDR mask (24)
    4. Make up a string consisting the address & mask

    EDIT: Added explanation to the implementation as requested by NathanOliver

    0 讨论(0)
  • 2020-12-29 11:40

    Here is the quick and dirty way

    require 'ipaddr'
    puts IPAddr.new("255.255.255.0").to_i.to_s(2).count("1")
    

    There should be proper function for that, I couldn't find that, so I just count "1"

    If you're going to be using the function in a number of places and don't mind monkeypatching, this could help:

    IPAddr.class_eval
      def to_cidr
        "/" + self.to_i.to_s(2).count("1")
      end
    end
    

    Then you get

    IPAddr.new('255.255.255.0').to_cidr
    # => "/24"
    
    0 讨论(0)
  • 2020-12-29 11:48

    Just as a FYI, and to keep the info easily accessible for those who are searching...

    Here's a simple way to convert from CIDR to netmask format:

    def cidr_to_netmask(cidr)
      IPAddr.new('255.255.255.255').mask(cidr).to_s
    end
    

    For instance:

    cidr_to_netmask(24) #=> "255.255.255.0"
    cidr_to_netmask(32) #=> "255.255.255.255"
    cidr_to_netmask(16) #=> "255.255.0.0"
    cidr_to_netmask(22) #=> "255.255.252.0"
    
    0 讨论(0)
  • 2020-12-29 11:51

    Quick and dirty conversion:

    "255.255.255.0".split(".").map { |e| e.to_i.to_s(2).rjust(8, "0") }.join.count("1").split(".")

    => I split mask in an Array

    .map { |e| e.to_i.to_s(2).rjust(8, "0") }

    => For each element in Array:

    .to_i

    => Convert into integer

    .to_s(2)

    => Convert integer into binary

    .rjust(8, "0")

    => Add padding

    => Map return a Array with same cardinality

    .join

    => Convert Array into a full string

    .count("1")

    => Count "1" characters => Give CIDR mask

        def mask_2_ciddr mask
          "/" + mask.split(".").map { |e| e.to_i.to_s(2).rjust(8, "0") }.join.count("1").to_s
        end
    
        mask_2_ciddr "255.255.255.0"
        => "/24"
        mask_2_ciddr "255.255.255.128"
        => "/25"
    
    0 讨论(0)
  • 2020-12-29 11:53

    Here's a more mathematical approach, avoiding strings at all costs:

    def cidr_mask
        Integer(32-Math.log2((IPAddr.new(mask,Socket::AF_INET).to_i^0xffffffff)+1))
    end
    

    with "mask" being a string like 255.255.255.0. You can modify it and change the first argument to just "mask" if "mask" is already an integer representation of an IP address.

    So for example, if mask was "255.255.255.0", IPAddr.new(mask,Socket::AF_INET).to_i would become 0xffffff00, which is then xor'd with 0xffffffff, which equals 255.

    We add 1 to that to make it a complete range of 256 hosts, then find the log base 2 of 256, which equals 8 (the bits used for the host address), then subtract that 8 from 32, which equals 24 (the bits used for the network address).

    We then cast to integer because Math.log2 returns a float.

    0 讨论(0)
提交回复
热议问题