Changeset 1034
- Timestamp:
- 02/11/26 14:51:02 (12 hours ago)
- Location:
- branches/stable
- Files:
-
- 5 edited
- 1 copied
-
. (modified) (1 prop)
-
DNSDB.pm (modified) (9 diffs)
-
bumpserial (copied) (copied from trunk/bumpserial )
-
dns-rpc.cgi (modified) (1 diff)
-
templates/log.tmpl (modified) (2 diffs)
-
templates/reclist.tmpl (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
branches/stable
- Property svn:mergeinfo changed
/trunk merged: 796,823,829-830,832,842,888
- Property svn:mergeinfo changed
-
branches/stable/DNSDB.pm
r1033 r1034 689 689 return ('FAIL', $errstr) if ! _check_hostname_form(${$args{host}}, ${$args{rectype}}, $args{defrec}, $args{revrec}); 690 690 } else { 691 # CNAME target check - IP addresses not allowed. Must be a more or less well-formed hostname. 692 return ('FAIL', "CNAME records cannot point directly to an IP address") 693 if ${$args{val}} =~ /^(?:[\d.]+|[0-9a-fA-F:]+)$/; 694 695 # Make sure target is a well-formed hostname 696 return ('FAIL', $errstr) if ! _check_hostname_form(${$args{val}}, ${$args{rectype}}, $args{defrec}, $args{revrec}); 697 698 # Forcibly append the domain name if the hostname being added does not end with the current domain name 699 my $pname = ($args{defrec} eq 'y' ? 'DOMAIN' : $self->domainName($args{id})); 700 ${$args{host}} =~ s/\.*$/\.$pname/ if ${$args{host}} !~ /$pname$/i; 701 702 # CNAMEs can not be used for parent nodes; just leaf nodes with no other record types 703 # Enforce this for the zone name 704 return ('FAIL', "The bare zone name may not be a CNAME") if ${$args{host}} eq $pname || ${$args{host}} =~ /^\@/; 691 # a bit expensive to put this here, but we need some kind of cheap flag for an RPZ zone with different rules 692 my $zname = $self->domainName($args{id}); 693 if ($zname =~ /\.rpz$/) { 694 # RPZ domains consist almost entirely of CNAME records, and have special rules for their syntax 695 # From the Unbound doc: https://unbound.docs.nlnetlabs.nl/en/latest/topics/filtering/rpz.html 696 # Supposedly other overrides are also valid 697 return ('FAIL', "Unsupported RPZ override ${$args{val}}") 698 unless ${$args{val}} =~ /^(?:\.|\*\.|rpz-passthru\.|rpz-drop\.|rpz-tcp-only\.)$/; 699 # Append the RPZ name 700 my $pname = ($args{defrec} eq 'y' ? 'DOMAIN' : $self->domainName($args{id})); 701 ${$args{host}} =~ s/\.*$/\.$pname/ if ${$args{host}} !~ /$pname$/i; 702 } else { 703 # CNAME target check - IP addresses not allowed. Must be a more or less well-formed hostname. 704 return ('FAIL', "CNAME records cannot point directly to an IP address") 705 if ${$args{val}} =~ /^(?:[\d.]+|[0-9a-fA-F:]+)$/; 706 707 # Make sure target is a well-formed hostname 708 return ('FAIL', $errstr) if ! _check_hostname_form(${$args{val}}, ${$args{rectype}}, $args{defrec}, $args{revrec}); 709 710 # Forcibly append the domain name if the hostname being added does not end with the current domain name 711 my $pname = ($args{defrec} eq 'y' ? 'DOMAIN' : $zname); 712 ${$args{host}} =~ s/\.*$/\.$pname/ if ${$args{host}} !~ /$pname$/i; 713 714 # CNAMEs can not be used for parent nodes; just leaf nodes with no other record types 715 # Enforce this for the zone name 716 return ('FAIL', "The bare zone name may not be a CNAME") if ${$args{host}} eq $pname || ${$args{host}} =~ /^\@/; 705 717 706 718 ##enhance: Look up the passed value to see if it exists. Ooo, fancy. 707 return ('FAIL', $errstr) if ! _check_hostname_form(${$args{val}}, ${$args{rectype}}, $args{defrec}, $args{revrec}); 708 } 719 return ('FAIL', $errstr) if ! _check_hostname_form(${$args{val}}, ${$args{rectype}}, $args{defrec}, $args{revrec}); 720 } # $zname !~ .rpz 721 } # revzone eq 'n' 709 722 710 723 return ('OK','OK'); … … 1033 1046 # Not strictly true, but SRV records not following this convention won't be found. 1034 1047 return ('FAIL',"SRV records must begin with _service._protocol [${$args{host}}]") 1035 unless ${$args{host}} =~ /^_[A-Za-z -]+\._[A-Za-z]+\.[a-zA-Z0-9-]+/;1048 unless ${$args{host}} =~ /^_[A-Za-z\d-]+\._[A-Za-z]+\.[a-zA-Z0-9-]+/; 1036 1049 1037 1050 # SRV target check - IP addresses not allowed. Must be a more or less well-formed hostname. … … 1048 1061 # Not strictly true, but SRV records not following this convention won't be found. 1049 1062 return ('FAIL',"SRV records must begin with _service._protocol [${$args{host}}]") 1050 unless ${$args{val}} =~ /^_[A-Za-z ]+\._[A-Za-z]+\.[a-zA-Z0-9-]+/;1063 unless ${$args{val}} =~ /^_[A-Za-z\d-]+\._[A-Za-z]+\.[a-zA-Z0-9-]+/; 1051 1064 1052 1065 # SRV target check - IP addresses not allowed. Must be a more or less well-formed hostname. … … 1075 1088 return ('OK','OK'); 1076 1089 } # done SRV record 1090 1091 # CAA record 1092 sub _validate_257 { 1093 my $self = shift; 1094 my $dbh = $self->{dbh}; 1095 1096 my %args = @_; 1097 1098 my $code = 'OK'; 1099 my $msg = ''; # Default to no message, because there are a lot of handwavy warning cases. 1100 1101 if ($args{revrec} eq 'n') { 1102 # Coerce all hostnames to end in ".DOMAIN" for group/default records, 1103 # or the intended parent domain for live records. 1104 my $pname = ($args{defrec} eq 'y' ? 'DOMAIN' : $self->domainName($args{id})); 1105 ${$args{host}} =~ s/\.*$/\.$pname/ if ${$args{host}} !~ /$pname$/i; 1106 1107 my ($caaflag, $caatag, $caadetail) = (${$args{val}} =~ /(\d+)\s+(\w+)\s+(.+)/); 1108 1109 return ('FAIL', "Poorly formed CAA record missing one or more of flag, tag, or detail") 1110 if (!defined($caaflag) || !defined($caatag) || !defined($caadetail)); 1111 1112 # flag is a bitfield, only bit 0 currently has meaning as "Issuer Critical" 1113 # Not 100% clear if this flag is permitted on known tags, or if it's 1114 # semantically null since the known tags are already defined. We'll allow it. 1115 return ('FAIL', "CAA flags other than 0 or 128 not currently supported in DNS") if $caaflag ne '0' && $caaflag ne '128'; 1116 1117 # known tags: 1118 # issue 1119 # issuewild 1120 # iodef (RFC5070) 1121 # auth (reserved, do not use) 1122 # path (reserved, do not use) 1123 # policy (reserved, do not use) 1124 return ('FAIL', "CAA tags may only use a-z, A-Z, and 0-9") if $caatag !~ /^[a-zA-Z0-9]+$/; 1125 return ('FAIL', "Can't use reserved CAA tag '$caatag'") if $caatag =~ /^(?:auth|path|policy)$/; 1126 if ($caatag !~ /^(?:issue|issuewild|iodef)$/) { 1127 $code = 'WARN'; 1128 $msg = ($msg ? $msg." " : '')."Unknown CAA tag '$caatag' will be published as-is."; 1129 } 1130 if (length($caatag) > 15) { 1131 $code = 'WARN'; 1132 $msg = ($msg ? $msg." " : '').'Custom CAA tag > 15 characters may not behave as intended.'; 1133 } 1134 1135 if ($caatag eq 'issue' || $caatag eq 'issuewild') { 1136 # Detail format is possibly as complex as: 1137 # [;|cert-authority [; key=value[ key=value ...]] 1138 # but arguably a strict reading says there can only be one key, and the 1139 # rest of the string after first = is the value, even if it appears to 1140 # contain extra key=value pairs. 1141 # See https://datatracker.ietf.org/doc/html/rfc6844 for full ABNF definition. 1142 # Either way all we need to validate is that it's within the specified characters. 1143 if ($caadetail eq ';') { 1144 # No certs permitted 1145 } else { 1146 my ($certauth,$remainder) = ($caadetail =~ /^\s*([a-zA-Z0-9.-]+)\s*((?:;|\s|$).*)?$/); 1147 if (!$certauth) { 1148 # We can't reasonably validate individual domains, just that it's well-formed 1149 return ('FAIL', "CAA authority domain must be a valid domain name"); 1150 } 1151 if ($remainder) { 1152 return ('FAIL', "CAA authority domain and optional key=value entry or entries must be separated by a ';'") 1153 if $remainder !~ /^\s*;/; 1154 $remainder =~ s/\s*;\s*//; 1155 # Just validate the characters in the remainder. Any details are CA-specific and not sanely validateable. 1156 return ('FAIL', "Invalid characters in optional key=value entry or entries") 1157 if $remainder !~ /^[a-zA-Z0-9]+\s*=[\x21-\x7e\s]+$/; 1158 } 1159 } 1160 } # issue/isseuewild 1161 1162 elsif ($caatag eq 'iodef') { 1163 # Two valid forms: 1164 # mailto:address@example.com 1165 # http://iodef.example.com/ 1166 # RFC seems a little handwavy whether https:// is valid or not, but the chained 1167 # RFC for the HTTP-based reporting protocol says that this should be assumed to 1168 # be a dedicated port (4590) and service, requiring TLS. Allowing https:// per 1169 # the detail description in https://datatracker.ietf.org/doc/html/rfc6844#section-5.4. 1170 return ('FAIL', "iodef tag data must reference a mailto: or http: URI") if $caadetail !~ /^(mailto|https?):/; 1171 if ($1 eq 'mailto') { 1172 # not going full RFC on validating form, just "reasonably sane" 1173 return ('FAIL', "Poorly formed email for iodef tag") if $caadetail !~ /^mailto:[^\s]+\@[a-zA-z0-9._-]+$/ 1174 } else { 1175 return ('FAIL', "Poorly formed URI for iodef tag") if $caadetail !~ m,^https?://[a-zA-z0-9._-]+/?$, 1176 } 1177 } # iodef 1178 1179 } else { 1180 # CAA records don't make much sense in reverse zones 1181 return ('FAIL', "CAA records not supported in reverse zones"); 1182 } 1183 1184 # Allow CAA records in default record sets for now, but it's a bit iffy 1185 # whether this makes any sense. Not nice to publish a default "issue ;" 1186 # record, then go through a support mess trying to figure out why a 1187 # customer can't register a cert somewhere. 1188 # if ($args{defrec} eq 'n') { 1189 # } else { 1190 # } 1191 1192 return ($code, $msg); 1193 } # done CAA record 1194 1077 1195 1078 1196 # Now the custom types … … 4393 4511 # Filtering on host/val (mainly normal record list) 4394 4512 if ($args{filter}) { 4395 $sql .= " AND (r.host ~* ? OR r.val ~* ? OR r.host ~* ? OR r.val ~* ?)"; 4396 my $tmp = join('.',reverse(split(/\./,$args{filter}))); 4397 push @bindvars, ($args{filter},$args{filter}); 4398 push @bindvars, ($tmp, $tmp); 4513 # not much use to end users, but internal callers may want more fine-grained restriction on CIDR ranges 4514 # we'll only support the value-comparison operators; bitwise/add/subtract don't make much sense in this context 4515 my $ipfilt = 0; 4516 if ($args{filter} =~ /^\s*(<|<=|=|>=|>|<>|<<|<<=|>>|>>=)\s*([\da-fA-F].+)\s*$/) { 4517 my $filt_op = $1; 4518 my $filt_val = $2; 4519 # do we have an IP-ish value? 4520 if ($filt_val =~ m,^(?:[\d.]+|[0-9a-f]+)(?:/\d+)?$,) { 4521 # now make sure 4522 my $tmp = new NetAddr::IP $filt_val; 4523 if ($tmp) { 4524 $sql .= " AND inetlazy(r.val) $filt_op ?"; 4525 push @bindvars, $filt_val; 4526 $ipfilt = 1; 4527 } # really looks like a valid IP/CIDR 4528 } # looks IPish 4529 } # has CIDR operator 4530 if (!$ipfilt) { 4531 # simple text matching, with a bit of mix-n-match to account for .arpa names 4532 $sql .= " AND (r.host ~* ? OR r.val ~* ? OR r.host ~* ? OR r.val ~* ?)"; 4533 my $tmp = join('.',reverse(split(/\./,$args{filter}))); 4534 push @bindvars, ($args{filter},$args{filter}); 4535 push @bindvars, ($tmp, $tmp); 4536 } 4399 4537 } 4400 4538 … … 4470 4608 # Filtering on host/val (mainly normal record list) 4471 4609 if ($args{filter}) { 4472 $sql .= " AND (r.host ~* ? OR r.val ~* ? OR r.host ~* ? OR r.val ~* ?)"; 4473 my $tmp = join('.',reverse(split(/\./,$args{filter}))); 4474 push @bindvars, ($args{filter},$args{filter}); 4475 push @bindvars, ($tmp, $tmp); 4610 # not much use to end users, but internal callers may want more fine-grained restriction on CIDR ranges 4611 # we'll only support the value-comparison operators; bitwise/add/subtract don't make much sense in this context 4612 my $ipfilt = 0; 4613 if ($args{filter} =~ /^\s*(<|<=|=|>=|>|<>|<<|<<=|>>|>>=)\s*([\da-fA-F].+)\s*$/) { 4614 my $filt_op = $1; 4615 my $filt_val = $2; 4616 # do we have an IP-ish value? 4617 if ($filt_val =~ m,^(?:[\d.]+|[0-9a-f]+)(?:/\d+)?$,) { 4618 # now make sure 4619 my $tmp = new NetAddr::IP $filt_val; 4620 if ($tmp) { 4621 $sql .= " AND inetlazy(r.val) $filt_op ?"; 4622 push @bindvars, $filt_val; 4623 $ipfilt = 1; 4624 } # really looks like a valid IP/CIDR 4625 } # looks IPish 4626 } # has CIDR operator 4627 if (!$ipfilt) { 4628 # simple text matching, with a bit of mix-n-match to account for .arpa names 4629 $sql .= " AND (r.host ~* ? OR r.val ~* ? OR r.host ~* ? OR r.val ~* ?)"; 4630 my $tmp = join('.',reverse(split(/\./,$args{filter}))); 4631 push @bindvars, ($args{filter},$args{filter}); 4632 push @bindvars, ($tmp, $tmp); 4633 } 4476 4634 } 4477 4635 … … 5829 5987 $warnmsg .= "Suspect record '".$rr->string."' may not be imported correctly: SRV records may not be bare IP addresses\n" 5830 5988 if $val =~ /^(?:(?:\d+\.){3}\d+|[a-fA-F0-9:]+)$/; 5831 } elsif ($type eq 'KEY') { 5989 } 5990 5991 elsif ($type eq 'CAA') { 5992 # Store CAA records without the syntactic quotes 5993 $val = join(" ", $rr->flags, $rr->tag, $rr->value); 5994 } 5995 5996 elsif ($type eq 'KEY') { 5832 5997 # we don't actually know what to do with these... 5833 5998 $val = $rr->flags.":".$rr->protocol.":".$rr->algorithm.":".$rr->key.":".$rr->keytag.":".$rr->privatekeyname; … … 6691 6856 elsif ($typemap{$type} eq 'CNAME') { 6692 6857 ($host,$val) = __revswap($host,$val) if $revrec eq 'y'; 6858 if ($zone =~ /\.rpz$/) { 6859 $val = '..' if $val eq '.'; 6860 } 6693 6861 print $datafile "C$host:$val:$ttl:$stamp:$loc\n" or die $!; 6694 6862 } # CNAME … … 6708 6876 print $datafile "$prefix\\000:$ttl:$stamp:$loc\n" or die $!; 6709 6877 } # SRV 6878 6879 elsif ($typemap{$type} eq 'CAA') { 6880 # CAA records really don't make much sense in reverse zones 6881 #($host,$val) = __revswap($host,$val) if $revrec eq 'y'; 6882 return if $revrec eq 'y'; 6883 6884 # data is a bitfield byte, length byte+string, then "everything else" 6885 6886 my $prefix = ":$host:257:"; 6887 6888 my ($caaflags, $caatag, $caadetail) = ($val =~ /(\d+)\s+(\w+)\s+(.+)/); 6889 $prefix .= sprintf "\\%0.3o", $caaflags; 6890 $prefix .= sprintf "\\%0.3o%s", length($caatag), $caatag; 6891 $caadetail =~ s/:/\\072/g; 6892 $caadetail =~ s/;/\\073/g; # Not strictly necessary but may be helpful validating records by eye 6893 $caadetail =~ s/^\s*"\s*//; # AXFR imports may produce strings with embedded quotes; these 6894 $caadetail =~ s/\s*"\s*$//; # are purely a syntactic crutch for BIND-style zone files 6895 print $datafile "$prefix$caadetail:$ttl:$stamp:$loc\n" or die $!; 6896 } # CAA 6710 6897 6711 6898 elsif ($typemap{$type} eq 'RP') { -
branches/stable/dns-rpc.cgi
r1033 r1034 1628 1628 if ($args{delsubs}) { 1629 1629 # Delete ALL EVARYTHING!!one11!! in $args{cidr} 1630 my $reclist = $dnsdb->getRecList(rpc => 1, defrec => 'n', revrec => 'y', id => $zonelist->[0]->{rdns_id}); 1630 1631 # Deleting a small $args{cidr} from a large reverse zone will sometimes 1632 # silently fail by not finding the appropriate record(s). Prepend a 1633 # Postgres CIDR operator to assist in filtering 1634 my $filt = "<<= $args{cidr}"; 1635 1636 my $reclist = $dnsdb->getRecList(rpc => 1, defrec => 'n', revrec => 'y', id => $zonelist->[0]->{rdns_id}, 1637 filter => $filt, offset => 'all'); 1638 1631 1639 foreach my $rec (@$reclist) { 1632 1640 my $reccidr = new NetAddr::IP $rec->{val}; -
branches/stable/templates/log.tmpl
r756 r1034 54 54 NAME=rdns_id>&ltype=rdns"><TMPL_VAR NAME=revzone></a></td> 55 55 <TMPL_IF childentries> 56 <td >56 <td style="word-break: break-all;"> 57 57 <ul class="collapsible nocheckbox notalist"> 58 58 <li class="notalist"> … … 68 68 </ul> 69 69 <TMPL_ELSE> 70 <td ><TMPL_VAR NAME=logentry>70 <td style="word-break: break-all;"><TMPL_VAR NAME=logentry> 71 71 </TMPL_IF> 72 72 </td> -
branches/stable/templates/reclist.tmpl
r756 r1034 71 71 NAME=stamp>)</TMPL_IF></td> 72 72 <td><TMPL_VAR NAME=type></td> 73 <td ><TMPL_VAR NAME=val></td>73 <td style="word-break: break-all;"><TMPL_VAR NAME=val></td> 74 74 <td><TMPL_VAR NAME=distance></td> 75 75 <td><TMPL_VAR NAME=weight></td>
Note:
See TracChangeset
for help on using the changeset viewer.
![[ DNS Administrator ]](/fx/dnsadmin-logo.png)