| [491] | 1 | #!/usr/bin/perl
 | 
|---|
 | 2 | # Quick utility to use post-import to convert great huge piles of
 | 
|---|
 | 3 | # A+PTR records to single A+PTR template records
 | 
|---|
 | 4 | ##
 | 
|---|
 | 5 | # $Id: compact-recs.pl 756 2017-06-13 17:58:57Z kdeugau $
 | 
|---|
| [756] | 6 | # Copyright 2013,2014 Kris Deugau <kdeugau@deepnet.cx>
 | 
|---|
| [491] | 7 | #
 | 
|---|
 | 8 | #    This program is free software: you can redistribute it and/or modify
 | 
|---|
 | 9 | #    it under the terms of the GNU General Public License as published by
 | 
|---|
 | 10 | #    the Free Software Foundation, either version 3 of the License, or
 | 
|---|
 | 11 | #    (at your option) any later version.
 | 
|---|
 | 12 | #
 | 
|---|
 | 13 | #    This program is distributed in the hope that it will be useful,
 | 
|---|
 | 14 | #    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
|---|
 | 15 | #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
|---|
 | 16 | #    GNU General Public License for more details.
 | 
|---|
 | 17 | #
 | 
|---|
 | 18 | #    You should have received a copy of the GNU General Public License
 | 
|---|
 | 19 | #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
|---|
 | 20 | ##
 | 
|---|
 | 21 | 
 | 
|---|
 | 22 | use strict;
 | 
|---|
 | 23 | use warnings;
 | 
|---|
 | 24 | 
 | 
|---|
| [548] | 25 | use lib '.';    ##uselib##
 | 
|---|
| [491] | 26 | use DNSDB;
 | 
|---|
 | 27 | 
 | 
|---|
 | 28 | usage() if !$ARGV[1];
 | 
|---|
 | 29 | 
 | 
|---|
 | 30 | sub usage {
 | 
|---|
 | 31 |   die qq(usage:  compact-recs.pl netblock pattern
 | 
|---|
 | 32 |     netblock  the CIDR block to define the A+PTR template on
 | 
|---|
 | 33 |     pattern   the pattern to define the new A+PTR template with, and
 | 
|---|
 | 34 |               to match A+PTR records within the netblock for deletion
 | 
|---|
 | 35 |         OR
 | 
|---|
 | 36 |         compact-recs.pl --batch patternfile
 | 
|---|
 | 37 |     patternfile should be a file containing a list of netblock-pattern
 | 
|---|
 | 38 |     pairs, whitespace separated
 | 
|---|
 | 39 | 
 | 
|---|
 | 40 |     A PTR template record will be created instead of an A+PTR template
 | 
|---|
 | 41 |     if the forward zone specified in the template is not present in
 | 
|---|
 | 42 |     the database.
 | 
|---|
 | 43 | 
 | 
|---|
 | 44 |     WARNING:  Multiple runs will result in duplicate template records.
 | 
|---|
 | 45 | );
 | 
|---|
 | 46 | }
 | 
|---|
 | 47 | 
 | 
|---|
 | 48 | my $dnsdb = new DNSDB or die "Couldn't create DNSDB object: ".$DNSDB::errstr."\n";
 | 
|---|
 | 49 | my $dbh = $dnsdb->{dbh};
 | 
|---|
 | 50 | 
 | 
|---|
 | 51 | my $code;
 | 
|---|
 | 52 | 
 | 
|---|
 | 53 | # get userdata for log
 | 
|---|
 | 54 | ($dnsdb->{logusername}, undef, undef, undef, undef, undef, $dnsdb->{logfullname}) = getpwuid($<);
 | 
|---|
 | 55 | $dnsdb->{loguserid} = 0;        # not worth setting up a pseudouser the way the RPC system does
 | 
|---|
 | 56 | $dnsdb->{logusername} = $dnsdb->{logusername}."/compact-recs.pl";
 | 
|---|
 | 57 | $dnsdb->{logfullname} = $dnsdb->{logusername} if !$dnsdb->{logfullname};
 | 
|---|
 | 58 | 
 | 
|---|
 | 59 | if ($ARGV[0] eq '--batch') {
 | 
|---|
 | 60 |   open NBLIST, "<$ARGV[1]";
 | 
|---|
 | 61 |   while (<NBLIST>) {
 | 
|---|
 | 62 |     next if /^#/;
 | 
|---|
 | 63 |     next if /^\s*$/;
 | 
|---|
 | 64 |     s/^\s*//;
 | 
|---|
 | 65 |     squashem(split(/\s+/));
 | 
|---|
 | 66 |   }
 | 
|---|
 | 67 | } else {
 | 
|---|
 | 68 |   my $cidr = new NetAddr::IP $ARGV[0];
 | 
|---|
 | 69 |   usage() if !$cidr;
 | 
|---|
 | 70 |   squashem($cidr, $ARGV[1]);
 | 
|---|
 | 71 | }
 | 
|---|
 | 72 | 
 | 
|---|
 | 73 | exit 0;
 | 
|---|
 | 74 | 
 | 
|---|
 | 75 | 
 | 
|---|
 | 76 | sub squashem {
 | 
|---|
 | 77 |   my $cidr = shift;
 | 
|---|
 | 78 |   my $patt = shift;
 | 
|---|
 | 79 | 
 | 
|---|
 | 80 |   $dbh->{AutoCommit} = 0;
 | 
|---|
 | 81 |   $dbh->{RaiseError} = 1;
 | 
|---|
 | 82 | 
 | 
|---|
 | 83 |   my ($zone,$ploc) = $dbh->selectrow_array("SELECT rdns_id,default_location FROM revzones WHERE revnet >>= ?",
 | 
|---|
 | 84 |         undef, ($cidr) );
 | 
|---|
 | 85 |   if (!$zone) {
 | 
|---|
 | 86 |     warn "$cidr is not within a zone currently managed here.\n";
 | 
|---|
 | 87 |     return;
 | 
|---|
 | 88 |   }
 | 
|---|
 | 89 |   my $soa = $dnsdb->getSOA('n', 'y', $zone);
 | 
|---|
 | 90 |   my $dparent = $dnsdb->_hostparent($patt) || 0;
 | 
|---|
 | 91 |   my $newtype = ($dparent ? 65283 : 65282);
 | 
|---|
 | 92 | 
 | 
|---|
 | 93 |   my ($istmpl) = $dbh->selectrow_array("SELECT count(*) FROM records WHERE rdns_id = ? AND ".
 | 
|---|
 | 94 |         "(type=65282 OR type=65283) AND val = ?", undef, ($zone, $cidr) );
 | 
|---|
 | 95 |   if ($istmpl) {
 | 
|---|
 | 96 |     print "Template already exists for $cidr, manual cleanup required\n";
 | 
|---|
 | 97 |     return;
 | 
|---|
 | 98 |   }
 | 
|---|
 | 99 | 
 | 
|---|
 | 100 |   print "Converting PTR and A+PTR records in $cidr matching $patt to single $typemap{$newtype} record\n";
 | 
|---|
 | 101 |   my $delcnt = 0;
 | 
|---|
 | 102 | 
 | 
|---|
 | 103 |   eval {
 | 
|---|
 | 104 |     my $getsth = $dbh->prepare("SELECT record_id,host,val FROM records ".
 | 
|---|
| [649] | 105 |         "WHERE (type = 12 OR type > 65000) AND inetlazy(val) << ?");
 | 
|---|
| [491] | 106 |     my $delsth = $dbh->prepare("DELETE FROM records WHERE record_id = ?");
 | 
|---|
 | 107 |     $getsth->execute($cidr);
 | 
|---|
 | 108 |     my $i = 0;
 | 
|---|
 | 109 |     while (my ($id,$host,$val) = $getsth->fetchrow_array) {
 | 
|---|
 | 110 |       my $cmp = $patt;
 | 
|---|
 | 111 |       DNSDB::_template4_expand(\$cmp, $val);
 | 
|---|
 | 112 |       $delsth->execute($id) if $cmp eq $host;
 | 
|---|
 | 113 |       $delcnt++ if $cmp eq $host;
 | 
|---|
 | 114 | #      print "got $id, '$host', '$val';  compare '$cmp'\t";
 | 
|---|
 | 115 | #      print "  delete\n" if $cmp eq $host;
 | 
|---|
 | 116 | #      print "  keep\n"  if $cmp ne $host;
 | 
|---|
 | 117 | #      last if $i++ >8;
 | 
|---|
 | 118 |     }
 | 
|---|
 | 119 | 
 | 
|---|
 | 120 |     $dbh->do("INSERT INTO records (domain_id, rdns_id, host, type, val, ttl, location) VALUES (?,?,?,?,?,?,?)",
 | 
|---|
 | 121 |         undef, ($dparent, $zone, $patt, $newtype, $cidr, $soa->{minttl}, $ploc) );
 | 
|---|
| [548] | 122 |     $dbh->do("UPDATE revzones SET changed='y' WHERE rdns_id = ?", undef, ($zone));
 | 
|---|
 | 123 |     $dbh->do("UPDATE domains SET changed='y' WHERE domain_id = ?", undef, ($dparent)) if $dparent;
 | 
|---|
| [491] | 124 |     $dnsdb->_log(rdns_id => $zone, domain_id => $dparent, group_id => 1,
 | 
|---|
 | 125 |         entry => "A+PTR and/or PTR records in $cidr matching $patt replaced by $typemap{$newtype} record for $cidr");
 | 
|---|
 | 126 | 
 | 
|---|
 | 127 | #    $dbh->rollback;
 | 
|---|
 | 128 |     $dbh->commit;
 | 
|---|
 | 129 |   };
 | 
|---|
 | 130 |   if ($@) {
 | 
|---|
 | 131 |     print "barf: $@\n";
 | 
|---|
 | 132 |     $dbh->rollback;
 | 
|---|
 | 133 |     return;
 | 
|---|
 | 134 |   }
 | 
|---|
 | 135 |   print " complete ($delcnt records)\n";
 | 
|---|
 | 136 | } # squashem ()
 | 
|---|