When using the dig
utility, be aware that the default EDNS buffer size advertised by dig
has changed in version 9.18 from previous versions. This difference can affect dig's results. If using multiple versions of dig when troubleshooting or monitoring DNS servers, use the information in this article to ensure relevant results across different versions of dig.
Versions of dig
dig
comes bundled with all ISC BIND distributions, vendors often provide older versions of ISC software. The version of dig
present can vary widely depending on the operating system or other factors. Some Linux distributions may provide relatively recent packages, while other operating systems may provide older versions of dig
. For example, macOS currently provides dig
version 9.10.
Additionally, users may may install multiple executables on a given system, either via packages with pre-built binaries or binaries built from source code. So when using dig
, be aware of the version, which can be found by running dig -v
, and whether more than one version of dig
exists on your system.
dig
version numbers
In systems with both BIND and dig, the version number of dig
matches the version number of BIND, as they are distributed together. Using matching versions of dig
and BIND on the same system is not required, but it is recommended.
Buffer size and EDNS
The Extended DNS protocol (EDNS) allows clients and servers to advertise their maximum UDP buffer size, which increases the the original DNS specification's 512-byte limit on the size of DNS data in a UDP datagram. For additional information about EDNS0, please read the following documents:
In versions with EDNS support prior to 9.18, dig
advertised a default EDNS buffer size of 4096 bytes. In version 9.18, the default was changed to 1232 bytes to comply with the recommendations produced by the 2020 DNS Flag Day. Add the +qr
option on the dig
command line to display query data in the dig
output. The "EDNS" line will contain a udp
parameter showing the maximum UDP buffer size that can be sent or received:
A query section from dig 9.16:
;; Sending:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39594
;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
A query section from dig 9.18:
;; Sending:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39594
;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
Effects on results
This difference in maximum UDP buffer size can affect dig
's results, depending on a number of factors. The same query may produce different results using 9.16 and earlier versions with the larger maximum size versus 9.18 and later versions with their smaller maximum size. Differences can include slower response times or query failures due to DNS response truncation or to IP fragmentation. Let's use an example to illustrate these effects.
dig +qr 2048.size.dns.netmeister.org
In this example, the above query sent to the local recursive resolver receives a response with a large number of "A" resource records. The size of the complete answer is 2025 bytes.
Version 9.16 and earlier
Using dig 9.16 with a default maximum advertised UDP buffer size of 4096 bytes, the server responds with the complete answer over UDP. This response is fragmented into two packets because the MTU on the network segments traversed is 1500 bytes, which is less than 2025 bytes. IP Fragmentation of the UDP datagrams can be seen using packet capture software such as tcpdump
or Wireshark, as seen in the image below:
The first packet contains the request. The second packet is the first part of the response, and contains the maximum number of bytes for a network path whose MTU is 1500 bytes (total frame length = 1514 bytes, which includes 14 bytes of Ethernet header). The third packet contains the remaining bytes of the response.
Fragmented DNS packets may fail to pass through firewalls or similar security devices, which disallow them on security grounds, or are just not capable of processing the fragments. Failure to receive all of a packet's fragments typically manifests as a timeout error for the requester.
Current versions
Using dig 9.18 with a default maximum advertised UDP buffer size of 1232 bytes, the server sends back a truncated response (DNS header with the TC flag = 1) because the complete DNS message would contain 2025 bytes--more than the 1232 byte maximum. Automatically, dig then switches to TCP, re-queries and retrieves the complete answer as expected.
; <<>> DiG 9.18.27 <<>> -4 2048.size.dns.netmeister.org +qr
;; global options: +cmd
;; Sending:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 25064
;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: a5d66f43b1109b6b
;; QUESTION SECTION:
;2048.size.dns.netmeister.org. IN A
;; QUERY SIZE: 69
;; Truncated, retrying in TCP mode.
;; Sending:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52149
;; flags: rd ad; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
; COOKIE: a5d66f43b1109b6b
;; QUESTION SECTION:
;2048.size.dns.netmeister.org. IN A
;; QUERY SIZE: 69
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 52149
;; flags: qr rd ra; QUERY: 1, ANSWER: 123, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;2048.size.dns.netmeister.org. IN A
;; ANSWER SECTION:
2048.size.dns.netmeister.org. 300 IN A 127.0.0.94
2048.size.dns.netmeister.org. 300 IN A 127.0.0.6
<records removed for brevity>
2048.size.dns.netmeister.org. 300 IN A 127.0.0.70
;; Query time: 3621 msec
;; SERVER: 192.168.1.254#53(192.168.1.254) (TCP)
;; WHEN: Wed May 22 23:03:31 PDT 2024
;; MSG SIZE rcvd: 2025
Note the two "Sending sections". The second contains:
Truncated, retrying in TCP mode.
Also, in version 9.18, the Statistics section at the end includes the transport layer protocol used, in this case TCP:
SERVER: 192.168.1.254#53(192.168.1.254) (TCP)
.
In Wireshark, the conversation looks like:
The first frame contains the UDP request, and the second the response with the truncation flag set in the DNS header (TC=1). This causes dig to switch to TCP, starting with the TCP three-way handshake in frames 3 to 5. The remaining frames exchange the DNS data.
Use of TCP avoids IP fragmentation, but takes longer to complete the request. The initial UDP request must first complete, then a TCP-based request must be completed, which takes longer than a corresponding UDP request because TCP first performs its "handshake" (exchange of segments with the SYN bit set) to establish the connection before exchanging data.
Additionally, administrators sometimes make the mistake of not allowing their firewalls to permit DNS over TCP, so the TCP traffic may be rejected or silently dropped. This manifests as a connection refused or timeout error when using dig
.
So, when using current versions of dig
, the likelihood of receiving truncated responses is greater since the default maximum UDP size is now smaller, making TCP re-query more likely.
Legacy behavior and current versions
If users with version 9.18 or greater need to generate queries with the older maximum UDP size of 4096 bytes, add +bufsize=4096
to the dig
command line, which overrides the default size of 1232 bytes. Similarly, older versions of dig
can behave like newer versions with the default of 1232 bytes by adding +bufsize=1232
to the command line. Shell aliases can be used to simplify typing, such as dig4k="dig +bufsize=4096"
.
Alternatively, dig
can be built from source with a different maximum as the default. In the 9.18 source code for dig
, edit the file dighost.h in the ./bin/dig/ directory and replace the value of 1232 with the desired value in the line defining the DEFAULT_EDNS_BUFSIZE constant:
#define DEFAULT_EDNS_BUFSIZE 1232
In the 9.16 and earlier source code for dig
, edit the file dig.h in the ./bin/dig/include/dig/ directory and replace the value of 4096 with the desired value for the same constant.