diff --git a/doc/arm/reference.rst b/doc/arm/reference.rst index c4245cf869..0453ca1d5d 100644 --- a/doc/arm/reference.rst +++ b/doc/arm/reference.rst @@ -7349,7 +7349,7 @@ records are also written to the zone's filename. Each rule grants or denies privileges. Rules are checked in the order in which they are specified in the :any:`update-policy` statement. Once a message has successfully matched a rule, the operation is immediately - granted or denied, and no further rules are examined. There are 16 types + granted or denied, and no further rules are examined. There are 23 types of rules; the rule type is specified by the ``ruletype`` field, and the interpretation of other fields varies depending on the rule type. @@ -7405,11 +7405,12 @@ records are also written to the zone's filename. send EOF - The ruletype field has 18 values: ``name``, ``subdomain``, ``zonesub``, + The ruletype field has 23 values: ``name``, ``subdomain``, ``zonesub``, ``wildcard``, ``self``, ``selfsub``, ``selfwild``, ``ms-self``, ``ms-selfsub``, ``ms-subdomain``, ``ms-subdomain-self-rhs``, ``krb5-self``, ``krb5-selfsub``, ``krb5-subdomain``, ``krb5-subdomain-self-rhs``, - ``tcp-self``, ``6to4-self``, and ``external``. + ``tcp-self``, ``6to4-self``, ``64-self``, ``60-self``, ``56-self``, + ``52-self``, ``48-self`` and ``external``. ``name`` With exact-match semantics, this rule matches when the name being updated is identical to the contents of the ``name`` field. @@ -7496,6 +7497,25 @@ records are also written to the zone's filename. .. note:: It is theoretically possible to spoof these TCP sessions. + ``64-self``, ``60-self``, ``56-self``, ``52-self``, ``48-self`` + These allow records at reverse IPv6 names at the specified + nibble boundary to be updated if a TCP request comes from + an IPv6 address in the matching prefix. These are intended + to allow ISP customers to add delgation records when using + DHCPv6 prefix delegations or when prefix delegation is used + within a site. + + :: + + grant * 64-self * NS DS; + grant ISP-DHCPv6-SERVER-KEY zonesub ANY; + + Which will allow customers to add delegation records and the + DHCPv6 server to clean up when the lease expires. + + .. note:: + It is theoretically possible to spoof these TCP sessions. + ``external`` This rule allows :iscman:`named` to defer the decision of whether to allow a given update to an external daemon. diff --git a/doc/misc/primary.zoneopt b/doc/misc/primary.zoneopt index dfa2b79661..4c5ecb21af 100644 --- a/doc/misc/primary.zoneopt +++ b/doc/misc/primary.zoneopt @@ -58,7 +58,7 @@ zone [ ] { sig-signing-type ; sig-validity-interval [ ]; // obsolete update-check-ksk ; // obsolete - update-policy ( local | { ( deny | grant ) ( 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ ] ; ... } ); + update-policy ( local | { ( deny | grant ) ( 48-self | 52-self | 56-self | 60-self | 64-self | 6to4-self | external | krb5-self | krb5-selfsub | krb5-subdomain | krb5-subdomain-self-rhs | ms-self | ms-selfsub | ms-subdomain | ms-subdomain-self-rhs | name | self | selfsub | selfwild | subdomain | tcp-self | wildcard | zonesub ) [ ] ; ... } ); zero-no-soa-ttl ; zone-statistics ( full | terse | none | ); }; diff --git a/lib/dns/include/dns/ssu.h b/lib/dns/include/dns/ssu.h index e391043616..60ae003671 100644 --- a/lib/dns/include/dns/ssu.h +++ b/lib/dns/include/dns/ssu.h @@ -41,9 +41,14 @@ typedef enum { dns_ssumatchtype_selfsubkrb5 = 15, dns_ssumatchtype_subdomainselfkrb5rhs = 16, dns_ssumatchtype_subdomainselfmsrhs = 17, - dns_ssumatchtype_max = 17, /* max value */ + dns_ssumatchtype_64self = 18, + dns_ssumatchtype_60self = 19, + dns_ssumatchtype_56self = 20, + dns_ssumatchtype_52self = 21, + dns_ssumatchtype_48self = 22, + dns_ssumatchtype_max = 22, /* max value */ - dns_ssumatchtype_dlz = 18 /* intentionally higher than _max */ + dns_ssumatchtype_dlz = 23 /* intentionally higher than _max */ } dns_ssumatchtype_t; typedef struct dns_ssuruletype { diff --git a/lib/dns/ssu.c b/lib/dns/ssu.c index 29ca14ee68..4821df8341 100644 --- a/lib/dns/ssu.c +++ b/lib/dns/ssu.c @@ -174,6 +174,16 @@ mtypetostring(dns_ssumatchtype_t matchtype) { return "local"; case dns_ssumatchtype_dlz: return "dlz"; + case dns_ssumatchtype_64self: + return "64-self"; + case dns_ssumatchtype_60self: + return "60-self"; + case dns_ssumatchtype_56self: + return "56-self"; + case dns_ssumatchtype_52self: + return "52-self"; + case dns_ssumatchtype_48self: + return "48-self"; } return "UnknownMatchType"; } @@ -282,44 +292,72 @@ reverse_from_address(dns_name_t *tcpself, const isc_netaddr_t *tcpaddr) { RUNTIME_CHECK(result == ISC_R_SUCCESS); } -static void -stf_from_address(dns_name_t *stfself, const isc_netaddr_t *tcpaddr) { - char buf[sizeof("X.X.X.X.Y.Y.Y.Y.2.0.0.2.IP6.ARPA.")]; +static bool +stf_from_address(dns_name_t *stfself, dns_ssumatchtype_t matchtype, + const isc_netaddr_t *tcpaddr) { + char buf[sizeof("1.2.3.4.5.6.7.8.1.2.3.4.5.6.7.8.IP6.ARPA.")]; isc_result_t result; const unsigned char *ap; isc_buffer_t b; unsigned long l; + char *s = buf; + int n; switch (tcpaddr->family) { case AF_INET: + if (matchtype != dns_ssumatchtype_6to4self) { + return false; + } l = ntohl(tcpaddr->type.in.s_addr); - result = snprintf( + n = snprintf( buf, sizeof(buf), "%lx.%lx.%lx.%lx.%lx.%lx.%lx.%lx.2.0.0.2.IP6.ARPA.", l & 0xf, (l >> 4) & 0xf, (l >> 8) & 0xf, (l >> 12) & 0xf, (l >> 16) & 0xf, (l >> 20) & 0xf, (l >> 24) & 0xf, (l >> 28) & 0xf); - RUNTIME_CHECK(result < sizeof(buf)); + RUNTIME_CHECK(n != -1 && (size_t)n < sizeof(buf)); break; case AF_INET6: ap = tcpaddr->type.in6.s6_addr; - result = snprintf( + n = snprintf( buf, sizeof(buf), - "%x.%x.%x.%x.%x.%x.%x.%x." - "%x.%x.%x.%x.IP6.ARPA.", - ap[5] & 0x0f, (ap[5] >> 4) & 0x0f, ap[4] & 0x0f, - (ap[4] >> 4) & 0x0f, ap[3] & 0x0f, (ap[3] >> 4) & 0x0f, - ap[2] & 0x0f, (ap[2] >> 4) & 0x0f, ap[1] & 0x0f, - (ap[1] >> 4) & 0x0f, ap[0] & 0x0f, (ap[0] >> 4) & 0x0f); - RUNTIME_CHECK(result < sizeof(buf)); + "%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.%x.IP6." + "ARPA.", + ap[7] & 0x0f, (ap[7] >> 4) & 0x0f, ap[6] & 0x0f, + (ap[6] >> 4) & 0x0f, ap[5] & 0x0f, (ap[5] >> 4) & 0x0f, + ap[4] & 0x0f, (ap[4] >> 4) & 0x0f, ap[3] & 0x0f, + (ap[3] >> 4) & 0x0f, ap[2] & 0x0f, (ap[2] >> 4) & 0x0f, + ap[1] & 0x0f, (ap[1] >> 4) & 0x0f, ap[0] & 0x0f, + (ap[0] >> 4) & 0x0f); + RUNTIME_CHECK(n != -1 && (size_t)n < sizeof(buf)); + switch (matchtype) { + case dns_ssumatchtype_64self: + break; + case dns_ssumatchtype_60self: + s += 2; + break; + case dns_ssumatchtype_56self: + s += 4; + break; + case dns_ssumatchtype_52self: + s += 6; + break; + case dns_ssumatchtype_48self: + case dns_ssumatchtype_6to4self: + s += 8; + break; + default: + UNREACHABLE(); + } break; default: UNREACHABLE(); } - isc_buffer_init(&b, buf, strlen(buf)); - isc_buffer_add(&b, strlen(buf)); + isc_buffer_init(&b, s, strlen(s)); + isc_buffer_add(&b, strlen(s)); result = dns_name_fromtext(stfself, &b, dns_rootname, 0); RUNTIME_CHECK(result == ISC_R_SUCCESS); + return true; } bool @@ -402,10 +440,20 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer, mtypetostring(rule->matchtype), namebuf); break; + case dns_ssumatchtype_48self: + case dns_ssumatchtype_52self: + case dns_ssumatchtype_56self: + case dns_ssumatchtype_60self: + case dns_ssumatchtype_64self: case dns_ssumatchtype_6to4self: stfself = dns_fixedname_initname(&fixed); - stf_from_address(stfself, addr); + if (!stf_from_address(stfself, + rule->matchtype, + addr)) + { + break; + } dns_name_format(stfself, namebuf, sizeof(namebuf)); isc_log_write( @@ -492,6 +540,11 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer, } break; case dns_ssumatchtype_tcpself: + case dns_ssumatchtype_48self: + case dns_ssumatchtype_52self: + case dns_ssumatchtype_56self: + case dns_ssumatchtype_60self: + case dns_ssumatchtype_64self: case dns_ssumatchtype_6to4self: if (!tcp || addr == NULL) { if (logit) { @@ -844,9 +897,24 @@ dns_ssutable_checkrules(dns_ssutable_t *table, const dns_name_t *signer, continue; } break; + case dns_ssumatchtype_48self: + case dns_ssumatchtype_52self: + case dns_ssumatchtype_56self: + case dns_ssumatchtype_60self: + case dns_ssumatchtype_64self: case dns_ssumatchtype_6to4self: stfself = dns_fixedname_initname(&fixed); - stf_from_address(stfself, addr); + if (!stf_from_address(stfself, rule->matchtype, addr)) { + if (logit) { + isc_log_write( + DNS_LOGCATEGORY_UPDATE_POLICY, + DNS_LOGMODULE_SSU, + ISC_LOG_DEBUG(99), + "update-policy: next " + "rule: not IPv6 address"); + } + continue; + } if (dns_name_iswildcard(rule->identity)) { if (!dns_name_matcheswildcard(stfself, rule->identity)) @@ -1123,6 +1191,16 @@ dns_ssu_mtypefromstring(const char *str, dns_ssumatchtype_t *mtype) { *mtype = dns_ssumatchtype_subdomain; } else if (strcasecmp(str, "external") == 0) { *mtype = dns_ssumatchtype_external; + } else if (strcasecmp(str, "64-self") == 0) { + *mtype = dns_ssumatchtype_64self; + } else if (strcasecmp(str, "60-self") == 0) { + *mtype = dns_ssumatchtype_60self; + } else if (strcasecmp(str, "56-self") == 0) { + *mtype = dns_ssumatchtype_56self; + } else if (strcasecmp(str, "52-self") == 0) { + *mtype = dns_ssumatchtype_56self; + } else if (strcasecmp(str, "48-self") == 0) { + *mtype = dns_ssumatchtype_48self; } else { return ISC_R_NOTFOUND; } diff --git a/lib/isccfg/check.c b/lib/isccfg/check.c index 2e8a4b2297..002f5f2475 100644 --- a/lib/isccfg/check.c +++ b/lib/isccfg/check.c @@ -2666,6 +2666,11 @@ check_update_policy(const cfg_obj_t *policy) { case dns_ssumatchtype_selfsubkrb5: case dns_ssumatchtype_selfsubms: case dns_ssumatchtype_tcpself: + case dns_ssumatchtype_48self: + case dns_ssumatchtype_52self: + case dns_ssumatchtype_56self: + case dns_ssumatchtype_60self: + case dns_ssumatchtype_64self: case dns_ssumatchtype_6to4self: if (tresult == ISC_R_SUCCESS && !dns_name_equal(dns_rootname, name)) diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c index 85d1c531c0..2465b81320 100644 --- a/lib/isccfg/namedconf.c +++ b/lib/isccfg/namedconf.c @@ -347,7 +347,12 @@ doc_matchname(cfg_printer_t *pctx, const cfg_type_t *type) { cfg_print_cstr(pctx, " ]"); } -static const char *matchtype_enums[] = { "6to4-self", +static const char *matchtype_enums[] = { "48-self", + "52-self", + "56-self", + "60-self", + "64-self", + "6to4-self", "external", "krb5-self", "krb5-selfsub",