Some readers will probably be aware that we are amongst the proponents of a
quite strict stance when it comes to filtering IPv6 packets with (certain)
Extension Headers and/or fragmentation, because those can be the source of many
security problems (as laid out
here,
here
or
here).
Actually I still think it was a very good idea of, amongst others, Randy Bush
and Ron Bonica to
suggest the deprecation of IPv6 fragmentation in the IETF.
On
the other hand there are voices arguing that fragmented IPv6 packets will be
needed in some cases, namely DNS[SEC]-related ones.
In this post I will discuss some details of this debate (taking place in many
circles, incl.
this thread
on the ipv6-hackers mailing list which, btw,
you should subscribe to).
For that purpose let’s dig right into the intricacies of DNS. Once a client (for
the protocol: this can also be a “DNS server” which then operates recursively,
that is querying other – usually “authoritative” – servers for information/DNS
records) performs a lookup operation, it has two choices as for the transport
protocol: UDP or TCP. Going over UDP is considered as the default approach, not
least because this is what the initial DNS specification
(RFC 1035) suggests. As of the same
RFC the response usually was expected not to exceed 512 bytes. Once it does
(e.g. in case of a zone transfer), TCP was to be used.
However, as of subsequent specifications, the client can additionally signal
that it supports certain extensions, the most important (for our discussion) of
which is EDNS0 (RFC 6891). By using
this option the client indicates it is capable and willing to get back a
response which exceeds the traditional 512 byte size of UDP based responses,
together with an actual value (of bytes).
Common values for the “UDP payload size” (which I’ll also call just “buffer
[size]” in the following) are in the 1280 to 1410 byte range (for reasons to
be found below, see also RFC 6891, sect. 6.2.3.: “Choosing between 1280 and 1410
bytes for IP (v4 or v6) over Ethernet would be reasonable.”), or 4096 (which is
generally supposed to fulfill all length needs induced by DNSSEC, see also the
“DNS Response Size Considerations” section in
this document).
As of the (current interpretation) of the relevant specs a client is also allowed to use TCP from the beginning, but in practice this does not happen very often, for several reasons not to be discussed at the moment.
Now let’s have a quick look at some aspects of potential behavior on the server side. Here, the main flag that a server has available to “signal sth” in direction of the client is the “truncated response” [TC] flag which indicates that the requested information could not be fit into the client’s buffer size (512 bytes in case EDNS0 is not set, $BUFFER once EDNS0 is used). Using TC essentially says: “dear client, the capabilities you offer are insufficient for using UDP for our communication, so please use TCP instead”.
Furthermore, for our discussion we have to keep in mind that middleboxes (e.g.
firewalls) can come into play, in particular as I’ll focus on enterprise
networks.
Mainly, these middleboxes can perform one or several of the following things
(for more potential failure cases see
here):
- do not allow DNS over TCP (I’ve seen this a lot 10-15 years ago but from my observations this is quite uncommon nowadays, in enterprise space).
- do not allow DNS “with options”, namely/including EDNS0. Again, this can/could be seen here+there but I do not consider this very common in our customer networks today either.
- drop DNS over UDP packets larger than 512 bytes. Once more, I’m not aware of many firewalls currently doing this.
- drop all fragments (well, this is in the middle of the debate 😉 and apparently this happens in quite some cases, see the measurement results in this paper. At this point it might further be noteworthy that, in the context of DNS, fragmentation itself might be the source of specific attacks as Amir Herzberg and Haya Shulman laid out in their “Fragmentation Considered Poisonous” paper, see also subsequent discussion on the dns-operations mailing list).
Last but not least there’s another factor to be considered: given UDP – in contrast to TCP – does not provide a way of segmenting traffic (which TCP actually can, based on the MSS) it has to use IP layer fragmentation once a datagram size exceeds the (local) link’s MTU. This behavior is, again, in the heart of our debate here.
Looking at the overall picture, in real life the most common cases might be the following:
Case 1: Server receives query (over UDP without EDNS0 set) which can be
answered within 512 bytes: send response over UDP, all good.
Case 2: Server receives query (over UDP without EDNS0 set) which can not be
answered within 512 bytes: respond with TC=1, and hope client will come back
using TCP (which may or may not work, depending on $MIDDLEBOXES).
Case 3: Server receives query (over UDP with EDNS0 set), but the response does not fit into client-signaled buffer: respond with TC=1, and hope client will come back using TCP (if that works, see above).
Case 4: Server receives query (over UDP with EDNS0 set), the response fits
into client-signaled $BUFFER and the response is smaller than local MTU: send
response in a single UDP packet, all good.
Case 5: Server receives query (over UDP with EDNS0 set), the response fits
into client-signaled $BUFFER but the response _is bigger_ than MTU: send
response in several fragments (which may or may not make it through to the
client, depending on $MIDDLEBOXES). Please keep in mind though that quite some
clients already avoid that scenario as they just signal $BUFFER sizes below
1500 (about 30% of queries with EDNS0 set,
as of this source).
Case 6: Server receives query over TCP and responds, using several segments if needed.
Thinking about a client’s options in the “Case 5” scenario – there’s actually mostly (an easy) one, that is sending the query via TCP. There’s a fair chance this one
- actually gets through $MIDDLEBOXES.
- is processed by the server (Standards Track RFC 5966 “DNS Transport over TCP – Implementation Requirements” comes to mind).
- the response datagrams get back to the client (as now it’s TCP segments as opposed to IP fragments).
You may (rightfully) tempted to ask: what’s the point then at all? Actually
there’s one caveat, that is potentially increased load on the DNS server
processing the query, given TCP requires more resources than UDP.
In the end of the day we have a classic tragedy of the commons situation here:
individual organizations (dropping IPv6 fragments at their network borders)
increase their own security posture by implementing a measure which in turn
increases the load on systems providing Internet infrastructure services. Are
those prepared to handle the additional load? You bet, they better are (while
there are DNS-savvy people who think that
“most people are capable of writing the one-line perl script that will put a dns responder into tcp exhaustion“.
I don’t expect that though).
Let me summarize:
- in the vast majority of situations the above “Case 5” will not happen at all, for one reason or another.
- in cases where it happens client-side TCP fallback will solve the problem, admittedly at the expense of some additional CPU cycles/bytes in memory used on some servers. Trying to be a good netizen, can this be considered a reasonable risk-reward situation? Yes, I think so.
- pursuing a mid-term strategy of (only) using DNS over TCP might be a good idea anyway, for obvious reasons.
To further conclude I’d like to point our readers to the (as usual: very sound)
study Geoff Huston recently performed on
“Measuring DNS Behaviour“,
involving several millions of queries for DNSSEC (read: large) records. In their
conclusion he states:
“the number of users who are unable to resolve a DNS name when DNS responses of
this size are involved appear to be no more than 1% of all users, and likely to
be significantly lower.”
So, just maybe, from an end-user perspective, there is not even a problem…
In any case we see no reason to deviate from our advice to drop all IPv6
fragments at network borders of enterprise networks, and we’ll happily discuss
the implications here (by means of comments) or on other channels ;-).
Thank you for reading so far, everybody have a great day
Enno