When choosing a server to send a DS query to take
account of the need for DS records for a domain
to come from the parent of that domain.
This commit is contained in:
Simon Kelley
2025-06-24 22:29:58 +01:00
parent ec8f3e65c1
commit 57e582492b
4 changed files with 23 additions and 11 deletions

View File

@@ -1938,7 +1938,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
char *name, char *limit, int first, int last, int ede); char *name, char *limit, int first, int last, int ede);
int server_samegroup(struct server *a, struct server *b); int server_samegroup(struct server *a, struct server *b);
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp); int dnssec_server(struct server *server, char *keyname, int is_ds, int *firstp, int *lastp);
#endif #endif
void mark_servers(int flag); void mark_servers(int flag);
void cleanup_servers(void); void cleanup_servers(void);

View File

@@ -95,6 +95,7 @@ void build_server_array(void)
A flag of F_SERVER returns an upstream server only. A flag of F_SERVER returns an upstream server only.
A flag of F_DNSSECOK disables NODOTS servers from consideration. A flag of F_DNSSECOK disables NODOTS servers from consideration.
A flag of F_DS returns parent domain server.
A flag of F_DOMAINSRV returns a domain-specific server only. A flag of F_DOMAINSRV returns a domain-specific server only.
A flag of F_CONFIG returns anything that generates a local A flag of F_CONFIG returns anything that generates a local
reply of IPv4 or IPV6. reply of IPv4 or IPV6.
@@ -106,12 +107,23 @@ int lookup_domain(char *domain, int flags, int *lowout, int *highout)
ssize_t qlen; ssize_t qlen;
int try, high, low = 0; int try, high, low = 0;
int nlow = 0, nhigh = 0; int nlow = 0, nhigh = 0;
char *cp, *qdomain = domain; char *cp, *qdomain;
/* may be no configured servers. */ /* may be no configured servers. */
if (daemon->serverarraysz == 0) if (daemon->serverarraysz == 0)
return 0; return 0;
/* DS records should come from the parent domain. */
if (flags & F_DS)
{
if ((cp = strchr(domain, '.')))
domain = cp+1;
else
domain = "";
}
qdomain = domain;
/* find query length and presence of '.' */ /* find query length and presence of '.' */
for (cp = qdomain, nodots = 1, qlen = 0; *cp; qlen++, cp++) for (cp = qdomain, nodots = 1, qlen = 0; *cp; qlen++, cp++)
if (*cp == '.') if (*cp == '.')
@@ -403,7 +415,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
setup_reply(header, flags, ede); setup_reply(header, flags, ede);
gotname &= ~F_QUERY; gotname &= ~(F_QUERY | F_DS);
if (flags & (F_NXDOMAIN | F_NOERR)) if (flags & (F_NXDOMAIN | F_NOERR))
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0); log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL, 0);
@@ -463,14 +475,14 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
} }
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp) int dnssec_server(struct server *server, char *keyname, int is_ds, int *firstp, int *lastp)
{ {
int first, last, index; int first, last, index;
/* Find server to send DNSSEC query to. This will normally be the /* Find server to send DNSSEC query to. This will normally be the
same as for the original query, but may be another if same as for the original query, but may be another if
servers for domains are involved. */ servers for domains are involved. */
if (!lookup_domain(keyname, F_SERVER | F_DNSSECOK, &first, &last)) if (!lookup_domain(keyname, F_SERVER | F_DNSSECOK | (is_ds ? F_DS : 0), &first, &last))
return -1; return -1;
for (index = first; index != last; index++) for (index = first; index != last; index++)

View File

@@ -1024,7 +1024,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
/* Make sure we don't expire and free the orig frec during the /* Make sure we don't expire and free the orig frec during the
allocation of a new one: third arg of get_new_frec() does that. */ allocation of a new one: third arg of get_new_frec() does that. */
if ((serverind = dnssec_server(forward->sentto, daemon->keyname, NULL, NULL)) != -1 && if ((serverind = dnssec_server(forward->sentto, daemon->keyname, STAT_ISEQUAL(status, STAT_NEED_DS), NULL, NULL)) != -1 &&
(server = daemon->serverarray[serverind]) && (server = daemon->serverarray[serverind]) &&
(nn = dnssec_generate_query(header, ((unsigned char *) header) + daemon->edns_pktsz, (nn = dnssec_generate_query(header, ((unsigned char *) header) + daemon->edns_pktsz,
daemon->keyname, forward->class, get_id(), daemon->keyname, forward->class, get_id(),
@@ -2199,7 +2199,7 @@ int tcp_from_udp(time_t now, int status, struct dns_header *header, ssize_t *ple
first = start = server->arrayposn; first = start = server->arrayposn;
last = first + 1; last = first + 1;
if (!STAT_ISEQUAL(status, STAT_OK) && (start = dnssec_server(server, name, &first, &last)) == -1) if (!STAT_ISEQUAL(status, STAT_OK) && (start = dnssec_server(server, name, STAT_ISEQUAL(status, STAT_NEED_DS), &first, &last)) == -1)
new_status = STAT_ABANDONED; new_status = STAT_ABANDONED;
else else
{ {
@@ -2307,7 +2307,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class, 0, m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class, 0,
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS); STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS);
if ((start = dnssec_server(server, keyname, &first, &last)) == -1) if ((start = dnssec_server(server, keyname, STAT_ISEQUAL(new_status, STAT_NEED_DS), &first, &last)) == -1)
{ {
new_status = STAT_ABANDONED; new_status = STAT_ABANDONED;
break; break;

View File

@@ -1248,7 +1248,7 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
/* Make the behaviour for DS and DNSKEY queries we forward the same /* Make the behaviour for DS and DNSKEY queries we forward the same
as for DS and DNSKEY queries we originate. */ as for DS and DNSKEY queries we originate. */
if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DS || qtype == T_DNSKEY)) if (option_bool(OPT_DNSSEC_VALID) && (qtype == T_DS || qtype == T_DNSKEY))
return F_DNSSECOK; return F_DNSSECOK | (qtype == T_DS ? F_DS : 0);
#endif #endif
return F_QUERY; return F_QUERY;