Ignore:
Timestamp:
02/11/26 13:13:59 (9 hours ago)
Author:
Kris Deugau
Message:

/branches/stable

Continue merging /trunk commits based on production

Location:
branches/stable
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/stable

  • branches/stable/DNSDB.pm

    r1032 r1033  
    33##
    44# $Id$
    5 # Copyright 2008-2017 Kris Deugau <kdeugau@deepnet.cx>
     5# Copyright 2008-2019 Kris Deugau <kdeugau@deepnet.cx>
    66#
    77#    This program is free software: you can redistribute it and/or modify
     
    294294##
    295295
     296## DNSDB::_zonetable()
     297# Takes default+rdns flags, returns appropriate zone table name
     298sub _zonetable {
     299  my $def = shift;
     300  my $rev = shift;
     301
     302  return 'domains' if $rev ne 'y';
     303  return 'revzones';
     304} # end _zonetable()
     305
    296306## DNSDB::_rectable()
    297307# Takes default+rdns flags, returns appropriate table name
     
    484494#  } elsif ($self->{log_channel} eq 'syslog') {
    485495#  }
    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
     501sub _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()
    487516
    488517
     
    9871016  push @ferr, "weight" unless ${$args{weight}} =~ /^\d+$/;
    9881017  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).")")
    9901019        unless ${$args{dist}} =~ /^\d+$/ && ${$args{weight}} =~ /^\d+$/ && ${$args{port}} =~ /^\d+$/;
    9911020
     
    12851314      # work here since we don't *know* which parent to put it in.
    12861315      # ${$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 >>= ?".
    12881317        " ORDER BY masklen(revnet) DESC", undef, (${$args{val}}));
    12891318      # Fail if no match;  we can't coerce a PTR-template type down to not include the PTR bit currently.
     
    24712500  eval {
    24722501    # 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()) ) );
    24752504
    24762505    # get the ID...
     
    26432672
    26442673## DNSDB::domainID()
    2645 # Takes a database handle and domain name
     2674# Takes a domain name and default location
    26462675# Returns the domain ID number
    26472676sub domainID {
     
    26732702
    26742703## 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
    26762706# Returns the rDNS ID number
    26772707sub revID {
     
    27512781  eval {
    27522782    # 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()) ) );
    27552785
    27562786    # get the ID...
     
    41834213  delete $ret->{val};
    41844214
     4215  my ($ser) = $dbh->selectrow_array("SELECT zserial FROM "._zonetable($def,$rev).
     4216        " WHERE "._recparent($def,$rev)." = ?", undef, $id);
     4217  $ret->{serial} = $ser;
     4218
    41854219  return $ret;
    41864220} # end getSOA()
     
    42404274        " retry $soa{retry}, expire $soa{expire}, minTTL $soa{minttl}, TTL $soa{ttl})";
    42414275    }
     4276    $self->_updateserial(%logdata);
    42424277    $logdata{entry} = $msg;
    42434278    $self->_log(%logdata);
     
    45884623    $dbh->do("INSERT INTO "._rectable($defrec, $revrec)." ($fields) VALUES ($vallen)",
    45894624        undef, @vallist);
     4625    $self->_updateserial(%logdata);
    45904626    $self->_log(%logdata);
    45914627    $dbh->commit;
     
    47884824  eval {
    47894825    $dbh->do("UPDATE "._rectable($defrec,$revrec)." SET $fields WHERE record_id=?", undef, (@vallist, $id) );
     4826    $self->_updateserial(%logdata);
    47904827    $self->_log(%logdata);
    47914828    $dbh->commit;
     
    48534890  eval {
    48544891    $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});
    48554894    $self->_log(domain_id => $rec->{domain_id}, rdns_id => $rec->{rdns_id},
    48564895        group_id => $self->parentID(id => $rec->{rdns_id}, type => 'revzone', revrec => 'y'),
     
    49034942
    49044943  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);
    49064946    $self->_log(%logdata);
    49074947    $dbh->commit;
     
    54585498## DNSDB::getZonesByCIDR()
    54595499# 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"
    54625507sub getZonesByCIDR {
    54635508  my $self = shift;
     
    54695514        " FROM revzones WHERE (revnet >>= ? OR revnet <<= ?)".
    54705515        (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  }
    54715521  my @svals = ($args{cidr}, $args{cidr});
    54725522  push @svals, $args{location} if defined $args{location};
     
    54835533#  status - active/inactive state flag (defaults to active)
    54845534#  rwsoa - overwrite-SOA flag (defaults to off)
     5535#  keepserial - keep the upstream serial number even if we overwrite the rest of the SOA
    54855536#  rwns - overwrite-NS flag (defaults to off, doesn't affect subdomain NS records)
    54865537#  merge - flag to automerge A or AAAA records with matching PTR records
     
    56335684    my $logparent;
    56345685
     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
    56355699    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;
    56395702      # get domain id so we can do the records
    56405703      ($zone_id) = $dbh->selectrow_array("SELECT currval('domains_domain_id_seq')");
    56415704      $domain_id = $zone_id;
    56425705      $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]");
    56445707    } 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) );
    56485710      # get revzone id so we can do the records
    56495711      ($zone_id) = $dbh->selectrow_array("SELECT currval('revzones_rdns_id_seq')");
    56505712      $rdns_id = $zone_id;
    56515713      $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]");
    56535715    }
    56545716
     
    56585720## caused a commit instead of barfing
    56595721
    5660     my $res = Net::DNS::Resolver->new;
    5661     $res->nameservers($ifrom);
    56625722    $res->axfr_start($zone)
    56635723        or die "Couldn't begin AXFR\n";
     
    62336293
    62346294      # 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      }
    62356309      #  - we are not using the cache
    62366310      #  - force_refresh is set
     
    62386312      #  - the cache file does not exist
    62396313      #  - the cache file is empty
    6240       #  - the zone contains ALIAS pseudorecords, which need to cascade changes from the upstream CNAME farm at every opportunity
    6241       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 records
    6243       }
    62446314      if (!$self->{usecache} || $self->{force_refresh} || $changed || !-e $cachefile || -z $cachefile) {
    62456315        if ($self->{usecache}) {
     
    64796549    # host contains pri-ns:responsible
    64806550    # val is abused to contain refresh:retry:expire:minttl
    6481 ##fixme:  "manual" serial vs tinydns-autoserial
    64826551    # let's be explicit about abusing $host and $val
    64836552    my ($email, $primary) = (split /:/, $host)[0,1];
    64846553    my ($refresh, $retry, $expire, $min_ttl) = (split /:/, $val)[0,1,2,3];
     6554    my $serial = 0;  # fail less horribly than leaving it empty?
    64856555    if ($revrec eq 'y') {
    64866556##fixme:  have to publish SOA records for each v4 /24 in sub-/16, and each /16 in sub-/8
     
    64886558# -> only need SOA for local chunks offset from reverse delegation boundaries, so v6 is fine
    64896559# 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);
    64906562      $zone = NetAddr::IP->new($zone);
    64916563      # handle split-n-multiply SOA for off-octet (8 < mask < 16) or (16 < mask < 24) v4 zones
     
    64936565        foreach my $szone ($zone->split($zone->masklen + (8 - $zone->masklen % 8))) {
    64946566          $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"
    64966568            or die $!;
    64976569        }
     
    64996571      }
    65006572      $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"
    65036580      or die $!;
    65046581  } # SOA
     
    68096886    }
    68106887    print $datafile "$rec:$ttl:$stamp:$loc\n" or die $!;
    6811 
    68126888  } # SSHFP
    68136889
Note: See TracChangeset for help on using the changeset viewer.