Changeset 1033 for branches/stable/DNSDB.pm
- Timestamp:
- 02/11/26 13:13:59 (9 hours ago)
- Location:
- branches/stable
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable
-
branches/stable/DNSDB.pm
r1032 r1033 3 3 ## 4 4 # $Id$ 5 # Copyright 2008-201 7Kris Deugau <kdeugau@deepnet.cx>5 # Copyright 2008-2019 Kris Deugau <kdeugau@deepnet.cx> 6 6 # 7 7 # This program is free software: you can redistribute it and/or modify … … 294 294 ## 295 295 296 ## DNSDB::_zonetable() 297 # Takes default+rdns flags, returns appropriate zone table name 298 sub _zonetable { 299 my $def = shift; 300 my $rev = shift; 301 302 return 'domains' if $rev ne 'y'; 303 return 'revzones'; 304 } # end _zonetable() 305 296 306 ## DNSDB::_rectable() 297 307 # Takes default+rdns flags, returns appropriate table name … … 484 494 # } elsif ($self->{log_channel} eq 'syslog') { 485 495 # } 486 } # end _log 496 } # end _log() 497 498 ## DNSDB::_updateserial() 499 # Update the serial number on a forward and/or reverse zone, and flag it as changed 500 # Takes a logdata hash 501 sub _updateserial { 502 my $self = shift; 503 my $dbh = $self->{dbh}; 504 505 my %args = @_; 506 507 ##fixme: add alternate serial schemes here 508 509 if ($args{rdns_id}) { 510 $dbh->do("UPDATE revzones SET changed = 'y',zserial = ? WHERE rdns_id = ?", undef, (scalar(time), $args{rdns_id}) ); 511 } 512 if ($args{domain_id}) { 513 $dbh->do("UPDATE domains SET changed = 'y',zserial = ? WHERE domain_id = ?", undef, (scalar(time), $args{domain_id}) ); 514 } 515 } # end _updateserial() 487 516 488 517 … … 987 1016 push @ferr, "weight" unless ${$args{weight}} =~ /^\d+$/; 988 1017 push @ferr, "port" unless ${$args{port}} =~ /^\d+$/; 989 return ('FAIL',"Distance, port and weight are required, and must be numeric (check ".join(", ", @ferr).")")1018 return ('FAIL',"Distance, port and weight are required, and must be numeric (check ".join(", ", @ferr).")") 990 1019 unless ${$args{dist}} =~ /^\d+$/ && ${$args{weight}} =~ /^\d+$/ && ${$args{port}} =~ /^\d+$/; 991 1020 … … 1285 1314 # work here since we don't *know* which parent to put it in. 1286 1315 # ${$args{val}} has been validated as a valid IP by now, in one of the above calls. 1287 my ($revid) = $dbh->selectrow_array("SELECT rdns_id FROM revzones WHERE revnet >> ?".1316 my ($revid) = $dbh->selectrow_array("SELECT rdns_id FROM revzones WHERE revnet >>= ?". 1288 1317 " ORDER BY masklen(revnet) DESC", undef, (${$args{val}})); 1289 1318 # Fail if no match; we can't coerce a PTR-template type down to not include the PTR bit currently. … … 2471 2500 eval { 2472 2501 # insert the domain... 2473 $dbh->do("INSERT INTO domains (domain,group_id,status,default_location ) VALUES (?,?,?,?)", undef,2474 ($domain, $group, $state, $defloc ));2502 $dbh->do("INSERT INTO domains (domain,group_id,status,default_location,zserial) VALUES (?,?,?,?,?)", undef, 2503 ($domain, $group, $state, $defloc, scalar(time()) ) ); 2475 2504 2476 2505 # get the ID... … … 2643 2672 2644 2673 ## DNSDB::domainID() 2645 # Takes a d atabase handle and domain name2674 # Takes a domain name and default location 2646 2675 # Returns the domain ID number 2647 2676 sub domainID { … … 2673 2702 2674 2703 ## DNSDB::revID() 2675 # Takes a database handle and reverse zone name 2704 # Takes a reverse zone name and default location 2705 # Assumes the reverse zone is in the logical CIDR form, not the formal .arpa form 2676 2706 # Returns the rDNS ID number 2677 2707 sub revID { … … 2751 2781 eval { 2752 2782 # insert the zone... 2753 $dbh->do("INSERT INTO revzones (revnet,group_id,status,default_location ) VALUES (?,?,?,?)", undef,2754 ($zone, $group, $state, $defloc ) );2783 $dbh->do("INSERT INTO revzones (revnet,group_id,status,default_location,zserial) VALUES (?,?,?,?,?)", undef, 2784 ($zone, $group, $state, $defloc, scalar(time()) ) ); 2755 2785 2756 2786 # get the ID... … … 4183 4213 delete $ret->{val}; 4184 4214 4215 my ($ser) = $dbh->selectrow_array("SELECT zserial FROM "._zonetable($def,$rev). 4216 " WHERE "._recparent($def,$rev)." = ?", undef, $id); 4217 $ret->{serial} = $ser; 4218 4185 4219 return $ret; 4186 4220 } # end getSOA() … … 4240 4274 " retry $soa{retry}, expire $soa{expire}, minTTL $soa{minttl}, TTL $soa{ttl})"; 4241 4275 } 4276 $self->_updateserial(%logdata); 4242 4277 $logdata{entry} = $msg; 4243 4278 $self->_log(%logdata); … … 4588 4623 $dbh->do("INSERT INTO "._rectable($defrec, $revrec)." ($fields) VALUES ($vallen)", 4589 4624 undef, @vallist); 4625 $self->_updateserial(%logdata); 4590 4626 $self->_log(%logdata); 4591 4627 $dbh->commit; … … 4788 4824 eval { 4789 4825 $dbh->do("UPDATE "._rectable($defrec,$revrec)." SET $fields WHERE record_id=?", undef, (@vallist, $id) ); 4826 $self->_updateserial(%logdata); 4790 4827 $self->_log(%logdata); 4791 4828 $dbh->commit; … … 4853 4890 eval { 4854 4891 $dbh->do("UPDATE records SET $delpar = ?, type = ? WHERE record_id = ?", undef, @sqlargs); 4892 # we have no %logdata in this sub 4893 $self->_updateserial(domain_id => $rec->{domain_id}, rdns_id => $rec->{rdns_id}); 4855 4894 $self->_log(domain_id => $rec->{domain_id}, rdns_id => $rec->{rdns_id}, 4856 4895 group_id => $self->parentID(id => $rec->{rdns_id}, type => 'revzone', revrec => 'y'), … … 4903 4942 4904 4943 eval { 4905 my $sth = $dbh->do("DELETE FROM "._rectable($defrec,$revrec)." WHERE record_id=?", undef, ($id)); 4944 $dbh->do("DELETE FROM "._rectable($defrec,$revrec)." WHERE record_id=?", undef, ($id)); 4945 $self->_updateserial(%logdata); 4906 4946 $self->_log(%logdata); 4907 4947 $dbh->commit; … … 5458 5498 ## DNSDB::getZonesByCIDR() 5459 5499 # Get a list of zone names and IDs that records for a passed CIDR block are within. 5460 # Optionally restrict to a specific location/view 5461 # Optionally leave off the default_location field 5500 # Arguments must be passed in a hash 5501 # Requires an argument "cidr" for the CIDR block to find parent/child zone(s) for 5502 # Accepts optional arguments: 5503 # - return_location: Flag indicating whether to return default_location or not 5504 # - location: Restrict matches to a particular location/view 5505 # - sort: Valid values are ASC or DESC; if omitted or set to something else 5506 # results will be "whatever the database returns" 5462 5507 sub getZonesByCIDR { 5463 5508 my $self = shift; … … 5469 5514 " FROM revzones WHERE (revnet >>= ? OR revnet <<= ?)". 5470 5515 (defined($args{location}) ? " AND default_location = ?" : ''); 5516 if ($args{sort}) { 5517 if ($args{sort} eq 'ASC' || $args{sort} eq 'DESC') { 5518 $sql .= " ORDER BY revnet $args{sort}"; 5519 } 5520 } 5471 5521 my @svals = ($args{cidr}, $args{cidr}); 5472 5522 push @svals, $args{location} if defined $args{location}; … … 5483 5533 # status - active/inactive state flag (defaults to active) 5484 5534 # rwsoa - overwrite-SOA flag (defaults to off) 5535 # keepserial - keep the upstream serial number even if we overwrite the rest of the SOA 5485 5536 # rwns - overwrite-NS flag (defaults to off, doesn't affect subdomain NS records) 5486 5537 # merge - flag to automerge A or AAAA records with matching PTR records … … 5633 5684 my $logparent; 5634 5685 5686 # Snarf the zone serial. Doing it here lets us log the serial we ultimately 5687 # import with, and cleanly override or not as per the options 5688 my $res = Net::DNS::Resolver->new; 5689 $res->nameservers($ifrom); 5690 my $soaq = $res->query($zone, "SOA"); 5691 die "Error retrieving SOA for $zone: ".$res->errorstring."\n" if !$soaq; 5692 my $ser = ($soaq->answer)[0]->{serial}; 5693 if ($args{rwsoa}) { 5694 if (!$args{keepserial}) { 5695 $ser = scalar(time); 5696 } 5697 } 5698 5635 5699 if ($rev eq 'n') { 5636 ##fixme: serial 5637 $dbh->do("INSERT INTO domains (domain,group_id,status) VALUES (?,?,?)", undef, 5638 ($zone, $group, $args{status}) ) or die $dbh->errstr; 5700 $dbh->do("INSERT INTO domains (domain,group_id,status,zserial) VALUES (?,?,?,?)", undef, 5701 ($zone, $group, $args{status}, $ser) ) or die $dbh->errstr; 5639 5702 # get domain id so we can do the records 5640 5703 ($zone_id) = $dbh->selectrow_array("SELECT currval('domains_domain_id_seq')"); 5641 5704 $domain_id = $zone_id; 5642 5705 $logparent = $self->_log(group_id => $group, domain_id => $domain_id, 5643 entry => "[Added ".($args{status} ? 'active' : 'inactive')." domain $zone via AXFR]");5706 entry => "[Added ".($args{status} ? 'active' : 'inactive')." domain $zone with serial $ser via AXFR]"); 5644 5707 } else { 5645 ##fixme: serial 5646 $dbh->do("INSERT INTO revzones (revnet,group_id,status) VALUES (?,?,?)", undef, 5647 ($cidr,$group,$args{status}) ); 5708 $dbh->do("INSERT INTO revzones (revnet,group_id,status,zserial) VALUES (?,?,?,?)", undef, 5709 ($cidr,$group,$args{status}, $ser) ); 5648 5710 # get revzone id so we can do the records 5649 5711 ($zone_id) = $dbh->selectrow_array("SELECT currval('revzones_rdns_id_seq')"); 5650 5712 $rdns_id = $zone_id; 5651 5713 $logparent = $self->_log(group_id => $group, rdns_id => $rdns_id, 5652 entry => "[Added ".($args{status} ? 'active' : 'inactive')." reverse zone $cidr via AXFR]");5714 entry => "[Added ".($args{status} ? 'active' : 'inactive')." reverse zone $cidr with serial $ser via AXFR]"); 5653 5715 } 5654 5716 … … 5658 5720 ## caused a commit instead of barfing 5659 5721 5660 my $res = Net::DNS::Resolver->new;5661 $res->nameservers($ifrom);5662 5722 $res->axfr_start($zone) 5663 5723 or die "Couldn't begin AXFR\n"; … … 6233 6293 6234 6294 # write fresh records if: 6295 # - the zone contains ALIAS pseudorecords, which need to cascade changes from the upstream CNAME farm at every opportunity 6296 if ( ($dbh->selectrow_array("SELECT count(*) FROM records WHERE domain_id = ? AND type=65300", undef, $domid))[0] ) { 6297 $changed = 1; # abuse this flag for zones with ALIAS records 6298 # also update the serial number, because while it shouldn't matter purely for serving 6299 # records, it WILL matter if AXFR becomes part of the publishing infrastructure 6300 $self->_updateserial(domain_id => $domid); 6301 } 6302 # - the zone contains records which expire in less than 10 minutes or became valid less than 10 minutes ago 6303 # note, no need to multi-bump the serial 6304 elsif ( ($dbh->selectrow_array("SELECT COUNT(*) FROM records WHERE domain_id = ? AND ". 6305 "stampactive='t' AND @(extract(epoch from stamp-now())) < 600", undef, $domid))[0] ) { 6306 $changed = 1; 6307 $self->_updateserial(domain_id => $domid); 6308 } 6235 6309 # - we are not using the cache 6236 6310 # - force_refresh is set … … 6238 6312 # - the cache file does not exist 6239 6313 # - the cache file is empty 6240 # - the zone contains ALIAS pseudorecords, which need to cascade changes from the upstream CNAME farm at every opportunity6241 if ( ($dbh->selectrow_array("SELECT count(*) FROM records WHERE domain_id = ? AND type=65300", undef, $domid))[0] ) {6242 $changed = 1; # abuse this flag for zones with ALIAS records6243 }6244 6314 if (!$self->{usecache} || $self->{force_refresh} || $changed || !-e $cachefile || -z $cachefile) { 6245 6315 if ($self->{usecache}) { … … 6479 6549 # host contains pri-ns:responsible 6480 6550 # val is abused to contain refresh:retry:expire:minttl 6481 ##fixme: "manual" serial vs tinydns-autoserial6482 6551 # let's be explicit about abusing $host and $val 6483 6552 my ($email, $primary) = (split /:/, $host)[0,1]; 6484 6553 my ($refresh, $retry, $expire, $min_ttl) = (split /:/, $val)[0,1,2,3]; 6554 my $serial = 0; # fail less horribly than leaving it empty? 6485 6555 if ($revrec eq 'y') { 6486 6556 ##fixme: have to publish SOA records for each v4 /24 in sub-/16, and each /16 in sub-/8 … … 6488 6558 # -> only need SOA for local chunks offset from reverse delegation boundaries, so v6 is fine 6489 6559 # anyone who says they need sub-nibble v6 delegations, at this time, needs their head examined. 6560 ##fixme?: alternate SOA serial schemes? 6561 ($serial) = $self->{dbh}->selectrow_array("SELECT zserial FROM revzones WHERE revnet=?", undef, $zone); 6490 6562 $zone = NetAddr::IP->new($zone); 6491 6563 # handle split-n-multiply SOA for off-octet (8 < mask < 16) or (16 < mask < 24) v4 zones … … 6493 6565 foreach my $szone ($zone->split($zone->masklen + (8 - $zone->masklen % 8))) { 6494 6566 $szone = _ZONE($szone, 'ZONE.in-addr.arpa', 'r', '.'); 6495 print $datafile "Z$szone:$primary:$email "."::$refresh:$retry:$expire:$min_ttl:$ttl:$stamp:$loc\n"6567 print $datafile "Z$szone:$primary:$email:$serial:$refresh:$retry:$expire:$min_ttl:$ttl:$stamp:$loc\n" 6496 6568 or die $!; 6497 6569 } … … 6499 6571 } 6500 6572 $zone = _ZONE($zone, 'ZONE', 'r', '.').($zone->{isv6} ? '.ip6.arpa' : '.in-addr.arpa'); 6501 } 6502 print $datafile "Z$zone:$primary:$email"."::$refresh:$retry:$expire:$min_ttl:$ttl:$stamp:$loc\n" 6573 } else { 6574 # just snarfing the right SOA serial for the zone type 6575 ##fixme?: alternate SOA serial schemes? 6576 ($serial) = $self->{dbh}->selectrow_array("SELECT zserial FROM domains WHERE domain=?", undef, $zone); 6577 } # revrec <> 'y' 6578 $serial = '' if !$serial; # suppress a "uninitialized value" warning. empty serial isn't an error, just falls back to tinydns' autoserial 6579 print $datafile "Z$zone:$primary:$email:$serial:$refresh:$retry:$expire:$min_ttl:$ttl:$stamp:$loc\n" 6503 6580 or die $!; 6504 6581 } # SOA … … 6809 6886 } 6810 6887 print $datafile "$rec:$ttl:$stamp:$loc\n" or die $!; 6811 6812 6888 } # SSHFP 6813 6889
Note:
See TracChangeset
for help on using the changeset viewer.
![[ DNS Administrator ]](/fx/dnsadmin-logo.png)