2012-11-15 11 views
6

chcę zrobić dwie rzeczy: Konwersja wejść adresowych IP na CIDR Oto kilka przykładowych wejść:Zakres IP do CIDR w 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 

Sprawdź, czy dany adres IP wpada w dowolnym CIDR. To musi być bardzo szybkie zapytanie, ponieważ jest to bardzo popularne wyszukiwanie w mojej aplikacji internetowej. Mam na myśli zrobienie czegoś takiego: waha

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

myślę konwersji IP na CIDR pozwoli wyszukiwań być szybsze niż to, co robimy teraz, który włamuje się do całkowitych oktety OD użytkownika. Następnie indeksujemy pierwsze dwa zestawy oktetów, aby częściowo dopasować do adresów IP. Inną opcją może być zamiana wszystkiego na int i porównywanie w ten sposób. Przerobiłem na ints z czymś podobnym do tego: IPAddr.new("1.1.1.1").to_i, ale wtedy musiałbym przechowywać górny i dolny adres IP dla każdego zakresu zamiast tylko jednego CIDR.

Proszę, daj mi znać, jeśli przeoczyłem jakiekolwiek popularne podejścia, popularne klejnoty lub repozytorium. Dzięki!

Odpowiedz

10

Dobrze, aby uzyskać notacji CIDR w zakresie, trzeba IP oraz liczbę bitów sieciowych (liczonych od maski sieci) .

Aby wyliczyć adresy z danego zakresu, można użyć klejnotu 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'] 

Można również obliczyć bity od maski sieci w locie:

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

i stworzyć szereg opiera się na dwóch adresów 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'] 

Więc teraz, że można tworzyć zakres CIDR, możesz sprawdzić, czy adres IP jest jego częścią:

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

+1 dla NetAddr. To jest bardzo fajne. –

+0

Dzięki za to. Skończyło się na tym, że konwertowałem wszystko na int, indeksując górne i dolne zakresy IP jako int do robienia naprawdę szybkich porównań.Twoja wskazówka, aby użyć NetAddr, pomogła mi we właściwym kierunku. Problem z naszym środowiskiem polega na tym, że wprowadzanie przez użytkownika określonych zakresów ip i symboli wieloznacznych sprawiłoby, że wyszukiwanie CIDR było znacznie bardziej skomplikowane, niż początkowo sądziłem. – John

+0

Konwersja zakresu na pojedyncze ips jest "konwertowaniem na CIDR (bloki)", ale niezbyt wydajna. – Stefan

5

Podejrzewam, że wszystko, czego potrzebujesz, to adres IPAddr. Używam tego, czy zdalny IP pochodzące z sieci prywatnej:

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

Pamiętaj tylko, aby "wymagać" ipaddr'' przed użyciem. – tothemario

5

Być może nie rozumiem tego pytania, ale wydaje się, że jeden aspekt tego pytania nie został rozwiązany, to jest przekształcenie zakresu adresów IP w jeden lub więcej wpisów CIDR.

Używam następującego podejścia do wyszukiwania podejrzanej aktywności IP na mojej zaporze, a jeśli jest to w kraju, który nie jest zainteresowany zezwoleniem na dostęp (wiesz kim jesteś), używam whois do wyszukiwania zakresu adresów, a następnie obliczyć scalone CIDRs następująco,

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) 

jest to przykład na sieci wewnętrznej, ale jest trywialny przedłużyć do publicznej bloku 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] 

wtedy mogę przekazać tę CIDR do mojego oprogramowania firewall (shorewall), aby ten dynamicznie upuścił ten identyfikator r (s).