aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2014-10-14 23:02:46 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2014-10-14 23:02:46 +0300
commit22ea7f92356b66406e7507002b826cbf12e14d52 (patch)
tree7a30a51940f2a82f63105a15000f7788e9384a40
parentc60e1f248a5b911e502b46420389aad42bb7fac9 (diff)
downloaddnstools-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.pm35
-rw-r--r--whoseip/whoseip.pl40
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});
}
}
}

Return to:

Send suggestions and report system problems to the System administrator.