7

我想做两件事:将 IP 地址输入转换为 CIDR 以下是一些示例输入:

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。这一定是一个非常快速的查询,因为它是我的网络应用程序中非常常见的查找。我正在考虑做这样的事情:

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。

如果我忽略了任何主流方法、流行的 gem 或 repo,请告诉我。谢谢!

4

4 回答 4

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
于 2012-11-15T22:36:17.470 回答
7

我怀疑你需要的一切都在 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}
于 2012-11-15T22:22:54.383 回答
5

Maybe I'm misunderstanding the question, but it seems that one aspect of this question has not been addressed, that is, converting a range of ip addresses to one or more CIDR entries.

I use the following approach to lookup suspicious ip activity on my firewall, and if it is in a country that I'm not interested in allowing access (you know who you are) I use whois to lookup the address range, and then calculate the merged CIDRs as follows,

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)

This is a example on an internal network, but it is trivial to extend to a public ip block,

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]

Then I can pass that CIDR to my firewall software (shorewall) to have it dynamically drop that cidr(s).

于 2013-11-04T15:01:25.697 回答
0

您可以使用NetAddr (> 2.xx) gem

使用 parse 类方法从其字符串表示创建 IPv4Net 对象。如果未指定,它将默认为 /32 网络掩码。

private_ips = NetAddr::IPv4Net.parse('192.168.0.0/16')

现在您使用 rel 方法来确定与另一个 IPv4Net 对象的关系。例如,如果我们想知道 '2.3.4.5/31' 是否属于private_ips

private_ips.rel(NetAddr::IPv4Net.parse('2.3.4.5/31')).eql?(1) || private_ips.rel(NetAddr::IPv4Net.parse('2.3.4.5/31')).eql?(0)
=> false

private_ips.rel(NetAddr::IPv4Net.parse('192.168.0.0/31')).eql?(1) || private_ips.rel(NetAddr::IPv4Net.parse('192.168.0.0/31')).eql?(0)
=> true

注意: rel 方法确定与另一个 IPv4Net 的关系。回报:

  • 如果此 IPv4Net 是其他的超网,则为 1。
  • 如果两者相等,则为 0。
  • -1 如果此 IPv4Net 是其他的子网。
  • 如果网络不相关,则为零。

Gem 文档链接

于 2022-02-15T21:01:30.567 回答