diff --git a/CHANGELOG b/CHANGELOG index d574ba0..3a43ad2 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -82,6 +82,21 @@ version 2.91 to queries which arrive a dnsmasq already carrying an EDNS client subnet. + Handle DS queries to auth zones. When dnsmasq is configured to + act as an authoritative server and has an authoritative zone + configured, and recieves a query for that zone _as_forwarder_ + it answers the query directly rather than forwarding it. This + doesn't affect the answer, but it saves dnsmasq forwarding the + query to the recusor upstream, whch then bounces it back to dnsmasq + in auth mode. The exception should be when the query is for the root + of zone, for a DS RR. The answer to that has to come from the parent, + via the recursor, and will typically be a proof-of-nonexistence + since dnsmasq doesn't support signed zones. This patch suppresses + local answers and forces forwarding to the upstream recursor for such + queries. It stops breakage when a DNSSEC validating client makes + queries to dnsmasq acting as forwarder for a zone for which it is + authoritative. + version 2.90 Fix reversion in --rev-server introduced in 2.88 which diff --git a/src/forward.c b/src/forward.c index 4c61c60..056a0c3 100644 --- a/src/forward.c +++ b/src/forward.c @@ -1691,15 +1691,27 @@ void receive_query(struct listener *listen, time_t now) &source_addr, auth_dns ? "auth" : "query", type); #ifdef HAVE_AUTH - /* find queries for zones we're authoritative for, and answer them directly */ + /* Find queries for zones we're authoritative for, and answer them directly. + The exception to this is DS queries for the zone route. They + have to come from the parent zone. Since dnsmasq's auth server + can't do DNSSEC, the zone will be unsigned, and anything using + dnsmasq as a forwarder and doing validation will be expecting to + see the proof of non-existence from the parent. */ if (!auth_dns && !option_bool(OPT_LOCALISE)) for (zone = daemon->auth_zones; zone; zone = zone->next) - if (in_zone(zone, daemon->namebuff, NULL)) - { - auth_dns = 1; - local_auth = 1; - break; - } + { + char *cut; + + if (in_zone(zone, daemon->namebuff, &cut)) + { + if (type != T_DS || cut) + { + auth_dns = 1; + local_auth = 1; + } + break; + } + } #endif #ifdef HAVE_LOOP @@ -2325,15 +2337,27 @@ unsigned char *tcp_request(int confd, time_t now, &peer_addr, auth_dns ? "auth" : "query", qtype); #ifdef HAVE_AUTH - /* find queries for zones we're authoritative for, and answer them directly */ + /* Find queries for zones we're authoritative for, and answer them directly. + The exception to this is DS queries for the zone route. They + have to come from the parent zone. Since dnsmasq's auth server + can't do DNSSEC, the zone will be unsigned, and anything using + dnsmasq as a forwarder and doing validation will be expecting to + see the proof of non-existence from the parent. */ if (!auth_dns && !option_bool(OPT_LOCALISE)) for (zone = daemon->auth_zones; zone; zone = zone->next) - if (in_zone(zone, daemon->namebuff, NULL)) - { - auth_dns = 1; - local_auth = 1; - break; - } + { + char *cut; + + if (in_zone(zone, daemon->namebuff, &cut)) + { + if (qtype != T_DS || cut) + { + auth_dns = 1; + local_auth = 1; + } + break; + } + } #endif norebind = domain_no_rebind(daemon->namebuff);