Changeset 1032 for branches/stable/DNSDB.pm
- Timestamp:
- 02/10/26 13:30:58 (19 hours ago)
- Location:
- branches/stable
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable
- Property svn:mergeinfo changed
/trunk merged: 750-755,758-772
- Property svn:mergeinfo changed
-
branches/stable/DNSDB.pm
r756 r1032 3 3 ## 4 4 # $Id$ 5 # Copyright 2008-201 6Kris Deugau <kdeugau@deepnet.cx>5 # Copyright 2008-2017 Kris Deugau <kdeugau@deepnet.cx> 6 6 # 7 7 # This program is free software: you can redistribute it and/or modify … … 983 983 ${$args{weight}} =~ s/\s*//g; 984 984 ${$args{port}} =~ s/\s*//g; 985 return ('FAIL',"Distance, port and weight are required, and must be numeric") 986 unless ${$args{weight}} =~ /^\d+$/ && ${$args{port}} =~ /^\d+$/; 985 my @ferr; 986 push @ferr, "distance" unless ${$args{dist}} =~ /^\d+$/; 987 push @ferr, "weight" unless ${$args{weight}} =~ /^\d+$/; 988 push @ferr, "port" unless ${$args{port}} =~ /^\d+$/; 989 return ('FAIL',"Distance, port and weight are required, and must be numeric (check ".join(",", @ferr).")") 990 unless ${$args{dist}} =~ /^\d+$/ && ${$args{weight}} =~ /^\d+$/ && ${$args{port}} =~ /^\d+$/; 987 991 988 992 ${$args{fields}} = "distance,weight,port,"; … … 1369 1373 } 1370 1374 return ('OK','OK'); 1371 } 1375 } # done delegation record 1376 1377 # ALIAS record 1378 # A specialized variant of the CNAME, which retrieves the A record list on each 1379 # export and publishes the A records instead. Primarily for "root CNAME" or "apex 1380 # alias" records. See https://secure.deepnet.cx/trac/dnsadmin/ticket/55. 1381 # Not allowed in reverse zones because this is already a hack, and reverse zones 1382 # don't get pointed to CNAMEed CDNs the way domains do. 1383 sub _validate_65300 { 1384 my $self = shift; 1385 my $dbh = $self->{dbh}; 1386 1387 my %args = @_; 1388 1389 return ('FAIL',"ALIAS records are not permitted in reverse zones") if $args{revrec} eq 'y'; 1390 1391 # Make sure target is a well-formed hostname 1392 return ('FAIL', $errstr) if ! _check_hostname_form(${$args{val}}, ${$args{rectype}}, $args{defrec}, $args{revrec}); 1393 1394 # Coerce all hostnames to end in ".DOMAIN" for group/default records, 1395 # or the intended parent domain for live records. 1396 my $pname = ($args{defrec} eq 'y' ? 'DOMAIN' : $self->domainName($args{id})); 1397 ${$args{host}} =~ s/\.*$/\.$pname/ if (${$args{host}} ne '@' && ${$args{host}} !~ /$pname$/i); 1398 1399 # Only do the cache thing on live/active records 1400 return ('OK','OK') unless $args{defrec} eq 'n'; 1401 1402 # now we check/update the cached target address info 1403 my ($iplist) = $self->{dbh}->selectrow_array("SELECT auxdata FROM records WHERE record_id = ?", undef, $args{recid}); 1404 my $warnmsg; 1405 $iplist = '' if !$iplist; 1406 1407 # shared target-name-to-IP converter 1408 my $liveips = $self->_grab_65300($args{recid}, ${$args{val}}); 1409 $liveips = '' if !$liveips; 1410 1411 # check to see if there was an OOOOPS checking for updated A records on the target. also make sure we have something cached. 1412 if (!$liveips) { 1413 if (!$iplist) { 1414 # not fatal since we do the lookup on export as well 1415 $warnmsg = "No cached data and no live DNS data for ALIAS target ${$args{val}}; record may be SKIPPED on export!"; 1416 } 1417 } 1418 1419 # munge the insert/update fieldlist and data array 1420 # note we always force this; if the target has changed the cached data is almost certainly invalid anyway 1421 if ($liveips && ($iplist ne $liveips)) { 1422 ${$args{fields}} .= "auxdata,"; 1423 push @{$args{vallist}}, $liveips; 1424 } 1425 1426 return ('WARN', join("\n", $errstr, $warnmsg) ) if $warnmsg; 1427 1428 return ('OK','OK'); 1429 } # done ALIAS record 1430 1431 # this segment used multiple places to update ALIAS target details 1432 sub _grab_65300 { 1433 my $self = shift; 1434 my $dbh = $self->{dbh}; 1435 1436 my $recid = shift; 1437 my $target = shift; 1438 1439 my $res = Net::DNS::Resolver->new; 1440 $res->tcp_timeout(2); 1441 $res->udp_timeout(2); 1442 my $reply = $res->query($target); 1443 1444 my $liveips = ''; 1445 if ($reply) { 1446 # default to a one-hour TTL, which should be variously modified down the chain. Arguably this could 1447 # default even lower, since "The Cloud" often uses sub-1-minute TTLs on the final A records. 1448 my $minttl = 3600; 1449 my @newlist; 1450 foreach my $rr ($reply->answer) { #@alist) { 1451 next unless $rr->type eq "A"; 1452 push @newlist, $rr->address; 1453 $minttl = $rr->ttl if $rr->ttl < $minttl; 1454 } 1455 # safety limit. could arguably take this lower, or for extra 1456 # complexity, reference off the zone SOA minTTL 1457 $minttl = 60 if $minttl < 60; 1458 # we don't need this to be perfectly correct IP address order, just consistent. 1459 $liveips = "$minttl:".join(':', sort(@newlist)) if @newlist; 1460 #fixme: should it be a formal error case if there are no A records returned? 1461 } else { 1462 $errstr = "Lookup failure retrieving ALIAS IP list: ".$res->errorstring; 1463 } 1464 1465 return $liveips; 1466 } # _grab_65300() 1467 1372 1468 1373 1469 # Subs not specific to a particular record type … … 4416 4512 4417 4513 # do simple validation first 4514 $ttl = '' if !$ttl; 4515 $ttl =~ s/\s*//g; 4418 4516 return ('FAIL', "TTL must be numeric") unless $ttl =~ /^-?\d+$/; 4419 4517 … … 4566 4664 4567 4665 # do simple validation first 4666 $ttl = '' if !$ttl; 4667 $ttl =~ s/\s*//g; 4568 4668 return ('FAIL', "TTL must be numeric") unless $ttl =~ /^-?\d+$/; 4569 4669 … … 5924 6024 # Error check - does the cache dir exist, if we're using one? 5925 6025 if ($self->{usecache}) { 5926 die "Cache directory does not exist\n" if !-e $self->{exportcache};6026 die "Cache directory $self->{exportcache} does not exist\n" if !-e $self->{exportcache}; 5927 6027 die "$self->{exportcache} is not a directory\n" if !-d $self->{exportcache}; 5928 6028 die "$self->{exportcache} must be both readable and writable\n" … … 6138 6238 # - the cache file does not exist 6139 6239 # - 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 } 6140 6244 if (!$self->{usecache} || $self->{force_refresh} || $changed || !-e $cachefile || -z $cachefile) { 6141 6245 if ($self->{usecache}) { … … 6398 6502 print $datafile "Z$zone:$primary:$email"."::$refresh:$retry:$expire:$min_ttl:$ttl:$stamp:$loc\n" 6399 6503 or die $!; 6400 6401 } elsif ($typemap{$type} eq 'A') { 6402 6504 } # SOA 6505 6506 elsif ($typemap{$type} eq 'A') { 6403 6507 ($host,$val) = __revswap($host,$val) if $revrec eq 'y'; 6404 6508 print $datafile "+$host:$val:$ttl:$stamp:$loc\n" or die $!; 6405 6406 } elsif ($typemap{$type} eq 'NS') { 6407 6509 } # A 6510 6511 elsif ($typemap{$type} eq 'NS') { 6408 6512 if ($revrec eq 'y') { 6409 6513 $val = NetAddr::IP->new($val); … … 6431 6535 print $datafile "\&$host"."::$val:$ttl:$stamp:$loc\n" or die $!; 6432 6536 } 6433 6434 } elsif ($typemap{$type} eq 'AAAA') { 6435 6537 } # NS 6538 6539 elsif ($typemap{$type} eq 'AAAA') { 6436 6540 ($host,$val) = __revswap($host,$val) if $revrec eq 'y'; 6437 6541 my $altgrp = 0; … … 6455 6559 } 6456 6560 print $datafile "$prefix:$ttl:$stamp:$loc\n" or die $!; 6457 6458 } elsif ($typemap{$type} eq 'MX') { 6459 6561 } # AAAA 6562 6563 elsif ($typemap{$type} eq 'MX') { 6460 6564 ($host,$val) = __revswap($host,$val) if $revrec eq 'y'; 6461 6565 print $datafile "\@$host"."::$val:$dist:$ttl:$stamp:$loc\n" or die $!; 6462 6463 } elsif ($typemap{$type} eq 'TXT') { 6464 6566 } # MX 6567 6568 elsif ($typemap{$type} eq 'TXT') { 6465 6569 ($host,$val) = __revswap($host,$val) if $revrec eq 'y'; 6466 6570 # le sigh. Some idiot DNS implementations don't seem to like tinydns autosplitting … … 6506 6610 #:3600 6507 6611 6508 } elsif ($typemap{$type} eq 'CNAME') { 6509 6612 } # TXT 6613 6614 elsif ($typemap{$type} eq 'CNAME') { 6510 6615 ($host,$val) = __revswap($host,$val) if $revrec eq 'y'; 6511 6616 print $datafile "C$host:$val:$ttl:$stamp:$loc\n" or die $!; 6512 6513 } elsif ($typemap{$type} eq 'SRV') { 6514 6617 } # CNAME 6618 6619 elsif ($typemap{$type} eq 'SRV') { 6515 6620 ($host,$val) = __revswap($host,$val) if $revrec eq 'y'; 6516 6621 … … 6525 6630 } 6526 6631 print $datafile "$prefix\\000:$ttl:$stamp:$loc\n" or die $!; 6527 6528 } elsif ($typemap{$type} eq 'RP') { 6529 6632 } # SRV 6633 6634 elsif ($typemap{$type} eq 'RP') { 6530 6635 ($host,$val) = __revswap($host,$val) if $revrec eq 'y'; 6531 6636 # RP consists of two mostly free-form strings. … … 6542 6647 } 6543 6648 print $datafile "$prefix\\000:$ttl:$stamp:$loc\n" or die $!; 6544 6545 } elsif ($typemap{$type} eq 'PTR') { 6546 6649 } # RP 6650 6651 elsif ($typemap{$type} eq 'PTR') { 6547 6652 $$recflags{$val}++; 6548 6653 if ($revrec eq 'y') { … … 6573 6678 print $datafile "^$host:$val:$ttl:$stamp:$loc\n" or die $!; 6574 6679 } 6575 6576 } elsif ($type == 65280) { # A+PTR 6577 6680 } # PTR 6681 6682 elsif ($type == 65280) { # A+PTR 6578 6683 $$recflags{$val}++; 6579 6684 print $datafile "=$host:$val:$ttl:$stamp:$loc\n" or die $!; 6580 6581 } elsif ($type == 65281) { # AAAA+PTR 6582 6685 } # A+PTR 6686 6687 elsif ($type == 65281) { # AAAA+PTR 6583 6688 $$recflags{$val}++; 6584 6689 # treat these as two separate records. since tinydns doesn't have … … 6593 6698 ##fixme: add a config flag to indicate use of the patch from http://www.fefe.de/dns/ 6594 6699 # type 6 is for AAAA+PTR, type 3 is for AAAA 6595 6596 } elsif ($type == 65282) { # PTR template 6597 6700 } # AAAA+PTR 6701 6702 elsif ($type == 65282) { # PTR template 6598 6703 # only useful for v4 with standard DNS software, since this expands all 6599 6704 # IPs in $zone (or possibly $val?) with autogenerated records … … 6608 6713 $self->__publish_subnet($val, $recflags, $host, $datafile, $ttl, $stamp, $loc, $zone, 1); 6609 6714 } 6610 6611 } elsif ($type == 65283) { # A+PTR template 6612 6715 } # PTR template 6716 6717 elsif ($type == 65283) { # A+PTR template 6613 6718 $val = NetAddr::IP->new($val); 6614 6719 # Just In Case. An A+PTR should be impossible to add to a v6 revzone via API. … … 6622 6727 $self->__publish_subnet($val, $recflags, $host, $datafile, $ttl, $stamp, $loc, $zone, 0); 6623 6728 } 6624 6625 } elsif ($type == 65284) { # AAAA+PTR template 6729 } # A+PTR template 6730 6731 elsif ($type == 65284) { # AAAA+PTR template 6626 6732 # Stub for completeness. Could be exported to DNS software that supports 6627 6733 # some degree of internal automagic in generic-record-creation 6628 6734 # (eg http://search.cpan.org/dist/AllKnowingDNS/ ) 6629 6630 } elsif ($type == 65285) { # Delegation 6735 } # AAAA+PTR template 6736 6737 elsif ($type == 65285) { # Delegation 6631 6738 # This is intended for reverse zones, but may prove useful in forward zones. 6632 6739 … … 6653 6760 } 6654 6761 } 6762 } # Delegation 6763 6764 elsif ($type == 65300) { # ALIAS 6765 # Implemented as a unique record in parallel with many other 6766 # management tools, for clarity VS formal behviour around CNAME 6767 # Mainly for "root CNAME" or "apex alias"; limited value for any 6768 # other use case since CNAME can generally be used elsewhere. 6769 6770 # .arpa zones don't need this hack. shouldn't be allowed into 6771 # the DB in the first place, but Just In Case... 6772 return if $revrec eq 'y'; 6773 6774 my ($iplist) = $self->{dbh}->selectrow_array("SELECT auxdata FROM records WHERE record_id = ?", undef, $recid); 6775 $iplist = '' if !$iplist; 6776 6777 # shared target-name-to-IP converter 6778 my $liveips = $self->_grab_65300($recid, $val); 6779 # only update the cache if the live lookup actually returned data 6780 if ($liveips && ($iplist ne $liveips)) { 6781 $self->{dbh}->do("UPDATE records SET auxdata = ? WHERE record_id = ?", undef, $liveips, $recid); 6782 $iplist = $liveips; 6783 } 6784 6785 # slice the TTL we'll actually publish off the front 6786 my @asubs = split ':', $iplist; 6787 my $attl = shift @asubs; 6788 6789 # output a plain old A record for each IP the target name really points to. 6790 # in the event that, for whatever reason, no A records are available for $val, nothing will be output. 6791 foreach my $subip (@asubs) { 6792 print $datafile "+$host:$subip:$attl:$stamp:$loc\n" or die $!; 6793 } 6794 } # ALIAS 6655 6795 6656 6796 ## … … 6658 6798 ## 6659 6799 6660 } elsif ($type == 44) { # SSHFP 6661 6800 elsif ($type == 44) { # SSHFP 6662 6801 ($host,$val) = __revswap($host,$val) if $revrec eq 'y'; 6663 6802 … … 6671 6810 print $datafile "$rec:$ttl:$stamp:$loc\n" or die $!; 6672 6811 6673 } else { 6812 } # SSHFP 6813 6814 else { 6674 6815 # raw record. we don't know what's in here, so we ASS-U-ME the user has 6675 6816 # put it in correctly, since either the user is messing directly with the … … 6682 6823 #print $datafile ":$host:$type:$val:$ttl:$stamp:$loc\n"; 6683 6824 6684 } # record type if-else6825 } # "other" 6685 6826 6686 6827 } # end _printrec_tiny()
Note:
See TracChangeset
for help on using the changeset viewer.
![[ DNS Administrator ]](/fx/dnsadmin-logo.png)