ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/myhttpd/netgeo.pl
Revision: 1.6
Committed: Thu Aug 30 03:35:56 2001 UTC (22 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.5: +5 -0 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #!/usr/bin/perl
2
3 # APNIC refer: KRNIC (for 211.104.0.0)
4
5 use Socket;
6 use Fcntl;
7
8 use Coro;
9 use Coro::Event;
10 use Coro::Semaphore;
11 use Coro::SemaphoreSet;
12 use Coro::Socket;
13
14 $Event::DIED = sub {
15 Event::verbose_exception_handler(@_);
16 #Event::unloop_all();
17 };
18
19 tie %netgeo::whois, BerkeleyDB::Btree,
20 -Env => $db_env,
21 -Filename => "whois",
22 -Flags => DB_CREATE,
23 or die "unable to create/open whois table";
24 $netgeo::iprange = new BerkeleyDB::Btree
25 -Env => $db_env,
26 -Filename => "iprange",
27 -Flags => DB_CREATE,
28 or die "unable to create/open iprange table";
29
30 package Whois;
31
32 use Coro::Event;
33
34 sub new {
35 my $class = shift;
36 my $name = shift;
37 my $ip = shift;
38 my $self = bless { name => $name, ip => $ip, @_ }, $class;
39 $self->{maxjobs} = new Coro::Semaphore $self->{maxjobs} || 1;
40 $self;
41 }
42
43 sub ip {
44 $_[0]{ip};
45 }
46
47 sub sanitize {
48 $_[1];
49 }
50
51 sub whois_request {
52 my ($self, $query) = @_;
53
54 my $id = "$self->{name}\x0$query";
55 my $whois = $netgeo::whois{$id};
56
57 unless (defined $whois) {
58 print "WHOIS($self->{name},$query)\n";
59
60 my $guard = $self->{maxjobs}->guard;
61 my $timeout = 5;
62
63 while () {
64 my $fh = new Coro::Socket
65 PeerAddr => $self->ip,
66 PeerPort => 'whois',
67 Timeout => 30;
68 if ($fh) {
69 print $fh "$query\n";
70 $fh->read($whois, 16*1024); # max 16k. whois stored
71 close $fh;
72 $whois =~ s/\015?\012/\n/g;
73 $whois = $self->sanitize($whois);
74 if ($whois eq ""
75 or ($whois =~ /query limit/i && $whois =~ /exceeded/i) # ARIN
76 or ($whois =~ /wait a while and try again/i) # ARIN
77 or ($whois =~ /^%ERROR:202:/) # RIPE/APNIC
78 ) {
79 print "retrying in $timeout seconds\n";#d#
80 do_timer(desc => "timer2", after => $timeout);
81 $timeout *= 2;
82 $timeout = 1 if $timeout > 600;
83 } else {
84 last;
85 }
86 }
87 }
88
89 $netgeo::whois{$id} = $whois;
90 }
91
92 $whois;
93 }
94
95 package Whois::ARIN;
96
97 use Date::Parse;
98
99 use base Whois;
100
101 sub sanitize {
102 local $_ = $_[1];
103 s/\n[\t ]{6,}([0-9.]+ - [0-9.]+)/ $1/g;
104 $_;
105 }
106
107 # there are only two problems with arin's whois database:
108 # a) the data cannot be trusted and often is old or even wrong
109 # b) the database format is nonparsable
110 # (no spaces between netname/ip and netnames can end in digits ;)
111 # of course, the only source to find out about global
112 # address distribution is... arin.
113 sub ip_request {
114 my ($self, $ip) = @_;
115
116 my $whois = $self->whois_request($ip);
117
118 return () if $whois =~ /^No match/;
119
120 if ($whois =~ /^To single out one record/m) {
121 my $handle;
122 while ($whois =~ /\G\S.*\(([A-Z0-9\-]+)\).*\n/mg) {
123 $handle = $1;
124 #return if $handle =~ /-(RIPE|APNIC)/; # heuristic, bbut bad because ripe might not have better info
125 }
126 $handle or die "$whois ($ip): unparseable multimatch\n";
127 $whois = $self->whois_request("!$handle");
128 }
129
130 my ($address, $info, $coordinator, undef) = split /\n\n/, $whois;
131
132 $info =~ /^\s+Netname: (\S+)$/mi
133 or die "$whois($ip): no netname\n";
134 my $netname = $1;
135
136 $info =~ /^\s+Netblock: ([0-9.]+\s+-\s+[0-9.]+)\s*$/mi
137 or die "$whois($ip): no netblock\n";
138 my $netblock = $1;
139
140 my $maintainer;
141
142 if ($info =~ /^\s+Maintainer: (\S+)\s*$/mi) {
143 $maintainer = "*ma: $1\n";
144 return if $1 =~ /^(?:AP|RIPE)$/;
145 }
146
147 $coordinator =~ s/^\s+Coordinator:\s*//si
148 or $coordinator = "";
149
150 $address =~ s/\n\s*(\S+)$//
151 or die "$whois($ip): no parseable country ($address)\n";
152 my $country = $1;
153
154 $address =~ s/^\s*/*de: /mg;
155 $coordinator =~ s/^\s*/*ad: /mg;
156
157 $whois = <<EOF;
158 *in: $netblock
159 *na: $netname
160 *cy: $country
161 $maintainer$address
162 $coordinator
163 EOF
164 $whois =~ s/\n+$//;
165 $whois;
166 }
167
168 package Whois::RIPE;
169
170 use base Whois;
171
172 sub sanitize {
173 local $_ = $_[1];
174 s/^%.*\n//gm;
175 s/^\n+//;
176 s/\n*$/\n/;
177 $_;
178 }
179
180 sub ip_request {
181 my ($self, $ip) = @_;
182
183 my $whois = $self->whois_request("-FSTin $ip");
184
185 $whois =~ /^\*in: 0\.0\.0\.0 - 255\.255\.255\.255/
186 and return;
187
188 $whois =~ /^\*ac: XXX0/m # 192.0.0.0
189 and return;
190
191 $whois =~ /^%ERROR:/m
192 and return;
193
194 #while ($whois =~ s/^\*(?:ac|tc):\s+(\S+)\n//m) {
195 # $whois .= $self->whois_request("-FSTpn $1");
196 #}
197
198 $whois =~ s/^\*(?:pn|nh|mb|ch|so|rz|ny|st|rm):.*\n//mg;
199
200 $whois =~ s/\n+$//;
201
202 $whois;
203 }
204
205 package netgeo;
206
207 use BerkeleyDB;
208 use Socket;
209
210 sub ip2int($) {
211 unpack "N", inet_aton $_[0];
212 }
213
214 sub int2ip($) {
215 inet_ntoa pack "N", $_[0];
216 }
217
218 our %WHOIS;
219
220 $WHOIS{ARIN} = new Whois::ARIN ARIN => "whois.arin.net", maxjobs => 12;
221 $WHOIS{RIPE} = new Whois::RIPE RIPE => "whois.ripe.net", maxjobs => 20;
222 $WHOIS{APNIC} = new Whois::RIPE APNIC => "whois.apnic.net", maxjobs => 20;
223
224 $whoislock = new Coro::SemaphoreSet;
225
226 sub ip_request {
227 my $ip = $_[0];
228
229 my $guard = $whoislock->guard($ip);
230
231 my $c = $iprange->db_cursor;
232 my $v;
233
234 if (!$c->c_get((inet_aton $ip), $v, DB_SET_RANGE)) {
235 my ($ip0, $ip1, $whois) = split /\x0/, $v;
236 my $_ip = ip2int $ip;
237 if ($ip0 <= $_ip && $_ip <= $ip1) {
238 return $whois;
239 }
240 }
241
242 my ($arin, $ripe, $apnic);
243
244 $whois = $WHOIS{APNIC}->ip_request($ip)
245 || $WHOIS{RIPE} ->ip_request($ip)
246 || $WHOIS{ARIN} ->ip_request($ip);
247
248 $whois =~ /^\*in: ([0-9.]+)\s+-\s+([0-9.]+)\s*$/mi
249 or do { warn "$whois($ip): no addresses found\n", last };
250
251 my ($ip0, $ip1) = ($1, $2);
252
253 my $_ip = ip2int($ip);
254 my $_ip0 = ip2int($ip0);
255 my $_ip1 = ip2int($ip1);
256
257 if ($_ip0 + 256 < $_ip1) {
258 $_ip = $_ip & 0xffffff00;
259 $_ip0 = $_ip if $_ip0 < $_ip;
260 $_ip1 = $_ip + 255 if $_ip1 > $_ip + 255;
261 }
262
263 $iprange->db_put((pack "N", $_ip1), (join "\x0", $_ip0, $_ip1, $whois));
264 (tied %whois)->db_sync;
265 $iprange->db_sync;
266
267 $whois;
268 }
269
270
271