首页 文章

红宝石中的网络掩码到CIDR

提问于
浏览
8

我一直在使用ip-address gem,它似乎没有能力从表单的网络掩码转换

255.255.255.0

进入CIDR表格

/24

有没有人有想法如何快速将前者转换为后者?

7 回答

  • 1

    这是快速而肮脏的方式

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

    应该有适当的功能,我找不到,所以我只算“1”

    如果你打算在很多地方使用这个功能并且不介意monkeypatching,这可能会有所帮助:

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

    然后你得到

    IPAddr.new('255.255.255.0').to_cidr
    # => "/24"
    
  • 12

    就像一个FYI一样,并且为那些正在搜索的人提供易于访问的信息...

    这是从CIDR转换为网络掩码格式的简单方法:

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

    例如:

    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"
    
  • 8

    这是一种更加数学化的方法,不惜一切代价避免使用字符串:

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

    “mask”是一个像255.255.255.0这样的字符串 . 如果“mask”已经是IP地址的整数表示,您可以修改它并将第一个参数更改为“mask” .

    因此,例如,如果掩码为“255.255.255.0”,则IPAddr.new(掩码,Socket :: AF_INET).to_i将变为0xffffff00,然后与0xffffffff进行xor'd,等于255 .

    我们将其加1以使其成为256个主机的完整范围,然后找到256的对数基数2,等于8(用于主机地址的位),然后从32减去8,等于24(位用于网络地址) .

    然后我们转换为整数,因为Math.log2返回一个浮点数 .

  • 0

    快速而肮脏的转换:

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

    =>我在数组中分割掩码

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

    =>对于Array中的每个元素:

    .to_i

    =>转换为整数

    .to_s(2)

    =>将整数转换为二进制

    .rjust(8, "0")

    =>添加填充

    => Map返回一个具有相同基数的数组

    .join

    =>将数组转换为完整字符串

    .count("1")

    =>计数“1”字符=>给出CIDR掩码

    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"
    
  • 5

    如果您不需要使用ip-address gem,则可以使用netaddr gem执行此操作

    require 'netaddr'
    
    def to_cidr_mask(dotted_mask)
      NetAddr::CIDR.create('0.0.0.0/'+dotted_mask).netmask
    end
    
    to_cidr_mask("255.224.0.0") # => "/11"
    
  • 5
    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"
    

    代码通过访问IPAddr实例的私有实例变量* @ mask_addr(地址,传递给serialize_ipaddr)来实现屏蔽 . 这不是推荐的方式(因为实例变量不是类公共API的一部分,但在这里它比在我看来解析来自#inspect的字符串更好 .

    所以过程如下:

    • 获取表示网络掩码的实例变量@mask_addr

    • 获取其二进制表示,例如 255.255.255.0 -> 4294967040 -> 11111111111111111111111100000000

    • 计算base-2数字中的1-s以获得CIDR掩码(24)

    • 组成一个包含地址和掩码的字符串

    编辑:根据NathanOliver的要求添加了对实现的解释

  • 2

    这是一种没有IPAddr gem的方法

    (('1'*cidr)+('0'*(32-cidr))).scan(/.{8}/m).map{|e|e.to_i(2)}.join('.')
    

相关问题