ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/myhttpd/netgeo.pl
(Generate patch)

Comparing Coro/myhttpd/netgeo.pl (file contents):
Revision 1.2 by root, Sat Aug 11 16:34:47 2001 UTC vs.
Revision 1.18 by root, Sat Dec 8 21:01:16 2007 UTC

3# APNIC refer: KRNIC (for 211.104.0.0) 3# APNIC refer: KRNIC (for 211.104.0.0)
4 4
5use Socket; 5use Socket;
6use Fcntl; 6use Fcntl;
7 7
8use PApp::SQL;
9
10use Coro; 8use Coro;
11use Coro::Event; 9use Coro::EV;
12use Coro::Semaphore; 10use Coro::Semaphore;
11use Coro::SemaphoreSet;
13use Coro::Socket; 12use Coro::Socket;
13use Coro::Timer;
14 14
15$Event::DIED = sub { 15use BerkeleyDB;
16 Event::verbose_exception_handler(@_); 16
17 #Event::unloop_all(); 17tie %netgeo::whois, BerkeleyDB::Btree,
18}; 18 -Env => $db_env,
19 -Filename => "whois",
20 -Flags => DB_CREATE,
21 or die "unable to create/open whois table";
22$netgeo::iprange = new BerkeleyDB::Btree
23 -Env => $db_env,
24 -Filename => "iprange",
25 -Flags => DB_CREATE,
26 or die "unable to create/open iprange table";
19 27
20package Whois; 28package Whois;
21 29
22use PApp::SQL;
23use Coro::Event; 30use Coro::EV;
24 31
25sub new { 32sub new {
26 my $class = shift; 33 my $class = shift;
27 my $name = shift; 34 my $name = shift;
28 my $ip = shift; 35 my $ip = shift;
39 $_[1]; 46 $_[1];
40} 47}
41 48
42sub whois_request { 49sub whois_request {
43 my ($self, $query) = @_; 50 my ($self, $query) = @_;
44 my ($id, $whois);
45 51
46 my $st = sql_exec \($id, $whois), 52 my $id = "$self->{name}\x0$query";
47 "select id, whois from whois 53 my $whois = $netgeo::whois{$id};
48 where nic = ? and query = ?",
49 $self->{name}, $query;
50 54
51 unless ($st->fetch) { 55 unless (defined $whois) {
56 print "WHOIS($self->{name},$query)\n";
57
52 my $guard = $self->{maxjobs}->guard; 58 my $guard = $self->{maxjobs}->guard;
53 my $timeout = 5; 59 my $timeout = 5;
54 60
55 while () { 61 while () {
56 my $fh = new Coro::Socket 62 my $fh = new Coro::Socket
57 PeerAddr => $self->ip, 63 PeerAddr => $self->ip,
58 PeerPort => 'whois', 64 PeerPort => $self->{port} || "whois",
59 Timeout => 30; 65 Timeout => 30;
60 if ($fh) { 66 if ($fh) {
61 print $fh "$query\n"; 67 print $fh "$query\n";
62 $fh->read($whois, 16*1024); # max 16k. whois stored 68 $fh->read($whois, 16*1024); # max 16k. whois stored
63 close $fh; 69 close $fh;
73 $timeout *= 2; 79 $timeout *= 2;
74 $timeout = 1 if $timeout > 600; 80 $timeout = 1 if $timeout > 600;
75 } else { 81 } else {
76 last; 82 last;
77 } 83 }
84 } else {
85 # only retry once a minute
86 print STDERR "unable to connect to $self->{ip} ($self->{name}), retrying...\n";
87 Coro::Timer::sleep 300;
78 } 88 }
79 } 89 }
80 90
81 sql_exec "replace into whois values (NULL,?,?,NULL,?,?)", 91 $netgeo::whois{$id} = $whois;
82 $self->{name}, $query, $whois, time;
83
84 my $st = sql_exec \$id,
85 "select id from whois
86 where nic = ? and query = ?",
87 $self->{name}, $query;
88 $st->fetch or die;
89 } 92 }
90 93
91 $whois; 94 $whois;
92} 95}
93 96
94package Whois::ARIN; 97package Whois::ARIN;
95 98
96use Date::Parse; 99use Date::Parse;
97use PApp::SQL;
98 100
99use base Whois; 101use base Whois;
100 102
101sub sanitize { 103sub sanitize {
102 local $_ = $_[1]; 104 local $_ = $_[1];
113sub ip_request { 115sub ip_request {
114 my ($self, $ip) = @_; 116 my ($self, $ip) = @_;
115 117
116 my $whois = $self->whois_request($ip); 118 my $whois = $self->whois_request($ip);
117 119
118 return () if $whois =~ /^No match/; 120 return if $whois =~ /^No match/;
119 121
120 if ($whois =~ /^To single out one record/m) { 122 if ($whois =~ /^To single out one record/m) {
121 my $handle; 123 my $handle;
122 while ($whois =~ /\G\S.*\(([A-Z0-9\-]+)\).*\n/mg) { 124 while ($whois =~ /\G\S.*\(([A-Z0-9\-]+)\).*\n/mg) {
123 $handle = $1; 125 $handle = $1;
124 #return if $handle =~ /-(RIPE|APNIC)/; # heuristic, bbut bad because ripe might not have better info 126 #return if $handle =~ /-(RIPE|APNIC)/; # heuristic, but bad because ripe might not have better info
125 } 127 }
126 $handle or die "$whois ($ip): unparseable multimatch\n"; 128 $handle or die "$whois ($ip): unparseable multimatch\n";
127 $whois = $self->whois_request("!$handle"); 129 $whois = $self->whois_request("!$handle");
128 } 130 }
129 131
165 $whois; 167 $whois;
166} 168}
167 169
168package Whois::RIPE; 170package Whois::RIPE;
169 171
170use PApp::SQL; 172use Socket;
171
172use base Whois; 173use base Whois;
173 174
174sub sanitize { 175sub sanitize {
175 local $_ = $_[1]; 176 local $_ = $_[1];
177
176 s/^%.*\n//gm; 178 s/^%.*\n//gm;
177 s/^\n+//; 179 s/^\n+//;
178 s/\n*$/\n/; 180 s/\n*$/\n/;
181
182 s/^inetnum:\s+/*in: /gm;
183 s/^admin-c:\s+/*ac: /gm;
184 s/^tech-c:\s+/*tc: /gm;
185 s/^owner-c:\s+/*oc: /gm;
186 s/^country:\s+/*cy: /gm;
187 s/^phone:\s+/*ph: /gm;
188 s/^remarks:\s+/*rm: /gm;
189 s/^changed:\s+/*ch: /gm;
190 s/^created:\s+/*cr: /gm;
191 s/^address:\s+/*ad: /gm;
192 s/^status:\s+/*st: /gm;
193 s/^inetrev:\s+/*ir: /gm;
194 s/^nserver:\s+/*ns: /gm;
195
179 $_; 196 $_;
180} 197}
181 198
182sub ip_request { 199sub ip_request {
183 my ($self, $ip) = @_; 200 my ($self, $ip) = @_;
184 201
185 my $whois = $self->whois_request("-FSTin $ip"); 202 my $whois = $self->whois_request("$self->{rflags}$ip");
203
204 $whois =~ s{
205 (2[0-5][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])
206 (?:\.
207 (2[0-5][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])
208 (?:\.
209 (2[0-5][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])
210 (?:\.
211 (2[0-5][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])
212 )?
213 )?
214 )?
215 /
216 ([0-9]+)
217 }{
218 my $ip = inet_aton sprintf "%d.%d.%d.%d", $1, $2, $3, $4;
219 my $net = 1 << (31 - $5);
220 my $mask = inet_aton 2 ** 32 - $net;
221
222 my $ip1 = $ip & $mask;
223 my $ip2 = $ip1 | inet_aton $net * 2 - 1;
224 (inet_ntoa $ip1) . " - " . (inet_ntoa $ip2);
225 }gex;
186 226
187 $whois =~ /^\*in: 0\.0\.0\.0 - 255\.255\.255\.255/ 227 $whois =~ /^\*in: 0\.0\.0\.0 - 255\.255\.255\.255/
188 and return; 228 and return;
189 229
230 $whois =~ /^\*de: This network range is not allocated to /m # APINIC e.g. 24.0.0.0
231 and return;
232
190 $whois =~ /^\*ac: XXX0/m # 192.0.0.0 233 $whois =~ /^\*ac: XXX0/m # 192.0.0.0
234 and return;
235
236 $whois =~ /^\*st: (?:ALLOCATED )?UNSPECIFIED/m
191 and return; 237 and return;
192 238
193 $whois =~ /^%ERROR:/m 239 $whois =~ /^%ERROR:/m
194 and return; 240 and return;
195 241
196 #while ($whois =~ s/^\*(?:ac|tc):\s+(\S+)\n//m) { 242 #while ($whois =~ s/^\*(?:ac|tc):\s+(\S+)\n//m) {
197 # $whois .= $self->whois_request("-FSTpn $1"); 243 # $whois .= $self->whois_request("-FSTpn $1");
198 #} 244 #}
199 245
246 #$whois =~ s/^\*(?:pn|nh|mb|ch|so|rz|ny|st|rm):.*\n//mg;
247
248 $whois =~ s/\n+$//;
249
250 $whois;
251}
252
253package Whois::RWHOIS;
254
255use base Whois;
256
257sub sanitize {
258 local $_ = $_[1];
259 s/^%referral\s+/referral:/gm;
260 s/^network://gm;
261 s/^%.*\n//gm;
262 s/^\n+//m;
263 s/\n*$/\n/m;
264
265 s/^(\S+):\s*/\L$1: /gm;
266 s/^ip-network-block:/*in:/gm;
267 s/^country-code:/*cy:/gm;
268 s/^tech-contact;i:/*tc:/gm;
269 s/^updated:/*ch:/gm;
270 s/^street-address:/*ad:/gm;
271 s/^org-name:/*rm:/gm;
272 s/^created:/*cr:/gm;
273
274 $_;
275}
276
277sub ip_request {
278 my ($self, $ip) = @_;
279
280 my $whois = $self->whois_request("$ip");
281
282 $whois =~ /^\*in: 0\.0\.0\.0 - 255\.255\.255\.255/
283 and return;
284
285 $whois =~ /^\*ac: XXX0/m # 192.0.0.0
286 and return;
287
288 $whois =~ /^%ERROR:/m
289 and return;
290
291 #while ($whois =~ s/^\*(?:ac|tc):\s+(\S+)\n//m) {
292 # $whois .= $self->whois_request("-FSTpn $1");
293 #}
294
200 $whois =~ s/^\*(?:pn|nh|mb|ch|so|rz|ny|st|rm):.*\n//mg; 295 $whois =~ s/^\*(?:pn|nh|mb|ch|so|rz|ny|st|rm):.*\n//mg;
201 296
202 $whois =~ s/\n+$//; 297 $whois =~ s/\n+$//;
203 298
204 $whois; 299 $whois;
205} 300}
206 301
207package main; 302package netgeo;
303
304use Socket;
305use BerkeleyDB;
208 306
209sub ip2int($) { 307sub ip2int($) {
210 unpack "N", inet_aton $_[0]; 308 unpack "N", inet_aton $_[0];
211} 309}
212 310
214 inet_ntoa pack "N", $_[0]; 312 inet_ntoa pack "N", $_[0];
215} 313}
216 314
217our %WHOIS; 315our %WHOIS;
218 316
219$WHOIS{ARIN} = new Whois::ARIN ARIN => "whois.arin.net", maxjobs => 12; 317#$WHOIS{ARIN} = new Whois::ARIN ARIN => "whois.arin.net", port => 43, maxjobs => 12;
318$WHOIS{ARIN} = new Whois::RWHOIS ARIN => "rwhois.arin.net", port => 4321, maxjobs => 12;
220$WHOIS{RIPE} = new Whois::RIPE RIPE => "whois.ripe.net", maxjobs => 20; 319$WHOIS{RIPE} = new Whois::RIPE RIPE => "whois.ripe.net", port => 43, rflags => "-FTin ", maxjobs => 20;
320$WHOIS{APNIC} = new Whois::RIPE APNIC => "whois.apnic.net", port => 43, rflags => "-FTin ", maxjobs => 20;
221$WHOIS{APNIC} = new Whois::RIPE APNIC => "whois.apnic.net", maxjobs => 20; 321$WHOIS{LACNIC} = new Whois::RIPE LACNIC => "whois.lacnic.net", port => 43, maxjobs => 20;
322
323$whoislock = new Coro::SemaphoreSet;
222 324
223sub ip_request { 325sub ip_request {
224 my $ip = $_[0]; 326 my $ip = $_[0];
225 my $_ip = ip2int($ip);
226 327
227 my $st = sql_exec \my($whois, $ip0), 328 my $guard = $whoislock->guard($ip);
228 "select data, ip0 from iprange
229 where ? <= ip1
230 having ip0 <= ?
231 order by ip1
232 limit 1",
233 $_ip, $_ip;
234 329
235 unless ($st->fetch) { 330 my $c = $iprange->db_cursor;
236 my ($arin, $ripe, $apnic); 331 my $v;
237 332
238 $whois = $WHOIS{APNIC}->ip_request($ip) 333 if (!$c->c_get((inet_aton $ip), $v, DB_SET_RANGE)) {
239 || $WHOIS{RIPE} ->ip_request($ip) 334 my ($ip0, $ip1, $whois) = split /\x0/, $v;
240 || $WHOIS{ARIN} ->ip_request($ip);
241
242 $whois =~ /^\*in: ([0-9.]+)\s+-\s+([0-9.]+)\s*$/mi
243 or warn "$whois($ip): no addresses found\n";
244 $whois =~ /^\*in: ([0-9.]+)\s+-\s+([0-9.]+)\s*$/mi
245 or return;
246
247 $whois =~ /^\*in: ([0-9.]+)\s+-\s+([0-9.]+)\s*$/mi
248 or die "$whois($ip): no addresses found\n";
249
250 my ($ip0, $ip1) = ($1, $2);
251
252 my $_ip0 = ip2int($ip0); 335 my $_ip = ip2int $ip;
253 my $_ip1 = ip2int($ip1); 336 if ($ip0 <= $_ip && $_ip <= $ip1) {
254 337 return $whois;
255 if ($_ip0 + 256 < $_ip1) {
256 $_ip = $_ip & 0xffffff00;
257 $_ip0 = $_ip if $_ip0 < $_ip;
258 $_ip1 = $_ip + 255 if $_ip1 > $_ip + 255;
259 } 338 }
260
261 sql_exec "replace into iprange values (?, ?, NULL, ?)",
262 $_ip0, $_ip1, $whois;
263
264 #print "$ip ($ip0, $ip1 ($_ip0, $_ip1)\n$whois\n";
265 } 339 }
266 340
267 $whois; 341 my ($arin, $ripe, $apnic);
268}
269 342
343 $whois = $WHOIS{RIPE}->ip_request($ip)
344 || $WHOIS{APNIC} ->ip_request($ip)
345 || $WHOIS{ARIN} ->ip_request($ip)
346# || $WHOIS{LACNIC}->ip_request($ip)
347 ;
270 348
349 $whois =~ /^\*in: ([0-9.]+)\s+-\s+([0-9.]+)\s*$/mi
350 or do { warn "$whois($ip): no addresses found\n", last };
271 351
352 my ($ip0, $ip1) = ($1, $2);
353
354 my $_ip = ip2int($ip);
355 my $_ip0 = ip2int($ip0);
356 my $_ip1 = ip2int($ip1);
357
358 if ($_ip0 + 256 < $_ip1) {
359 $_ip = $_ip & 0xffffff00;
360 $_ip0 = $_ip if $_ip0 < $_ip;
361 $_ip1 = $_ip + 255 if $_ip1 > $_ip + 255;
362 }
363
364 $iprange->db_put((pack "N", $_ip1), (join "\x0", $_ip0, $_ip1, $whois));
365 (tied %whois)->db_sync;
366 $iprange->db_sync;
367
368 $whois;
369}
370
371if (0) {
372 #print ip_request "68.52.164.8"; # goof
373 #print "\n\n";
374 #print ip_request "200.202.220.222"; # lacnic
375 #print "\n\n";
376 #print ip_request "62.116.167.250";
377 #print "\n\n";
378 #print ip_request "133.11.128.254"; # jp
379 #print "\n\n";
380 print ip_request "80.131.153.93";
381 print "\n\n";
382}
383
3841;
385
386

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines