2009-12-01 99 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