| [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 649 2014-06-23 21:52:37Z kdeugau $ | 
|---|
|  | 6 | # Copyright 2013 Kris Deugau <kdeugau@deepnet.cx> | 
|---|
|  | 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 () | 
|---|