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

255.255.255.0 

进入 CIDR 表格

/24

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

有帮助吗?

解决方案

下面是快速和肮脏的方式

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"

其他提示

正如仅供参考,并保持信息方便对于那些谁正在寻找...

下面是从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"

下面是一个更数学方法,避免不惜一切代价字符串:

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(掩模,插座:: AF_INET).to_i将成为0xffffff00,然后将其与为0xffffffff,它等于255进行XOR运算

我们添加1到使它256项主机的一个完整的范围内,则找到日志基256 2,它等于8(用于主机地址的位),然后减去8从32,其等于24 (用于网络地址的比特)。

我们然后浇铸到整数因为Math.log2返回float。

快捷粗略的转换:

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

=>添加填充

=>地图返回具有相同基数的阵列

.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"

如果您不需要使用IP地址的宝石,你可以做到这一点的 netaddr中宝石

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" 
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 的一部分,但这里它比解析字符串更好 #检查 在我看来。

所以流程如下:

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

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

下面是一种方法来做到这一点而不IPADDR宝石

(('1'*cidr)+('0'*(32-cidr))).scan(/.{8}/m).map{|e|e.to_i(2)}.join('.')
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top