Thomas Bätzler 写道:
Hi,
Jeff Pang <[EMAIL PROTECTED]> asked:

I have a text file which contains lots of IPs,like:

58.253.0.0/16;
58.254.0.0/16;
58.255.0.0/16;
60.0.0.0/16;
60.1.0.0/16;
60.10.0.0/16;
60.16.0.0/16;
60.17.0.0/16;
60.18.0.0/16;
60.19.0.0/16;
60.2.0.0/16;
60.20.0.0/16;
60.21.0.0/16;
60.22.0.0/16;
60.23.0.0/16;
60.3.0.0/16;

My question is,given an IP,ie 59.32.232.33,how can I know it exists in this file or not?
Is there a module already?thanks.

It's not a module, but here's some of my code that
might be useful if you want to test many ip adresses
against a fixed set of networks.

It is built on the facts that IP adresses can be converted to integers that retain the ordering
of the adresses and that networks are a range of
ip adresses - so your problem is really figuring
out whether a number x falls into one of n discrete
intervals.

The method of choice for this kind of problem is
doing a binary search.

I've tested several approaches and settled for
dynamically creating an unrolled variant of an
iterative binary search.

HTH,
Thomas


Hello Thomas,

I tried your codes,it's good I think.
I've modified some of the codes to fit my situation.
But if the network data files include too much IPs,my program used up all memory and couldn't get continued.
Below are my modified codes.Attachments are two network data files.

Any suggestion guys?Thanks.


================================
#!/usr/bin/perl
use strict;
use warnings;
use Socket;
#use Data::Dumper;

#------------------
# main
#------------------

# read from ISPs' network data files,each item in files looks like "222.85.93.0/24" # "tel_acl.txt" store TEL's network data,"cnc_acl.txt" store CNC's network data.
our $teldata = build_array("tel_acl.txt");
our $cncdata = build_array("cnc_acl.txt");

# default ISP,when an IP belong to neither TEL nor CNC,then specify it to this default ISP
our $default_isp = 'unknown';

#
# main loop,accept an ip from STDIN
#
while(<>) {
    chomp;
    my $isp = query_an_ip($_);
    print $isp,"\n";
}


#------------------
# subroutines
#------------------

#
# verify an ip belong to which ISP
#
sub query_an_ip {
        my $ip = shift;
        my $int = ip_to_number($ip);

        if (binSearch($teldata,$int) != -1) {
                return 'tel';
        } elsif (binSearch($cncdata,$int) != -1) {
                return 'cnc';
        } else {
                return $default_isp;
        }
}

#
# build an array for binary search
#

sub build_array {
    my $file = shift;
    my @data = ();

    open FILE,$file or die $!;
    while(<FILE>) {
        next unless /^(\d+\.\d+\.\d+\.\d+)\/(\d+)/;
        my ($netnum,$mask) = ($1,$2);

        # translate netnum and mask to int
        $netnum = ip_to_number($netnum);
        $mask = make_mask($mask);

        # Sanity check: Network number ANDed to the host mask must be 0
        next if $netnum & $mask;

        for (my $i=$netnum;$i<=$netnum+$mask;$i++) {
            push @data,$i
        }
    }
    close FILE;

    # sort this array and get rid of duplicated items
    my %tmp;
    @data = grep { ++$tmp{$_} < 2 }
            sort {$a <=> $b} @data;

    return [EMAIL PROTECTED];
}


#
# number of mask bits => inverted Bit mask
#
# converts the xx number of mask bits (in ip.ip.ip.ip/xx) to an
# inverted bit mask, i.e. 24 becomes 0x000000FF
#

sub make_mask {

    if( $_[0] < 0 || $_[0] > 32 ){
        die "Illegal mask /$_[0]";
    } else {
        return( 2 ** ( 32 - $_[0] ) - 1);
    }
}


#
# ip.ip.ip.ip => 0x????????
#
# convert a dottect decimal IP address to an unsigned long number
# in host byte order.
#

sub ip_to_number {

    if( defined ( my $nl = inet_aton( $_[0] ) ) ){
        # convert network to host byte order
        return( unpack( 'N', $nl ) );
    } else {
        die "Invalid IP address '$_[0]'!\n";
    }
}


#
# binary search,need a sorted array
#

sub binSearch
{
    my $arr_ref = shift;
    my $key = shift;
    my $low = 0;
    my $high = $#$arr_ref;

    my $middle;

    while($low <= $high) {
        $middle = int(($low+$high)/2);
        if ($key == $arr_ref->[$middle]) {
            return $middle;
        } elsif ($key < $arr_ref->[$middle]) {
            $high = $middle -1;
        } else {
            $low = $middle +1;
        }
    }

    return -1;
}

--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/


Reply via email to