source: branches/stable/cgi-bin/extras/db2rwhois.pl@ 899

Last change on this file since 899 was 618, checked in by Kris Deugau, 11 years ago

/branches/stable

Commit some cleanup and bugfixing from production

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