[Mimedefang] Stupid question? - subnet
jmiller at purifieddata.net
jmiller at purifieddata.net
Mon Feb 10 18:07:01 EST 2003
On Mon, 10 Feb 2003, David F. Skoll wrote:
> On Mon, 10 Feb 2003, Jim McCullars wrote:
>
> > It's a string comparison, so you may be looking at a fairly complicated
> > regex to do the test you want (I say "may be" because I don't know how to
> > decode a CIDR address string to a range of addresses).
>
> You might want to look at a Perl module to do CIDR comparisons; I think
> Net::CIDR::Lite might be just the ticket:
>
> http://search.cpan.org/author/DOUGW/Net-CIDR-Lite-0.14/Lite.pm
>
> Or perhaps NetAddr::IP is more to your liking:
>
> http://search.cpan.org/author/LUISMUNOZ/NetAddr-IP-3.14/IP.pm
>
> Or Net::CIDR:
>
> http://search.cpan.org/author/MRSAM/Net-CIDR-0.04/CIDR.pm
>
> What was that horrible Perl slogan again? "TIMTOWTDI"?
>
Just thought I'd append some ip calculation code I wrote a long time
ago (btw, I used code out of ipcalc.pl, but I don't know where that lives
anymore). This will do the job you want and a lot more without the
need for more modules, though they'll probably do the job just as well.
An easier way would be to specify the begining and end IP's in a range you
want to match, and use the ip2dec sub below to convert all ips to decimal,
and check to see if the given IP is in that range.
--
Josh I.
Disclaimer: this code was heavily tested, but pulled it out of another
module I wrote, so if it doesn't work, or blows up your machine, it's not
my fault, I could have missed something, etc :-) As it is here, it hasn't
been tested.
Also, it should probably be considered under the GPL cause a few pieces
are pulled right out of some other GPL'd code (ipcalc.pl).
if (&is_in_netblock($RelayAddr,'62.253.177.96/27') {
## do stuff if it's in there
}
# this should also work:
if (&is_in_netblock($RelayAddr,'62.253.177.96/255.255.255.224') {
## do stuff if it's in there
}
# this should also work (notice block IP isn't a valid start of a
# netblock, the code will figure out where the block really stats/ends
# and see if the RelayAddr is in the real block, allowing you to be
# a little sloppy/careless)
if (&is_in_netblock($RelayAddr,'62.253.177.101/27') {
## do stuff if it's in there
}
sub is_in_netblock
{
my ($ip,$block) = @_;
my ($b_ip,$b_mask) = split(/\//,$block);
$ip = &is_valid_dq($ip);
$b_ip = &is_valid_dq($ip);
if ( (! $ip) || (! $b_ip) ) { return 0; }
return 0 unless &is_valid_netmask($b_mask);
my $d_ip = &ip2dec($ip);
my ($network,$broadcast) = &get_net_broad($b_ip,$b_mask);
my $d_net = &ip2dec($network);
my $d_broad = &ip2dec($broadcast);
if ( ($d_ip <= $d_broad) && ($d_ip >= $d_net) )
{
return 1;
} else {
return 0;
}
}
sub get_net_broad
{
my ($host,$mask);
if ( (defined($_[0])) && (defined($_[1])) && ($host = &is_valid_dq($_[0])) && ($mask = is_valid_netmask($_[1])) )
{
my $m = pack( "B*",("1" x $mask) . ("0" x (32 - $mask)) );
my $h = dqtobin($host);
my $n = $h & $m;
my $nm = pack( "B*",("0" x $mask) . ("1" x (32 - $mask)) );
my $b = $n | $nm;
my $hmin = pack("B*",("0"x31) . "1") | $n;
my $hmax = pack("B*",("0"x $mask) . ("1" x (31 - $mask)) . "0" ) | $n;
my $origonaladdress = $host;
my $network = &bintodq($n);
my $bitmask = $mask;
my $fullnetmask = &bintodq($m);
my $minhost = &bintodq($hmin);
my $maxhost = &bintodq($hmax);
my $broadcast = &bintodq($b);
my $numberOhosts = (2 ** (32 - $mask)) -2 ;
my $numberOips = (2 ** (32 - $mask));
# my @returnvals = ($origonaladdress,$network,$bitmask,$fullnetmask,$minhost,$maxhost,$broadcast,$numberOhosts,$numberOips);
return ($network,$broadcast);
} else {
return 0;
}
}
sub is_valid_netmask {
my $mask = $_[0];
if ($mask =~ /^\d+$/) {
if ( ($mask > 32) || ($mask < 1) ) {
return 0;
}
} else {
if (! ($mask = &is_valid_dq($mask)) ) {
return 0;
}
$mask = dqtocidr($mask);
}
return $mask;
}
sub dqtocidr
{
my $dq = shift;
$b = &dqtobin($dq);
my $cidr = 1;
while (unpack("B$cidr",$b) !~ /0/) {
$cidr++;
last if ($cidr == 33);
}
$cidr--;
return $cidr;
}
sub dqtobin {
my @dq;
my $q;
my $i;
my $bin;
foreach $q (split /\./,$_[0]) {
push @dq,$q;
}
for ($i = 0; $i < 4 ; $i++) {
if (! defined $dq[$i]) {
push @dq,0;
}
}
$bin = pack("CCCC", at dq); # 4 unsigned chars
return $bin;
}
sub ip2dec
{
return(&bin2dec(&ip2bin(shift)));
}
sub bin2dec
{
return unpack("N", pack("B32", substr("0" x 32 . shift, -32)));
}
sub ip2bin
{
my $ipaddr;
if ($ipaddr = &is_valid_dq(shift)) {
my @ip = split('\.',$ipaddr);
foreach(@ip) {
my $bin = &dec2bin($_);
$bin = substr($bin,-8); # takes just last 8 chars
$_ = $bin;
}
my $bin_ip = join('', at ip);
return $bin_ip;
} else {
return 0;
}
}
sub is_valid_dq {
my $value = $_[0];
my $test = $value;
my $i;
my $corrected;
$test =~ s/\.//g;
if ($test !~ /^\d+$/) {
return 0;
}
my @value = split /\./, $value, 4;
for ($i = 0; $i<4; $i++) {
if (! defined ($value[$i]) ) {
$value[$i] = 0;
}
if ( ($value[$i] !~ /^\d+$/) ||
($value[$i] < 0) ||
($value[$i] > 255) )
{
return 0;
}
}
$corrected = join ".", @value;
return $corrected;
}
More information about the MIMEDefang
mailing list