Checking range of IP addresses

T

tim

A Perl script I wrote for a CGI is getting spammed. So I'm identifying
and blocking ranges of IP addresses.

At first I used IF statements like this:

# 218.73.64.0 - 218.73.79.255 banned
@ip = split(/\./, $ENV{'REMOTE_ADDR'});
if ($ip[0] == 218 && $ip[1] == 73 && ($ip[2] >= 64 && $ip[2] <= 79)) {
$banned = 1;
}

I know that's probably horrible programming and not very elegant. But
it worked.

Now the list I want to block is getting longer. I could continue to add
IF statements but I feel that's probably stupid.

Any suggestions how I might try to more elegantly process a list of
banned IP's?

Thanks!
--Tim
 
G

Gunnar Hjalmarsson

A Perl script I wrote for a CGI is getting spammed. So I'm identifying
and blocking ranges of IP addresses.

At first I used IF statements like this:

# 218.73.64.0 - 218.73.79.255 banned
@ip = split(/\./, $ENV{'REMOTE_ADDR'});
if ($ip[0] == 218 && $ip[1] == 73 && ($ip[2] >= 64 && $ip[2] <= 79)) {
$banned = 1;
}

I know that's probably horrible programming and not very elegant. But
it worked.

Now the list I want to block is getting longer. I could continue to add
IF statements but I feel that's probably stupid.

Any suggestions how I might try to more elegantly process a list of
banned IP's?

Taking the chance that also this idea is stupid, I couldn't help
reinventing the wheel:

my $ip = '218.73.72.100';
print "Banned\n" if banned($ip);

sub banned {
my $ip = shift;
while (<DATA>) {
if (/^(\S+)\s*-\s*(\S+)$/) {
my $begin = pack 'C4', split /\./, $1;
my $end = pack 'C4', split /\./, $2;
my $packedip = pack 'C4', split /\./, $ip;
return 1 if $packedip ge $begin and $packedip le $end;
} else {
chomp;
return 1 if $ip eq $_;
}
}
return 0;
}

__DATA__
60.70.80.90
218.73.64.0 - 218.73.79.255
 
J

Joe Smith

Gunnar said:
Taking the chance that also this idea is stupid, I couldn't help
reinventing the wheel:

Your wheel doesn't work.
my $ip = '218.73.72.100';
print "Banned\n" if banned($ip);
print "Still banned\n" if banned($ip);

The second call to banned() does not operate the same way
as the first call. Not good.

-Joe
 
G

Gunnar Hjalmarsson

Joe said:
Your wheel doesn't work.


print "Still banned\n" if banned($ip);

The second call to banned() does not operate the same way
as the first call. Not good.

Well, I never claimed it would work for multiple calls. Whether one call
is sufficient depends on how it's supposed to be used, doesn't it? The
OP seemed to just need a way to decide if REMOTE_ADDR would get access
to a script, and there is only one REMOTE_ADDR ...

The main point with posting the code snippet was to call the OP's
attention to how the pack() function can be used.
 
T

tim

Gunnar said:
Taking the chance that also this idea is stupid, I couldn't help
reinventing the wheel:

Thank you for both of your replies. I'd not previously heard of Net::IP
and I'm studying it.

I also like your new wheel, even though it doesn't handle multiple
calls. I admit knowing nothing about this pack() function. I will study
your code until I understand it.

Thanks again!

--Tim
 
G

Gunnar Hjalmarsson

I also like your new wheel, even though it doesn't handle multiple
calls.

If you find the approach useful, a natural application of it is to store
and maintain the list of IP ranges in a separate file, and let the
banned() function open/close the file. Doing so would take care of 'the
multiple call issue' (even if I don't think that's an issue in your case).
I admit knowing nothing about this pack() function. I will study
your code until I understand it.

To be honest, I'm not too comfortable with it either, but I have learned
that it's useful for comparing and sorting IP addresses. Please feel
free to ask here if you get stuck.
Thanks again!

You're welcome.
 
A

Anno Siegel

Gunnar Hjalmarsson said:
A Perl script I wrote for a CGI is getting spammed. So I'm identifying
and blocking ranges of IP addresses.
[...]

Taking the chance that also this idea is stupid, I couldn't help
reinventing the wheel:

my $ip = '218.73.72.100';
print "Banned\n" if banned($ip);

sub banned {
my $ip = shift;
while (<DATA>) {
if (/^(\S+)\s*-\s*(\S+)$/) {
my $begin = pack 'C4', split /\./, $1;
my $end = pack 'C4', split /\./, $2;
my $packedip = pack 'C4', split /\./, $ip;
return 1 if $packedip ge $begin and $packedip le $end; ^^^^^^^^^^^
} else {
chomp;
return 1 if $ip eq $_; ^^^^^^^^^^^
}
}
return 0;
}

Any reason why you don't just

return $packedip ge $begin and $packedip le $end;

and

return $ip eq $_;

Anno
 
A

Anno Siegel

Joe Smith said:
Your wheel doesn't work.

print "Still banned\n" if banned($ip);

The second call to banned() does not operate the same way
as the first call. Not good.

That's easily fixed. Change

sub banned {
my $ip = shift;
while (<DATA>) {
# ...
}
}

to

{
my @data;
sub banned {
@data = <DATA> unless @data;
my $ip = shift;
for ( @data ) {
# ...
}
}
}

Anno

Anno
 
G

Gunnar Hjalmarsson

Anno said:
^^^^^^^^^^^

Any reason why you don't just

return $packedip ge $begin and $packedip le $end;

and

return $ip eq $_;

No reason whatsoever. ;-)
 
T

tim

To Gunnar and others:

That snippet of code and the following comments turned out to be what I
needed. I modified to suit my needs and it's working great.

Thanks!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top