Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent TCP socket connection retries

How can I prevent TCP from making multiple socket connection attempts?

Background

I'm trying to get a rough estimate of the round-trip-time to a client. The high-level protocol I have to work with gives no way to determine the RTT, nor does it have any sort of no-op reqeust/response flow. So, I'm attempting to get information directly from the lower layers. In particular, I know that the client will actively reject TCP connection attempts on a particular port.

Me -> Client: SYN
Client -> Me: ACK, RST

Code

  long lStartTime = System.nanoTime() / 1000000;
  long lEndTime;

  // Attempt to connect to the remote party.  We don't mind whether this
  // succeeds or fails.
  try
  {
    // Connect to the remote system.
    lSocket.connect(mTarget, MAX_PING_TIME_MS);

    // Record the end time.
    lEndTime = System.nanoTime() / 1000000;

    // Close the socket.
    lSocket.close();
  }
  catch (SocketTimeoutException|IOException lEx)
  {
    lEndTime = System.nanoTime() / 1000000;
  }

  // Calculate the interval.
  lInterval = lEndTime - lStartTime;
  System.out.println("Interval = " + lInterval);

Problem

Using Wireshark, I see that the call to lSocket.connect makes three (failed) attempts to connect the socket before giving up - with an apparently arbitrary inter-attempt interval (often ~300ms).

Me -> Client: SYN
Client -> Me: ACK, RST
Me -> Client: SYN
Client -> Me: ACK, RST
Me -> Client: SYN
Client -> Me: ACK, RST

Question

Is there any way to make TCP give up after a single SYN/RST pair?

I've looked through some of the Java code. I wondered if I was on to a winner when the comment on AbstractPlainSocketImpl said...

/**
 * The workhorse of the connection operation.  Tries several times to
 * establish a connection to the given <host, port>.  If unsuccessful,
 * throws an IOException indicating what went wrong.
 */

...but sadly there's no evidence of looping/retries in that function or any of the other (non-native) functions that I've looked at.

Where does this retry behaviour actually come from? And how can it be controlled?

Alternatives

I may also be open to alternatives, but not...

  • Using ICMP echo requests (pings). I know that many clients won't respond to them.
  • Using raw sockets. One of the platforms is Windows, which these days severely limits the ability to use raw sockets. (I also think the Linux network stack jumps in unhelpfully if it's caught in the cross-fire of an application trying to use a raw socket to do TCP.)
  • Using the JNI, except as a last resort. My code needs to work on at least 2 very different operating systems.
like image 410
Andrew Rose Avatar asked Mar 14 '14 22:03

Andrew Rose


1 Answers

TCP connect retries are a function of the OS's socket implementation. Configuring this depends on the platform. See https://security.stackexchange.com/questions/34607/why-is-the-server-returning-3-syn-ack-packets-during-a-syn-scan for a description of what this is and why it is happening.

On Windows, you should be able to modify the retry count in the registry:

  • HKLM\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\TcpMaxConnectRetransmissions

Settings related to the RTT are detailed in that documentation as well.

On Linux, the accepted answer in the linked Security post talks about how to configure this parameter:

On a Linux system, see the special files in /proc/sys/net/ipv4/ called tcp_syn_retries and tcp_synack_retries: they contain the number of times the kernel would emit SYN (respectively SYN+ACK) on a given connection ... this is as simple as echo 3 > tcp_synack_retries ...

Note that this is a system-wide setting.

You can read the current values by reading the registry settings (on Windows) or reading the contents of the special files (on Linux).

Also, MSDN has this to say about the TCP connect RTT on Windows:

TCP/IP adjusts the frequency of retransmissions over time. The delay between the original transmission and the first retransmission for each interface is determined by the value of the TcpInitialRTT entry. By default, it is three seconds. This delay doubles after each attempt. After the final attempt, TCP/IP waits for an interval equal to double the last delay, and then it abandons the connection request.

By the way, re: raw sockets - Yes, you would have an extremely difficult time. Also, as of Windows XP SP2, Windows won't actually let you specify TCP protocol numbers for raw sockets under any circumstances (see Limitations).

Also, as an aside: Make sure that the TCP connection is not being blocked by a separate firewall in front of the client, otherwise you only end up measuring round trip time to the firewall.

like image 167
Jason C Avatar answered Oct 15 '22 05:10

Jason C