Changeset 543 for trunk/DNSDB.pm
- Timestamp:
- 12/10/13 16:22:10 (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/DNSDB.pm
r542 r543 31 31 use POSIX; 32 32 use Fcntl qw(:flock); 33 use Time::TAI64 qw(:tai64); 33 34 34 35 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); … … 3536 3537 my $id = shift; 3537 3538 3539 ##fixme: do we need a knob to twist to switch between unix epoch and postgres time string? 3538 3540 my $sql = "SELECT record_id,host,type,val,ttl". 3539 3541 ($defrec eq 'n' ? ',location' : ''). 3540 3542 ($revrec eq 'n' ? ',distance,weight,port' : ''). 3541 (($defrec eq 'y') ? ',group_id FROM ' : ',domain_id,rdns_id FROM ').3543 (($defrec eq 'y') ? ',group_id FROM ' : ',domain_id,rdns_id,stamp,stamp < now() AS ispast,expires,stampactive FROM '). 3542 3544 _rectable($defrec,$revrec)." WHERE record_id=?"; 3543 3545 my $ret = $dbh->selectrow_hashref($sql, undef, ($id) ); … … 3608 3610 $newsort =~ s/^,//; 3609 3611 3612 ##fixme: do we need a knob to twist to switch from unix epoch to postgres time string? 3610 3613 my $sql = "SELECT r.record_id,r.host,r.type,r.val,r.ttl"; 3611 $sql .= ",l.description AS locname" if $args{defrec} eq 'n'; 3614 $sql .= ",l.description AS locname,stamp,r.stamp < now() AS ispast,r.expires,r.stampactive" 3615 if $args{defrec} eq 'n'; 3612 3616 $sql .= ",r.distance,r.weight,r.port" if $args{revrec} eq 'n'; 3613 3617 $sql .= " FROM "._rectable($args{defrec},$args{revrec})." r "; … … 3627 3631 my $ret = $dbh->selectall_arrayref($sql, { Slice => {} }, (@bindvars) ); 3628 3632 $errstr = "Error retrieving records: ".$dbh->errstr if !$ret; 3633 3629 3634 return $ret; 3630 3635 } # end getRecList() … … 3685 3690 my $location = shift; 3686 3691 $location = '' if !$location; 3692 3693 my $expires = shift; 3694 $expires = 1 if $expires eq 'until'; # Turn some special values into the appropriate booleans. 3695 $expires = 0 if $expires eq 'after'; 3696 my $stamp = shift; 3697 $stamp = '' if !$stamp; # Timestamp should be a string at this point. 3687 3698 3688 3699 # Spaces are evil. … … 3745 3756 push @vallist, ($$host,$$rectype,$$val,$ttl,$id); 3746 3757 3747 # locations are not for default records, silly coder!3748 3758 if ($defrec eq 'n') { 3759 # locations are not for default records, silly coder! 3749 3760 $fields .= ",location"; 3750 3761 push @vallist, $location; 3751 } 3762 # timestamps are rare. 3763 if ($stamp) { 3764 $fields .= ",stamp,expires,stampactive"; 3765 push @vallist, $stamp, $expires, 'y'; 3766 } else { 3767 $fields .= ",stampactive"; 3768 push @vallist, 'n'; 3769 } 3770 } 3771 3772 # a little magic to get the right number of ? placeholders based on how many values we're providing 3752 3773 my $vallen = '?'.(',?'x$#vallist); 3753 3774 … … 3777 3798 $logdata{entry} .= "', TTL $ttl"; 3778 3799 $logdata{entry} .= ", location ".$self->getLoc($location)->{description} if $location; 3800 $logdata{entry} .= ($expires eq 'after' ? ', valid after ' : ', expires at ').$stamp if $stamp; 3779 3801 3780 3802 # Allow transactions, and raise an exception on errors so we can catch it later. … … 3830 3852 $location = '' if !$location; 3831 3853 3854 my $expires = shift; 3855 $expires = 1 if $expires eq 'until'; # Turn some special values into the appropriate booleans. 3856 $expires = 0 if $expires eq 'after'; 3857 my $stamp = shift; 3858 $stamp = '' if !$stamp; # Timestamp should be a string at this point. 3859 3832 3860 # just set it to an empty string; failures will be caught later. 3833 3861 $$host = '' if !$$host; … … 3901 3929 ($defrec eq 'y' ? $oldrec->{group_id} : ($revrec eq 'n' ? $oldrec->{domain_id} : $oldrec->{rdns_id})) ); 3902 3930 3903 # locations are not for default records, silly coder!3904 3931 if ($defrec eq 'n') { 3932 # locations are not for default records, silly coder! 3905 3933 $fields .= ",location"; 3906 3934 push @vallist, $location; 3935 # timestamps are rare. 3936 if ($stamp) { 3937 $fields .= ",stamp,expires,stampactive"; 3938 push @vallist, $stamp, $expires, 'y'; 3939 } else { 3940 $fields .= ",stampactive"; 3941 push @vallist, 'n'; 3942 } 3907 3943 } 3908 3944 … … 3958 3994 $logdata{entry} .= "', TTL $oldrec->{ttl}"; 3959 3995 $logdata{entry} .= ", location ".$self->getLoc($oldrec->{location})->{description} if $oldrec->{location}; 3996 $logdata{entry} .= ($oldrec->{expires} ? ', expires at ' : ', valid after ').$oldrec->{stamp} 3997 if $oldrec->{stampactive}; 3960 3998 $logdata{entry} .= "\nto\n"; 3961 3999 # More NS special … … 3969 4007 $logdata{entry} .= "', TTL $ttl"; 3970 4008 $logdata{entry} .= ", location ".$self->getLoc($location)->{description} if $location; 4009 $logdata{entry} .= ($expires eq 'after' ? ', valid after ' : ', expires at ').$stamp if $stamp; 3971 4010 3972 4011 local $dbh->{AutoCommit} = 0; … … 4975 5014 my $soasth = $dbh->prepare("SELECT host,type,val,distance,weight,port,ttl,record_id,location ". 4976 5015 "FROM records WHERE rdns_id=? AND type=6"); 4977 my $recsth = $dbh->prepare("SELECT host,type,val,distance,weight,port,ttl,record_id,location ".5016 my $recsth = $dbh->prepare("SELECT host,type,val,distance,weight,port,ttl,record_id,location,extract(epoch from stamp),expires,stampactive ". 4978 5017 "FROM records WHERE rdns_id=? AND not type=6 ". 4979 5018 "ORDER BY masklen(CAST(val AS inet)) DESC, CAST(val AS inet)"); … … 5008 5047 5009 5048 $recsth->execute($revid); 5010 while (my ($host,$type,$val,$dist,$weight,$port,$ttl,$recid,$loc ) = $recsth->fetchrow_array) {5049 while (my ($host,$type,$val,$dist,$weight,$port,$ttl,$recid,$loc,$stamp,$expires,$stampactive) = $recsth->fetchrow_array) { 5011 5050 next if $recflags{$recid}; 5012 5051 5013 $loc = '' if !$loc; # de-nullify - just in case 5014 ##fixme: handle case of record-with-location-that-doesn't-exist better. 5015 # note this currently fails safe (tested) - records with a location that 5016 # doesn't exist will not be sent to any client 5017 # $loc = '' if !$lochash->{$loc}; 5018 5019 ##fixme: record validity timestamp. tinydns supports fiddling with timestamps. 5020 # note $ttl must be set to 0 if we want to use tinydns's auto-expiring timestamps. 5021 # timestamps are TAI64 5022 # ~~ 2^62 + time() 5023 my $stamp = ''; 5024 5025 # support tinydns' auto-TTL 5026 $ttl = '' if $ttl == -1; 5052 # not sure this is necessary for revzones. 5053 # # Spaces are evil. 5054 # $val =~ s/^\s+//; 5055 # $val =~ s/\s+$//; 5056 # if ($typemap{$type} ne 'TXT') { 5057 # # Leading or trailng spaces could be legit in TXT records. 5058 # $host =~ s/^\s+//; 5059 # $host =~ s/\s+$//; 5060 # } 5027 5061 5028 5062 _printrec_tiny(*ZONECACHE, 'y', \%recflags, $revzone, 5029 $host, $type, $val, $dist, $weight, $port, $ttl, $loc, $stamp )5063 $host, $type, $val, $dist, $weight, $port, $ttl, $loc, $stamp, $expires, $stampactive) 5030 5064 if *ZONECACHE; 5031 5065 … … 5062 5096 5063 5097 my $domsth = $dbh->prepare("SELECT domain_id,domain,status,changed FROM domains WHERE status=1"); 5064 $recsth = $dbh->prepare("SELECT host,type,val,distance,weight,port,ttl,record_id,location ".5098 $recsth = $dbh->prepare("SELECT host,type,val,distance,weight,port,ttl,record_id,location,extract(epoch from stamp),expires,stampactive ". 5065 5099 "FROM records WHERE domain_id=?"); # Just exclude all types relating to rDNS 5066 5100 # "FROM records WHERE domain_id=? AND type < 65280"); # Just exclude all types relating to rDNS … … 5083 5117 5084 5118 $recsth->execute($domid); 5085 while (my ($host,$type,$val,$dist,$weight,$port,$ttl,$recid,$loc ) = $recsth->fetchrow_array) {5119 while (my ($host,$type,$val,$dist,$weight,$port,$ttl,$recid,$loc,$stamp,$expires,$stampactive) = $recsth->fetchrow_array) { 5086 5120 next if $recflags{$recid}; 5087 5088 $loc = '' if !$loc; # de-nullify - just in case5089 ##fixme: handle case of record-with-location-that-doesn't-exist better.5090 # note this currently fails safe (tested) - records with a location that5091 # doesn't exist will not be sent to any client5092 # $loc = '' if !$lochash->{$loc};5093 5094 ##fixme: record validity timestamp. tinydns supports fiddling with timestamps.5095 # note $ttl must be set to 0 if we want to use tinydns's auto-expiring timestamps.5096 # timestamps are TAI645097 # ~~ 2^62 + time()5098 my $stamp = '';5099 5100 # support tinydns' auto-TTL5101 $ttl = '' if $ttl == -1;5102 5121 5103 5122 # Spaces are evil. … … 5111 5130 5112 5131 _printrec_tiny(*ZONECACHE, 'n', \%recflags, 5113 $dom, $host, $type, $val, $dist, $weight, $port, $ttl, $loc, $stamp )5132 $dom, $host, $type, $val, $dist, $weight, $port, $ttl, $loc, $stamp, $expires, $stampactive) 5114 5133 if *ZONECACHE; 5115 5134 … … 5150 5169 # Utility sub for __export_tiny above 5151 5170 sub _printrec_tiny { 5152 my ($datafile,$revrec,$recflags,$zone,$host,$type,$val,$dist,$weight,$port,$ttl,$loc,$stamp) = @_; 5171 my ($datafile,$revrec,$recflags,$zone,$host,$type,$val,$dist,$weight,$port,$ttl,$loc,$stamp,$expires,$stampactive) = @_; 5172 5173 $loc = '' if !$loc; # de-nullify - just in case 5174 ##fixme: handle case of record-with-location-that-doesn't-exist better. 5175 # note this currently fails safe (tested) - records with a location that 5176 # doesn't exist will not be sent to any client 5177 # $loc = '' if !$lochash->{$loc}; 5178 5179 5180 ## Records that are valid only before or after a set time 5181 5182 # record due to expire sometime is the complex case. we don't want to just 5183 # rely on tinydns' auto-adjusting TTLs, because the default TTL in that case 5184 # is one day instead of the SOA minttl as BIND might do. 5185 5186 # consider the case where a record is set to expire a week ahead, but the next 5187 # day later you want to change it NOW (or as NOWish as you get with your DNS 5188 # management practice). but now you're stuck, because someone, somewhere, 5189 # has just done a lookup before your latest change was published, and they'll 5190 # be caching that old, broken record for 1 day instead of your zone default 5191 # TTL. 5192 5193 # $stamp-$ttl is the *latest* we can publish the record with the defined TTL 5194 # to still have the expiry happen as scheduled, but we need to find some 5195 # *earlier* point. We can maybe guess, and 2x TTL is probably reasonable, 5196 # but we need info on the export frequency. 5197 5198 # export the normal, non-expiring record up until $stamp-<guesstimate>, then 5199 # switch to exporting a record with the TAI64 stamp and a 0 TTL so tinydns 5200 # takes over TTL management. 5201 5202 if ($stampactive) { 5203 if ($expires) { 5204 # record expires at $stamp; decide if we need to keep the TTL and ignore 5205 # the stamp for a time or if we need to change the TTL to 0 and convert 5206 # $stamp to TAI64 so tinydns can use $stamp to autoadjust the TTL on the fly. 5207 # extra hack, optimally needs more knowledge of data export frequency 5208 # smack the idiot customer who insists on 0 TTLs; they can suck up and 5209 # deal with a 10-minute TTL. especially on scheduled changes. note this 5210 # should be (export freq * 2), but we don't know the actual export frequency. 5211 $ttl = 300 if $ttl == 0; #hack phtui 5212 my $ahead = (86400 < $ttl*2 ? 86400 : $ttl*2); 5213 if ((time() + $ahead) < $stamp) { 5214 # more than 2x TTL OR more than one day (whichever is less) from expiry time; publish normal record 5215 $stamp = ''; 5216 } else { 5217 # less than 2x TTL from expiry time, let tinydns take over TTL management and publish the TAI64 stamp. 5218 $ttl = 0; 5219 $stamp = unixtai64($stamp); 5220 $stamp =~ s/\@//; 5221 } 5222 } else { 5223 # record is "active after"; convert epoch from database to TAI64, publish, and collect $200. 5224 $stamp = unixtai64($stamp); 5225 $stamp =~ s/\@//; 5226 } 5227 } else { 5228 # flag for active timestamp is false; don't actually put a timestamp in the output 5229 $stamp = ''; 5230 } 5231 5232 # support tinydns' auto-TTL 5233 $ttl = '' if $ttl == -1; 5234 # these are WAY FREAKING HIGH - higher even than most TLD registry TTLs! 5235 # NS 259200 => 3d 5236 # all others 86400 => 1d 5153 5237 5154 5238 if ($revrec eq 'y') {
Note:
See TracChangeset
for help on using the changeset viewer.