ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-Whois-IP/IP.pm
(Generate patch)

Comparing Net-Whois-IP/IP.pm (file contents):
Revision 1.1 by root, Thu Nov 28 10:34:13 2002 UTC vs.
Revision 1.2 by root, Sat Nov 30 02:45:47 2002 UTC

9=head1 DESCRIPTION 9=head1 DESCRIPTION
10 10
11=over 4 11=over 4
12 12
13=cut 13=cut
14
15# http://www.irr.net/docs/rpsl.html
14 16
15package Net::Whois::IP; 17package Net::Whois::IP;
16 18
17BEGIN { 19BEGIN {
18 $VERSION = 0.01; 20 $VERSION = 0.01;
19 @EXPORT_OK = qw(); 21 @EXPORT_OK = qw();
20} 22}
21 23
22use base Exporter; 24use base Exporter;
23 25
24=item 26use Carp;
25 27
26=cut 28use Socket;
29
30use BerkeleyDB;
31
32use Coro;
33use Coro::Event;
34use Coro::Semaphore;
35use Coro::SemaphoreSet;
36use Coro::Socket;
37use Coro::Timer;
38use Coro::Channel;
39
40my %server;
41
42sub new_btree {
43 new BerkeleyDB::Btree
44 -Env => $db_env,
45 -Filename => $_[0],
46 -Flags => DB_CREATE,
47 or die "$_[0]: unable to create/open table";
48}
49
50package Net::Whois::IP::base;
51
52sub new {
53 my $class = shift;
54 my $self = bless {
55 name => @_,
56 }, $class;
57 $self->{request} ||= new Coro::Channel $self->{request_backlog} || 10;
58 $self->{daemon} = Coro::async { shift->_daemon } $self;
59 $self->{cache} = Net::Whois::IP::new_btree "whois_" . lc $self->{name};
60 $server{$self->{name}} = $self;
61}
62
63sub _failure {
64 my $self = shift;
65 undef $self->{fh};
66 Coro::Timer::sleep 1.5 ** $self->{retry} - 2 if $self->{retry};
67 $self->{retry}++ if $self->{retry} < 17;
68}
69
70sub _ok {
71 my $self = shift;
72 $self->{retry} = 0;
73}
74
75sub _query {
76 my ($self, $query) = @_;
77
78 my $response;
79
80 if (!$self->{cache}->db_get($query, $response)) {
81 $response =~ s/^[^\x00]+\x00//;
82 return $response;
83 }
84
85 my $request = {
86 ready => (new Coro::Semaphore 0),
87 query => $query,
88 };
89
90 $self->{request}->put($request);
91 $request->{ready}->down;
92
93 $response = time . "\x00" . $request->{response};
94
95 $self->{cache}->db_put($query, $response);
96
97 $request->{response};
98}
99
100sub ip_query {
101 my ($self, $ip) = @_;
102 $self->_query($ip);
103}
104
105sub parse_ip_response {
106 my ($self, $response) = @_;
107 my %response;
108 while ($response =~ /^([^:]+):[ \t]*(.*)$/mg) {
109 push @{$response{$1}}, $2;
110 }
111 \%response;
112}
113
114package Net::Whois::IP::whois;
115
116# plain whois, as used by ripe and apnic
117
118use base Net::Whois::IP::base;
119
120sub _daemon {
121 my $self = shift;
122 while (my $request = $self->{request}->get) {
123 my $fh = new Coro::Socket PeerHost => $self->{server}
124 or $self->_failure, redo;
125
126 $fh->print("$request->{query}\012");
127 $fh->sysread($request->{response}, 16384);
128 length $request->{response}
129 or $self->_failure, redo;
130
131 $self->_ok;
132 $request->{ready}->up;
133 }
134}
135
136sub ip_query {
137 my ($self, $ip) = @_;
138 $self->SUPER::ip_query($ip);
139}
140
141sub parse_ip_response {
142 my ($self, $response) = @_;
143 $response =~ s/^%.*//mg;
144 $response =~ s/^\012+//;
145 $response =~ s/\012\012.*//s;
146 $self->SUPER::parse_ip_response($response);
147}
148
149package Net::Whois::IP::jpnic;
150
151# totally different result format
152
153use base Net::Whois::IP::whois;
154
155sub ip_query {
156 my ($self, $ip) = @_;
157 $self->SUPER::ip_query("$ip/e");
158}
159
160sub parse_ip_response {
161 my ($self, $response) = @_;
162 $response =~ s/^\[\s.*//mg;
163 $response =~ s/^(?:\w\.\ )? \[ ([^\]]+) \] (.*) (?:\012(?=\s))?/$1: $2/mgx;
164 $self->SUPER::parse_ip_response($response);
165}
166
167package Net::Whois::IP::ripe;
168
169# keepalive whois, as used by ripe and apnic
170
171use base Net::Whois::IP::whois;
172
173sub _daemon {
174 my $self = shift;
175 my $fh;
176
177 while (my $request = $self->{request}->get) {
178 unless ($self->{fh}) {
179 $fh = new Coro::Socket PeerHost => $self->{server};
180 $fh or $self->_failure, redo;
181 }
182
183 $fh->print("-k $request->{query}\012");
184 $request->{response} = $fh->readline("\012\012\012");
185 length $request->{response}
186 or $self->_failure, redo;
187
188 $self->_ok;
189 $request->{ready}->up;
190 }
191}
192
193package Net::Whois::IP::rwhois;
194
195# rwhois 1.5
196
197use base Net::Whois::IP::base;
198
199sub _request {
200 my $self = shift;
201 my ($response, $error);
202
203 $self->{fh}->print("$_[0]\015\012");
204 while (defined (my $line = $self->{fh}->readline)) {
205 $line =~ s/[\015\012]+$/\n/g;
206 $response .= $line;
207 $line =~ /^%(ok|error)/ and return $response;
208 }
209 return;
210}
211
212sub _daemon {
213 my $self = shift;
214 while (my $request = $self->{request}->get) {
215 unless ($self->{fh}) {
216 $self->{fh} = new Coro::Socket PeerHost => $self->{server};
217 $self->{fh} or $self->_failure, redo;
218 $self->{fh}->readline =~ /^%rwhois / or $self->_failure, redo;
219 $self->_request("-rwhois V-1.5 Net::Whois::IP") or $self->_failure, redo;
220 $self->_request("-forward off") or $self->_failure, redo;
221 $self->_request("-holdconnect on") or $self->_failure, redo;
222 }
223 $request->{response} = $self->_request($request->{query})
224 or $self->_failure, redo;
225 $request->{response} =~ s/^%error 330.*/%ok/m;
226 $self->_ok;
227 $request->{ready}->up;
228 }
229}
230
231sub ip_query {
232 my ($self, $ip) = @_;
233 $self->SUPER::ip_query("network $ip");
234}
235
236sub parse_ip_response {
237 my ($self, $response) = @_;
238 $response =~ s/^([^:]+):([^:]+):/$1-\L$2: /mg;
239 $response =~ s/^%.*//mg;
240 $response =~ s/\012\012.*//s;
241 $self->SUPER::parse_ip_response($response);
242}
243
244package Net::Whois::IP;
245
246sub ip_range {
247 my $range = $_[0];
248
249 if ($range =~ /^
250 (2[0-5][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])
251 (?:\.
252 (2[0-5][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])
253 (?:\.
254 (2[0-5][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])
255 (?:\.
256 (2[0-5][0-9]|1[0-9][0-9]|[1-9][0-9]|[0-9])
257 )?
258 )?
259 )?
260 \/
261 ([0-9]+)
262 $/x) {
263 my $ip = inet_aton sprintf "%d.%d.%d.%d", $1, $2, $3, $4;
264 my $net = 1 << (31 - $5);
265 my $mask = inet_aton 2 ** 32 - $net;
266
267 my $ip1 = $ip & $mask;
268 my $ip2 = $ip1 | inet_aton $net * 2 - 1;
269 return unpack "N2", "$ip1$ip2";
270 } elsif ($range =~ /^\s*([0-9.]+)\s*-\s*([0-9.]+)\s*$/) {
271 unpack "N2", pack "N2", $1, $2;
272 } else {
273 die "$range: unable to parse ip range";
274 }
275}
276
277# add a referral to a specific server
278sub add_referral {
279 my ($netblock, $server) = @_;
280 my ($ip0, $ip1) = ip_range $netblock;
281 $db_referral->db_put((pack "N*", $ip1, $ip0) ^ "\x00\x00\x00\x00\xff\xff\xff\xff", "S" . $server->{name});
282}
283
284# get all referrals
285sub parse_referral {
286 my ($query, $server) = @_;
287 my $referral = $arin->_query("referral $query");
288
289 while ($referral =~ /^referral:Referred-Auth-Area:([0-9.\/]+)$/mg) {
290 add_referral $1, $server;
291 }
292}
293
294sub init(;%) {
295 my (%arg) = @_;
296 $arg{db_home} or $arg{db_env} or Carp::croak "either db_home or db_env home must be set";
297 $db_env = $arg{db_env} || do {
298 mkdir $arg{db_home}, 0700;
299
300 $db_env = new BerkeleyDB::Env
301 -Home => $arg{db_home},
302 -Cachesize => $arg{db_cachesize} || 1_000_000,
303 -ErrFile => $arg{db_errfile} || "/dev/fd/2",
304 -ErrPrefix => "NET-WHOIS-IP",
305 -Verbose => 1,
306 -Flags => DB_CREATE|DB_RECOVER|DB_INIT_MPOOL|DB_INIT_TXN
307 or die "$arg{db_home}: unable to create database home";
308 };
309
310 $arin = new Net::Whois::IP::rwhois "ARIN", server => "rwhois.arin.net:rwhois(4321)";
311
312 $ripe = new Net::Whois::IP::ripe "RIPE", server => "whois.ripe.net:whois(43)";
313 $lacnic = new Net::Whois::IP::whois "LACNIC", server => "whois.lacnic.net:whois(43)";
314 $brnic = new Net::Whois::IP::whois "BRNIC", server => "whois.registro.br:whois(43)";
315 $apnic = new Net::Whois::IP::ripe "APNIC", server => "whois.apnic.net:whois(43)";
316 $jpnic = new Net::Whois::IP::jpnic "JPNIC", server => "whois.nic.ad.jp:whois(43)";
317
318 $db_referral = new_btree "referral";
319
320 add_referral "129.13.0.0/16", $ripe;
321 add_referral "200.0.0.0/8", $lacnic;
322 add_referral "200.128.0.0/9", $brnic;
323
324 parse_referral "32.0.0.0", $ripe;
325 parse_referral "202.0.0.0", $apnic;
326 parse_referral "192.50.0.0", $apnic;
327
328 add_referral "133.0.0.0/8", $jpnic;
329}
330
331###
332
333init db_home => "/tmp/whois";
334
335sub ip_query {
336 my $ip = shift;
337
338 print "Q?$ip ";
339
340 my $server = $arin;
341
342 my $c = $db_referral->db_cursor;
343
344 my ($k, $v) = (inet_aton $ip);
345 if (!$c->c_get($k, $v, DB_SET_RANGE)) {
346 my ($ip1, $ip0) = unpack "N*", $k ^ "\x00\x00\x00\x00\xff\xff\xff\xff";
347 my $ipn = unpack "N", inet_aton $ip;
348
349 if ($ip0 <= $ipn && $ipn <= $ip1) {
350 if ($v =~ s/^S//) {
351 $server = $server{$v} if $server{$v};
352 } elsif ($v =~ s/^I//) {
353 die;
354 } else {
355 # database corrupted or newer
356 }
357 }
358 }
359
360 print "($ip,$server->{name})\n";
361 $server->parse_ip_response($server->ip_query($ip));
362}
363
364for (qw(132.64.0.0 129.13.162.91 193.166.90.111 213.189.83.103 161.142.8.76 66.68.103.189 200.149.85.112 210.49.200.207 133.11.128.254)) {
365 use PApp::Util;
366 warn PApp::Util::dumpval ip_query($_);
367}
368
369exit;
370
371__END__
27 372
281; 3731;
29 374
30=back 375=back
31 376

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines