Changeset 690 for branches/stable/dns-rpc.cgi
- Timestamp:
- 10/14/15 17:54:51 (9 years ago)
- Location:
- branches/stable
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/stable
-
branches/stable/dns-rpc.cgi
r548 r690 83 83 'dnsdb.getRecList' => \&getRecList, 84 84 'dnsdb.getRecCount' => \&getRecCount, 85 'dnsdb.addRec' => \& addRec,86 'dnsdb.updateRec' => \& updateRec,85 'dnsdb.addRec' => \&rpc_addRec, 86 'dnsdb.updateRec' => \&rpc_updateRec, 87 87 #sub downconvert { 88 88 'dnsdb.addOrUpdateRevRec' => \&addOrUpdateRevRec, 89 'dnsdb.updateRevSet' => \&updateRevSet, 90 'dnsdb.splitTemplate' => \&splitTemplate, 91 'dnsdb.resizeTemplate' => \&resizeTemplate, 92 'dnsdb.templatesToRecords' => \&templatesToRecords, 89 93 'dnsdb.delRec' => \&delRec, 90 94 'dnsdb.delByCIDR' => \&delByCIDR, 95 'dnsdb.delRevSet' => \&delRevSet, 91 96 #sub getLogCount {} 92 97 #sub getLogEntries {} 93 98 'dnsdb.getRevPattern' => \&getRevPattern, 99 'dnsdb.getRevSet' => \&getRevSet, 94 100 'dnsdb.getTypelist' => \&getTypelist, 95 101 'dnsdb.getTypemap' => \&getTypemap, … … 192 198 _commoncheck(\%args, 'y'); 193 199 194 my ($code, $msg) = $dnsdb->addDomain($args{domain}, $args{group}, $args{state}, $args{ location});200 my ($code, $msg) = $dnsdb->addDomain($args{domain}, $args{group}, $args{state}, $args{defloc}); 195 201 die "$msg\n" if $code eq 'FAIL'; 196 202 return $msg; # domain ID … … 202 208 _commoncheck(\%args, 'y'); 203 209 die "Need forward/reverse zone flag\n" if !$args{revrec}; 210 die "Need zone identifier\n" if !$args{zone}; 204 211 205 212 my ($code,$msg); … … 211 218 $zoneid = $dnsdb->domainID($args{zone}) if $args{revrec} eq 'n'; 212 219 $zoneid = $dnsdb->revID($args{zone}) if $args{revrec} eq 'y'; 213 die "Can't find zone: $dnsdb->errstr\n" if !$zoneid;220 die "Can't find zone: ".$dnsdb->errstr."\n" if !$zoneid; 214 221 ($code,$msg) = $dnsdb->delZone($zoneid, $args{revrec}); 215 222 } 216 223 die "$msg\n" if $code eq 'FAIL'; 217 224 return $msg; 218 } 225 } # delZone() 219 226 220 227 #sub domainName {} … … 227 234 228 235 my $domid = $dnsdb->domainID($args{domain}); 229 die "$dnsdb->errstr\n" if !$domid;236 die $dnsdb->errstr."\n" if !$domid; 230 237 return $domid; 231 238 } … … 240 247 my ($code, $msg) = $dnsdb->addRDNS($args{revzone}, $args{revpatt}, $args{group}, $args{state}, $args{defloc}); 241 248 die "$msg\n" if $code eq 'FAIL'; 242 return $msg; # domainID249 return $msg; # zone ID 243 250 } 244 251 … … 397 404 my $ret = $dnsdb->getRecLine($args{defrec}, $args{revrec}, $args{id}); 398 405 399 die "$dnsdb->errstr\n" if !$ret;406 die $dnsdb->errstr."\n" if !$ret; 400 407 401 408 return $ret; … … 430 437 431 438 # fail if we *still* don't have a valid zone ID 432 die "$dnsdb->errstr\n" if !$args{id};439 die $dnsdb->errstr."\n" if !$args{id}; 433 440 434 441 # and finally retrieve the records. … … 436 443 offset => $args{offset}, nrecs => $args{nrecs}, sortby => $args{sortby}, 437 444 sortorder => $args{sortorder}, filter => $args{filter}); 438 die "$dnsdb->errstr\n" if !$ret;445 die $dnsdb->errstr."\n" if !$ret; 439 446 440 447 return $ret; … … 455 462 $args{direction} = 'ASC' if !$args{direction}; 456 463 457 my $ret = $dnsdb->getRecCount($args{defrec}, $args{revrec}, $args{id}, $args{filter}); 458 459 die "$dnsdb->errstr\n" if !$ret; 464 my $ret = $dnsdb->getRecCount(defrec => $args{defrec}, revrec => $args{revrec}, 465 id => $args{id}, filter => $args{filter}); 466 467 die $dnsdb->errstr."\n" if !$ret; 460 468 461 469 return $ret; 462 470 } 463 471 464 sub addRec { 472 # The core sub uses references for some arguments to allow limited modification for 473 # normalization or type+zone matching/mapping/availability. 474 sub rpc_addRec { 465 475 my %args = @_; 466 476 … … 489 499 die "$msg\n" if $code eq 'FAIL'; 490 500 return $msg; 491 } 492 493 sub updateRec {501 } # rpc_addRec 502 503 sub rpc_updateRec { 494 504 my %args = @_; 495 505 … … 499 509 500 510 # put some caller-friendly names in their rightful DB column places 501 $args{val} = $args{address} ;502 $args{host} = $args{name} ;511 $args{val} = $args{address} if !$args{val}; 512 $args{host} = $args{name} if !$args{host}; 503 513 504 514 # get old line, so we can update only the bits that the caller passed to change … … 508 518 } 509 519 # stamp has special handling when blank or 0. "undefined" from the caller should mean "don't change" 510 $args{stamp} = $oldrec->{stamp} if !defined($args{stamp}) && defined($oldrec->{stamp});520 $args{stamp} = $oldrec->{stamp} if !defined($args{stamp}) && $oldrec->{stampactive}; 511 521 512 522 # allow passing text types rather than DNS integer IDs … … 522 532 die "$msg\n" if $code eq 'FAIL'; 523 533 return $msg; 524 } 534 } # rpc_updateRec 525 535 526 536 # Takes a passed CIDR block and DNS pattern; adds a new record or updates the record(s) affected … … 530 540 _commoncheck(\%args, 'y'); 531 541 my $cidr = new NetAddr::IP $args{cidr}; 542 543 ##fixme: Minor edge case; if we receive calls one after the other to update 544 # to the same thing, we bulk out the log with useless notices. Leaving this 545 # for future development since this should be rare in practice. 532 546 533 547 my $zonelist = $dnsdb->getZonesByCIDR(%args); … … 542 556 my $reclist = $dnsdb->getRecList(defrec => 'n', revrec => 'y', 543 557 id => $zonelist->[0]->{rdns_id}, filter => $filt); 558 ##fixme: Figure some new magic to automerge new incoming A(AAA)+PTR requests 559 # with existing A records to prevent duplication of A(AAA) records 544 560 if (scalar(@$reclist) == 0) { 545 561 # Aren't Magic Numbers Fun? See pseudotype list in dnsadmin. 546 my $type = ($cidr->{isv6} ? 65284: ($cidr->masklen == 32 ? 65280 : 65283) );547 addRec(defrec =>'n', revrec => 'y', parent_id => $zonelist->[0]->{rdns_id}, type => $type,562 my $type = ($cidr->{isv6} ? ($cidr->masklen == 128 ? 65281 : 65284) : ($cidr->masklen == 32 ? 65280 : 65283) ); 563 rpc_addRec(defrec => 'n', revrec => 'y', parent_id => $zonelist->[0]->{rdns_id}, type => $type, 548 564 address => "$cidr", %args); 549 565 } else { … … 554 570 || $rec->{type} == 65282 || $rec->{type} == 65283 || $rec->{type} == 65284; 555 571 next unless $rec->{val} eq $filt; # make sure we really update the record we want to update. 556 $dnsdb->updateRec(defrec =>'n', revrec => 'y', id => $rec->{record_id},557 parent_id => $zonelist->[0]->{rdns_id}, %args);572 rpc_updateRec(defrec =>'n', revrec => 'y', id => $rec->{record_id}, 573 parent_id => $zonelist->[0]->{rdns_id}, address => "$cidr", %args); 558 574 $flag = 1; 559 575 last; # only do one record. … … 563 579 # Aren't Magic Numbers Fun? See pseudotype list in dnsadmin. 564 580 my $type = ($cidr->{isv6} ? 65282 : ($cidr->masklen == 32 ? 65280 : 65283) ); 565 $dnsdb->addRec(defrec =>'n', revrec => 'y', parent_id => $zonelist->[0]->{rdns_id}, type => $type,581 rpc_addRec(defrec => 'n', revrec => 'y', parent_id => $zonelist->[0]->{rdns_id}, type => $type, 566 582 address => "$cidr", %args); 567 583 } … … 578 594 if (scalar(@$reclist) == 0) { 579 595 my $type = ($args{cidr}->{isv6} ? 65282 : ($args{cidr}->masklen == 32 ? 65280 : 65283) ); 580 $dnsdb->addRec(defrec =>'n', revrec => 'y', parent_id => $zdata->{rdns_id}, type => $type,596 rpc_addRec(defrec => 'n', revrec => 'y', parent_id => $zdata->{rdns_id}, type => $type, 581 597 address => "$args{cidr}", %args); 582 598 } else { … … 585 601 # types are nominally impossible here. 586 602 next unless $rec->{type} == 65282 || $rec->{type} == 65283 || $rec->{type} == 65284; 587 $dnsdb->updateRec(defrec =>'n', revrec => 'y', id => $rec->{record_id},603 rpc_updateRec(defrec => 'n', revrec => 'y', id => $rec->{record_id}, 588 604 parent_id => $zdata->{rdns_id}, %args); 589 605 last; # only do one record. … … 592 608 } # iterate zones within $cidr 593 609 } # done $cidr-contains-zones 594 } 610 ##fixme: what about errors? what about warnings? 611 } # done addOrUpdateRevRec() 612 613 # Update rDNS on a whole batch of IP addresses. Presented as a separate sub via RPC 614 # since RPC calls can be s...l...o...w.... 615 sub updateRevSet { 616 my %args = @_; 617 618 _commoncheck(\%args, 'y'); 619 620 my @ret; 621 # loop over passed IP/hostname pairs 622 foreach my $key (keys %args) { 623 next unless $key =~ m{^host_((?:[\d.]+|[\da-f:]+)(?:/\d+)?)$}; 624 my $ip = $1; 625 push @ret, addOrUpdateRevRec(cidr => $ip, name => $args{$key}, %args); 626 } 627 ##fixme: what about errors? what about warnings? 628 return \@ret; 629 } # done updateRevSet() 630 631 # Split a template record as per a passed CIDR. 632 # Requires the CIDR and the new mask length 633 sub splitTemplate { 634 my %args = @_; 635 636 _commoncheck(\%args, 'y'); 637 638 my $cidr = new NetAddr::IP $args{cidr}; 639 640 my $zonelist = $dnsdb->getZonesByCIDR(%args); 641 642 if (scalar(@$zonelist) == 0) { 643 # enhh.... WTF? 644 645 } elsif (scalar(@$zonelist) == 1) { 646 my $zone = new NetAddr::IP $zonelist->[0]->{revnet}; 647 if ($zone->contains($cidr)) { 648 # Find the first record in the reverse zone that matches the CIDR we're splitting... 649 my $reclist = $dnsdb->getRecList(defrec => 'n', revrec => 'y', 650 id => $zonelist->[0]->{rdns_id}, filter => $cidr, sortby => 'val', sortorder => 'DESC'); 651 my $oldrec; 652 foreach my $rec (@$reclist) { 653 my $reccidr = new NetAddr::IP $rec->{val}; 654 next unless $cidr->contains($reccidr); # not sure this is needed here 655 # ... and is a reverse-template type. 656 # Could arguably trim the list below to just 65282, 65283, 65284 657 next unless $rec->{type} == 12 || $rec->{type} == 65280 || $rec->{type} == 65281 || 658 $rec->{type} == 65282 || $rec->{type} == 65283 ||$rec->{type} == 65284; 659 # snag old record so we can copy its data 660 $oldrec = $dnsdb->getRecLine('n', 'y', $rec->{record_id}); 661 last; # we've found one record that meets our criteria; Extras Are Irrelevant 662 } 663 664 my @newblocks = $cidr->split($args{newmask}); 665 # Change the existing record with the new CIDR 666 my $up_res = rpc_updateRec(%args, val => $newblocks[0], id => $oldrec->{record_id}, defrec => 'n', revrec => 'y'); 667 my @ret; 668 # the update is assumed to have succeeded if it didn't fail. 669 ##fixme: find a way to save and return "warning" states? 670 push @ret, {block => "$newblocks[0]", code => "OK", msg => $up_res}; 671 # And now add new record(s) for each of the new CIDR entries, reusing the old data 672 for (my $i = 1; $i <= $#newblocks; $i++) { 673 my $newval = "$newblocks[$i]"; 674 my @recargs = ('n', 'y', $oldrec->{rdns_id}, \$oldrec->{host}, \$oldrec->{type}, \$newval, 675 $oldrec->{ttl}, $oldrec->{location}, 0, ''); 676 my ($code, $msg) = $dnsdb->addRec(@recargs); 677 # Note failures here are not fatal; this should typically only ever be called by IPDB 678 push @ret, {block => "$newblocks[$i]", code => $code, msg => $up_res}; 679 } 680 # return an info hash in case of warnings doing the update or add(s) 681 return \@ret; 682 683 } else { # $cidr > $zone but we only have one zone 684 # ebbeh? CIDR is only partly represented in DNS. This needs manual intervention. 685 return "Warning: $args{cidr} is only partly represented in DNS. Check and update DNS records manually."; 686 } # done single-zone-contains-$cidr 687 688 } else { 689 # multiple zones nominally "contain" $cidr 690 } # done $cidr-contains-zones 691 692 } # done splitTemplate() 693 694 # Resize a template according to an old/new CIDR pair 695 # Takes the old cidr in $args{oldcidr} and the new in $args{newcidr} 696 sub resizeTemplate { 697 my %args = @_; 698 699 _commoncheck(\%args, 'y'); 700 701 my $oldcidr = new NetAddr::IP $args{oldcidr}; 702 my $newcidr = new NetAddr::IP $args{newcidr}; 703 die "$oldcidr and $newcidr do not overlap" 704 unless $oldcidr->contains($newcidr) || $newcidr->contains($oldcidr); 705 $args{cidr} = $args{oldcidr}; 706 707 my $up_res; 708 709 my $zonelist = $dnsdb->getZonesByCIDR(%args); 710 if (scalar(@$zonelist) == 0) { 711 # enhh.... WTF? 712 713 } elsif (scalar(@$zonelist) == 1) { 714 my $zone = new NetAddr::IP $zonelist->[0]->{revnet}; 715 if ($zone->contains($oldcidr)) { 716 # Find record(s) matching the old and new CIDR 717 718 my $sql = q( 719 SELECT record_id,host,val 720 FROM records 721 WHERE rdns_id = ? 722 AND type IN (12, 65280, 65281, 65282, 65283, 65284) 723 AND (val = ? OR val = ?) 724 ORDER BY masklen(inetlazy(val)) ASC 725 ); 726 my $sth = $dnsdb->{dbh}->prepare($sql); 727 $sth->execute($zonelist->[0]->{rdns_id}, "$oldcidr", "$newcidr"); 728 my $upd_id; 729 my $oldhost; 730 while (my ($recid, $host, $val) = $sth->fetchrow_array) { 731 my $tcidr = NetAddr::IP->new($val); 732 if ($tcidr == $newcidr) { 733 # Match found for new CIDR. Delete this record. 734 $up_res = $dnsdb->delRec('n', 'y', $recid); 735 } else { 736 # Update this record, then exit the loop 737 $up_res = rpc_updateRec(%args, val => $newcidr, id => $recid, defrec => 'n', revrec => 'y'); 738 last; 739 } 740 # Your llama is on fire 741 } 742 $sth->finish; 743 744 return "Template record for $oldcidr changed to $newcidr."; 745 746 } else { # $cidr > $zone but we only have one zone 747 # ebbeh? CIDR is only partly represented in DNS. This needs manual intervention. 748 return "Warning: $args{cidr} is only partly represented in DNS. Check and update DNS records manually."; 749 } # done single-zone-contains-$cidr 750 751 } else { 752 # multiple zones nominally "contain" $cidr 753 } 754 755 return $up_res; 756 } # done resizeTemplate() 757 758 # Convert one or more template records to a set of individual IP records. Expands the template. 759 # Handle the case of nested templates, although the primary caller (IPDB) should not be 760 # able to generate records that would trigger that case. 761 # Accounts for existing PTR or A+PTR records same as on-export template expansion. 762 # Takes a list of templates and a bounding CIDR? 763 sub templatesToRecords { 764 my %args = @_; 765 766 _commoncheck(\%args, 'y'); 767 768 my %iplist; 769 my @retlist; 770 771 my $zsth = $dnsdb->{dbh}->prepare("SELECT rdns_id,group_id FROM revzones WHERE revnet >>= ?"); 772 # Going to assume template records with no expiry 773 # Also note IPv6 template records don't expand sanely the way v4 records do 774 my $recsth = $dnsdb->{dbh}->prepare(q( 775 SELECT record_id, domain_id, host, type, val, ttl, location 776 FROM records 777 WHERE rdns_id = ? 778 AND type IN (12, 65280, 65282, 65283) 779 AND inetlazy(val) <<= ? 780 ORDER BY masklen(inetlazy(val)) DESC 781 )); 782 my $insth = $dnsdb->{dbh}->prepare("INSERT INTO records (domain_id, rdns_id, host, type, val, ttl, location)". 783 " VALUES (?,?,?,?,?,?,?)"); 784 my $delsth = $dnsdb->{dbh}->prepare("DELETE FROM records WHERE record_id = ?"); 785 my %typedown = (12 => 12, 65280 => 65280, 65281 => 65281, 65282 => 12, 65283 => 65280, 65284 => 65281); 786 787 my @checkrange; 788 789 local $dnsdb->{dbh}->{AutoCommit} = 0; 790 local $dnsdb->{dbh}->{RaiseError} = 1; 791 792 eval { 793 foreach my $template (@{$args{templates}}) { 794 $zsth->execute($template); 795 my ($zid,$zgrp) = $zsth->fetchrow_array; 796 if (!$zid) { 797 push @retlist, {$template, "Zone not found"}; 798 next; 799 } 800 $recsth->execute($zid, $template); 801 while (my ($recid, $domid, $host, $type, $val, $ttl, $loc) = $recsth->fetchrow_array) { 802 # Skip single IPs with PTR or A+PTR records 803 if ($type == 12 || $type == 65280) { 804 $iplist{"$val/32"}++; 805 next; 806 } 807 my @newips = NetAddr::IP->new($template)->split(32); 808 $type = $typedown{$type}; 809 foreach my $ip (@newips) { 810 next if $iplist{$ip}; 811 my $newhost = $host; 812 $dnsdb->_template4_expand(\$newhost, $ip->addr); 813 $insth->execute($domid, $zid, $newhost, $type, $ip->addr, $ttl, $loc); 814 $iplist{$ip}++; 815 } 816 $delsth->execute($recid); 817 $dnsdb->_log(group_id => $zgrp, domain_id => $domid, rdns_id => $zid, 818 entry => "$template converted to individual $typemap{$type} records"); 819 push @retlist, "$template converted to individual records"; 820 } # record fetch 821 } # foreach passed template CIDR 822 823 $dnsdb->{dbh}->commit; 824 }; 825 if ($@) { 826 die "Error converting a template record to individual records: $@"; 827 } 828 829 return \@retlist; 830 831 } # done templatesToRecords() 595 832 596 833 sub delRec { … … 601 838 _reccheck(\%args); 602 839 603 my ($code, $msg) = $dnsdb->delRec($args{defrec}, $args{re crev}, $args{id});840 my ($code, $msg) = $dnsdb->delRec($args{defrec}, $args{revrec}, $args{id}); 604 841 605 842 die "$msg\n" if $code eq 'FAIL'; … … 611 848 612 849 _commoncheck(\%args, 'y'); 850 851 # Caller may pass 'n' in delsubs. Assume it should be false/undefined 852 # unless the caller explicitly requested 'yes' 853 $args{delsubs} = 0 if $args{delsubs} ne 'y'; 854 855 # Don't delete the A component of an A+PTR by default 856 $args{delforward} = 0 if !$args{delforward}; 613 857 614 858 # much like addOrUpdateRevRec() … … 623 867 my $zone = new NetAddr::IP $zonelist->[0]->{revnet}; 624 868 if ($zone->contains($cidr)) { 625 626 869 if ($args{delsubs}) { 627 870 # Delete ALL EVARYTHING!!one11!! in $args{cidr} … … 638 881 my ($code,$msg) = $dnsdb->delRec('n', 'y', $rec->{record_id}); 639 882 } else { 883 ##fixme: AAAA+PTR? 640 884 my $ret = $dnsdb->downconvert($rec->{record_id}, $DNSDB::reverse_typemap{A}); 641 885 } … … 644 888 # Edge case; we've just gone and axed all the records in the reverse zone. 645 889 # Re-add one to match the parent if we've been given a pattern to use. 646 $dnsdb->addRec(defrec =>'n', revrec => 'y', parent_id => $zonelist->[0]->{rdns_id},647 type => ($zone->{isv6} ? 65284 : 65283), address => "$cidr", %args);890 rpc_addRec(defrec => 'n', revrec => 'y', parent_id => $zonelist->[0]->{rdns_id}, 891 type => ($zone->{isv6} ? 65284 : 65283), address => "$cidr", name => $args{parpatt}, %args); 648 892 } 649 893 650 894 } else { 651 895 # Selectively delete only exact matches on $args{cidr} 652 653 896 # We need to strip the CIDR mask on IPv4 /32 assignments, or we can't find single-IP records 654 897 my $filt = ($cidr->{isv6} || $cidr->masklen != 32 ? "$cidr" : $cidr->addr); … … 666 909 } else { 667 910 my $ret = $dnsdb->downconvert($rec->{record_id}, $DNSDB::reverse_typemap{A}); 668 die "$dnsdb->errstr\n" if !$ret;911 die $dnsdb->errstr."\n" if !$ret; 669 912 return "A+PTR for $args{cidr} split and PTR removed"; 670 913 } … … 686 929 # yes, yes we do, past the close of the else 687 930 # my $type = ($args{cidr}->{isv6} ? 65282 : ($args{cidr}->masklen == 32 ? 65280 : 65283) ); 688 # addRec(defrec =>'n', revrec => 'y', parent_id => $zdata->{rdns_id}, type => $type,931 # rpc_addRec(defrec => 'n', revrec => 'y', parent_id => $zdata->{rdns_id}, type => $type, 689 932 # address => "$args{cidr}", %args); 690 933 } else { … … 706 949 # We've just gone and axed all the records in the reverse zone. 707 950 # Re-add one to match the parent if we've been given a pattern to use. 708 $dnsdb->addRec(defrec =>'n', revrec => 'y', parent_id => $zdata->{rdns_id},951 rpc_addRec(defrec => 'n', revrec => 'y', parent_id => $zdata->{rdns_id}, 709 952 type => ($cidr->{isv6} ? 65284 : 65283), 710 953 address => $zdata->{revnet}, name => $args{parpatt}, %args); … … 715 958 } # end delByCIDR() 716 959 960 # Batch-delete a set of reverse entries similar to updateRevSet 961 sub delRevSet { 962 my %args = @_; 963 964 _commoncheck(\%args, 'y'); 965 966 my @ret; 967 # loop over passed CIDRs in args{cidrlist} 968 foreach my $cidr (split(',', $args{cidrlist})) { 969 push @ret, delByCIDR(cidr => $cidr, %args) 970 } 971 972 return \@ret; 973 } # end delRevSet() 974 717 975 #sub getLogCount {} 718 976 #sub getLogEntries {} … … 726 984 } 727 985 986 sub getRevSet { 987 my %args = @_; 988 989 _commoncheck(\%args, 'y'); 990 991 return $dnsdb->getRevSet($args{cidr}, $args{group}); 992 } 993 728 994 sub getTypelist { 729 995 my %args = @_; … … 755 1021 _commoncheck(\%args, 'y'); 756 1022 757 my @arglist = ($args{zoneid}); 1023 $args{reverse} = 'n' if !$args{reverse} || $args{reverse} ne 'y'; 1024 my @arglist = ($args{zoneid}, $args{reverse}); 758 1025 push @arglist, $args{status} if defined($args{status}); 759 1026
Note:
See TracChangeset
for help on using the changeset viewer.