Hi all
I have dos-style wildcard ip addresses and some ip address ranges
held in a text file, one per line like this ...
127.0.0.0/8
10.0.0.0-10.0.1.255
192.168.1.*
172.?.*.*
10.0.1?.*
... which I'm trying to convert into cidr notation to use with
Net::CIDR to create a lookup cache.
The first example is already in cidr notation so I can feed that
direct to the cache and the second converts straight to cidr
using 'range2cidr'. I can also code for the third and fourth
examples without problems ...
192.168.1.* == 192.168.1.0 - 192.168.1.255
172.?.*.* == 172.0.0.0 - 172.9.255.255
... because each of the affected octets contains only a wildcard
thus limiting the possible minimum and maximum values.
The fifth example is defeating me because the min/max values of
the ? are dependent both on its relative position in the octet
and on the quantity of, and values of, any prior and subsequent
numbers and/or question marks, thus ...
input required output [ min/max ]
10.0.1?.* == 10.0.10.0 - 10.0.19.255 [ 0/9 ]
10.0.1??.* == 10.0.100.0 - 10.0.199.255 [ 0/9 ] [ 0/9 ]
10.0.2?.* == 10.0.20.0 - 10.0.29.255 [ 0/9 ]
10.0.25?.* == 10.0.250.0 - 10.0.255.255 [ 0/5 ]
10.0.2??.* == 10.0.200.0 - 10.0.255.255 [ 0/5 ] [ 0/5 ]
10.0.?00.* == 10.0.0.0 - 10.0.200.255 [ 0/2 ]
10.0.??0.* == 10.0.0.0 - 10.0.250.255 [ 0/2 ] [ 0/5 ]
I've thought about this long enough to realise that my simplistic
procedural approach isn't likely to result in a good algorithm -
except, that is, for the minimum values in each case!
Am I missing something obvious? Is there a better way to go about
this, a maths-based solution, perhaps, or a module?
This is my test code thus far. I've also included the test script
I've devised for subsequent queries to the cache. If there's a
better (quicker, simpler, smaller) way of doing this, I'd be glad
to hear about it.
--
| #!perl
| # test.pl
|
| use strict;
| use warnings;
| use Net::CIDR;
| use Data::Dumper;
|
| my %cache;
|
| my @inputs = qw(127.0.0.0/8 10.0.0.0-10.0.1.255 192.168.1.* 172.?.*.*
10.0.1?.*);
| # invalid result from last array entry
|
| foreach my $input (@inputs) {
| print "\ninput: $input\n";
| if ($input =~ /^\d+.*\//) {
| print "cidr : $input\n";
| cidr_add($input, "Some cidr text");
| }
| if ($input =~ /^\d+\..*-.*\d+\./) {
| my @cidr = Net::CIDR::range2cidr($input);
| print "cidr : $_\n" foreach @cidr;
| cidr_add($_, "Some range text") foreach @cidr;
| }
| if ($input =~ /\*|\?/) {
| my (@lo_octs, @hi_octs);
| my @in_octs = split /\./, $input;
| # nb. add a check for 4 quads and pad if reqd
| foreach my $in (@in_octs) {
| # print "in: \'$in\'\n";
| if ($in eq "*") {
| push @lo_octs, 0;
| push @hi_octs, 255;
| } elsif ($in eq "?") {
| push @lo_octs, 0;
| push @hi_octs, 9;
| } elsif ($in =~ /\*|\?/) {
| my ($lo_num, $hi_num);
| my @nos = split '', $in;
| foreach my $n (@nos) {
| if ($n =~ /\d/) {
| $lo_num .= $n;
| $hi_num .= $n;
| } elsif ($n eq "?") {
| # run out of ideas
| } elsif ($n eq "*") {
| # run out of steam
| }
| }
| } else {
| push @lo_octs, $in;
| push @hi_octs, $in;
| }
| }
| my $result = join(".", @lo_octs)."-".join(".", @hi_octs);
| print "range: $result\n";
| my @cidr = Net::CIDR::range2cidr($result);
| print "cidr : $_\n" foreach @cidr;
| cidr_add($_, "Some wildcard text") foreach @cidr;
| }
| }
|
| # print "\n\n", Dumper(%cache);
|
| # test cache
| exit unless $ARGV[0];
|
| my $ip = $ARGV[0];
| my ($output, $result) = lookup($ip);
| print "\nip=$ip", "; result=$result", "; output=$output", "\n";
|
| sub cidr_add {
| my ($cidr, $text) = @_;
| my @range = Net::CIDR::cidr2octets($cidr);
| $cache{$_}{text} = $text foreach (@range);
| print "added: $cidr\n" if (%cache);
| }
|
| sub lookup {
| my $ip = shift;
| print "\nCache lookup for $ip\n";
| my @octets = split /\./, $ip;
| my $count = scalar @octets;
| while ($count > 0) {
| my @octs;
| push @octs, $octets[$_] for (0..($count - 1));
| my $oct = join ".", @octs;
| print "Check $oct\n";
| if (exists $cache{$oct}) {
| return($cache{$oct}{text}, "hit");
| }
| $count--;
| }
| return($ip, "miss");
| }
--
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
http://learn.perl.org/