2009-12-01 102 views
7

我一直在使用的IP地址宝石一直和它似乎不具备从形式网络掩码CIDR红宝石

255.255.255.0 

的子网掩码转换成CIDR形式的能力

/24 

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

+0

一种解决方案可能是使用ipadmin宝石,而不是它看起来更完整。 我仍然有兴趣从代码的角度来看看这个解决方案。 –

回答

11

这里是快速和肮脏的方式

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" 
+0

我不确定有什么比使用count更合适(“1”)。也许这样? 32 - (2 ** 32 - 1 - IPAddr.new(“255.255.255.0”)to_i).to_s(2)。长度' –

+0

在C中,我可能会转移到右侧,并使用&1进行测试,直到它达到1,例如,“bits = 32; unsigned int ipaddr = 0xFFFFFF00; while(ipaddr&1 == 0){ipaddr = ipaddr> > 1; bits - ;}'对于上面的情况,我只需要向右移8次就可以了。 – YOU

9

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

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

如果您不需要使用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" 
4

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

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的等于8(用于主机地址的位)的日志库2,然后从32中减去8,即等于24(用于网络地址的位)。

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

4

快速和脏的转换:

.to_i

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

=>我在Array

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

=>在阵列分割掩码对于每个元素

=>转换成整数

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

该代码通过访问私人达到掩蔽实例变量* @ mask_addr)的IPAddr实例(地址,传入serialize_ipaddr)。这是不推荐的方式(如实例变量不是类的公共API的一部分,但在这里比在我看来解析来自#inspect字符串更好

所以过程如下:

  1. 获取实例变量@mask_addr表示掩码
  2. 获取其二进制表示例如255.255.255.0 -> 4294967040 -> 11111111111111111111111100000000
  3. 计数的1-S中的基极 - 2号以获取CIDR掩模(24)
  4. 弥补由地址&面具

编辑字符串:加解释的实施由NathanOliver

的要求
+0

尽管此代码片段可能会解决问题,但[包括解释](http://meta.stackexchange.com/questions/114762/explaining-entirely- code-based-answers)确实有助于提高您的质量帖子。请记住,您将来会为读者回答问题,而这些人可能不知道您的代码建议的原因。 – NathanOliver