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/


Reply via email to