Re: [tcpm] Faster application handshakes with SYN/ACK payloads

Joe Touch <touch@ISI.EDU> Sun, 03 August 2008 13:26 UTC

Return-Path: <>
Received: from [] (localhost []) by (Postfix) with ESMTP id 623AF3A6A71; Sun, 3 Aug 2008 06:26:35 -0700 (PDT)
Received: from localhost (localhost []) by (Postfix) with ESMTP id B2E533A6A71 for <>; Sun, 3 Aug 2008 06:26:33 -0700 (PDT)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: 1.389
X-Spam-Level: *
X-Spam-Status: No, score=1.389 tagged_above=-999 required=5 tests=[BAYES_00=-2.599, FRT_STOCK2=3.988]
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id nRFYjW-1dxG7 for <>; Sun, 3 Aug 2008 06:26:32 -0700 (PDT)
Received: from ( []) by (Postfix) with ESMTP id BDCE03A63D3 for <>; Sun, 3 Aug 2008 06:26:32 -0700 (PDT)
Received: from [] ( []) by (8.13.8/8.13.8) with ESMTP id m73DQk0L006469 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NOT); Sun, 3 Aug 2008 06:26:49 -0700 (PDT)
Message-ID: <>
Date: Sun, 03 Aug 2008 06:26:08 -0700
From: Joe Touch <touch@ISI.EDU>
User-Agent: Thunderbird (Windows/20080708)
MIME-Version: 1.0
To: Adam Langley <>
References: <> <> <> <> <>
In-Reply-To: <>
X-Enigmail-Version: 0.95.6
X-ISI-4-43-8-MailScanner: Found to be clean
Subject: Re: [tcpm] Faster application handshakes with SYN/ACK payloads
X-Mailman-Version: 2.1.9
Precedence: list
List-Id: TCP Maintenance and Minor Extensions Working Group <>
List-Unsubscribe: <>, <>
List-Archive: <>
List-Post: <>
List-Help: <>
List-Subscribe: <>, <>
Content-Transfer-Encoding: 7bit
Content-Type: text/plain; charset="us-ascii"; Format="flowed"

Hash: SHA1

Hi, Adam,

Again, popping up a level, you've made a good case for a socket option
that lets the server app signal its TCP to try to send data in the
SYNACK. TCPs that do this will; TCPs that don't will fail on the socket
option, and the server will know.

I am unclear why the client TCP is involved in this; if the data is
sent, it will either be acknowledged or retransmitted. There is no
change to the semantics, and only a change to timing (which NOTHING in
TCP ensures anyway).

As a minor note, it doesn't seem useful to extend that socket option to
say how much data to put in the SYNACK; nothing else in TCP knows about
application data boundaries, and I think it would be a mistake to assume
that. You might add something like:

	setsockopt(SEND_SA_DATA, bytecount)

	bytecount = number of data bytes the app is *suggesting*
	the SA include; this is NOT guaranteed to be enforced
	by TCP

if the sockopt succeeds, the app should reasonably assume that bytecount
bytes are sent in the SYNACK if available when the SYNACK is sent

As a final question (I'm not a sockets expert), it might be that there
are other socket modifications to allow users to write to connections
that are not yet open (or can they just be queued up? in which case, it
seems like the socket must be completely bound, i.e., this might not
work for unbound LISTENs).

Specific notes below...


Adam Langley wrote:
| Thanks for your detailed response, I fear that there's a
| misunderstanding somewhere and that's almost certainly the fault of my
| inadequate writeups. Please let me try again:
| At the moment, almost no stacks will send payloads in the SYNACK even
| though they could as an optimisation. This springs from a few reasons:
|   R1) Processing time for a SYN must be minimal to mitigate the
| effects of SYN floods. Even waking up an application to process a SYN
| would greatly increase the costs.
|   R2) Replies to SYNs must be small, otherwise it provides a way to
| amplify a DDoS attacks using false source IP addresses.
|   R3) The ubiquitous sockets API doesn't make it easy to do so.

This sounds like a really good reason to extend the API to have a flag
that allows the server app to ask its TCP to send data in the SYN-ACK if
possible. That sounds consistent with the overall TCP model, AFAICT.

I see no good way to have the application tell TCP how many bytes to
send, or to have TCP tell the app this. That is an API change that lets
the app know about segment boundaries, and that's inconsistent with
TCP's API semantics.

| I'm proposing that a constant payload (optionally with 8 random bytes)
| overcomes R1 and R3. And limiting the size of that payload to 64 bytes
| overcomes R2.

I don't understand the "8 random bytes" issue; the data path should be
sending data from the app only, and that's not random.

| There are protocols that could immediately benefit from a gradual
| deployment of hosts which supported a setsockopt to set a constant
| payload and hosts that would ACK and enqueue such a payload.

The sockopt sounds OK - but I'm not too sure about knowing the payload
boundaries at the app layer. Again, that is inconsistent with TCP
presenting a stream model.

~ > Additionally, this would also be easy to deploy. For clients that
| don't support it, they will ACK only the SYN flag and then the server
| knows to include the payload again in the next frame.


| However, the sockets API has guided the design of many application
| level protocols. Because of this, these protocols are often designed
| such that
|   * The client starts the exchange: see HTTP
|   * The exchange is large, since there's little space pressure: SSH
| algorithm agreement uses strings like "diffie-hellman-group14-sha1"
| (28 bytes) because of this.


| Modifications to take advantage of SYNACK payloads would then require
| changes to the application level protocol. This could be managed by
| assigning new ports, trying connections on the new ports first,
| backing off etc. However, given that this is a partly a latency
| optimisation, that's an anathema.

I don't see this at all. Apps don't need any modification, other than to
set the "send data early in the SYNACK" flag. That can be set by default
on a per-port basis, or set within the app directly.

| So I additionally define an option that the application layer can set
| and query that advertises support for this trick and allows many more
| application level protocols to take advantage of it.

***this is the big question***

Why do you need an option that does this? Seems like the app can always
TRY to do it, and the data just gets retransmitted if dropped (i.e., not
supported at the receiver).

|> (side note) Such an option might be useful, but might also be an issue.
|> It tests the fact that TCPs ignore unknown options, a test that might
|> fail. It also tests the fact that middleboxes should pass options
|> unmodified, which also might fail.
| Because of this, I wanted to make sure that clients were free to retry
| a connection without the option in the case that something was
| reacting badly to it.

Wouldn't it be simpler to do this without an option at all, then?
Version: GnuPG v1.4.9 (MingW32)
Comment: Using GnuPG with Mozilla -

tcpm mailing list