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

Last change on this file since 833 was 680, checked in by Kris Deugau, 10 years ago

/trunk

Update db2rwhois for new database structure:

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