diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 1bda100..d1abed6 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -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); int server_samegroup(struct server *a, struct server *b); #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 void mark_servers(int flag); void cleanup_servers(void); diff --git a/src/domain-match.c b/src/domain-match.c index fa8484a..935a2d3 100644 --- a/src/domain-match.c +++ b/src/domain-match.c @@ -95,6 +95,7 @@ void build_server_array(void) A flag of F_SERVER returns an upstream server only. 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_CONFIG returns anything that generates a local reply of IPv4 or IPV6. @@ -106,12 +107,23 @@ int lookup_domain(char *domain, int flags, int *lowout, int *highout) ssize_t qlen; int try, high, low = 0; int nlow = 0, nhigh = 0; - char *cp, *qdomain = domain; - + char *cp, *qdomain; + /* may be no configured servers. */ if (daemon->serverarraysz == 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 '.' */ for (cp = qdomain, nodots = 1, qlen = 0; *cp; qlen++, 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); - gotname &= ~F_QUERY; + gotname &= ~(F_QUERY | F_DS); if (flags & (F_NXDOMAIN | F_NOERR)) 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 -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; - + /* Find server to send DNSSEC query to. This will normally be the same as for the original query, but may be another if 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; for (index = first; index != last; index++) diff --git a/src/forward.c b/src/forward.c index 31f0769..d921753 100644 --- a/src/forward.c +++ b/src/forward.c @@ -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 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]) && (nn = dnssec_generate_query(header, ((unsigned char *) header) + daemon->edns_pktsz, 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; 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; 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, 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; break; diff --git a/src/rfc1035.c b/src/rfc1035.c index bb63083..9cdc2a6 100644 --- a/src/rfc1035.c +++ b/src/rfc1035.c @@ -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 as for DS and DNSKEY queries we originate. */ 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 return F_QUERY;