diff --git a/lib/dns/include/dns/name.h b/lib/dns/include/dns/name.h index 01f776debb..1cf7129b81 100644 --- a/lib/dns/include/dns/name.h +++ b/lib/dns/include/dns/name.h @@ -1298,10 +1298,17 @@ dns_name_isula(const dns_name_t *owner); bool dns_name_istat(const dns_name_t *name); -/* +/*%< * Determine if 'name' is a potential 'trust-anchor-telemetry' name. */ +bool +dns_name_isdnssvcb(const dns_name_t *name); +/*%< + * Determine if 'name' is a dns service name, + * i.e. it starts with and optional _port label followed by a _dns label. + */ + ISC_LANG_ENDDECLS /* diff --git a/lib/dns/name.c b/lib/dns/name.c index b8a9ec46f0..96586def8c 100644 --- a/lib/dns/name.c +++ b/lib/dns/name.c @@ -2376,3 +2376,57 @@ dns_name_istat(const dns_name_t *name) { } return (true); } + +bool +dns_name_isdnssvcb(const dns_name_t *name) { + unsigned char len, len1; + const unsigned char *ndata; + + REQUIRE(VALID_NAME(name)); + + if (name->labels < 1 || name->length < 5) { + return (false); + } + + ndata = name->ndata; + len = len1 = ndata[0]; + INSIST(len <= name->length); + ndata++; + + if (len < 2 || ndata[0] != '_') { + return (false); + } + if (isdigit(ndata[1]) && name->labels > 1) { + char buf[sizeof("65000")]; + long port; + char *endp; + + /* + * Do we have a valid _port label? + */ + if (len > 6U || (ndata[1] == '0' && len != 2)) { + return (false); + } + memcpy(buf, ndata + 1, len - 1); + buf[len - 1] = 0; + port = strtol(buf, &endp, 10); + if (*endp != 0 || port < 0 || port > 0xffff) { + return (false); + } + + /* + * Move to next label. + */ + ndata += len; + INSIST(len1 + 1U < name->length); + len = *ndata; + INSIST(len + len1 + 1U <= name->length); + ndata++; + } + + if (len == 4U && strncasecmp((const char *)ndata, "_dns", 4) == 0) { + return (true); + } + + return (false); +}