- Timestamp:
- 01/20/23 16:37:06 (2 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/DNSDB/ExportBIND.pm
r880 r881 40 40 ## export reverse zones 41 41 42 my $soasth = $dnsdb->{dbh}->prepare("SELECT host,type,val,distance,weight,port,ttl,record_id,location ". 43 "FROM records WHERE rdns_id=? AND type=6"); 42 my $soasth = $dnsdb->{dbh}->prepare("SELECT host,val,ttl,record_id,location FROM records WHERE rdns_id=? AND type=6"); 44 43 # record order matters for reverse zones because we need to override larger templates with smaller ones. 45 my $recsth = $dnsdb->{dbh}->prepare("SELECT host,type,val,distance,weight,port,ttl,record_id,location,extract(epoch from stamp),expires,stampactive ". 46 "FROM records WHERE rdns_id=? AND NOT type=6 ". 47 "ORDER BY masklen(inetlazy(val)) DESC, inetlazy(val)"); 44 my $recsth = $dnsdb->{dbh}->prepare( 45 "SELECT host,type,val,distance,weight,port,ttl,record_id,location,extract(epoch from stamp),expires,stampactive ". 46 "FROM records WHERE rdns_id=? AND NOT type=6 ". 47 "ORDER BY masklen(inetlazy(val)) DESC, inetlazy(val), record_id"); 48 48 49 49 # Fetch active zone list 50 50 my $revsth = $dnsdb->{dbh}->prepare("SELECT rdns_id,revnet,status,changed,default_location FROM revzones WHERE status=1 ". 51 51 "ORDER BY masklen(revnet),revnet DESC, rdns_id"); 52 52 # Unflag changed zones, so we can maybe cache the export and not redo everything every time 53 53 my $zonesth = $dnsdb->{dbh}->prepare("UPDATE revzones SET changed='n' WHERE rdns_id=?"); 54 55 my %recflags; # need this to be independent for forward vs reverse zones, as they're not merged 56 54 57 $revsth->execute(); 55 56 my %recflags; # need this to be independent for forward vs reverse zones, as they're not merged57 58 58 while (my ($revid,$revzone,$revstat,$changed,$defloc) = $revsth->fetchrow_array) { 59 59 my $cidr = NetAddr::IP->new($revzone); … … 69 69 # fetch a list of views/locations present in the zone. we need to publish a file for each one. 70 70 # in the event that no locations are present (~~ $viewlist is empty), /%view collapses to nothing in the zone path 71 # my (@loclist) = $dnsdb->{dbh}->selectrow_array("SELECT DISTINCT location FROM records WHERE rdns_id = ?", undef, $revid);72 71 my $tmplocs = $dnsdb->{dbh}->selectall_arrayref("SELECT DISTINCT location FROM records WHERE rdns_id = ?", undef, $revid); 73 72 my @loclist; … … 80 79 eval { 81 80 81 ##fixme: use tmpfile module for more secure temp files? want the zone name at least in it anyway, not sure that works... 82 82 my $arpazone = DNSDB::_ZONE($cidr, 'ZONE', 'r', '.').($cidr->{isv6} ? '.ip6.arpa' : '.in-addr.arpa'); 83 83 my $zfile = $cidr->network->addr."-".$cidr->masklen; … … 96 96 $zfilepath =~ s,[^\w./-],_,g; 97 97 98 # open $zonefiles{$loc}, ">", $zfilepath; 98 # safety check, may need tweaking for race conditions 99 my $zpathbase = $zfilepath; 100 $zpathbase =~ s{/[^/]+$}{}; 101 if (!-e $zpathbase) { 102 mkdir $zpathbase; 103 } else { 104 die "$zpathbase is not a directory\n" unless -d $zpathbase; 105 } 99 106 100 107 # write fresh records if: 101 # - we are not using the cache 108 # - the zone contains records which expire in less than 10 minutes or became valid less than 10 minutes ago 109 # note, no need to multi-bump the serial 110 if ( ($dnsdb->{dbh}->selectrow_array("SELECT COUNT(*) FROM records WHERE rdns_id = ? AND ". 111 "stampactive='t' AND @(extract(epoch from stamp-now())) < 600", undef, $revid))[0] ) { 112 $changed = 1; 113 $dnsdb->_updateserial(domain_id => $domid); 114 } 115 # - we are not using the cache 116 # if ($dnsdb->{usecache} 102 117 # - force_refresh is set 103 118 # - the zone has changed 104 # - the cache file does not exist 105 # - the cache file is empty 106 if ($dnsdb->{force_refresh} || $changed || !-e $zfilepath || -z $zfilepath) { 107 # if (!$dnsdb->{usecache} || $dnsdb->{force_refresh} || $changed || !-e $cachefile || -z $cachefile) { 119 # - the zone file does not exist 120 # - the zone file is empty 121 elsif ($dnsdb->{force_refresh} || $changed || !-e $zfilepath || -z $zfilepath) { 108 122 # if ($dnsdb->{usecache}) { 109 123 # open ZONECACHE, ">$tmpcache" or die "Error creating temporary file $tmpcache: $!\n"; … … 112 126 open $zonefiles{$loc}, ">", $zfilepath or die "Error creating temporary file $zfilepath: $!\n"; 113 127 128 # Header for human convenience 129 ##fixme? vary arpazone/cidr in header and error message per showrev_arpa, or possibly 130 # new dedicated setting, or possibly interact with with bind_export_fqdn? 114 131 printf {$zonefiles{$loc}} "; %s in view %s exported %s\n", $arpazone, $loc, scalar(localtime) 115 or die "Error writing header [$cidr, '$loc']: $!\n"; 116 117 # need to fetch this separately since the rest of the records all (should) have real IPs in val 132 or die "Error writing header [$arpazone, '$loc']: $!\n"; 133 134 # Fetch the SOA separately as we publish it separately for each location with this loop, 135 # mainly because we want it first in the zone file 118 136 $soasth->execute($revid); 119 my (@zsoa) = $soasth->fetchrow_array(); 137 my ($soa_host, $soa_val, $soa_ttl, $soa_id, $soa_loc) = $soasth->fetchrow_array; 138 120 139 ##fixme: do we even need @loclist passed in? 121 printrec_bind($dnsdb, \%zonefiles, \@loclist, $zsoa[7], 'y', \%recflags, $cidr, 122 $zsoa[0], $zsoa[1], $zsoa[2], $zsoa[3], $zsoa[4], $zsoa[5], $zsoa[6], $loc, ''); 140 printrec_bind($dnsdb, \%zonefiles, \@loclist, $soa_id, 'y', \%recflags, $cidr, 141 $soa_host, 6, $soa_val, 0, 0, 0, $soa_ttl, $loc, ''); 142 123 143 } # if force_refresh etc 124 144 125 145 # tag the zonefile for publication in the view 126 146 push @{$viewzones{$loc}}, $arpazone; 147 127 148 } # foreach @loclist 128 149 129 150 # now the meat of the records 130 151 $recsth->execute($revid); 131 132 152 while (my ($host, $type, $val, $dist, $weight, $port, $ttl, $recid, $loc, $stamp, $expires, $stampactive) 133 153 = $recsth->fetchrow_array) { 134 154 next if $recflags{$recid}; 155 156 # Spaces are evil. 157 $val =~ s/^\s+//; 158 $val =~ s/\s+$//; 159 if ($typemap{$type} ne 'TXT') { 160 # Leading or trailng spaces could be legit in TXT records. 161 $host =~ s/^\s+//; 162 $host =~ s/\s+$//; 163 } 135 164 136 165 # Check for out-of-zone data … … 149 178 } # is $val a raw .arpa name? 150 179 151 # Spaces are evil.152 $val =~ s/^\s+//;153 $val =~ s/\s+$//;154 if ($typemap{$type} ne 'TXT') {155 # Leading or trailng spaces could be legit in TXT records.156 $host =~ s/^\s+//;157 $host =~ s/\s+$//;158 }159 160 180 printrec_bind($dnsdb, \%zonefiles, \@loclist, $recid, 'y', \%recflags, $revzone, 161 181 $host, $type, $val, $dist, $weight, $port, $ttl, $loc, $stamp, $expires, $stampactive); … … 202 222 ## and now the domains 203 223 204 $soasth = $dnsdb->{dbh}->prepare("SELECT host,type,val,distance,weight,port,ttl,record_id,location ". 205 "FROM records WHERE domain_id=? AND type=6"); 224 $soasth = $dnsdb->{dbh}->prepare("SELECT host,val,ttl,record_id,location FROM records WHERE domain_id=? AND type=6"); 206 225 # record order needs to match reverse zone ordering for IP values, or A+PTR 207 226 # template records don't cascade/expand correctly to match the reverse zones. … … 211 230 # ordering by nominal parent-child label hierarchy (as actually found live 212 231 # in some AXFRed zone files) would take a lot of chewing on data 213 $recsth = $dnsdb->{dbh}->prepare("SELECT host,type,val,distance,weight,port,ttl,record_id,location,extract(epoch from stamp),expires,stampactive ". 214 "FROM records WHERE domain_id=? AND NOT type=6 ". 215 "ORDER BY masklen(inetlazy(val)) DESC, inetlazy(val), record_id"); 232 $recsth = $dnsdb->{dbh}->prepare( 233 "SELECT host,type,val,distance,weight,port,ttl,record_id,location,extract(epoch from stamp),expires,stampactive ". 234 "FROM records WHERE domain_id=? AND NOT type=6 ". 235 "ORDER BY masklen(inetlazy(val)) DESC, inetlazy(val), record_id"); 216 236 # "FROM records WHERE domain_id=? AND type < 65280"); # Just exclude all types relating to rDNS 217 237 218 238 # Fetch active zone list 219 my $domsth = $dnsdb->{dbh}->prepare("SELECT domain_id,domain,status,changed FROM domains WHERE status=1 ORDER BY domain_id"); 239 my $domsth = $dnsdb->{dbh}->prepare("SELECT domain_id,domain,status,changed,default_location FROM domains WHERE status=1 ". 240 "ORDER BY domain_id"); 220 241 # Unflag changed zones, so we can maybe cache the export and not redo everything every time 221 242 $zonesth = $dnsdb->{dbh}->prepare("UPDATE domains SET changed='n' WHERE domain_id=?"); 222 $domsth->execute();223 243 224 244 # Clear %reclfags, since we explicitly want to NOT carry "I've published this … … 231 251 # %recflags = (); 232 252 253 $domsth->execute(); 233 254 while (my ($domid,$domain,$domstat,$changed) = $domsth->fetchrow_array) { 234 255 … … 240 261 push @loclist, ($tloc->[0] eq '' ? 'common' : $tloc->[0]); 241 262 } 263 242 264 my %zonefiles; # zone file handles 243 265 … … 247 269 my $zfile = $domain; # can probably drop this intermediate 248 270 my $tmpcache = "tmp.$zfile.$$"; # safety net. don't overwrite a previous known-good file 271 249 272 foreach my $loc (@loclist) { 250 273 my $zfilepath = $dnsdb->{bind_export_zone_path}; 251 274 $zfilepath =~ s/\%view/$loc/; 252 275 $zfilepath =~ s/\%zone/$zfile/; 253 # $zfilepath =~ s/\%arpazone/$arpazone/;254 276 255 277 # Just In Case(TM) 256 278 $zfilepath =~ s,[^\w./-],_,g; 257 279 258 # open $zonefiles{$loc}, ">", $zfilepath; 259 print "open zonefile for '$loc', '$zfilepath'\n"; 260 280 # safety check, may need tweaking for race conditions 281 my $zpathbase = $zfilepath; 282 $zpathbase =~ s{/[^/]+$}{}; 283 if (!-e $zpathbase) { 284 mkdir $zpathbase; 285 } else { 286 die "$zpathbase is not a directory\n" unless -d $zpathbase; 287 } 261 288 262 289 # write fresh records if: … … 275 302 $dnsdb->_updateserial(domain_id => $domid); 276 303 } 304 # - we are not using the cache 305 # if ($dnsdb->{usecache} 306 # - force_refresh is set 307 # - the zone has changed 308 # - the zone file does not exist 309 # - the zone file is empty 277 310 # if (!$self->{usecache} || $self->{force_refresh} || $changed || !-e $cachefile || -z $cachefile) { 278 311 if ($dnsdb->{force_refresh} || $changed || !-e $zfilepath || -z $zfilepath) { 279 open $zonefiles{$loc}, ">", $zfilepath or die "Error creating temporary file $zfilepath: $!\n";280 281 312 # if ($self->{usecache}) { 282 313 # open ZONECACHE, ">$tmpcache" or die "Error creating temporary file $tmpcache: $!\n"; 283 314 # $zonefilehandle = *ZONECACHE; 284 315 # } 285 286 # need to fetch this separately so the SOA comes first in the flatfile.... 287 # Just In Case we need/want to reimport from the flatfile later on. 288 $soasth->execute($domid); 289 my (@zsoa) = $soasth->fetchrow_array(); 290 291 # drop in a header line so we know when things went KABOOM 316 open $zonefiles{$loc}, ">", $zfilepath or die "Error creating temporary file $zfilepath: $!\n"; 317 318 # Header for human convenience 292 319 printf {$zonefiles{$loc}} "; %s in view %s exported %s\n", $domain, $loc, scalar(localtime) 293 320 or die "Error writing header [$domain, '$loc']: $!\n"; 294 321 295 printrec_bind($dnsdb, \%zonefiles, \@loclist, $zsoa[7], 'n', \%recflags, $domain, 296 $zsoa[0], $zsoa[1], $zsoa[2], $zsoa[3], $zsoa[4], $zsoa[5], $zsoa[6], $loc, ''); 297 298 # $self->_printrec_tiny($zonefilehandle, $zsoa[7], 'n',\%recflags, $domain, 299 # $zsoa[0],$zsoa[1],$zsoa[2],$zsoa[3],$zsoa[4],$zsoa[5],$zsoa[6],$zsoa[8],''); 322 # Fetch the SOA separately as we publish it separately for each location with this loop, 323 # mainly because we want it first in the zone file 324 $soasth->execute($domid); 325 my ($soa_host, $soa_val, $soa_ttl, $soa_id, $soa_loc) = $soasth->fetchrow_array; 326 $dnsdb->{dbh}->selectrow_array( 327 "SELECT host,val,ttl,record_id,location FROM records WHERE domain_id=? AND type=6"); 328 329 ##fixme: do we even need @loclist passed in? 330 printrec_bind($dnsdb, \%zonefiles, \@loclist, $soa_id, 'n', \%recflags, $domain, 331 $soa_host, 6, $soa_val, 0, 0, 0, $soa_ttl, $loc, ''); 300 332 301 333 } # if force_refresh etc … … 303 335 # tag the zonefile for publication in the view 304 336 push @{$viewzones{$loc}}, $domain; 337 305 338 } # foreach @loclist 306 339 340 # now the meat of the records 307 341 $recsth->execute($domid); 308 342 while (my ($host,$type,$val,$dist,$weight,$port,$ttl,$recid,$loc,$stamp,$expires,$stampactive) = $recsth->fetchrow_array) { … … 327 361 } 328 362 329 $recflags{$recid} = 1;330 331 363 printrec_bind($dnsdb, \%zonefiles, \@loclist, $recid, 'n', \%recflags, $domain, 332 364 $host, $type, $val, $dist, $weight, $port, $ttl, $loc, $stamp, $expires, $stampactive); 365 366 $recflags{$recid} = 1; 333 367 334 368 } # while ($recsth)
Note:
See TracChangeset
for help on using the changeset viewer.