Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Perl: Общие вопросы > Проверка персечения диапазона IP со списком


Автор: GoDleSS 12.9.2008, 15:24
Доброго времени суток, уважаемые форумчане!

Попалась мне задачка одна, а красивых методов пока не придумал, может кто подскажет из собственного опыта:
Есть диапазон ip-адресов, заданный в виде 192.168.0.1 - 192.168.1.254.
Есть список таких же диапазонов.
Цель: проверить, пересекается ли введенный диапазон с любым диапазоном из списка.

Строить по всем диапазонам массивы - глупо.
Можно, конечно, перевести в число и проверять, т.е. что-то вроде:
Код

...
my ($start, $stop) = int_range($start_ip, $stop_ip);
my $error = 0;
foreach my $elem (@ranges_list) {
  ($elem->{start}, $elem->{stop}) = int_range($elem->{start}, $elem->{stop});
  if ( ($start >= $elem->{start} && $start <= $elem->{stop}) || 
       ($stop <= $elem->{stop}  && $stop  >= $elem->{start}) ) {
    $error = 1;
    last;
  }
}

...
sub int_range {
    my $start = shift || return(0);
    my $stop  = shift || return(0);

    my @start = split(/\./, $start);
    my @stop  = split(/\./, $stop);

    ($start, $stop) = (0, 0);
    for (my $i = 4; $i > 0; $i--) {
        $start += $start[4 - $i] * (256**($i - 1));
        $stop  += $stop[4 - $i] * (256**($i - 1));
    }

    return ($start, $stop);
}

Но хотелось бы нечто более красивое smile

Автор: AriX 12.9.2008, 17:18
Net::IP, Net::Patricia.

Автор: GoDleSS 13.9.2008, 16:57
Цитата

Net::IP, Net::Patricia.

Хмм, мне казалось, что эти модули подходят про проверки вхождения единичного айпи-адреса в в диапазон. Но не диапазона в список диапазонов.
И еще один момент, мне не хотелось бы внедрять в систему дополнительные модули, стараемся сего избегать по возможности.

Автор: nitr 13.9.2008, 19:04
GoDleSS, тогда попытайтесь поискать ответ на форуме, при мне такие случаи обсуждались, и там тоже без модуля делали.

Автор: Bulat 15.9.2008, 10:37
GoDleSS, делал я нечто подобное(правда там не мало делалось на уровне БД, поэтому не думаю что конкретно мои решения в данном случае подойдут, но суть ... ), есть такая функция inet_aton(), по-моему везде под одним и тем же именем идет, преобразовывает из чисел и точек в единое число. На мой взгляд один из оптимальных способов для работы с IP-адресами. smile

Автор: DaemonSuw 15.9.2008, 22:32
Bulat, вы правы! GoDleSS, вот пример перевода

#!/usr/bin/perl

Код

print ip2int("111.12.32.12");

sub ip2int{
   my ($i)=@_;
   $i=~/(\d+)\.(\d+)\.(\d+)\.(\d+)/;
   return $1*256*256*256+$2*256*256+$3*256+$4;


Автор: GoDleSS 16.9.2008, 07:35
DaemonSuw, если посмотрите, примерно также и решал задачу перевода, подход чуть другой просто.


Bulat, появились на почве первой задачи еще и дополнительные, там(ради разнообразия) решил как раз с помощью inet_aton/pack/unpack и обратный перевод unpack/inet_ntoa

Автор: gcc 16.9.2008, 08:05
Код

Например, задача преобразования IP-адреса из формата xxx.xxx.xxx.xxx в int (для сохранения в БД).  Самый быстрый вариант

Код

my $ip_int = unpack("N", pack("C4", split(/\./, $ip)));

© ginnie

у вас список чтоли большой очень? разве ip в хэше оно много места занимает? или там много хостов за сутки будут проверять ip?

Автор: GoDleSS 16.9.2008, 11:05
Цитата

у вас список чтоли большой очень? разве ip в хэше оно много места занимает? или там много хостов за сутки будут проверять ip?

Объем порядочный - это задачка для биллинговой системе, заказ под конкретного клиента, а клиент - крупный московский оператор.
Просто произошла небольшая несостыковка схемы нашей биллинговой системы и пожеланий оператора, но клиент-то всегда прав =)

В целом с задачей разобрался, доведу когда до ума - отпишу. 
Цитата
unpack("N", pack("C4", split(/\./, $ip)));

На данный момент лучшее решение.

Автор: Bulat 16.9.2008, 11:20
Цитата(GoDleSS @  16.9.2008,  11:05 Найти цитируемый пост)
Объем порядочный - это задачка для биллинговой системе

Хм, я тоже когда с биллингом возился, как раз столкнулся с подобного рода задачей, но решал сразу в базе, в MySQL есть одноименная функция. smile

Автор: GoDleSS 16.9.2008, 11:28
Цитата

Хм, я тоже когда с биллингом возился, как раз столкнулся с подобного рода задачей, но решал сразу в базе, в MySQL есть одноименная функция.

1. В базе не стоит по ряду причин(в моем случае)
2. Пользуем Оракл(хотя в нем как раз возможностей навалом)

Автор: DaemonSuw 16.9.2008, 20:40
GoDleSS, извиняюсь просмотрел, и в правду тоже самое)))
gcc, это круто)))
Код

print unpack("N", pack("C4", split(/\./, $ip)));
 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)