Subject: [RFC PATCH] Add a no-auto-edns compatibility option Since 2.91, dnsmasq automatically adds EDNS0 to an upstream UDP query which does not already contain an OPT record. Add an opt-in compatibility setting for upstream servers or intervening devices which do not handle these queries correctly. With --no-auto-edns, skip only this automatic creation of an OPT record. Existing EDNS0 is retained, including client-supplied records and records created for explicitly configured EDNS features or DNSSEC. Continue to apply the existing UDP-size adjustment when an OPT record is present. Default behaviour and TCP query forwarding are unchanged. Document the option in the manual and command-line help. Based on the locally maintained dnsmasq 2.93 no-auto-edns v2 patch; rebased onto current upstream without OpenWrt packaging changes. Base-commit: a9880c595f052d63859d6ed8aa86a3a6b007bf20 --- man/dnsmasq.8 | 11 +++++++++++ src/dnsmasq.h | 3 ++- src/forward.c | 10 ++++++++-- src/option.c | 4 ++++ 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/man/dnsmasq.8 b/man/dnsmasq.8 index 89233257ef5a6d9e3e8163aaffd2e342dfae54ed..12da8a02bb0e6b25e1fbc98ce33138781079cdf9 100644 --- a/man/dnsmasq.8 +++ b/man/dnsmasq.8 @@ -199,6 +199,17 @@ Specify the largest EDNS.0 UDP packet which is supported by the DNS forwarder. Defaults to 1232, which is the recommended size following the DNS flag day in 2020. Only increase if you know what you are doing. .TP +.B --no-auto-edns +Do not automatically add an EDNS0 OPT pseudo-record when forwarding a +UDP DNS query which does not already contain one. This is a compatibility +option for upstream DNS servers or network devices which fail to handle +EDNS0 queries. The default is to add EDNS0 and advertise the size set by +.B --edns-packet-max. +An existing OPT record, whether supplied by the client or added by an +explicitly enabled feature such as DNSSEC validation, is retained and its +advertised UDP size is still adjusted in the usual way. This option does +not disable EDNS0 or DNSSEC, and does not change TCP query forwarding. +.TP .B \-Q, --query-port= Send outbound DNS queries from, and listen for their replies on, the specific UDP port instead of using random ports. NOTE diff --git a/src/dnsmasq.h b/src/dnsmasq.h index ecff18d652573749cda46a90486300b0d8d83bbf..059b967709b0fbf9fda2b84a0ea9a925be091fe8 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -296,7 +296,8 @@ struct event_desc { #define OPT_LEASEQUERY 77 #define OPT_LOG_ONLY_FAILED 78 #define OPT_LOG_MALLOC 79 -#define OPT_LAST 80 +#define OPT_NO_AUTO_EDNS 80 +#define OPT_LAST 81 #define OPTION_BITS (sizeof(unsigned int)*8) #define OPTION_SIZE ( (OPT_LAST/OPTION_BITS)+((OPT_LAST%OPTION_BITS)!=0) ) diff --git a/src/forward.c b/src/forward.c index f736c302f10caa82b76b8b047aaf3fef2f64e230..0517ebe5af6d48f9b475ccb9831dc5cc5d6d112d 100644 --- a/src/forward.c +++ b/src/forward.c @@ -513,8 +513,14 @@ static void forward_query(int udpfd, union mysockaddr *udpaddr, forwarded = 0; - /* Advertise the size of UDP reply we can accept. */ - plen = add_pseudoheader(header, plen, daemon->edns_pktsz, 0, NULL, 0, 0, 0); + /* Since 2.91 dnsmasq normally adds EDNS0 to every upstream query. + In compatibility mode, retain EDNS0 only when the query already has + a pseudo-header, for example because the client supplied it or an + enabled feature such as DNSSEC created it. */ + if (!option_bool(OPT_NO_AUTO_EDNS) || + find_pseudoheader(header, plen, NULL, NULL, NULL, NULL)) + plen = add_pseudoheader(header, plen, daemon->edns_pktsz, + 0, NULL, 0, 0, 0); /* check for send errors here (no route to host) if we fail to send to all nameservers, send back an error diff --git a/src/option.c b/src/option.c index 44bd52274397e70275c1507becb09eb97ba4f934..75f61917152d1eb714d2852349d9f275814a6768 100644 --- a/src/option.c +++ b/src/option.c @@ -201,6 +201,7 @@ struct myoption { #define LOPT_LEASEQUERY 389 #define LOPT_SPLIT_RELAY 390 #define LOPT_LOG_MALLOC 391 +#define LOPT_NO_AUTO_EDNS 392 #ifdef HAVE_GETOPT_LONG static const struct option opts[] = @@ -257,6 +258,7 @@ static const struct myoption opts[] = { "no-round-robin", 0, 0, LOPT_NORR }, { "no-0x20-encode", 0, 0, LOPT_NO_ENCODE }, { "do-0x20-encode", 0, 0, LOPT_DO_ENCODE }, + { "no-auto-edns", 0, 0, LOPT_NO_AUTO_EDNS }, { "cache-rr", 1, 0, LOPT_CACHE_RR }, { "addn-hosts", 1, 0, 'H' }, { "hostsdir", 1, 0, LOPT_HOST_INOTIFY }, @@ -608,6 +610,8 @@ static struct { { LOPT_NORR, OPT_NORR, NULL, gettext_noop("Suppress round-robin ordering of DNS records."), NULL }, { LOPT_NO_ENCODE, OPT_NO_0x20, NULL, gettext_noop("Suppress DNS bit 0x20 encoding."), NULL }, { LOPT_DO_ENCODE, OPT_DO_0x20, NULL, gettext_noop("Enable DNS bit 0x20 encoding."), NULL }, + { LOPT_NO_AUTO_EDNS, OPT_NO_AUTO_EDNS, NULL, + gettext_noop("Do not add EDNS0 to plain upstream DNS queries."), NULL }, { LOPT_NO_IDENT, OPT_NO_IDENT, NULL, gettext_noop("Do not add CHAOS TXT records."), NULL }, { LOPT_CACHE_RR, ARG_DUP, "", gettext_noop("Cache this DNS resource record type."), NULL }, { LOPT_MAX_PROCS, ARG_ONE, "", gettext_noop("Maximum number of concurrent tcp connections."), NULL },