Subject: Re: [dnsext] EDNS Page Option to handle large responses

From: Michael Graff <[email-masked]>
Date: Thu, 18 Jun 2009 14:17:18 -0500

Dean Anderson wrote:

>> The worst possible attack are otherwise valid queries.  The worst
>> possible transport is TCP due to the high cost of maintaining a TCP
>> endpoint on a server.  One is cheap, 50,000 are not.
> 
> Ah. Well, scalability is always hard. That doesn't make it a DDoS 
> attack.  50,000 UDP queries per second is hard, too. In fact, just about 
> about as hard as 50,000 TCP queries.

Very true.  however, a DDoS using TCP would use significantly more
resources on the auth server than a UDP attack would.

UDP is more or less "fire and forget."  TCP requires buffers in the
kernel and state tracking in the kernel.  For a stateless protocol like
DNS, it is scary to start relying on state stored somewhere.

> Simulation is unnecessary as the math is simple: TCP takes 5 packets to
> setup and shutdown a connection. UDP takes 2.

If you count packets, sure.  If you consider kernel state, firewall/load
balancing filtering state that must be maintained, etc. it gets quite
complicated quite fast, and every situation will be slightly different.

It's not about packets to me.  Packets, even 3x as many, is well
understood.  It's about load on the server infrastructure itself that
worries me.  You can only add so many machines before it's clear
something is not sanely scalable.

- --Michael

--
to unsubscribe send a message to [email-masked] with
the word 'unsubscribe' in a single line as the message text body.
archive: <http://ops.ietf.org/lists/namedroppers/>

---

From: Matthew Dempsky <[email-masked]>
Date: Thu, 18 Jun 2009 12:54:54 -0700

> DNS, it is scary to start relying on state stored somewhere.

For a protocol like DNS, couldn't we eliminate all state on the
server?  If the server uses TCP syn-cookies, there's no state to keep
between the server's SYN-ACK response and the client's subsequent ACK;
if the client only sends one DNS query per TCP session and includes
that query in its initial ACK packet, then the server can immediately
start answering the query, writing the response the same as it would
for UDP.  I'm not sure what to do about the FIN/ACK handshakes, but I
suspect that can be handled somehow, and worst case I don't think
sending RSTs would have any negative consequences here.  Servers could
continue supporting some finite number of stateful TCP connections
like they do now to handle old client behavior.

I'm pretty sure this would require new functionality in the server's
TCP stack and probably the DNS server.  For clients to benefit from
this, they would also have to make sure to pack the query into the ACK
packet (I thought I read that Linux's TCP stack already supports this,
but I can't find anything on it right now).

---

From: Michael Graff <[email-masked]>
Date: Thu, 18 Jun 2009 15:08:16 -0500

> like they do now to handle old client behavior.

Are you proposing that we tweak TCP in order to serve DNS data?  :)

Until you get an ACK from the remote end, you have to hold data in a
local buffer.  That is the sort of state I mean when I say "state."  We
might be able to make that state very, very small by limiting the socket
buffer space to 4k or so, but this is getting pretty tricky and, worse,
I suspect every OS will still have vastly different overhead.  Even in
the best situation, TCP is higher overhead when talking to a large
number of endpoints than UDP, and solutions which require a lot of state
to be retained in the kernel scare me.

SCTP seems workable if it can be used in an unreliable mode.  It will
still require some in-kernel state per endpoint, but that state seems
easy to spec for in terms of memory/descriptor limits.  Not that any of
this is easy; part of the problem is we're trying to work around a IP
datagram issue by using IP datagrams and all the tricks we've added to
IP in the last 15 years.  At the end of the day, it's not that much
different than what Bittorrent users did to work around filtering based
on content, that is to hide the content in various ways.

> but I can't find anything on it right now).

HTTP got away with this sort of thing, and it has been useful for other
protocols as well.  Handling the HTTP headers in the kernel was a major
boost to avoid one additional kernel/userland crossing, as was "don't
bother me until you receive X bytes," for instance.  However, I'm not
certain beyond that mechanism how far we could push for TCP stack
changes even on the limited number of platforms authority servers run
on.  I personally don't think that is a path to follow.

- --Michael

---

From: Matthew Dempsky <[email-masked]>
Date: Thu, 18 Jun 2009 13:28:53 -0700

[Resending because IETF's mailing list software likes to
intermittently reject mail from gmail's servers.]

> Are you proposing that we tweak TCP in order to serve DNS data?  :)

Does setting DF=1 when sending UDP packets count as "tweaking" UDP?
(I'm interpreting "tweak TCP" to mean alter the TCP protocol, but
perhaps you just mean alter DNS's usage of it.)

I'm just pointing out it's possible to serve DNS over TCP without
requiring the server to keep any more state than it would for serving
DNS over UDP and without requiring any TCP protocol changes.

> local buffer.

Only if you want to resend the query at the TCP level.  The kernel
could throw away that state and close the session if it's pressed for
memory, and then the client can repeat its query.

You won't have any more guarantee of getting a response than you would
with UDP, but the response is more likely to reach the client than a
fragmented UDP response, and each TCP segment will include entropy
from the source port and sequence numbers, so blind attackers will not
be able to spoof parts of large responses.

---

From: Michael Graff <[email-masked]>
Date: Thu, 18 Jun 2009 15:31:21 -0500

> DNS over UDP and without requiring any TCP protocol changes.

I don't agree.  When you send data with TCP, you must await the remote
end's ACK of it before discarding it from your send buffer.  That's
state, and I don't see how it can be avoided with TCP.  It's a
fundamental property of TCP, and not doing that would mean it's not TCP
anymore.

> memory, and then the client can repeat its query.

Not if it is still called TCP.  What you are proposing sounds a lot like
SCTP with unreliable transmission though.

- --Michael

---

From: Nicholas Weaver <[email-masked]>
Date: Thu, 18 Jun 2009 13:52:19 -0700

On Jun 18, 2009, at 1:31 PM, Michael Graff wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Matthew Dempsky wrote:
>

For DNS if you are willing to do it in the kernel, probably not,  
because you can play SYN-cookie like games, and your response has the  
ACK, so if the response is dropped, the sender will retransmit the  
query.

> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.8 (Darwin)
> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
>
> iEYEARECAAYFAko6pBkACgkQ+NNi0s9NRJ3tQACeIvAsZrlr3OI2UzrKaSA5hGKm
> EdAAnR5DKKSyWYPzUszSXQITL6p+QcD3
> =VyTT
> -----END PGP SIGNATURE-----
>
> --

---

From: Michael Graff <[email-masked]>
Date: Thu, 18 Jun 2009 16:04:52 -0500

Nicholas Weaver wrote:
> For DNS if you are willing to do it in the kernel, probably not, because
> you can play SYN-cookie like games, and your response has the ACK, so if
> the response is dropped, the sender will retransmit the query.

You can optimize the connection phase, and perhaps even the disconnect.
You could even say that a buffer on a client is not a big deal (although
on recursive servers, I'd disagree there too) or just a matter of scaling.

You cannot do away with in-kernel retransmit buffers on any general
purpose OS like NetBSD, FreeBSD, SunOS, etc.  They are part of TCP, and
while you can make them very small, you must have them.  Making them
smaller than the data you are sending as a response is also less than
useful.

Getting rid of them on the sender or receiver means you're just pushing
remembering that up to the application, or making something that is not TCP.

- --Michael

---

From: Nicholas Weaver <[email-masked]>
Date: Thu, 18 Jun 2009 14:18:43 -0700

On Jun 18, 2009, at 2:04 PM, Michael Graff wrote:

>> because

I disagree:  For DNS (and DNS ONLY) you can do user-level TCP without  
needing a retransmit buffer, and as long as you have only a single  
query and for a particular IP/txid/port you respond deterministically:

You can use a syn-cookie type game so you don't need state for the ACK  
for the SYN-ACK.

For the response, you generate the response but don't increment the  
ACK field to ACK the request until the final packet, and for the final  
packet you send a FIN immediately (half-close the connection).

Thus:

Dpacket1, dpacket2, dpacket3, all do not ACK the query
FIN, which ACKs the query

Thus ANY packet loss will cause the sender to retransmit the query  
packet, which allows the server to regenerate what Dpacket, Dpacket2,  
dpacket3, FIN should be.

---

From: Michael Graff <[email-masked]>
Date: Thu, 18 Jun 2009 16:25:39 -0500

Nicholas Weaver wrote:
> For the response, you generate the response but don't increment the ACK
> field to ACK the request until the final packet, and for the final

If the packet were delayed, and you then transmit different data as a
response, what happens?  And if the client then gets two different
versions of the data, what happens?

I don't think tweaking TCP as a common practice in order to fix this is
a good, solid, scalable way forward.  TCP is what TCP is, and while
changing it for some cases might be a good idea, I don't think this is
one of them.

- --Michael

---

From: Nicholas Weaver <[email-masked]>
Date: Thu, 18 Jun 2009 14:29:24 -0700

On Jun 18, 2009, at 2:25 PM, Michael Graff wrote:

>> ACK

Clients usually happily accept the first one and go from there.  AFter  
all, packet injection attacks work on WiFi quite well.  :)

And who says that it has to be two different versions of the data: you  
can be deterministic for a particular IP/Port/ID three-tuple.

I don't necessarily think its a good idea, but it IS clear that, if  
actually desired, you could do "Stateless TCP" for DNS.