edns-udp-size in server statement
https://ftp.isc.org/isc/bind9/9.16.1/doc/arm/Bv9ARM.ch05.html#server_statement_definition_and_usage points out that edns-udp-size
in a server statement, which sets a single UDP size for all packets sent to the server, differs from the behavior of edns-udp-size
in options or view statements, where it specifies a maximum value. It goes on to warn that "The server statement behavior may be brought into conformance with the options/view behavior in future releases."
I'm writing to share what I believe to be a valid real-world use case for the current behavior, and therefore a reason to preserve it.
As of this writing, I have discovered that a certain set of authoritative nameservers neglects to set the TC flag when they truncate a response to the following query:
$ dig +norec +dnssec +bufsize=512 +ignore +qr @a.gov-servers.net rh202ns2.355.dhhs.gov a
; <<>> DiG 9.11.17 <<>> +norec +dnssec +bufsize=512 +ignore +qr @a.gov-servers.net rh202ns2.355.dhhs.gov a
; (2 servers found)
;; global options: +cmd
;; Sending:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30828
;; flags: ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 512
; COOKIE: cd7bdc7c0652450f
;; QUESTION SECTION:
;rh202ns2.355.dhhs.gov. IN A
;; QUERY SIZE: 62
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 30828
;; flags: qr; QUERY: 1, ANSWER: 0, AUTHORITY: 9, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;rh202ns2.355.dhhs.gov. IN A
;; AUTHORITY SECTION:
dhhs.gov. 86400 IN NS rh120ns2.368.dhhs.gov.
dhhs.gov. 86400 IN NS rh202ns2.355.dhhs.gov.
dhhs.gov. 86400 IN NS rh120ns1.368.dhhs.gov.
dhhs.gov. 86400 IN NS rh202ns1.355.dhhs.gov.
dhhs.gov. 3600 IN DS 51937 8 1 5B557959E1E4CB05FE667CD0EE98D0C5D243D71A
dhhs.gov. 3600 IN DS 635 8 2 3DA74CE6083E79B5FCA8BD5516CE7201774BAEBDE7D1314A32A113A7 74635410
dhhs.gov. 3600 IN DS 51937 8 2 8CDF39C362FD8A982E141B25DEBA8D6957419A7C025A40CC493255BD 6D5352D7
dhhs.gov. 3600 IN DS 635 8 1 CC30699D55C70F38F9653E71B6A8553803ED67D9
dhhs.gov. 3600 IN RRSIG DS 8 2 3600 20200421161007 20200414161007 36558 gov. m1OXbWkv/Rvkb+y6Ytnvtde6pdJXBVOYG6ha0llcV+43bf9o0pHVa7xX J23MSpLzBytY0m61XO8hVUPmln7Rkz+gX5HuIjweMiqoT2MbVC5LjMu7 Z38kG2cV3xkjMs2MCM3Cl5MdnLmt9swdhu+Weue5NsOixr0dTDmrhaXs 3jRDJk1Nd7Wav/MgYvz1/LyMT5AmDlSwQO+W+QQwBnbd+A==
;; Query time: 12 msec
;; SERVER: 69.36.157.30#53(69.36.157.30)
;; WHEN: Tue Apr 14 19:36:25 UTC 2020
;; MSG SIZE rcvd: 500
This is one of the authoritative nameservers for gov.
providing a referral response for dhhs.gov.
. Since the nameservers in the referral are themselves underneath dhhs.gov.
, it is absolutely essential that this response include glue A records; without them, it is impossible for a recursive resolver to follow the delegation. But in this case the glue A records have been omitted in order for the response to fit within 512 bytes, and no TC flag is set to tell the resolver it should retry over TCP. Which is not our fault, of course, but that doesn't mean it's not our problem.
Now consider a freshly-initialized BIND recursive resolver. Because BIND always advertises a UDP buffer size of 512 the first time it queries any given remote server, if the first recursive query we attempt to handle after startup is for rh202ns2.355.dhhs.gov a
then we will receive the above problematic answer (TC=0, no glue A records) from one of the gov servers, conclude that no glue records exist (i.e. the delegation is hopelessly broken), and return SERVFAIL to our recursive client.
Interestingly this SERVFAIL condition will not persist indefinitely; since our first query against 69.36.157.30 with buffer size 512 was "successful" (in the sense that we didn't get a timeout or a NOTIMPL / FORMERR / SERVFAIL), our next subsequent attempt to query 69.36.157.30 will advertise a larger buffer size which does in fact happen to be large enough to hold all the glue records, allowing us to follow the delegation and retrieve the desired answer. But each time we restart named (and maybe for other reasons too, I'm not sure) we'll try 512 again and end up back at SERVFAIL.
Which brings us to edns-udp-size
: configuring
options {
edns-udp-size 1232;
};
is no help at all in this scenario because BIND will still try 512 first. But
# a.gov-servers.net
server 69.36.157.30 {
edns-udp-size 1232;
};
# b.gov-servers.net
server 209.112.123.30 {
edns-udp-size 1232;
};
# c.gov-servers.net
server 69.36.153.30 {
edns-udp-size 1232;
};
# d.gov-servers.net
server 81.19.194.30 {
edns-udp-size 1232;
};
is an effective workaround that we can implement on the BIND recursive resolver, until such time as we can convince someone to fix the authoritative nameservers (which are not under our control).
Of course we could also use tcp-only yes;
as a workaround, but it's nice to have both alternatives available.
For the record:
- I did my proof-of-concept testing with BIND 9.11.17, but the ARM statement warning that this behavior might be removed someday is still present in 9.16.1.
- What matters to me is that the behavior still be available; I would be perfectly happy to configure it using a different option name in order to reduce confusion.
Thanks for reading!