Skip to main content Skip to search
Alex Vayl
Posted by
Alex Vayl on
August 17, 2016

When DNS Uses UDP Versus TCP

The original specifications for the Domain Name Service (DNS), contained in RFC 1034 (Mockapetris 1987a) which specifies the concepts and facilities provided by the DNS, and RFC 1035 (Mockapetris 1987b) which details the implementation and specification, called for the DNS to respond to queries only over the User Datagram Protocol (UDP) of the TCP/IP communication suite, and respond with only a single datagram.  While UDP is quite fast due to its stateless design, it does carry the significant limitation of a 512-byte datagram.  This means that in practice, the largest DNS query answer that can fit inside a single datagram is approximately 464 bytes, largely depending upon the length of the query, authority, and additional fields. (Of note, the maximum number of IPs you can return in a single A record is 13).


In practice, this means that if the answer to a DNS query exceeds approximately 464 bytes, the answer will be truncated and the trailing portion lost.


$ curl -s -X PUT -H 'X-NSONE-Key: <key>' -d "{ \"zone\": \"example.com\", \"domain\": \"test.example.com\", \"type\": \"TXT\", \"answers\": [ { \"answer\": [ \"`for i in {1..1024}; do echo -n x; done`\" ] } ] }" https://api.nsone.net/v1/zones/example.com/test.example.com/TXT | jq .

{

  "domain": "test.example.com",

  "zone": "example.com",

  "use_client_subnet": true,

  "answers": [

    {

      "answer": [

        "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

      ],

      "id": "57226d0d59272400060fb009"

    }

  ],

  "id": "57226d0d59272400060fb00a",

  "regions": {},

  "meta": {},

  "link": null,

  "filters": [],

  "ttl": 3600,

  "tier": 1,

  "type": "TXT",

  "networks": [

    0

  ]

}

</key>

Here we create the TXT record test.example.com with an answer exactly 1KB in length.

Next, we query the record using dig with EDNS0 explicitly disabled:


$ dig +noedns test.example.com. @dns1.p01.nsone.net TXT

;; Truncated, retrying in TCP mode.

The message Truncated, retrying in TCP mode indicates that an incomplete answer was received, and that dig was made aware of the situation by the TC (truncate) flag being set in the response header.

Additionally, dig then re-queried the record over TCP, a much slower process but one that allows the answer to exceed approximately 464 bytes. Through this retry mechanism over TCP, dig successfully retrieved the full answer.

This situation is avoided through the use of the Extension Mechanisms for DNS specified in RFC 2671, and which among other things allows the use of large UDP packets that exceed 512 bytes’ length.

It is also worth noting that the DNS uses TCP by default for zone transfers via the DNS query types AXFR (full) and IXFR (incremental). This transport choice is specified in the original RFCs for the DNS.