2012-11-15 11 views
6

voglio fare due cose: Convertire ingressi indirizzo IP in CIDR Qui ci sono alcuni input di esempio:Intervallo IP su 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 

Verificare se un dato indirizzo IP rientra in una CIDR. Questa deve essere una query molto veloce, in quanto è una ricerca molto comune nella mia app web. Sto pensando di fare qualcosa di simile:

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

Penso convertire intervalli di indirizzi IP in CIDR lascerò che le ricerche più veloce di quello che stiamo facendo ora, che sta rompendo in ottetti interi del IP. Quindi indicizziamo i primi due set di ottetti parzialmente corrispondenti agli IP. Un'altra opzione potrebbe essere la conversione di tutto in int e fare confronti in questo modo. Mi piacerebbe convertire in int con qualcosa di simile a questo IPAddr.new("1.1.1.1").to_i ma poi avrei bisogno di memorizzare un IP superiore e inferiore per ogni intervallo invece di un solo CIDR.

Per favore fatemi sapere se sto trascurando qualsiasi approccio tradizionale, gemme popolari o repo. Grazie!

risposta

10

Beh, per ottenere la notazione CIDR di una serie, è necessario un IP e il numero di bit di rete (calcolato dalla maschera di rete) .

Per enumerare gli indirizzi di un determinato intervallo, è possibile utilizzare la gemma NetAddr (< 2.x).

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

È possibile anche calcolare i bit dalla maschera di rete al volo:

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

E per creare una gamma basata su due indirizzi 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'] 

Quindi, ora che è possibile creare un intervallo CIDR, è possibile verificare se un IP è una parte di esso:

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

+1 per NetAddr. È molto bello. –

+0

Grazie per questo. Ho finito per convertire tutto in int, indicizzando gli intervalli di ip superiore e inferiore come ints per fare confronti veramente veloci.Il tuo consiglio di usare NetAddr mi ha aiutato a portarmi nella giusta direzione. Il problema con il nostro ambiente è che gli input dell'utente di specifici intervalli ip e caratteri jolly renderebbero la ricerca CIDR molto più complicata di quanto pensassi inizialmente. – John

+0

la conversione di un intervallo in single ips è di "conversione in CIDR (blocchi)", ma non molto efficiente. – Stefan

5

Sospetto che tutto ciò che serve sia in IPAddr. Io lo uso per vedere se la IP remoto è venuta da una rete privata:

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

Ricordarsi di "richiedere" ipaddr "prima di utilizzarlo. – tothemario

5

Forse sto fraintendendo la domanda, ma sembra che non sia stato affrontato un aspetto di questa domanda, ovvero, convertire un intervallo di indirizzi IP in una o più voci CIDR.

Io uso il seguente approccio per cercare attività IP sospette sul mio firewall, e se è in un paese che non sono interessato a consentire l'accesso (sai chi sei) io uso whois per cercare l'intervallo di indirizzi, e quindi calcolare le CIDRs unite come segue,

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) 

Questo è un esempio su una rete interna, ma è banale per estendere ad un blocco IP pubblico,

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] 

allora posso passare che CIDR al mio software firewall (shorewall) per far cadere dinamicamente quel cid r (s).

Problemi correlati