7

2つのことをしたいと思います。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に該当するかどうかを確認します。これは、私のWebアプリで非常に一般的なルックアップであるため、非常に高速なクエリである必要があります。私はこのようなことをすることを考えています:

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

IP範囲をCIDRに変換すると、IPを整数オクテットに分割する現在行っている処理よりも高速にルックアップできるようになると思います。次に、最初の2セットのオクテットにインデックスを付けて、IPと部分的に一致させます。別のオプションは、すべてをintに変換し、その方法で比較を行うことです。このようなものでintに変換しますIPAddr.new("1.1.1.1").to_iが、単一のCIDRではなく、範囲ごとに上限と下限のIPを格納する必要があります。

主流のアプローチ、人気のある宝石、レポを見落としている場合はお知らせください。ありがとう!

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

そして、2つの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

質問を誤解しているかもしれませんが、この質問の1つの側面、つまり、IPアドレスの範囲を1つ以上の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を動的に削除することができます。

于 2013-11-04T15:01:25.697 に答える
0

NetAddr(> 2.xx)gemを使用できます。

解析クラスメソッドを使用して、文字列表現から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。
  • 2つが等しい場合は0。
  • このIPv4Netが他のサブネットである場合は-1。
  • ネットワークが無関係の場合はnil。

宝石ドキュメントリンク

于 2022-02-15T21:01:30.567 に答える