Changeset 913
- Timestamp:
- 08/13/25 15:28:21 (13 hours ago)
- Location:
- branches/secondaryzones
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/secondaryzones
-
branches/secondaryzones/DNSDB.pm
r911 r913 2783 2783 2784 2784 2785 ## DNSDB::addRDNS 2786 # Adds a reverse DNS zone 2787 # Takes a database handle, CIDR block, reverse DNS pattern, numeric group, 2788 # and boolean(ish) state (active/inactive) 2789 # Returns a status code and message 2790 sub addRDNS { 2791 my $self = shift; 2792 my $dbh = $self->{dbh}; 2793 my $zone = shift; 2794 2795 # Autodetect formal .arpa zones 2796 if ($zone =~ /\.arpa\.?$/) { 2797 my $code; 2798 ($code,$zone) = _zone2cidr($zone); 2799 return ('FAIL', $zone) if $code eq 'FAIL'; 2800 } 2801 $zone = NetAddr::IP->new($zone); 2802 2803 return ('FAIL',"Zone name must be a valid CIDR netblock") unless ($zone && $zone->addr !~ /^0/); 2804 my $revpatt = shift; # construct a custom (A/AAAA+)? PTR template record 2805 my $group = shift; 2806 my $state = shift; 2807 my $defloc = shift || ''; 2808 2809 $state = 1 if $state =~ /^active$/; 2810 $state = 1 if $state =~ /^on$/; 2811 $state = 0 if $state =~ /^inactive$/; 2812 $state = 0 if $state =~ /^off$/; 2813 2814 return ('FAIL',"Invalid zone status") if $state !~ /^\d+$/; 2815 2816 # quick check to start to see if we've already got one 2817 my ($rdns_id) = $dbh->selectrow_array("SELECT rdns_id FROM revzones WHERE revnet = ? AND default_location = ?", 2818 undef, ("$zone", $defloc)); 2819 2820 return ('FAIL', "Zone already exists") if $rdns_id; 2821 2822 # Allow transactions, and raise an exception on errors so we can catch it later. 2823 # Use local to make sure these get "reset" properly on exiting this block 2824 local $dbh->{AutoCommit} = 0; 2825 local $dbh->{RaiseError} = 1; 2826 2827 my $warnstr = ''; 2828 my $defttl = 3600; # 1 hour should be reasonable. And unless things have gone horribly 2829 # wrong, we should have a value to override this anyway. 2830 2831 # Wrap all the SQL in a transaction 2832 eval { 2833 # insert the zone... 2834 $dbh->do("INSERT INTO revzones (revnet,group_id,status,default_location,zserial) VALUES (?,?,?,?,?)", undef, 2835 ($zone, $group, $state, $defloc, scalar(time()) ) ); 2836 2837 # get the ID... 2838 ($rdns_id) = $dbh->selectrow_array("SELECT currval('revzones_rdns_id_seq')"); 2839 2840 $self->_log(rdns_id => $rdns_id, group_id => $group, 2841 entry => "Added ".($state ? 'active' : 'inactive')." reverse zone $zone"); 2842 2843 # ... and now we construct the standard records from the default set. NB: group should be variable. 2844 my $sth = $dbh->prepare("SELECT host,type,val,ttl FROM default_rev_records WHERE group_id=?"); 2845 my $sth_in = $dbh->prepare("INSERT INTO records (rdns_id,domain_id,host,type,val,ttl,location)". 2846 " VALUES ($rdns_id,?,?,?,?,?,?)"); 2847 $sth->execute($group); 2848 while (my ($host,$type,$val,$ttl) = $sth->fetchrow_array()) { 2849 # Silently skip v4/v6 mismatches. This is not an error, this is expected. 2850 if ($zone->{isv6}) { 2851 next if ($type == 65280 || $type == 65283); 2852 } else { 2853 next if ($type == 65281 || $type == 65284); 2854 } 2855 2856 $host =~ s/ADMINDOMAIN/$self->{domain}/g; 2857 2858 # Check to make sure the IP stubs will fit in the zone. Under most usage failures here should be rare. 2859 # On failure, tack a note on to a warning string and continue without adding this record. 2860 # While we're at it, we substitute $zone for ZONE in the value. 2861 if ($val eq 'ZONE') { 2862 # If we've got a pattern, we skip the default record version on (A+)PTR-template types 2863 next if $revpatt && ($type == 65282 || $type == 65283); 2864 ##fixme? do we care if we have multiple whole-zone templates? 2865 $val = $zone->network; 2866 } elsif ($val =~ /ZONE/) { 2867 my $tmpval = $val; 2868 $tmpval =~ s/ZONE//; 2869 # Bend the rules and allow single-trailing-number PTR or PTR template records to be inserted 2870 # as either v4 or v6. May make this an off-by-default config flag 2871 # Note that the origin records that may trigger this **SHOULD** already have ZONE,\d 2872 if ($type == 12 || $type == 65282) { 2873 $tmpval =~ s/[,.]/::/ if ($tmpval =~ /^[,.]\d+$/ && $zone->{isv6}); 2874 $tmpval =~ s/[,:]+/./ if ($tmpval =~ /^(?:,|::)\d+$/ && !$zone->{isv6}); 2875 } 2876 my $addr; 2877 if ($self->_ipparent('n', 'y', \$tmpval, $rdns_id, \$addr)) { 2878 $val = $addr->addr; 2879 } else { 2880 $warnstr .= "\nDefault record '$val $typemap{$type} $host' doesn't fit in $zone, skipping"; 2881 next; 2882 } 2883 } 2884 2885 # Substitute $zone for ZONE in the hostname, but only for non-NS records. 2886 # NS records get this substitution on the value instead. 2887 $host = _ZONE($zone, $host) if $type != 2; 2888 2889 # Fill in the forward domain ID if we can find it, otherwise: 2890 # Coerce type down to PTR or PTR template if we can't 2891 my $domid = 0; 2892 if ($type >= 65280) { 2893 if (!($domid = $self->_hostparent($host))) { 2894 $warnstr .= "\nRecord added as PTR instead of $typemap{$type}; domain not found for $host"; 2895 $type = $reverse_typemap{PTR}; 2896 $domid = 0; # just to be explicit. 2897 } 2898 } 2899 2900 _caseclean(\$type, \$host, \$val, 'n', 'y') if $self->{lowercase}; 2901 2902 $sth_in->execute($domid,$host,$type,$val,$ttl,$defloc); 2903 2904 if ($typemap{$type} eq 'SOA') { 2905 my @tmp1 = split /:/, $host; 2906 my @tmp2 = split /:/, $val; 2907 $self->_log(rdns_id => $rdns_id, group_id => $group, 2908 entry => "[new $zone] Added SOA record [contact $tmp1[0]] [master $tmp1[1]] ". 2909 "[refresh $tmp2[0]] [retry $tmp2[1]] [expire $tmp2[2]] [minttl $tmp2[3]], TTL $ttl"); 2910 $defttl = $tmp2[3]; 2911 } else { 2912 my $logentry = "[new $zone] Added record '$host $typemap{$type} $val', TTL $ttl"; 2913 $logentry .= ", default location ".$self->getLoc($defloc)->{description} if $defloc; 2914 $self->_log(rdns_id => $rdns_id, domain_id => $domid, group_id => $group, entry => $logentry); 2915 } 2916 } 2917 2918 # Generate record based on provided pattern. 2919 if ($revpatt) { 2920 my $host; 2921 my $type = ($zone->{isv6} ? 65284 : 65283); 2922 my $val = $zone->network; 2923 2924 # Substitute $zone for ZONE in the hostname. 2925 $host = _ZONE($zone, $revpatt); 2926 2927 my $domid = 0; 2928 if (!($domid = $self->_hostparent($host))) { 2929 $warnstr .= "\nDefault pattern added as PTR template instead of $typemap{$type}; domain not found for $host"; 2930 $type = 65282; 2931 $domid = 0; # just to be explicit. 2932 } 2933 2934 $sth_in->execute($domid,$host,$type,$val,$defttl,$defloc); 2935 my $logentry = "[new $zone] Added record '$host $typemap{$type}"; 2936 $self->_log(rdns_id => $rdns_id, domain_id => $domid, group_id => $group, 2937 entry => $logentry." $val', TTL $defttl from pattern"); 2938 } 2939 2940 # If there are warnings (presumably about default records skipped for cause) log them 2941 $self->_log(rdns_id => $rdns_id, group_id => $group, entry => "Warning(s) adding $zone:$warnstr") 2942 if $warnstr; 2943 2944 # once we get here, we should have suceeded. 2945 $dbh->commit; 2946 }; # end eval 2947 2948 if ($@) { 2949 my $msg = $@; 2950 eval { $dbh->rollback; }; 2951 $self->_log(group_id => $group, entry => "Failed adding reverse zone $zone ($msg)") 2952 if $self->{log_failures}; 2953 $dbh->commit; # since we enabled transactions earlier 2954 return ('FAIL',$msg); 2955 } else { 2956 my $retcode = 'OK'; 2957 if ($warnstr) { 2958 $resultstr = $warnstr; 2959 $retcode = 'WARN'; 2960 } 2961 return ($retcode, $rdns_id); 2962 } 2963 2964 } # end addRDNS() 2965 2966 2785 2967 ## DNSDB::delZone() 2786 2968 # Delete a forward or reverse zone. … … 2980 3162 return $revid if $revid; 2981 3163 } # end revID() 2982 2983 2984 ## DNSDB::addRDNS2985 # Adds a reverse DNS zone2986 # Takes a database handle, CIDR block, reverse DNS pattern, numeric group,2987 # and boolean(ish) state (active/inactive)2988 # Returns a status code and message2989 sub addRDNS {2990 my $self = shift;2991 my $dbh = $self->{dbh};2992 my $zone = shift;2993 2994 # Autodetect formal .arpa zones2995 if ($zone =~ /\.arpa\.?$/) {2996 my $code;2997 ($code,$zone) = _zone2cidr($zone);2998 return ('FAIL', $zone) if $code eq 'FAIL';2999 }3000 $zone = NetAddr::IP->new($zone);3001 3002 return ('FAIL',"Zone name must be a valid CIDR netblock") unless ($zone && $zone->addr !~ /^0/);3003 my $revpatt = shift; # construct a custom (A/AAAA+)? PTR template record3004 my $group = shift;3005 my $state = shift;3006 my $defloc = shift || '';3007 3008 $state = 1 if $state =~ /^active$/;3009 $state = 1 if $state =~ /^on$/;3010 $state = 0 if $state =~ /^inactive$/;3011 $state = 0 if $state =~ /^off$/;3012 3013 return ('FAIL',"Invalid zone status") if $state !~ /^\d+$/;3014 3015 # quick check to start to see if we've already got one3016 my ($rdns_id) = $dbh->selectrow_array("SELECT rdns_id FROM revzones WHERE revnet = ? AND default_location = ?",3017 undef, ("$zone", $defloc));3018 3019 return ('FAIL', "Zone already exists") if $rdns_id;3020 3021 # Allow transactions, and raise an exception on errors so we can catch it later.3022 # Use local to make sure these get "reset" properly on exiting this block3023 local $dbh->{AutoCommit} = 0;3024 local $dbh->{RaiseError} = 1;3025 3026 my $warnstr = '';3027 my $defttl = 3600; # 1 hour should be reasonable. And unless things have gone horribly3028 # wrong, we should have a value to override this anyway.3029 3030 # Wrap all the SQL in a transaction3031 eval {3032 # insert the zone...3033 $dbh->do("INSERT INTO revzones (revnet,group_id,status,default_location,zserial) VALUES (?,?,?,?,?)", undef,3034 ($zone, $group, $state, $defloc, scalar(time()) ) );3035 3036 # get the ID...3037 ($rdns_id) = $dbh->selectrow_array("SELECT currval('revzones_rdns_id_seq')");3038 3039 $self->_log(rdns_id => $rdns_id, group_id => $group,3040 entry => "Added ".($state ? 'active' : 'inactive')." reverse zone $zone");3041 3042 # ... and now we construct the standard records from the default set. NB: group should be variable.3043 my $sth = $dbh->prepare("SELECT host,type,val,ttl FROM default_rev_records WHERE group_id=?");3044 my $sth_in = $dbh->prepare("INSERT INTO records (rdns_id,domain_id,host,type,val,ttl,location)".3045 " VALUES ($rdns_id,?,?,?,?,?,?)");3046 $sth->execute($group);3047 while (my ($host,$type,$val,$ttl) = $sth->fetchrow_array()) {3048 # Silently skip v4/v6 mismatches. This is not an error, this is expected.3049 if ($zone->{isv6}) {3050 next if ($type == 65280 || $type == 65283);3051 } else {3052 next if ($type == 65281 || $type == 65284);3053 }3054 3055 $host =~ s/ADMINDOMAIN/$self->{domain}/g;3056 3057 # Check to make sure the IP stubs will fit in the zone. Under most usage failures here should be rare.3058 # On failure, tack a note on to a warning string and continue without adding this record.3059 # While we're at it, we substitute $zone for ZONE in the value.3060 if ($val eq 'ZONE') {3061 # If we've got a pattern, we skip the default record version on (A+)PTR-template types3062 next if $revpatt && ($type == 65282 || $type == 65283);3063 ##fixme? do we care if we have multiple whole-zone templates?3064 $val = $zone->network;3065 } elsif ($val =~ /ZONE/) {3066 my $tmpval = $val;3067 $tmpval =~ s/ZONE//;3068 # Bend the rules and allow single-trailing-number PTR or PTR template records to be inserted3069 # as either v4 or v6. May make this an off-by-default config flag3070 # Note that the origin records that may trigger this **SHOULD** already have ZONE,\d3071 if ($type == 12 || $type == 65282) {3072 $tmpval =~ s/[,.]/::/ if ($tmpval =~ /^[,.]\d+$/ && $zone->{isv6});3073 $tmpval =~ s/[,:]+/./ if ($tmpval =~ /^(?:,|::)\d+$/ && !$zone->{isv6});3074 }3075 my $addr;3076 if ($self->_ipparent('n', 'y', \$tmpval, $rdns_id, \$addr)) {3077 $val = $addr->addr;3078 } else {3079 $warnstr .= "\nDefault record '$val $typemap{$type} $host' doesn't fit in $zone, skipping";3080 next;3081 }3082 }3083 3084 # Substitute $zone for ZONE in the hostname, but only for non-NS records.3085 # NS records get this substitution on the value instead.3086 $host = _ZONE($zone, $host) if $type != 2;3087 3088 # Fill in the forward domain ID if we can find it, otherwise:3089 # Coerce type down to PTR or PTR template if we can't3090 my $domid = 0;3091 if ($type >= 65280) {3092 if (!($domid = $self->_hostparent($host))) {3093 $warnstr .= "\nRecord added as PTR instead of $typemap{$type}; domain not found for $host";3094 $type = $reverse_typemap{PTR};3095 $domid = 0; # just to be explicit.3096 }3097 }3098 3099 _caseclean(\$type, \$host, \$val, 'n', 'y') if $self->{lowercase};3100 3101 $sth_in->execute($domid,$host,$type,$val,$ttl,$defloc);3102 3103 if ($typemap{$type} eq 'SOA') {3104 my @tmp1 = split /:/, $host;3105 my @tmp2 = split /:/, $val;3106 $self->_log(rdns_id => $rdns_id, group_id => $group,3107 entry => "[new $zone] Added SOA record [contact $tmp1[0]] [master $tmp1[1]] ".3108 "[refresh $tmp2[0]] [retry $tmp2[1]] [expire $tmp2[2]] [minttl $tmp2[3]], TTL $ttl");3109 $defttl = $tmp2[3];3110 } else {3111 my $logentry = "[new $zone] Added record '$host $typemap{$type} $val', TTL $ttl";3112 $logentry .= ", default location ".$self->getLoc($defloc)->{description} if $defloc;3113 $self->_log(rdns_id => $rdns_id, domain_id => $domid, group_id => $group, entry => $logentry);3114 }3115 }3116 3117 # Generate record based on provided pattern.3118 if ($revpatt) {3119 my $host;3120 my $type = ($zone->{isv6} ? 65284 : 65283);3121 my $val = $zone->network;3122 3123 # Substitute $zone for ZONE in the hostname.3124 $host = _ZONE($zone, $revpatt);3125 3126 my $domid = 0;3127 if (!($domid = $self->_hostparent($host))) {3128 $warnstr .= "\nDefault pattern added as PTR template instead of $typemap{$type}; domain not found for $host";3129 $type = 65282;3130 $domid = 0; # just to be explicit.3131 }3132 3133 $sth_in->execute($domid,$host,$type,$val,$defttl,$defloc);3134 my $logentry = "[new $zone] Added record '$host $typemap{$type}";3135 $self->_log(rdns_id => $rdns_id, domain_id => $domid, group_id => $group,3136 entry => $logentry." $val', TTL $defttl from pattern");3137 }3138 3139 # If there are warnings (presumably about default records skipped for cause) log them3140 $self->_log(rdns_id => $rdns_id, group_id => $group, entry => "Warning(s) adding $zone:$warnstr")3141 if $warnstr;3142 3143 # once we get here, we should have suceeded.3144 $dbh->commit;3145 }; # end eval3146 3147 if ($@) {3148 my $msg = $@;3149 eval { $dbh->rollback; };3150 $self->_log(group_id => $group, entry => "Failed adding reverse zone $zone ($msg)")3151 if $self->{log_failures};3152 $dbh->commit; # since we enabled transactions earlier3153 return ('FAIL',$msg);3154 } else {3155 my $retcode = 'OK';3156 if ($warnstr) {3157 $resultstr = $warnstr;3158 $retcode = 'WARN';3159 }3160 return ($retcode, $rdns_id);3161 }3162 3163 } # end addRDNS()3164 3164 3165 3165
Note:
See TracChangeset
for help on using the changeset viewer.