Here's a sample implementation of the above outline:
#!/usr/bin/perl -w
use strict;
# BrowserUk's conversion subs
sub bin2dd{ join '.', unpack 'C4', pack 'N', $_[0] }
sub dd2bin{ unpack 'N', pack 'C4', split '\.', $_[0] }
my @ips;
push @ips, shift while @ARGV && -1 == index $ARGV[0], '/';
die "usage: $0 IPs subnets\n" unless @ips && @ARGV;
my %subnets;
foreach my $subnet (@ARGV) {
my ($net, $plen) = split /\//, $subnet;
$net .= '.0' x (3 - $net =~ tr/.//);
my $net_bin = dd2bin $net;
my $zero_bits = ~(~0 << 32-$plen);
if ($net_bin & $zero_bits) {
print STDERR "warning: fixing $net/$plen => ";
$net_bin &= ~$zero_bits;
$net = bin2dd $net_bin;
print STDERR "$net/$plen\n";
}
$subnets{"$net_bin/$plen"} = "$net/$plen";
}
foreach my $ip (@ips) {
my $ip_bin = dd2bin $ip;
foreach my $plen (8..32) {
my $key = (~0 << 32-$plen & $ip_bin) . "/$plen";
if (exists $subnets{$key}) {
print "$ip matches $subnets{$key}\n";
# last;
}
}
}
__END__
$ ip-in-subnet.pl 192.168.1.7 64.96.128.11 2.219.155.11 \
8.8.8.8 64.96.128.0/28 64.96.128.0/17 64.96.128.11/32 64/8 \
192.168.1.0/24 192.168/16 8/8 2.219/16
192.168.1.7 matches 192.168.0.0/16
192.168.1.7 matches 192.168.1.0/24
64.96.128.11 matches 64.0.0.0/8
64.96.128.11 matches 64.96.128.0/17
64.96.128.11 matches 64.96.128.0/28
64.96.128.11 matches 64.96.128.11/32
2.219.155.11 matches 2.219.0.0/16
8.8.8.8 matches 8.0.0.0/8
Update 1: bloody 'noexpandtab'!
Update 2: added a bit of error checking