【问题标题】:IP Range to CIDR in Ruby/Rails?Ruby/Rails 中的 IP 范围到 CIDR?
【发布时间】:2012-11-04 14:08:03
【问题描述】:

我想做两件事:将 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,请告诉我。谢谢!

【问题讨论】:

    标签: ruby-on-rails ruby ip ip-address cidr


    【解决方案1】:

    好吧,要获得范围的 CIDR 表示法,您需要一个 IP 和网络位数(根据网络掩码计算)。

    要枚举给定范围的地址,您可以使用NetAddr (

    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
    

    【讨论】:

    • 谢谢。我最终将所有内容都转换为 int,将上下 ip 范围索引为 int 以进行非常快速的比较。您使用 NetAddr 的提示帮助我找到了正确的方向。我们的环境存在的问题是,特定 IP 范围和通配符的用户输入会使 CIDR 查找比我最初想象的复杂得多。
    • 将范围转换为单个 ips 就是“转换为 CIDR(块)”,但效率不高。
    • 我明白,时间已经过去了,但请注意NetAddr.range。此方法创建一个数组,因此如果您尝试为 /8 网络掩码创建范围,例如,它将创建一个包含 16777214 个项目 的数组,这样效率不高,并且会为您的应用。相反,我建议您使用以下构造:range = lower..upper。这将创建 Range 对象并允许您检查 CIDR 是否在范围内,如下所示:cidr = NetAddr::CIDR.create('192.168.1.0/24'); range.cover?(cidr)
    【解决方案2】:

    我怀疑您需要的一切都在 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}
    

    【讨论】:

    • 使用前记得require 'ipaddr'
    【解决方案3】:

    也许我误解了这个问题,但似乎这个问题的一个方面没有得到解决,即将一系列 ip 地址转换为一个或多个 CIDR 条目。

    我使用以下方法在我的防火墙上查找可疑的 ip 活动,如果它位于我不感兴趣的国家/地区允许访问(你知道你是谁)我使用 whois 来查找地址范围,并且然后按如下方式计算合并后的 CIDR,

    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),让它动态删除该 cidr。

    【讨论】:

      猜你喜欢
      • 2023-04-05
      • 2017-10-06
      • 1970-01-01
      • 1970-01-01
      • 2020-10-19
      • 1970-01-01
      • 2012-11-07
      • 2012-04-30
      • 2017-01-14
      相关资源
      最近更新 更多