source: trunk/cgi-bin/extras/db2rwhois.pl @ 380

Last change on this file since 380 was 380, checked in by Kris Deugau, 15 years ago

/trunk

Merge bugfixes/updates from /branches/stable r317 through r379

  • Property svn:executable set to *
  • Property svn:keywords set to Date Rev Author
File size: 10.7 KB
Line 
1#!/usr/bin/perl
2# -T
3# ipdb/cgi-bin/extras/db2rwhois.pl
4# Pull data from ipdb and mangle it into RWHOIS
5# Initial version 03/26/2004 kdeugau against IPDB v1
6###
7# Revision info
8# $Date: 2008-01-22 21:11:01 +0000 (Tue, 22 Jan 2008) $
9# SVN revision $Rev: 380 $
10# Last update by $Author: kdeugau $
11###
12# Copyright (C) 2004-2007 - Kris Deugau
13
14use strict;
15use warnings;
16use DBI;
17use NetAddr::IP;
18use MyIPDB;
19use File::Path 'rmtree';
20
21$ENV{"PATH"} = "/bin;/usr/bin";
22
23my $rwhoisDataPath = "/etc/rwhoisd";
24
25my @autharea;
26my $authrw;
27# Use the template file to allow us to keep persistent nodes aside from netblock data
28open AUTHTEMPLATE, "<$rwhoisDataPath/rwhoisd.auth_template";
29my $template_persist;
30while (<AUTHTEMPLATE>) {
31  next if /^##/;
32  $template_persist = 1 if /^[a-z]/i;
33  $autharea[0] .= $_;
34}
35
36my ($dbh,$msg) = connectDB_My;
37
38# For WHOIS purposes this may not be very useful.  YMMV, we'll see.
39#initIPDBGlobals($dbh);
40
41my @masterblocks;
42my %netnameprefix;
43
44# Get the list of live directories for potential deletion
45opendir RWHOISROOT, $rwhoisDataPath;
46my %rwhoisdirs;
47foreach (readdir RWHOISROOT) {
48  $rwhoisdirs{$_} = 1 if /^net-/;
49}
50closedir RWHOISROOT;
51
52# prefetch alloctype data
53my $sth = $dbh->prepare("select type,def_custid,arin_netname from alloctypes");
54$sth->execute;
55while (my @data = $sth->fetchrow_array) {
56  $netnameprefix{$data[0]} = $data[2];
57}
58
59# Get the list of masters to export
60my $msth = $dbh->prepare("select cidr,ctime,mtime from masterblocks where rwhois='y'");
61$msth->execute;
62
63# Prepare to select subblocks for each master
64# Make sure to remove the private netblocks from this,
65# no use or point in broadcasting our use of them.
66# Also remove the details of our "reserved CORE/WAN" blocks;  they're not critical.
67my $ssth = $dbh->prepare("select cidr,custid,type,city,description,createstamp,modifystamp,swip ".
68        "from allocations where ".
69        "not (cidr <<= '192.168.0.0/16') and ".
70        "not (cidr <<= '172.16.0.0/12') and ".
71        "not (cidr <<= '10.0.0.0/8') and ".
72        "not (type = 'wr') and ".
73        "masklen(cidr) <=30 and ".
74        "cidr <<= ?");
75
76# Customer data, for those rare blocks we really need to delegate.
77my $custsth = $dbh->prepare("select name,street,city,province,country,pocode,phone,tech_handle,special ".
78        "from customers where custid=?");
79
80# Fill in data about our master blocks as allocated from ARIN
81# We open separate files for each of these as appropriate.
82# Changes in master blocks are treated as complete new masters - since we're exporting
83# all data every time, this isn't so terrible as it might seem.
84my $i=0;
85while (my @data = $msth->fetchrow_array()) {
86
87  $masterblocks[$i] = new NetAddr::IP $data[0];
88  my ($ctime,undef) = split /\s/, $data[1];
89  my ($mtime,undef) = split /\s/, $data[2];
90
91  print "$masterblocks[$i] $ctime $mtime\n";
92
93  my $date;
94  chomp ($date = `/bin/date +"%Y-%m-%d"`);
95
96  my $rwnet = "net-".$masterblocks[$i]->addr."-".$masterblocks[$i]->masklen;
97
98  # unflag the directory for deletion.  Whee!  Roundabout!
99  delete $rwhoisdirs{$rwnet};
100
101# Hokay.  Gonna do checks *here* to see if we need to create new master trees
102  my $netdatadir = "$rwhoisDataPath/$rwnet";
103  if (! -e $netdatadir) {
104    print " New master $masterblocks[$i]!\n";
105    print "  Creating directories...\n";
106    mkdir $netdatadir;
107    mkdir "$netdatadir/attribute_defs";
108    mkdir "$netdatadir/data";
109    mkdir "$netdatadir/data/network";
110    mkdir "$netdatadir/data/org";
111    mkdir "$netdatadir/data/referral";
112
113    my $serial;
114    chomp ($serial = `/bin/date '+%Y%m%d'000000000`);
115
116    print "  Creating SOA...\n";
117    open SOAFILE, ">$netdatadir/soa";
118    print SOAFILE qq(Serial-Number: $serial
119Refresh-Interval: 3600
120Increment-Interval: 1800
121Retry-Interval: 1800
122Time-To-Live: 86400
123Primary-Server: rwhois.example.com:4321
124Hostmaster: dns\@example.com
125);
126    close SOAFILE;
127
128    print "  Creating Schema...\n";
129    open SCHEMAFILE, ">$netdatadir/schema";
130    print SCHEMAFILE qq(name: network
131attributedef: $rwnet/attribute_defs/network.tmpl
132dbdir: $rwnet/data/network
133Schema-Version: $serial
134---
135name: organization
136attributedef: $rwnet/attribute_defs/org.tmpl
137dbdir: $rwnet/data/org
138description: Organization object
139Schema-Version: $serial
140---
141name: referral
142attributedef:$rwnet/attribute_defs/referral.tmpl
143dbdir:$rwnet/data/referral
144Schema-Version: $serial
145);
146    close SCHEMAFILE;
147
148    print "  Copying template files...\n";
149    qx { /bin/cp $rwhoisDataPath/skel/attribute_defs/* $netdatadir/attribute_defs/ };
150
151    print "  Creating org data...\n";
152    open ORGDATAFILE, ">$netdatadir/data/org/friendlyisp.txt";
153    print ORGDATAFILE qq(ID: NETBLK-ISP.$masterblocks[$i]
154Auth-Area: $masterblocks[$i]
155Org-Name: Friendly ISP
156Street-Address: 123 4th Street
157City: Anytown
158State: ON
159Postal-Code: H0H 0H0
160Country-Code: CA
161Phone: 000-555-1234
162Created: 20040308
163Updated: 20040308
164);
165    close ORGDATAFILE;
166
167    # Generate auth_area record, and add it to the array.
168    $authrw = 1;        # Flag for rewrite and daemon reload/restart
169
170  } # new master
171
172  # do this for all masters, so that we can use this array to export the data
173  # to rwhoisd.auth_area later if we need to
174  push @autharea, qq(type:master
175name:$masterblocks[$i]
176data-dir: $rwnet/data
177schema-file: $rwnet/schema
178soa-file: $rwnet/soa
179);
180
181  # Recreate the net-nnn.nnn.nnn.nnn-nn.txt data file
182  my $masterfilename = "$rwnet/data/network/".$masterblocks[$i]->addr."-".$masterblocks[$i]->masklen.".txt";
183
184  open MASTERFILE,">$rwhoisDataPath/$masterfilename";
185
186  print MASTERFILE "ID: NETBLK-ISP.$masterblocks[$i]\n".
187        "Auth-Area: $masterblocks[$i]\n".
188        "Network-Name: ISP-".$masterblocks[$i]->network."\n".
189        "IP-Network: $masterblocks[$i]\n".
190        "IP-Network-Block: ".$masterblocks[$i]->range."\n".
191        "Org-Name: Friendly ISP\n".
192        "Street-Address: 123 4th Street\n".
193        "City: Anytown\n".
194        "StateProv: Ontario\n".
195        "Postal-Code: H0H 0H0\n".
196        "Country-Code: CA\n".
197        "Tech-Contact: ISP-ARIN-HANDLE\n".
198        "Created: $ctime\n".
199        "Updated: $mtime\n".
200        "Updated-By: noc\@example.com\n";
201
202  # And now the subblocks
203  $ssth->execute("$masterblocks[$i]");
204  while (my ($cidr, $custid, $type, $city, $desc, $ctime, $mtime, $swip) = $ssth->fetchrow_array) {
205
206# We get master block info from @masterblocks.
207 # ID: NETBLK-ISP.10.0.0.0/8
208 # Auth-Area: 10.0.0.0/8
209 # Network-Name: ISP-10.0.2.144
210 # IP-Network: 10.0.2.144.144/29
211 # IP-Network-Block: 10.0.2.144 - 10.0.2.151
212 # Organization: WidgetCorp
213 # Tech-Contact: bob@widgetcorp.com
214 # Admin-Contact: ISP-ARIN-HANDLE
215 # Created: 20040314
216 # Updated: 20040314
217 # Updated-By: noc@example.com
218
219    # Get the "full" network number
220    my $net = new NetAddr::IP $cidr;
221
222# Assumptions:  All data in ipdb is public
223# If not, we need another field to indicate "public/private".
224
225# cidr custid type city description notes maskbits
226
227# Fill in a generic entry for nameless allocations
228if ($desc =~ /^\s*$/) { $desc = 'Friendly ISP'; }
229
230    # Fix up datestamps.  We don't *really* need sub-microsecond resolution on our exports...
231    ($ctime) = ($ctime =~ /^(\d+-\d+-\d+)\s+/);
232    ($mtime) = ($mtime =~ /^(\d+-\d+-\d+)\s+/);
233
234# Notes:
235# Network-name should contain some component of "description"
236# Cust address/contact data should be included;  NB, no phone for ARIN!
237#  network:ID: NET-WIDGET
238#  network:Network-Name: WIDGET                 [IPDB description, sort of]
239#  network:IP-Network: 10.1.1.0/24
240#  network:Org-Name: Widget Corp                [Cust name;  from billing?]
241#  network:Street-Address: 211 Oak Drive        [May need more than one line, OR...]
242#  network:City: Pineville                      [...this line...]
243#  network:StateProv: WI                        [...and this line...]
244#  network:Postal-Code: 48888                   [...and this line]
245#  network:Country-Code: US
246#  network:Tech-Contact: BZ142-MYRWHOIS         [ARIN handle?]
247#  network:Updated: 19991221                    [timestamp from db]
248#  network:Updated-By: jo@myrwhois.net          [noc@example, since that's our POC for IP netspace issues]
249#  network:Class-Name:network                   [Provided by rWHOIS protocol]
250
251    my $netname = $netnameprefix{$type};
252
253    if ($swip eq 'n') {
254      print MASTERFILE "---\nID: NETBLK-ISP.$masterblocks[$i]\n".
255        "Auth-Area: $masterblocks[$i]\n".
256        "Network-Name: $netname-".$net->network."\n".
257        "IP-Network: $net\n".
258        "IP-Network-Block: ".$net->range."\n".
259        "Org-Name: Friendly ISP\n".
260        "Street-Address: 123 4th Street\n".
261        "City: Anytown\n".
262        "StateProv: Ontario\n".
263        "Postal-Code: H0H 0H0\n".
264        "Country-Code: CA\n".
265        "Tech-Contact: ISP-ARIN-HANDLE\n".
266        "Created: $ctime\n".
267        "Updated: $mtime\n".
268        "Updated-By: noc\@example.com\n";
269    } else {
270      $custsth->execute($custid);
271      my ($name, $street, $city, $prov, $country, $pocode, $phone, $tech, $special) = $custsth->fetchrow_array;
272      $custsth->finish;
273      if ($special && $special =~ /NetName/ && $special =~ /$cidr/) {
274        ($netname) = ($special =~ /NetName$cidr: ([A-Z0-9_-]+)/);
275      } else {
276        $netname .= "-".$net->network;
277      }
278      print MASTERFILE "---\nID: NETBLK-ISP.$masterblocks[$i]\n".
279        "Auth-Area: $masterblocks[$i]\n".
280        "Network-Name: $netname\n".
281        "IP-Network: $net\n".
282        "IP-Network-Block: ".$net->range."\n".
283        "Org-Name: ".($name ? $name : 'Friendly ISP')."\n".
284        "Street-Address: ".($street ? $street : '123 4th Street')."\n".
285        "City: ".($city ? $city : 'Anytown')."\n".
286        "StateProv: ".($prov ? $prov : 'Ontario')."\n".
287        "Postal-Code: ".($pocode ? $pocode : 'H0H 0H0')."\n".
288        "Country-Code: ".($country ? $country : 'CA')."\n".
289        "Tech-Contact: ".($tech ? $tech : 'ISP-ARIN-HANDLE')."\n".
290        "Created: $ctime\n".
291        "Updated: $mtime\n".
292        "Updated-By: noc\@example.com\n";
293    } # swip
294
295  } # while $ssth->fetchrow_array()
296
297  close MASTERFILE;
298
299  $i++;
300} # while $msth->fetchrow_array()
301
302# Now we see if there's obsolete netdata directories to be deleted,
303# and therefore an auth-area file to regenerate
304foreach my $netdir (keys %rwhoisdirs) {
305  print "deleting obsolete directory $netdir...\n";
306  rmtree ( "$rwhoisDataPath/$netdir", { verbose => 1, error => \my $errlist } );
307  for my $diag (@$errlist) {
308    my ($file, $message) = each %$diag;
309    if ($file eq '') {
310      print "general error: $message\n";
311    }
312  }
313  $authrw = 1;  # there's probably a more efficient place to put this.  Feh.
314}
315
316# Regenerate rwhoisd.auth_area if needed
317if ($authrw) {
318  print "Regenerating auth_area\n";
319  open RWHOISDAUTH, ">$rwhoisDataPath/rwhoisd.auth_area";
320  print RWHOISDAUTH "# WARNING: This file is autogenerated!  Any static nodes should\n".
321                "# be entered in /etc/rwhoisd/rwhoisd.auth_template\n";
322  if ($template_persist) {
323    print RWHOISDAUTH shift @autharea;
324    print RWHOISDAUTH "---\n";
325  }
326  # feh.  we need to know when we're at the end of the loop, because then
327  # we DON'T want to write the separator...
328  for (;@autharea;) {   # my head hurts.
329    print RWHOISDAUTH shift @autharea;
330    print RWHOISDAUTH "---\n" if @autharea;
331  }
332  close RWHOISDAUTH;
333
334  # restart/reload rwhoisd
335  if (-e "$rwhoisDataPath/rwhoisd.pid") {       # no pidfile, no restart.
336    print "Restarting rwhoisd\n";
337    open PIDFILE, "<$rwhoisDataPath/rwhoisd.pid";
338    my ($rwpid) = (<PIDFILE> =~ /^(\d+)/);
339    close PIDFILE;
340    kill 'HUP', $rwpid;
341  }
342}
343
344# and finally
345$dbh->disconnect;
Note: See TracBrowser for help on using the repository browser.