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