Can a port be re-used before TIME-WAIT expires?
In a TCP conversation, the communicating peers use port numbers to communicate with each other. The way they uniquely identify the sessions is with a four tuple (Source IP address, Source Port, Destination IP address, Destination Port). The four tuple represents a unique socket over which full duplex communication works between the communicating peers.
From connection initiation to connection closure the socket transitions through different states. They are: LISTENING, SYN-SEND, SYN-RECEIVED, ESTABLISHED, FIN-WAIT1, FIN-WAIT2, LAST-ACK, CLOSING, CLOSED, TIME-WAIT, and CLOSE-WAIT.
All these socket states and their transitions are explained in the socket state diagram available on page 22 of RFC793: http://www.faqs.org/rfcs/rfc793.html
In the socket communication, the peer who initiates the FIN transitions through FIN-WAIT1, FIN-WAIT2 and TIME-WAIT. Once the socket is in TIME-WAIT, it waits for 2MSL (http://msdn.microsoft.com/en-us/library/ms819739.aspx). When the socket is in TIME-WAIT state, the socket is not used.
In a situation where the server side socket goes to a TIME-WAIT state and the client reconnects to the server within 2MSL (default TIME-WAIT time), there are 2 things that can happen:
- The server will not respond to the SYN packets from the client because the socket is in the TIME-WAIT state.
- The server may accept the SYN from the client and change the state of the socket from TIME-WAIT to ESTABLISHED. This is known as TIME-WAIT assassination, or incarnation of a previous connection.
The key to scenario ‘2’ above is that the ISN (Initial Sequence number) of the SYN sent needs to be higher than the highest sequence number used in the previous session. If the ISN is not as expected, the server will not respond to the SYN and the socket will wait for 2MSL before being available for use again.
Microsoft’s TCP/IP implementation employs this functionality. This feature allows the use of the available socket more quickly and increases performance. This is explained in RFC 1122 – Requirements for Internet Hosts – Communication Layers on Page 87: http://tools.ietf.org/html/rfc1122#page-87
Here’s a snippet from the RFC:
TCP TIME-WAIT Assassination works very well between Windows systems and may not work as expected when Windows is communicating with hosts running other TCP/IP implementations. RFC1337, Hazards of TIME-WAIT Assassination, discusses possible pitfalls: http://tools.ietf.org/rfc/rfc1337.txt
To demonstrate how TCP TIME-WAIT Assassination works, I used a tool on a Windows 7 system that always uses the same source port to connect to an IIS server running Windows server 2003 Standard Edition with Service Pack 2. I used Network Monitor to capture a network trace of this behavior. It is worth noting that the TCPTimedWaitDelay registry entry has not been changed from its default.
In the below trace:
- F-no= Frame no
- C = Client
- S= Server
- SRC= Source
- DEST= Destination
- SEQ-no= Sequence Number
- ACK-NO= Acknowledgement number
- The highlighted frames above show the source port 55000 and destination port 80 being re-used.
- The client reconnects to the same server within 664ms and the server accepts the connection.
- All Sequence numbers in the SYN packets are higher than the previous sequence number.
- Since the server initiated a closure, the server side socket goes into the TIME-WAIT state.
- If the TIME-WAIT Assassination was not working then the server would not accept the connection within such a short period.
With this article I have tried to explain how TCP TIME-WAIT assassination is implemented in Windows and how it is useful in situations where an application requires re-using the same source port immediately after it has been gracefully closed. If you have any questions on this or related to this then please feel free to post it and I will try to answer it.
– Kapil Thacker