- Timestamp:
- 02/27/26 18:19:50 (13 hours ago)
- Location:
- branches/stable
- Files:
-
- 2 edited
- 1 copied
-
. (modified) (1 prop)
-
DNSDB.pm (modified) (6 diffs)
-
bulkdel.pl (copied) (copied from trunk/bulkdel.pl )
Legend:
- Unmodified
- Added
- Removed
-
branches/stable
- Property svn:mergeinfo changed
/trunk merged: 912,929,966,1002,1007
- Property svn:mergeinfo changed
-
branches/stable/DNSDB.pm
r1048 r1049 2717 2717 2718 2718 2719 ## DNSDB::addRDNS 2720 # Adds a reverse DNS zone 2721 # Takes a database handle, CIDR block, reverse DNS pattern, numeric group, 2722 # and boolean(ish) state (active/inactive) 2723 # Returns a status code and message 2724 sub addRDNS { 2725 my $self = shift; 2726 my $dbh = $self->{dbh}; 2727 my $zone = shift; 2728 2729 # Autodetect formal .arpa zones 2730 if ($zone =~ /\.arpa\.?$/) { 2731 my $code; 2732 ($code,$zone) = _zone2cidr($zone); 2733 return ('FAIL', $zone) if $code eq 'FAIL'; 2734 } 2735 $zone = NetAddr::IP->new($zone); 2736 2737 return ('FAIL',"Zone name must be a valid CIDR netblock") unless ($zone && $zone->addr !~ /^0/); 2738 my $revpatt = shift; # construct a custom (A/AAAA+)? PTR template record 2739 my $group = shift; 2740 my $state = shift; 2741 my $defloc = shift || ''; 2742 2743 $state = 1 if $state =~ /^active$/; 2744 $state = 1 if $state =~ /^on$/; 2745 $state = 0 if $state =~ /^inactive$/; 2746 $state = 0 if $state =~ /^off$/; 2747 2748 return ('FAIL',"Invalid zone status") if $state !~ /^\d+$/; 2749 2750 # quick check to start to see if we've already got one 2751 my ($rdns_id) = $dbh->selectrow_array("SELECT rdns_id FROM revzones WHERE revnet = ? AND default_location = ?", 2752 undef, ("$zone", $defloc)); 2753 2754 return ('FAIL', "Zone already exists") if $rdns_id; 2755 2756 # Allow transactions, and raise an exception on errors so we can catch it later. 2757 # Use local to make sure these get "reset" properly on exiting this block 2758 local $dbh->{AutoCommit} = 0; 2759 local $dbh->{RaiseError} = 1; 2760 2761 my $warnstr = ''; 2762 my $defttl = 3600; # 1 hour should be reasonable. And unless things have gone horribly 2763 # wrong, we should have a value to override this anyway. 2764 2765 # Wrap all the SQL in a transaction 2766 eval { 2767 # insert the zone... 2768 $dbh->do("INSERT INTO revzones (revnet,group_id,status,default_location,zserial) VALUES (?,?,?,?,?)", undef, 2769 ($zone, $group, $state, $defloc, scalar(time()) ) ); 2770 2771 # get the ID... 2772 ($rdns_id) = $dbh->selectrow_array("SELECT currval('revzones_rdns_id_seq')"); 2773 2774 $self->_log(rdns_id => $rdns_id, group_id => $group, 2775 entry => "Added ".($state ? 'active' : 'inactive')." reverse zone $zone"); 2776 2777 # ... and now we construct the standard records from the default set. NB: group should be variable. 2778 my $sth = $dbh->prepare("SELECT host,type,val,ttl FROM default_rev_records WHERE group_id=?"); 2779 my $sth_in = $dbh->prepare("INSERT INTO records (rdns_id,domain_id,host,type,val,ttl,location)". 2780 " VALUES ($rdns_id,?,?,?,?,?,?)"); 2781 $sth->execute($group); 2782 while (my ($host,$type,$val,$ttl) = $sth->fetchrow_array()) { 2783 # Silently skip v4/v6 mismatches. This is not an error, this is expected. 2784 if ($zone->{isv6}) { 2785 next if ($type == 65280 || $type == 65283); 2786 } else { 2787 next if ($type == 65281 || $type == 65284); 2788 } 2789 2790 $host =~ s/ADMINDOMAIN/$self->{domain}/g; 2791 2792 # Check to make sure the IP stubs will fit in the zone. Under most usage failures here should be rare. 2793 # On failure, tack a note on to a warning string and continue without adding this record. 2794 # While we're at it, we substitute $zone for ZONE in the value. 2795 if ($val eq 'ZONE') { 2796 # If we've got a pattern, we skip the default record version on (A+)PTR-template types 2797 next if $revpatt && ($type == 65282 || $type == 65283); 2798 ##fixme? do we care if we have multiple whole-zone templates? 2799 $val = $zone->network; 2800 } elsif ($val =~ /ZONE/) { 2801 my $tmpval = $val; 2802 $tmpval =~ s/ZONE//; 2803 # Bend the rules and allow single-trailing-number PTR or PTR template records to be inserted 2804 # as either v4 or v6. May make this an off-by-default config flag 2805 # Note that the origin records that may trigger this **SHOULD** already have ZONE,\d 2806 if ($type == 12 || $type == 65282) { 2807 $tmpval =~ s/[,.]/::/ if ($tmpval =~ /^[,.]\d+$/ && $zone->{isv6}); 2808 $tmpval =~ s/[,:]+/./ if ($tmpval =~ /^(?:,|::)\d+$/ && !$zone->{isv6}); 2809 } 2810 my $addr; 2811 if ($self->_ipparent('n', 'y', \$tmpval, $rdns_id, \$addr)) { 2812 $val = $addr->addr; 2813 } else { 2814 $warnstr .= "\nDefault record '$val $typemap{$type} $host' doesn't fit in $zone, skipping"; 2815 next; 2816 } 2817 } 2818 2819 # Substitute $zone for ZONE in the hostname, but only for non-NS records. 2820 # NS records get this substitution on the value instead. 2821 $host = _ZONE($zone, $host) if $type != 2; 2822 2823 # Fill in the forward domain ID if we can find it, otherwise: 2824 # Coerce type down to PTR or PTR template if we can't 2825 my $domid = 0; 2826 if ($type >= 65280) { 2827 if (!($domid = $self->_hostparent($host))) { 2828 $warnstr .= "\nRecord added as PTR instead of $typemap{$type}; domain not found for $host"; 2829 $type = $reverse_typemap{PTR}; 2830 $domid = 0; # just to be explicit. 2831 } 2832 } 2833 2834 _caseclean(\$type, \$host, \$val, 'n', 'y') if $self->{lowercase}; 2835 2836 $sth_in->execute($domid,$host,$type,$val,$ttl,$defloc); 2837 2838 if ($typemap{$type} eq 'SOA') { 2839 my @tmp1 = split /:/, $host; 2840 my @tmp2 = split /:/, $val; 2841 $self->_log(rdns_id => $rdns_id, group_id => $group, 2842 entry => "[new $zone] Added SOA record [contact $tmp1[0]] [master $tmp1[1]] ". 2843 "[refresh $tmp2[0]] [retry $tmp2[1]] [expire $tmp2[2]] [minttl $tmp2[3]], TTL $ttl"); 2844 $defttl = $tmp2[3]; 2845 } else { 2846 my $logentry = "[new $zone] Added record '$host $typemap{$type} $val', TTL $ttl"; 2847 $logentry .= ", default location ".$self->getLoc($defloc)->{description} if $defloc; 2848 $self->_log(rdns_id => $rdns_id, domain_id => $domid, group_id => $group, entry => $logentry); 2849 } 2850 } 2851 2852 # Generate record based on provided pattern. 2853 if ($revpatt) { 2854 my $host; 2855 my $type = ($zone->{isv6} ? 65284 : 65283); 2856 my $val = $zone->network; 2857 2858 # Substitute $zone for ZONE in the hostname. 2859 $host = _ZONE($zone, $revpatt); 2860 2861 my $domid = 0; 2862 if (!($domid = $self->_hostparent($host))) { 2863 $warnstr .= "\nDefault pattern added as PTR template instead of $typemap{$type}; domain not found for $host"; 2864 $type = 65282; 2865 $domid = 0; # just to be explicit. 2866 } 2867 2868 $sth_in->execute($domid,$host,$type,$val,$defttl,$defloc); 2869 my $logentry = "[new $zone] Added record '$host $typemap{$type}"; 2870 $self->_log(rdns_id => $rdns_id, domain_id => $domid, group_id => $group, 2871 entry => $logentry." $val', TTL $defttl from pattern"); 2872 } 2873 2874 # If there are warnings (presumably about default records skipped for cause) log them 2875 $self->_log(rdns_id => $rdns_id, group_id => $group, entry => "Warning(s) adding $zone:$warnstr") 2876 if $warnstr; 2877 2878 # once we get here, we should have suceeded. 2879 $dbh->commit; 2880 }; # end eval 2881 2882 if ($@) { 2883 my $msg = $@; 2884 eval { $dbh->rollback; }; 2885 $self->_log(group_id => $group, entry => "Failed adding reverse zone $zone ($msg)") 2886 if $self->{log_failures}; 2887 $dbh->commit; # since we enabled transactions earlier 2888 return ('FAIL',$msg); 2889 } else { 2890 my $retcode = 'OK'; 2891 if ($warnstr) { 2892 $resultstr = $warnstr; 2893 $retcode = 'WARN'; 2894 } 2895 return ($retcode, $rdns_id); 2896 } 2897 2898 } # end addRDNS() 2899 2900 2719 2901 ## DNSDB::delZone() 2720 2902 # Delete a forward or reverse zone. … … 2914 3096 return $revid if $revid; 2915 3097 } # end revID() 2916 2917 2918 ## DNSDB::addRDNS2919 # Adds a reverse DNS zone2920 # Takes a database handle, CIDR block, reverse DNS pattern, numeric group,2921 # and boolean(ish) state (active/inactive)2922 # Returns a status code and message2923 sub addRDNS {2924 my $self = shift;2925 my $dbh = $self->{dbh};2926 my $zone = shift;2927 2928 # Autodetect formal .arpa zones2929 if ($zone =~ /\.arpa\.?$/) {2930 my $code;2931 ($code,$zone) = _zone2cidr($zone);2932 return ('FAIL', $zone) if $code eq 'FAIL';2933 }2934 $zone = NetAddr::IP->new($zone);2935 2936 return ('FAIL',"Zone name must be a valid CIDR netblock") unless ($zone && $zone->addr !~ /^0/);2937 my $revpatt = shift; # construct a custom (A/AAAA+)? PTR template record2938 my $group = shift;2939 my $state = shift;2940 my $defloc = shift || '';2941 2942 $state = 1 if $state =~ /^active$/;2943 $state = 1 if $state =~ /^on$/;2944 $state = 0 if $state =~ /^inactive$/;2945 $state = 0 if $state =~ /^off$/;2946 2947 return ('FAIL',"Invalid zone status") if $state !~ /^\d+$/;2948 2949 # quick check to start to see if we've already got one2950 my ($rdns_id) = $dbh->selectrow_array("SELECT rdns_id FROM revzones WHERE revnet = ? AND default_location = ?",2951 undef, ("$zone", $defloc));2952 2953 return ('FAIL', "Zone already exists") if $rdns_id;2954 2955 # Allow transactions, and raise an exception on errors so we can catch it later.2956 # Use local to make sure these get "reset" properly on exiting this block2957 local $dbh->{AutoCommit} = 0;2958 local $dbh->{RaiseError} = 1;2959 2960 my $warnstr = '';2961 my $defttl = 3600; # 1 hour should be reasonable. And unless things have gone horribly2962 # wrong, we should have a value to override this anyway.2963 2964 # Wrap all the SQL in a transaction2965 eval {2966 # insert the zone...2967 $dbh->do("INSERT INTO revzones (revnet,group_id,status,default_location,zserial) VALUES (?,?,?,?,?)", undef,2968 ($zone, $group, $state, $defloc, scalar(time()) ) );2969 2970 # get the ID...2971 ($rdns_id) = $dbh->selectrow_array("SELECT currval('revzones_rdns_id_seq')");2972 2973 $self->_log(rdns_id => $rdns_id, group_id => $group,2974 entry => "Added ".($state ? 'active' : 'inactive')." reverse zone $zone");2975 2976 # ... and now we construct the standard records from the default set. NB: group should be variable.2977 my $sth = $dbh->prepare("SELECT host,type,val,ttl FROM default_rev_records WHERE group_id=?");2978 my $sth_in = $dbh->prepare("INSERT INTO records (rdns_id,domain_id,host,type,val,ttl,location)".2979 " VALUES ($rdns_id,?,?,?,?,?,?)");2980 $sth->execute($group);2981 while (my ($host,$type,$val,$ttl) = $sth->fetchrow_array()) {2982 # Silently skip v4/v6 mismatches. This is not an error, this is expected.2983 if ($zone->{isv6}) {2984 next if ($type == 65280 || $type == 65283);2985 } else {2986 next if ($type == 65281 || $type == 65284);2987 }2988 2989 $host =~ s/ADMINDOMAIN/$self->{domain}/g;2990 2991 # Check to make sure the IP stubs will fit in the zone. Under most usage failures here should be rare.2992 # On failure, tack a note on to a warning string and continue without adding this record.2993 # While we're at it, we substitute $zone for ZONE in the value.2994 if ($val eq 'ZONE') {2995 # If we've got a pattern, we skip the default record version on (A+)PTR-template types2996 next if $revpatt && ($type == 65282 || $type == 65283);2997 ##fixme? do we care if we have multiple whole-zone templates?2998 $val = $zone->network;2999 } elsif ($val =~ /ZONE/) {3000 my $tmpval = $val;3001 $tmpval =~ s/ZONE//;3002 # Bend the rules and allow single-trailing-number PTR or PTR template records to be inserted3003 # as either v4 or v6. May make this an off-by-default config flag3004 # Note that the origin records that may trigger this **SHOULD** already have ZONE,\d3005 if ($type == 12 || $type == 65282) {3006 $tmpval =~ s/[,.]/::/ if ($tmpval =~ /^[,.]\d+$/ && $zone->{isv6});3007 $tmpval =~ s/[,:]+/./ if ($tmpval =~ /^(?:,|::)\d+$/ && !$zone->{isv6});3008 }3009 my $addr;3010 if ($self->_ipparent('n', 'y', \$tmpval, $rdns_id, \$addr)) {3011 $val = $addr->addr;3012 } else {3013 $warnstr .= "\nDefault record '$val $typemap{$type} $host' doesn't fit in $zone, skipping";3014 next;3015 }3016 }3017 3018 # Substitute $zone for ZONE in the hostname, but only for non-NS records.3019 # NS records get this substitution on the value instead.3020 $host = _ZONE($zone, $host) if $type != 2;3021 3022 # Fill in the forward domain ID if we can find it, otherwise:3023 # Coerce type down to PTR or PTR template if we can't3024 my $domid = 0;3025 if ($type >= 65280) {3026 if (!($domid = $self->_hostparent($host))) {3027 $warnstr .= "\nRecord added as PTR instead of $typemap{$type}; domain not found for $host";3028 $type = $reverse_typemap{PTR};3029 $domid = 0; # just to be explicit.3030 }3031 }3032 3033 _caseclean(\$type, \$host, \$val, 'n', 'y') if $self->{lowercase};3034 3035 $sth_in->execute($domid,$host,$type,$val,$ttl,$defloc);3036 3037 if ($typemap{$type} eq 'SOA') {3038 my @tmp1 = split /:/, $host;3039 my @tmp2 = split /:/, $val;3040 $self->_log(rdns_id => $rdns_id, group_id => $group,3041 entry => "[new $zone] Added SOA record [contact $tmp1[0]] [master $tmp1[1]] ".3042 "[refresh $tmp2[0]] [retry $tmp2[1]] [expire $tmp2[2]] [minttl $tmp2[3]], TTL $ttl");3043 $defttl = $tmp2[3];3044 } else {3045 my $logentry = "[new $zone] Added record '$host $typemap{$type} $val', TTL $ttl";3046 $logentry .= ", default location ".$self->getLoc($defloc)->{description} if $defloc;3047 $self->_log(rdns_id => $rdns_id, domain_id => $domid, group_id => $group, entry => $logentry);3048 }3049 }3050 3051 # Generate record based on provided pattern.3052 if ($revpatt) {3053 my $host;3054 my $type = ($zone->{isv6} ? 65284 : 65283);3055 my $val = $zone->network;3056 3057 # Substitute $zone for ZONE in the hostname.3058 $host = _ZONE($zone, $revpatt);3059 3060 my $domid = 0;3061 if (!($domid = $self->_hostparent($host))) {3062 $warnstr .= "\nDefault pattern added as PTR template instead of $typemap{$type}; domain not found for $host";3063 $type = 65282;3064 $domid = 0; # just to be explicit.3065 }3066 3067 $sth_in->execute($domid,$host,$type,$val,$defttl,$defloc);3068 my $logentry = "[new $zone] Added record '$host $typemap{$type}";3069 $self->_log(rdns_id => $rdns_id, domain_id => $domid, group_id => $group,3070 entry => $logentry." $val', TTL $defttl from pattern");3071 }3072 3073 # If there are warnings (presumably about default records skipped for cause) log them3074 $self->_log(rdns_id => $rdns_id, group_id => $group, entry => "Warning(s) adding $zone:$warnstr")3075 if $warnstr;3076 3077 # once we get here, we should have suceeded.3078 $dbh->commit;3079 }; # end eval3080 3081 if ($@) {3082 my $msg = $@;3083 eval { $dbh->rollback; };3084 $self->_log(group_id => $group, entry => "Failed adding reverse zone $zone ($msg)")3085 if $self->{log_failures};3086 $dbh->commit; # since we enabled transactions earlier3087 return ('FAIL',$msg);3088 } else {3089 my $retcode = 'OK';3090 if ($warnstr) {3091 $resultstr = $warnstr;3092 $retcode = 'WARN';3093 }3094 return ($retcode, $rdns_id);3095 }3096 3097 } # end addRDNS()3098 3098 3099 3099 … … 4704 4704 4705 4705 return ('FAIL', "expires must be 1, 't', or 'until', or 0, 'f', or 'after'") 4706 if ($stamp && ! $expires)4706 if ($stamp && !defined($expires)) 4707 4707 || ($stamp && $expires ne '0' && $expires ne '1' && $expires ne 't' && $expires ne 'f'); 4708 4708 … … 4748 4748 4749 4749 return ($retcode,$retmsg) if $retcode eq 'FAIL'; 4750 4751 # Minor cleanup of invalid DNS labels 4752 ##fixme: seems like map should be used here to be decently Perlish, but any time I stick 4753 # a s/// inside the block map only returns the match/replace count instead of whatever 4754 # the changed $_ is for some reason 4755 my @hbits = split /\./, $$host; 4756 foreach (@hbits) { 4757 s/^-+//; 4758 s/-+$//; 4759 } 4760 $$host = join '.', @hbits; 4750 4761 4751 4762 # Set up database fields and bind parameters … … 4864 4875 4865 4876 return ('FAIL', "expires must be 1, 't', or 'until', or 0, 'f', or 'after'") 4866 if ($stamp && ! $expires)4877 if ($stamp && !defined($expires)) 4867 4878 || ($stamp && $expires ne '0' && $expires ne '1' && $expires ne 't' && $expires ne 'f'); 4868 4879 … … 4915 4926 4916 4927 return ($retcode,$retmsg) if $retcode eq 'FAIL'; 4928 4929 # Minor cleanup of invalid DNS labels 4930 ##fixme: seems like map should be used here to be decently Perlish, but any time I stick 4931 # a s/// inside the block map only returns the match/replace count instead of whatever 4932 # the changed $_ is for some reason 4933 my @hbits = split /\./, $$host; 4934 foreach (@hbits) { 4935 s/^-+//; 4936 s/-+$//; 4937 } 4938 $$host = join '.', @hbits; 4917 4939 4918 4940 # Set up database fields and bind parameters. Note only the optional fields
Note:
See TracChangeset
for help on using the changeset viewer.
![[ DNS Administrator ]](/fx/dnsadmin-logo.png)