12

我一直在使用 ip-address gem,它似乎无法从形式的网络掩码转换

255.255.255.0 

进入 CIDR 表格

/24

有谁知道如何快速将前者转换为后者?

4

7 回答 7

14

这是快速而肮脏的方式

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

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

如果您要在多个地方使用该功能并且不介意猴子补丁,这可能会有所帮助:

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"
于 2009-12-01T13:08:06.400 回答
11

仅供参考,并让正在搜索的人可以轻松访问信息......

这是从 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"
于 2011-06-07T18:15:44.467 回答
5

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

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

其中“掩码”是一个类似 255.255.255.0 的字符串。如果“掩码”已经是 IP 地址的整数表示,您可以修改它并将第一个参数更改为“掩码”。

例如,如果掩码为“255.255.255.0”,则 IPAddr.new(mask,Socket::AF_INET).to_i 将变为 0xffffff00,然后与 0xffffffff 异或,等于 255。

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

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

于 2012-05-30T19:36:19.137 回答
5

快速而肮脏的转换:

"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") }

=> 对于数组中的每个元素:

.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"
于 2012-10-26T13:16:24.540 回答
2

如果你不需要使用 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" 
于 2011-10-25T14:52:25.270 回答
1
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 实例(地址,传递给 serialize_ipaddr)的私有实例变量 *@mask_addr 来实现屏蔽。这是不推荐的方式(因为实例变量不是类公共 API 的一部分,但在我看来,这比从#inspect解析字符串要好。

所以过程如下:

  1. 获取代表网络掩码的实例变量@mask_addr
  2. 获取它的二进制表示,例如255.255.255.0 -> 4294967040 -> 11111111111111111111111100000000
  3. 计算 base-2 数字中的 1-s 以获得 CIDR 掩码 (24)
  4. 组成一个包含地址和掩码的字符串

编辑:按照 NathanOliver 的要求添加了对实现的解释

于 2015-10-20T09:54:32.747 回答
0

这是一种没有 IPAddr gem 的方法

(('1'*cidr)+('0'*(32-cidr))).scan(/.{8}/m).map{|e|e.to_i(2)}.join('.')
于 2018-11-02T14:51:11.807 回答