2012-11-15 18 views
6

Ich möchte zwei Dinge tun: Wandeln Sie IP-Adresse Eingänge in CIDR Hier sind einige Beispiele Eingänge:IP-Bereich zu CIDR in Ruby/Rails?

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

Überprüfen Sie, ob eine bestimmte IP-Adresse in jede CIDR fällt. Dies muss eine sehr schnelle Abfrage sein, da es sich um eine sehr häufige Suche in meiner Web-App handelt. Ich denke, so etwas wie dies zu tun:

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

Ich denke Umwandlung IP-Bereiche in CIDR wird Lookups sein lassen schneller als das, was wir jetzt tun, die die IP-Adressen in ganzzahlige Oktetts bricht. Wir indexieren dann die ersten zwei Oktettsätze, um sie teilweise mit IPs abzugleichen. Eine andere Option könnte sein, alles in Ints umzuwandeln und Vergleiche auf diese Weise durchzuführen. Ich mag diese IPAddr.new("1.1.1.1").to_i zu ints mit etwas umwandeln, aber dann würde ich eine obere und untere IP für jeden Bereich anstatt nur einen einzigen CIDR speichern muß.

Bitte lassen Sie mich wissen, ob ich irgendwelche Mainstream-Ansätze bin mit Blick auf beliebte Edelsteine ​​oder Repo. Vielen Dank!

Antwort

10

Nun, um die CIDR-Schreibweise eines Bereichs zu erhalten, müssen Sie eine IP und die Anzahl der Netzwerk-Bits (aus dem netmask berechnet) .

Um die Adressen eines bestimmten Bereichs aufzulisten, können Sie das NetAddr (< 2.x) Juwel verwenden.

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'] 

Sie können auch die Bits aus dem netmask on the fly berechnen:

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

und einen Bereich zu schaffen, basierend auf zwei IPs:

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'] 

Also jetzt, dass Sie erstellen können ein CIDR-Bereich, können Sie prüfen, ob eine IP-Adresse dazu gehört:

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

+1 für NetAddr. Es ist sehr cool. –

+0

Danke dafür. Letztendlich konvertierte ich alles in Ints, indexierte die oberen und unteren IP-Bereiche als Ints, um wirklich schnelle Vergleiche zu machen.Dein Tipp, den NetAddr zu benutzen, half mir, in die richtige Richtung zu kommen. Das Problem mit unserer Umgebung ist, dass Benutzereingaben von bestimmten IP-Bereichen und Platzhaltern CIDR-Lookup viel komplizierter als ich ursprünglich dachte. – John

+0

Umwandlung eines Bereichs in einzelne ips ist OFC "Umwandlung in CIDR (Blöcke)", aber nicht sehr effizient. – Stefan

5

Ich vermute, alles, was Sie ist in IPAddr müssen. Ich diese verwenden, um zu sehen, ob das Remote-IP von einem privaten Netzwerk kommt:

['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

Denken Sie daran, 'require‚ipaddr'' bevor Sie es. – tothemario

5

ich Mißverständnis die Frage Mag sein, aber es scheint, dass ein Aspekt dieser Frage nicht angesprochen wurde, das heißt, eine Reihe von IP-Adressen an einen oder mehrere CIDR Einträge konvertieren.

Ich verwende den folgenden Ansatz, um verdächtige IP-Aktivitäten auf meiner Firewall nachzuschlagen, und wenn es in einem Land ist, das nicht daran interessiert ist, den Zugriff zu erlauben (Sie wissen, wer Sie sind), verwende ich Whois, um den Adressbereich zu suchen. und dann berechnen die fusionierte CIDRs wie folgt

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) 

Dies ist ein Beispiel für ein internes Netzwerk, aber es ist trivial zu einem öffentlichen IP-Block zu erweitern,

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] 

dann kann ich, dass CIDR passieren an meine Firewall-Software (shorewall), um diese CID dynamisch fallen zu lassen r (s).