Задачка про CIDR
Отсюда:
Задача такова: есть ASCIIZ-строка с IP-адресом, надо вернуть true, если этот адрес попадает в один из диапазонов, перечисленных в файле.
Файл текстовый такого формата,
192.168.1.3,192.168.1.5
192.168.2.4,193.0.0.3
Файл не отсортирован, дипапазоны произвольные и могут пересекаться. Первый адрес меньше второго или равен ему. Пересечение диапазонов можно обрабатывать двумя путями: лиюо отказываться грузить такой файл и выдавать что с чем пересеклось, либо не отказываться и корректно работать в таких условиях.
Файл грузится один раз и потом десятки миллионов раз лукапится. Записей в конфиге - сотни.
Решение:
PS. Вкралась ошибка: неправильно сгенерил список ip адресов, надо
Результат:
PS2. Скорость слабо зависит от количества сетей:
Задача такова: есть ASCIIZ-строка с IP-адресом, надо вернуть true, если этот адрес попадает в один из диапазонов, перечисленных в файле.
Файл текстовый такого формата,
192.168.1.3,192.168.1.5
192.168.2.4,193.0.0.3
Файл не отсортирован, дипапазоны произвольные и могут пересекаться. Первый адрес меньше второго или равен ему. Пересечение диапазонов можно обрабатывать двумя путями: лиюо отказываться грузить такой файл и выдавать что с чем пересеклось, либо не отказываться и корректно работать в таких условиях.
Файл грузится один раз и потом десятки миллионов раз лукапится. Записей в конфиге - сотни.
Решение:
# cat > z.pl
#! /usr/bin/perl
use Net::Patricia;
use Net::CIDR::Lite;
my $pt = new Net::Patricia;
my $cidr = new Net::CIDR::Lite;
open F, shift or die;
while () {
chomp; s#,#-#;
foreach my $m ($cidr->add_range($_)->list) { $pt->add_string($m) }
}
foreach (<>) {
chomp;
print $_, ":", $pt->match_string($_) ? "YES" : "NO", "\n";
}
^D
# perl z.pl /tmp/ip.range =( print -l 192.168.1.1 192.168.1.4 )
192.168.1.1:NO
192.168.1.4:YES
# perl -le 'foreach (0..$ARGV[0]) { printf "%d.%d.%d.%d\n", rand()%255, rand()%255, rand()%255, rand()%255 }' 10240000 >| /tmp/ip.list
# wc -l /tmp/ip.list
10240001 /tmp/ip.list
# time perl z.pl /tmp/ip.range /tmp/ip.list >| /dev/null
Real: 120.10s User: 105.21s System: 1.31s Percent: 88%% Cmd: perl z.pl /tmp/ip.range /tmp/ip.list >| /dev/null
#
PS. Вкралась ошибка: неправильно сгенерил список ip адресов, надо
# perl -le 'foreach (0..$ARGV[0]) { printf "%d.%d.%d.%d\n", int(rand(255)), int(rand(255)), int(rand(255)), int(rand(255)) }' 10240000 >| /tmp/ip.list
Результат:
# time perl z.pl /tmp/ip.range /tmp/ip.list >| /dev/null
Real: 176.98s User: 153.23s System: 2.20s Percent: 87%% Cmd: perl z.pl /tmp/ip.range /tmp/ip.list >| /dev/null
PS2. Скорость слабо зависит от количества сетей:
# for i in {1..300}; do a=$[ $RANDOM%255 ]; b=$[ $RANDOM%255 ]; c=$[ $RANDOM%254 ]; d=$[ $RANDOM%254 ]; print "$a.$b.$c.$d,$a.$b.$[$c+1].$[$d+1]"; done >| /tmp/ip.range2
# time perl z.pl /tmp/ip.range2 /tmp/ip.list >| /dev/null
Real: 187.54s User: 173.13s System: 1.98s Percent: 93%% Cmd: perl z.pl /tmp/ip.range2 /tmp/ip.list >| /dev/null
#