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

Last change on this file since 417 was 417, checked in by Kris Deugau, 12 years ago

/trunk

Rearrangements and tweaks toward releaseability:

  • Add Makefile to install halfway-sanely
  • Add .spec file
  • Shuffle "use IPDB;" and "use MyIPDB;" lines so that we can automagically insert a suitable "use lib..." line during 'make install'
  • Check copyright statements
  • Clear up some defaults, and place a number of "constants" in IPDB/MyIPDB rather than having them hardcoded all over the place (Still need to think of a sane way to do this for ipdb.psql's alloctype preseeding)
  • Tweak $VERSION identifier in IPDB.pm so it can be defined in the Makefile
  • Clean up some dangling bits from repository history conversion, remove unneeded "use ..." statements
  • Tweak rWHOIS export script to use more globals and "constants" from (My)IPDB.pm, and more Perl internals than system()-equivalents. Add a few fixme comments for longer-term flexibility improvements.
  • Property svn:executable set to *
  • Property svn:keywords set to Date Rev Author
File size: 11.3 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: 2010-06-30 21:48:03 +0000 (Wed, 30 Jun 2010) $
9# SVN revision $Rev: 417 $
10# Last update by $Author: kdeugau $
11###
12# Copyright (C) 2004-2010 - Kris Deugau
13
14use strict;
15use warnings;
16use DBI;
17use NetAddr::IP;
18use File::Path 'rmtree';
19use POSIX qw(strftime);
20
21# don't remove!  required for GNU/FHS-ish install from tarball
22##uselib##
23
24use MyIPDB;
25
26#$ENV{"PATH"} = "/bin;/usr/bin";
27
28my $rwhoisDataPath = "/etc/rwhoisd";
29
30my @autharea;
31my $authrw;
32# Use the template file to allow us to keep persistent nodes aside from netblock data
33open AUTHTEMPLATE, "<$rwhoisDataPath/rwhoisd.auth_template";
34my $template_persist;
35while (<AUTHTEMPLATE>) {
36  next if /^##/;
37  $template_persist = 1 if /^[a-z]/i;
38  $autharea[0] .= $_;
39}
40
41my ($dbh,$msg) = connectDB_My;
42
43# For WHOIS purposes this may not be very useful.  YMMV, we'll see.
44#initIPDBGlobals($dbh);
45
46my @masterblocks;
47my %netnameprefix;
48
49# Get the list of live directories for potential deletion
50opendir RWHOISROOT, $rwhoisDataPath;
51my %rwhoisdirs;
52foreach (readdir RWHOISROOT) {
53  $rwhoisdirs{$_} = 1 if /^net-/;
54}
55closedir RWHOISROOT;
56
57# prefetch alloctype data
58my $sth = $dbh->prepare("select type,def_custid,arin_netname from alloctypes");
59$sth->execute;
60while (my @data = $sth->fetchrow_array) {
61  $netnameprefix{$data[0]} = $data[2];
62}
63
64# Get the list of masters to export
65my $msth = $dbh->prepare("select cidr,ctime,mtime from masterblocks where rwhois='y'");
66$msth->execute;
67
68# Prepare to select subblocks for each master
69# Make sure to remove the private netblocks from this,
70# no use or point in broadcasting our use of them.
71# Also remove the details of our "reserved CORE/WAN" blocks;  they're not critical.
72my $ssth = $dbh->prepare("select cidr,custid,type,city,description,createstamp,modifystamp,swip ".
73        "from allocations where ".
74        "not (cidr <<= '192.168.0.0/16') and ".
75        "not (cidr <<= '172.16.0.0/12') and ".
76        "not (cidr <<= '10.0.0.0/8') and ".
77        "not (type = 'wr') and ".
78        "masklen(cidr) <=30 and ".
79        "cidr <<= ?");
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
85# Fill in data about our master blocks as allocated from ARIN
86# We open separate files for each of these as appropriate.
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.
89my $i=0;
90while (my @data = $msth->fetchrow_array()) {
91
92  $masterblocks[$i] = new NetAddr::IP $data[0];
93  my ($ctime,undef) = split /\s/, $data[1];
94  my ($mtime,undef) = split /\s/, $data[2];
95
96  print "$masterblocks[$i] $ctime $mtime\n";
97
98  my $date = strftime("%Y-%m-%d", localtime);
99
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
106  my $netdatadir = "$rwhoisDataPath/$rwnet";
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
117    my $serial = strftime("%Y%m%d%H%M%S000", localtime);
118
119##fixme: SOA should be different every time data changes, therefore need to rewrite this ~~ every export :(
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
127Primary-Server: rwhois.example.com:4321
128Hostmaster: dns\@example.com
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";
153##fixme: find a way to do this without a shell (or functional equivalent)
154    qx { /bin/cp $rwhoisDataPath/skel/attribute_defs/* $netdatadir/attribute_defs/ };
155
156##fixme: not sure if this is even necessary, since it's not referenced anywhere I can recall...
157    print "  Creating org data...\n";
158    open ORGDATAFILE, ">$netdatadir/data/org/ourorg.txt";
159    print ORGDATAFILE qq(ID: NETBLK-ISP.$masterblocks[$i]
160Auth-Area: $masterblocks[$i]
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
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
187  # Recreate the net-nnn.nnn.nnn.nnn-nn.txt data file
188  my $masterfilename = "$rwnet/data/network/".$masterblocks[$i]->addr."-".$masterblocks[$i]->masklen.".txt";
189
190  open MASTERFILE,">$rwhoisDataPath/$masterfilename";
191
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".
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".
204        "Created: $ctime\n".
205        "Updated: $mtime\n".
206        "Updated-By: noc\@example.com\n";
207
208  # And now the subblocks
209  $ssth->execute("$masterblocks[$i]");
210  while (my ($cidr, $custid, $type, $city, $desc, $ctime, $mtime, $swip) = $ssth->fetchrow_array) {
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
225    # Get the "full" network number
226    my $net = new NetAddr::IP $cidr;
227
228# Assumptions:  All data in ipdb is public
229# If not, we need another field to indicate "public/private".
230
231# cidr custid type city description notes maskbits
232
233# Fill in a generic entry for nameless allocations
234if ($desc =~ /^\s*$/) { $desc = $IPDB::org_name; }
235
236    # Fix up datestamps.  We don't *really* need sub-microsecond resolution on our exports...
237    ($ctime) = ($ctime =~ /^(\d+-\d+-\d+)\s+/);
238    ($mtime) = ($mtime =~ /^(\d+-\d+-\d+)\s+/);
239
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]
256
257    my $netname = $netnameprefix{$type};
258
259    if ($swip eq 'n') {
260      print MASTERFILE "---\nID: NETBLK-ISP.$masterblocks[$i]\n".
261        "Auth-Area: $masterblocks[$i]\n".
262        "Network-Name: $netname-".$net->network."\n".
263        "IP-Network: $net\n".
264        "IP-Network-Block: ".$net->range."\n".
265        "Org-Name: $IPDB::org_name\n".
266        "Street-Address: $IPDB::org_street\n".
267        "City: $IPDB::org_city\n".
268        "StateProv: $IPDB::org_prov_state\n".
269        "Postal-Code: $IPDB::org_pocode\n".
270        "Country-Code: $IPDB::org_country\n".
271        "Tech-Contact: $IPDB::org_techhandle\n".
272        "Created: $ctime\n".
273        "Updated: $mtime\n".
274        "Updated-By: noc\@example.com\n";
275    } else {
276      $custsth->execute($custid);
277      my ($name, $street, $city, $prov, $country, $pocode, $phone, $tech, $special) = $custsth->fetchrow_array;
278      $custsth->finish;
279      if ($special && $special =~ /NetName/ && $special =~ /$cidr/) {
280        ($netname) = ($special =~ /NetName$cidr: ([A-Z0-9_-]+)/);
281      } else {
282        $netname .= "-".$net->network;
283      }
284      print MASTERFILE "---\nID: NETBLK-ISP.$masterblocks[$i]\n".
285        "Auth-Area: $masterblocks[$i]\n".
286        "Network-Name: $netname\n".
287        "IP-Network: $net\n".
288        "IP-Network-Block: ".$net->range."\n".
289        "Org-Name: ".($name ? $name : $IPDB::org_name)."\n".
290        "Street-Address: ".($street ? $street : $IPDB::org_street)."\n".
291        "City: ".($city ? $city : $IPDB::org_city)."\n".
292        "StateProv: ".($prov ? $prov : $IPDB::org_prov_state)."\n".
293        "Postal-Code: ".($pocode ? $pocode : $IPDB::org_pocode)."\n".
294        "Country-Code: ".($country ? $country : $IPDB::org_country)."\n".
295        "Tech-Contact: ".($tech ? $tech : $IPDB::org_techhandle)."\n".
296        "Created: $ctime\n".
297        "Updated: $mtime\n".
298        "Updated-By: noc\@example.com\n";
299    } # swip
300
301  } # while $ssth->fetchrow_array()
302
303  close MASTERFILE;
304
305  $i++;
306} # while $msth->fetchrow_array()
307
308# Now we see if there's obsolete netdata directories to be deleted,
309# and therefore an auth-area file to regenerate
310foreach my $netdir (keys %rwhoisdirs) {
311  print "deleting obsolete directory $netdir...\n";
312  rmtree ( "$rwhoisDataPath/$netdir", { verbose => 1, error => \my $errlist } );
313  for my $diag (@$errlist) {
314    my ($file, $message) = each %$diag;
315    if ($file eq '') {
316      print "general error: $message\n";
317    }
318  }
319  $authrw = 1;  # there's probably a more efficient place to put this.  Feh.
320}
321
322# Regenerate rwhoisd.auth_area if needed
323if ($authrw) {
324  print "Regenerating auth_area\n";
325  open RWHOISDAUTH, ">$rwhoisDataPath/rwhoisd.auth_area";
326  print RWHOISDAUTH "# WARNING: This file is autogenerated!  Any static nodes should\n".
327                "# be entered in /etc/rwhoisd/rwhoisd.auth_template\n";
328  if ($template_persist) {
329    print RWHOISDAUTH shift @autharea;
330    print RWHOISDAUTH "---\n";
331  }
332  # feh.  we need to know when we're at the end of the loop, because then
333  # we DON'T want to write the separator...
334  for (;@autharea;) {   # my head hurts.
335    print RWHOISDAUTH shift @autharea;
336    print RWHOISDAUTH "---\n" if @autharea;
337  }
338  close RWHOISDAUTH;
339
340  # restart/reload rwhoisd
341  if (-e "$rwhoisDataPath/rwhoisd.pid") {       # no pidfile, no restart.
342    print "Restarting rwhoisd\n";
343    open PIDFILE, "<$rwhoisDataPath/rwhoisd.pid";
344    my ($rwpid) = (<PIDFILE> =~ /^(\d+)/);
345    close PIDFILE;
346    kill 'HUP', $rwpid;
347  }
348}
349
350# and finally
351$dbh->disconnect;
Note: See TracBrowser for help on using the repository browser.