diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2014-10-14 23:02:46 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2014-10-14 23:02:46 +0300 |
commit | 22ea7f92356b66406e7507002b826cbf12e14d52 (patch) | |
tree | 7a30a51940f2a82f63105a15000f7788e9384a40 | |
parent | c60e1f248a5b911e502b46420389aad42bb7fac9 (diff) | |
download | dnstools-22ea7f92356b66406e7507002b826cbf12e14d52.tar.gz dnstools-22ea7f92356b66406e7507002b826cbf12e14d52.tar.bz2 |
whoseip: keep arbitrary additional data in the cache database
* whoseip/Whoseip/DB.pm (ipdb_save_page): Save additional data
(serialized hash).
(ipdb_get_page): Decode serialized additional data.
(ipdb_insert): Take hash as additional arguments.
* whoseip/whoseip.pl (range2count): Handle multiple ranges.
(cidr_to_range): New function. Use in all functions instead
of Net::CIDR::cidr2range.
(serve): Pass cidr as additional argument to ipdb_insert
-rw-r--r-- | whoseip/Whoseip/DB.pm | 35 | ||||
-rw-r--r-- | whoseip/whoseip.pl | 40 |
2 files changed, 55 insertions, 20 deletions
diff --git a/whoseip/Whoseip/DB.pm b/whoseip/Whoseip/DB.pm index b7cba34..fbd3a61 100644 --- a/whoseip/Whoseip/DB.pm +++ b/whoseip/Whoseip/DB.pm @@ -19,6 +19,7 @@ package Whoseip::DB; use strict; use Fcntl qw(SEEK_SET SEEK_CUR); use Socket qw(inet_ntoa); +use Storable qw(freeze thaw); require Exporter; our @ISA = qw(Exporter); @@ -124,7 +125,8 @@ B<Offset> B<Size> B<Description> 16 4 Entry 0: network mask 20 4 Entry 0: timestamp 24 2 Entry 0: ISO 3166-1 country code - + 26 4 Entry 0: length of additional data + 30 ? Entry 0: additional data . . . . . . . . . @@ -133,6 +135,8 @@ B<Offset> B<Size> B<Description> 16+N*14 4 Entry N: network mask 20+N*14 4 Entry N: timestamp 24+N*14 2 Entry N: ISO 3166-1 country code + 26+N*14 4 Entry N: length of additional data + 30+N*14 ? Entry N: additional data When a leaf page is encountered, the IP address in question is compared with each entry in turn using the usual procedure (B<AND>ing with the network @@ -239,10 +243,11 @@ sub ipdb_save_page($$) { } elsif ($page->{type} == IPDB_PAGE_LEAF) { my @a; foreach my $ent (@{$page->{tab}}) { - push @a, @{$ent}; + push @a, @{$ent}[0 .. 3],freeze($ent->[4]); } $ret = syswrite($dbf->{fd}, - pack('LLL(LLLa2)*@'."$dbf->{pagesize}", $page->{type}, + pack('LLL(LLLa2L/a)*@'."$dbf->{pagesize}", + $page->{type}, $#{$page->{tab}} + 1, $page->{next}, @a)); @@ -349,10 +354,11 @@ sub ipdb_get_page($$) { my ($x, @a) = unpack('LL257', $s); $ret{tab} = \@a; } elsif ($ret{type} == IPDB_PAGE_LEAF) { - (my $x, my $nent, $ret{next}, my @a) = - unpack('LLL(LLLa2)*', $s); - for (my $i = 0; $i < $nent; $i += 4) { - push @{$ret{tab}}, [ $a[$i], $a[$i+1], $a[$i+2], $a[$i+3] ]; + (my $x, my $nent, $ret{next}) = + unpack('LLL', $s); + my ($x1, $x2, $x3, @a) = unpack("LLL(LLLa2L/a)$nent", $s); + for (my $i = 0; $i < $nent; $i += 5) { + push @{$ret{tab}}, [ @a[$i .. $i+3], thaw $a[$i+4] ]; } # print "$nent\n"; # print join(', ', @{$ret{tab}})."\n"; @@ -459,10 +465,10 @@ sub ipdb_lookup($$) { foreach my $r (@{$page->{tab}}) { if (($ipn & $r->[1]) == $r->[0]) { # FIXME: check timestamp - - return ( country => $r->[3], + return ( ( country => $r->[3], network => inet_ntoa(pack('N', $r->[0])), - netmask => inet_ntoa(pack('N', $r->[1])) ); + netmask => inet_ntoa(pack('N', $r->[1])) ), + %{$r->[4]}); } } return undef if (!$page->{next}); @@ -479,8 +485,11 @@ Inserts into the database I<$cidr> and the corresponding country code I<$country Currently, I<$cidr> must be in the form B<I<Net-address>/I<Netmask-length>>. =cut -sub ipdb_insert($$$) { - my ($dbf, $cidr, $country) = @_; +sub ipdb_insert { + my $dbf = shift; + my $cidr = shift; + my $country = shift; + local %_ = @_; my @ipo; my $ipn; my $masklen; @@ -541,7 +550,7 @@ sub ipdb_insert($$$) { } } - push @{$page->{tab}}, [ $ipn, $netmask, time(), $country ]; + push @{$page->{tab}}, [ $ipn, $netmask, time(), $country, \%_ ]; $page->{dirty} = 1; return 1; diff --git a/whoseip/whoseip.pl b/whoseip/whoseip.pl index dc512df..d5f5f11 100644 --- a/whoseip/whoseip.pl +++ b/whoseip/whoseip.pl @@ -19,7 +19,7 @@ use Getopt::Long qw(:config gnu_getopt no_ignore_case); use IO::Socket; use Pod::Usage; use Pod::Man; -use Socket qw(:DEFAULT :crlf); +use Socket qw(:DEFAULT :crlf inet_ntoa); use Net::CIDR; use Whoseip::DB qw(:all); @@ -143,9 +143,33 @@ sub str2ipv4 { } sub range2count { + my $count = 0; + foreach my $arg (@_) { my @a = split /-/, shift; - return 0 unless $#a == 1; - return str2ipv4($a[1]) - str2ipv4($a[0]) + 1; + next unless $#a == 1; + $count += str2ipv4($a[1]) - str2ipv4($a[0]) + 1; + } + return $count; +} + +sub cidr_to_range { + my @a; + + @a = sort { $a->[0] <=> $b->[0] } + map { + map { [ map { str2ipv4($_) } split(/-/, $_, 2) ] } + Net::CIDR::cidr2range($_) + } split /,/, shift; + + for (my $i = 1; $i <= $#a; $i++) { + if ($a[$i]->[0] == $a[$i-1]->[1] + 1) { + $a[$i-1]->[1] = $a[$i]->[1]; + splice @a, $i, 1; + } + } + + return join ',', map { inet_ntoa(pack('N', $_->[0])) . '-' . + inet_ntoa(pack('N', $_->[1])) } @a; } # ############ @@ -238,7 +262,7 @@ sub lacnic_decode { $cidr = "$1.0/$2"; } $ref->{cidr} = $cidr; - $ref->{range} = join ',', Net::CIDR::cidr2range($cidr); + $ref->{range} = cidr_to_range($cidr); $ref->{count} = range2count($ref->{range}); } elsif ($input =~ /^country:\s+(.+)/) { $ref->{country} = $1; @@ -293,7 +317,7 @@ sub nic_ad_jp_decode { my ($input, $ref) = @_; if ($input =~ /^a\.\s+\[Network Number\]\s+(.+)/) { $ref->{cidr} = $1; - $ref->{range} = join ',', Net::CIDR::cidr2range($ref->{cidr}); + $ref->{range} = cidr_to_range($ref->{cidr}); $ref->{count} = range2count($ref->{range}); $ref->{country} = 'JP'; } @@ -414,9 +438,11 @@ sub serve { %res = ipdb_lookup($dbf, $term); if (defined($res{country})) { $res{status} = 'OK'; + unless (defined($res{cidr})) { $res{cidr} = Net::CIDR::addrandmask2cidr($res{network}, $res{netmask}); - $res{range} = join ',', Net::CIDR::cidr2range($res{cidr}); + } + $res{range} = cidr_to_range($res{cidr}); $res{count} = range2count($res{range}); return %res; } @@ -435,7 +461,7 @@ sub serve { $res{status} = 'OK'; if (defined($dbf)) { foreach my $cidr (split /,/, $res{cidr}) { - ipdb_insert($dbf, $cidr, $res{country}); + ipdb_insert($dbf, $cidr, $res{country}, cidr=>$res{cidr}); } } } |