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