… | |
… | |
2 | |
2 | |
3 | # APNIC refer: KRNIC (for 211.104.0.0) |
3 | # APNIC refer: KRNIC (for 211.104.0.0) |
4 | |
4 | |
5 | use Socket; |
5 | use Socket; |
6 | use Fcntl; |
6 | use Fcntl; |
7 | |
|
|
8 | use PApp::SQL; |
|
|
9 | |
7 | |
10 | use Coro; |
8 | use Coro; |
11 | use Coro::Event; |
9 | use Coro::Event; |
12 | use Coro::Semaphore; |
10 | use Coro::Semaphore; |
|
|
11 | use Coro::SemaphoreSet; |
13 | use Coro::Socket; |
12 | use Coro::Socket; |
14 | |
13 | |
15 | $Event::DIED = sub { |
14 | $Event::DIED = sub { |
16 | Event::verbose_exception_handler(@_); |
15 | Event::verbose_exception_handler(@_); |
17 | #Event::unloop_all(); |
16 | #Event::unloop_all(); |
18 | }; |
17 | }; |
19 | |
18 | |
20 | $PApp::SQL::DBH = PApp::SQL::connect_cached __FILE__, "DBI:mysql:netgeo" or die; |
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"; |
21 | |
29 | |
22 | package Whois; |
30 | package Whois; |
23 | |
31 | |
24 | use PApp::SQL; |
|
|
25 | use Coro::Event; |
32 | use Coro::Event; |
26 | |
33 | |
27 | sub new { |
34 | sub new { |
28 | my $class = shift; |
35 | my $class = shift; |
29 | my $name = shift; |
36 | my $name = shift; |
… | |
… | |
41 | $_[1]; |
48 | $_[1]; |
42 | } |
49 | } |
43 | |
50 | |
44 | sub whois_request { |
51 | sub whois_request { |
45 | my ($self, $query) = @_; |
52 | my ($self, $query) = @_; |
46 | my ($id, $whois); |
|
|
47 | |
53 | |
48 | my $st = sql_exec \($id, $whois), |
54 | my $id = "$self->{name}\x0$query"; |
49 | "select id, whois from whois |
55 | my $whois = $netgeo::whois{$id}; |
50 | where nic = ? and query = ?", |
|
|
51 | $self->{name}, $query; |
|
|
52 | |
56 | |
53 | Coro::cede; |
57 | unless (defined $whois) { |
|
|
58 | print "WHOIS($self->{name},$query)\n"; |
54 | |
59 | |
55 | unless ($st->fetch) { |
|
|
56 | my $guard = $self->{maxjobs}->guard; |
60 | my $guard = $self->{maxjobs}->guard; |
57 | my $timeout = 5; |
61 | my $timeout = 5; |
58 | |
62 | |
59 | while () { |
63 | while () { |
60 | my $fh = new Coro::Socket |
64 | my $fh = new Coro::Socket |
… | |
… | |
80 | last; |
84 | last; |
81 | } |
85 | } |
82 | } |
86 | } |
83 | } |
87 | } |
84 | |
88 | |
85 | sql_exec "replace into whois values (NULL,?,?,NULL,?,?)", |
89 | $netgeo::whois{$id} = $whois; |
86 | $self->{name}, $query, $whois, time; |
|
|
87 | |
|
|
88 | my $st = sql_exec \$id, |
|
|
89 | "select id from whois |
|
|
90 | where nic = ? and query = ?", |
|
|
91 | $self->{name}, $query; |
|
|
92 | $st->fetch or die; |
|
|
93 | } |
90 | } |
94 | |
91 | |
95 | $whois; |
92 | $whois; |
96 | } |
93 | } |
97 | |
94 | |
98 | package Whois::ARIN; |
95 | package Whois::ARIN; |
99 | |
96 | |
100 | use Date::Parse; |
97 | use Date::Parse; |
101 | use PApp::SQL; |
|
|
102 | |
98 | |
103 | use base Whois; |
99 | use base Whois; |
104 | |
100 | |
105 | sub sanitize { |
101 | sub sanitize { |
106 | local $_ = $_[1]; |
102 | local $_ = $_[1]; |
… | |
… | |
169 | $whois; |
165 | $whois; |
170 | } |
166 | } |
171 | |
167 | |
172 | package Whois::RIPE; |
168 | package Whois::RIPE; |
173 | |
169 | |
174 | use PApp::SQL; |
|
|
175 | |
|
|
176 | use base Whois; |
170 | use base Whois; |
177 | |
171 | |
178 | sub sanitize { |
172 | sub sanitize { |
179 | local $_ = $_[1]; |
173 | local $_ = $_[1]; |
180 | s/^%.*\n//gm; |
174 | s/^%.*\n//gm; |
… | |
… | |
206 | $whois =~ s/\n+$//; |
200 | $whois =~ s/\n+$//; |
207 | |
201 | |
208 | $whois; |
202 | $whois; |
209 | } |
203 | } |
210 | |
204 | |
211 | package main; |
205 | package netgeo; |
|
|
206 | |
|
|
207 | use BerkeleyDB; |
|
|
208 | use Socket; |
212 | |
209 | |
213 | sub ip2int($) { |
210 | sub ip2int($) { |
214 | unpack "N", inet_aton $_[0]; |
211 | unpack "N", inet_aton $_[0]; |
215 | } |
212 | } |
216 | |
213 | |
… | |
… | |
222 | |
219 | |
223 | $WHOIS{ARIN} = new Whois::ARIN ARIN => "whois.arin.net", maxjobs => 12; |
220 | $WHOIS{ARIN} = new Whois::ARIN ARIN => "whois.arin.net", maxjobs => 12; |
224 | $WHOIS{RIPE} = new Whois::RIPE RIPE => "whois.ripe.net", maxjobs => 20; |
221 | $WHOIS{RIPE} = new Whois::RIPE RIPE => "whois.ripe.net", maxjobs => 20; |
225 | $WHOIS{APNIC} = new Whois::RIPE APNIC => "whois.apnic.net", maxjobs => 20; |
222 | $WHOIS{APNIC} = new Whois::RIPE APNIC => "whois.apnic.net", maxjobs => 20; |
226 | |
223 | |
|
|
224 | $whoislock = new Coro::SemaphoreSet; |
|
|
225 | |
227 | sub ip_request { |
226 | sub ip_request { |
228 | my $ip = $_[0]; |
227 | my $ip = $_[0]; |
229 | my $_ip = ip2int($ip); |
|
|
230 | |
228 | |
231 | my $st = sql_exec \my($whois, $ip0), |
229 | my $guard = $whoislock->guard($ip); |
232 | "select data, ip0 from iprange |
|
|
233 | where ? <= ip1 |
|
|
234 | having ip0 <= ? |
|
|
235 | order by ip1 |
|
|
236 | limit 1", |
|
|
237 | $_ip, $_ip; |
|
|
238 | |
230 | |
239 | Coro::cede; |
231 | my $c = $iprange->db_cursor; |
240 | |
232 | my $v; |
241 | unless ($st->fetch) { |
|
|
242 | my ($arin, $ripe, $apnic); |
|
|
243 | |
233 | |
244 | $whois = $WHOIS{APNIC}->ip_request($ip) |
234 | if (!$c->c_get((inet_aton $ip), $v, DB_SET_RANGE)) { |
245 | || $WHOIS{RIPE} ->ip_request($ip) |
235 | my ($ip0, $ip1, $whois) = split /\x0/, $v; |
246 | || $WHOIS{ARIN} ->ip_request($ip); |
|
|
247 | |
|
|
248 | $whois =~ /^\*in: ([0-9.]+)\s+-\s+([0-9.]+)\s*$/mi |
|
|
249 | or warn "$whois($ip): no addresses found\n"; |
|
|
250 | $whois =~ /^\*in: ([0-9.]+)\s+-\s+([0-9.]+)\s*$/mi |
|
|
251 | or return; |
|
|
252 | |
|
|
253 | $whois =~ /^\*in: ([0-9.]+)\s+-\s+([0-9.]+)\s*$/mi |
|
|
254 | or die "$whois($ip): no addresses found\n"; |
|
|
255 | |
|
|
256 | my ($ip0, $ip1) = ($1, $2); |
|
|
257 | |
|
|
258 | my $_ip0 = ip2int($ip0); |
236 | my $_ip = ip2int $ip; |
259 | my $_ip1 = ip2int($ip1); |
237 | if ($ip0 <= $_ip && $_ip <= $ip1) { |
260 | |
238 | return $whois; |
261 | if ($_ip0 + 256 < $_ip1) { |
|
|
262 | $_ip = $_ip & 0xffffff00; |
|
|
263 | $_ip0 = $_ip if $_ip0 < $_ip; |
|
|
264 | $_ip1 = $_ip + 255 if $_ip1 > $_ip + 255; |
|
|
265 | } |
239 | } |
266 | |
|
|
267 | sql_exec "replace into iprange values (?, ?, NULL, ?)", |
|
|
268 | $_ip0, $_ip1, $whois; |
|
|
269 | |
|
|
270 | #print "$ip ($ip0, $ip1 ($_ip0, $_ip1)\n$whois\n"; |
|
|
271 | } |
240 | } |
272 | |
241 | |
273 | $whois; |
242 | my ($arin, $ripe, $apnic); |
274 | } |
|
|
275 | |
243 | |
|
|
244 | $whois = $WHOIS{APNIC}->ip_request($ip) |
|
|
245 | || $WHOIS{RIPE} ->ip_request($ip) |
|
|
246 | || $WHOIS{ARIN} ->ip_request($ip); |
276 | |
247 | |
|
|
248 | $whois =~ /^\*in: ([0-9.]+)\s+-\s+([0-9.]+)\s*$/mi |
|
|
249 | or do { warn "$whois($ip): no addresses found\n", last }; |
277 | |
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 | |