2012-11-15 40 views
6

我想要做的兩件事情:將IP地址投入CIDR 下面是一些例子輸入:在Ruby/Rails中使用CIDR的IP範圍?

1.1.1.1  
192.168.*.* #=> 192.168.0-255.0-255 
192.168.1.2-20 
1.1.1-10.1-100 

檢查給定的IP地址屬於任何CIDR。這必須是一個非常快速的查詢,因爲它是我的web應用程序中非常常見的查詢。我想這樣做是這樣的:

def matches?(request) 
    valid = @ips.select {|cidr| cidr.contains?(request.remote_ip) } 
    !valid.empty? 
end 

我想,把IP地址範圍爲CIDR會讓查找比我們現在在做什麼,這是打破了IP的成整數個字節更快。然後,我們將前兩組八位字節索引爲與IP的部分匹配。另一種選擇可能是將所有內容都轉換爲整數並進行比較。我會轉換爲像這樣的IPAddr.new("1.1.1.1").to_i整數整數,但然後我需要存儲每個範圍的上限和下限IP,而不是隻有一個CIDR。

請讓我知道,如果我忽略任何主流方法,流行的寶石或回購。謝謝!

回答

10

好了,來獲得一定範圍的CIDR標記,你需要一個IP和網絡的比特數(從網絡掩碼計算) 。

要枚舉給定範圍的地址,您可以使用NetAddr(< 2.x)gem。

p NetAddr::CIDR.create('192.168.1.0/24').enumerate 
    => ['192.168.1.0', '192.168.1.1', '192.168.1.2'... '192.168.1.255'] 

您可以從網絡掩碼上飛也算位:

mask_int = NetAddr.netmask_to_i('255.255.255.0') 
p NetAddr.mask_to_bits(mask_int) 
    => 24 

而且基於兩個IP地址來創建一個範圍:

lower = NetAddr::CIDR.create('192.168.1.1') 
upper = NetAddr::CIDR.create('192.168.1.10') 
p NetAddr.range(lower, upper) 
    => ['192.168.1.2', '192.168.1.3'... '192.168.1.9'] 

所以,現在你可以創建一個CIDR範圍,你可以檢查,看是否IP是它的一部分:

cidr = NetAddr::CIDR.create('192.168.1.0/24') 
p cidr.contains?('192.168.1.10') 
    => true 
+0

對於NetAddr爲+1。它非常酷。 –

+0

感謝您的支持。我最終將所有內容都轉換爲int,將整個上下ip範圍索引爲int,以便快速進行比較。您使用NetAddr的提示幫助我朝正確的方向發展。我們的環境問題是用戶輸入特定的IP範圍和通配符會使CIDR查找比我最初想象的複雜得多。 – John

+0

將範圍轉換爲單個ips是「轉換爲CIDR(塊)」,但效率不高。 – Stefan

5

我懷疑你需要的一切都在IPAddr中。我使用它來查看遠程IP是從專用網絡來:

['127.0.0.0/8', '10.0.0.0/8', '172.16.0.0/12', '192.168.0.0/16', '192.168.10.0/8' 
].none?{|block| IPAddr.new(block) === request.remote_ip} 
+2

請記住在使用之前需要'ipaddr''。 – tothemario

5

也許我誤解了這個問題,但似乎這個問題的一個方面還沒有得到解決,即將一系列IP地址轉換爲一個或多個CIDR條目。

我使用下面的方法在我的防火牆上查找可疑的ip活動,如果它在我不感興趣允許訪問的國家(您知道您是誰),我使用whois來查找地址範圍,然後計算合併CIDRs如下,

whois xxx.yyy.zzz.123 
# find address range for this ip 
range="xxx.yyy.zzz.0-xxx.yyy.zzz.255".split(/\s*-\s*/) 
lower=range[0] 
upper=range[1] 
ip_net_range = NetAddr.range(lower, upper, :Inclusive => true, :Objectify => true) 
cidrs = NetAddr.merge(ip_net_range, :Objectify => true) 

這是一個內部網絡上的例子,但它是微不足道的延伸到公共IP塊,

whois 192.168.1.3 
range="192.168.0.0 - 192.168.255.255".split(/\s*-\s*/) 
upper=range[0] 
lower=range[1] 
ip_net_range = NetAddr.range(lower, upper, :Inclusive => true, :Objectify => true) 
cidrs = NetAddr.merge(ip_net_range, :Objectify => true) 
p cidrs 
[192.168.0.0/16] 

然後我可以傳遞CIDR到我的防火牆軟件(shorewall),讓它動態地刪除該cid R(S)。