In the last post, we have explained the TCP 3-way handshaking from an abstract point of view, and knew that one of the main functions of this handshaking is to exchange and synchronize some parameters for the TCP connection endpoints to facilitate its job.
We also knew that two of the main parameters that the end-points exchange in the TCP 3-way handshaking are the SEQUENCE and ACK numbers. Today, we will continue the 3-way handshaking process in more details.
Above is a TCP capture file which I downloaded from “Wireshark” wiki page that shows 3 packets in sequence between two end-hosts. From the figure we can conclude the following:
- These 3 consecutive packets belong to two end-hosts with IP addresses 192.168.1.104 that we will refer to as a client and 188.8.131.52 that we will refer to as server.
- One of the two hosts is a client (192.168.1.104) that initiated a TCP connection to an HTTP server (184.108.40.206), we can conclude it was an HTTP server from the fact that the destination TCP port was 80(HTTP) in the first packet.
The following sequence of events happens to the client creating the TCP connection:
- The user on the client machine has requested to open an HTTP page on a remote server.
- The client machine application-layer will send the HTTP request (as a stream of data, let’s say they are 10,000-bytes of data) to the kernel which will place them into a memory place called the “send buffer”. This memory allocation will be a place holder for any data stream received from the upper-layers.
- The kernel will call the TCP which will find these data stream from the “send buffer”, it will count them in bytes and mark them as (bytes not sent, and the recipient may be ready for it) using a pointer.
- In the other hand, TCP will also allocate another place in memory called the “receive buffer” in which it will receive data streams from the server over the network.
- The “receive buffer” is always limited, because memory is limited on this client, so TCP will set a parameter called “RWIN” or the “receive window”. This parameter will be sent into the TCP SYN packet and will simply tell the server how much data the server can send to the client without receiving an acknowledgement.
- The “RWIN” value will be lower than or equal to the “receive buffer” allocated. This makes sense, since the client will not be able to receive data stream from the server that cannot fit into its receive buffer allocated in memory.
- Now, the TCP has 10,000 of bytes into the “send buffer” which is ready to be sent over the network, but it doesn’t know, how much of those 10,000 bytes should be sent every time. For example, should the TCP send the whole stream on one segment immediately? Should it be divided into 2 segments, each with 5000 bytes and be sent one segment per second? This question can be answered with the MSS (Maximum Segment Size) that the TCP will also set in the TCP SYN packet.
- Maximum Segment Size is another value that will be sent into the SYN packet to inform the server that it needs to divide the data stream in its send buffer into fixed-size segments, and each of them will be of the MSS value.
- So, to recap; The client TCP will now send 3 parameters in its SYN packet to the server, the first one is the Initial Sequence Number (ISN), the second is the receive-window (RWIN) and the third is the maximum-segment-size (MSS). These 3 parameters combined will be stored as a data structure in the client system and will be called TCB or Transmission Control Block, which is analogous to the FIB table or any state table in the networking lingo.
- The transmission control block (TCB) maintain the state of every TCP connection, and it include the values of the receive and send buffers, the RWIN of the local system and the RWIN received from the remote server, the MSS of the local and remote server, the SEQ/ACK numbers of the local and the remote server and the re-transmission timer values that the local system has calculated. As I said, it’s a state table for the TCP connection that is created.
- TCP on the client will start building the socket, by searching for an unused TCP source port, here the client found source port 49859. It will create a socket with the source/destination IP addresses and TCP port numbers and append this socket to the TCB.
- Applying this on the example above; TCP on the client machine will send the TCP SYN packet to the server telling it that I will begin my counting of Sequence Numbers from the value 0, and you can send 8192 of bytes to me without me acknowledging them, and these bytes should be sent over segments, each will be of a 1440 bytes size.
- Once the socket is ready, TCP will send the TCP SYN packet, then transition the TCB state for this connection from being “CLOSED” to “SYN_SENT”. If you’re on windows, you can check this using “netstat -n”.
- TCP on the client will wait until it hears a TCP SYN/ACK packet from the server, negotiating its parameters.
Now, the following sequence of events would happen to the server accepting the TCP connection:
- The server will receive a TCP SYN packet over TCP port 80, and because it’s an HTTP server, port 80 is open. The server will allocate a “receive buffer” and set an RWIN value lower than or equal to the receive window. It also will allocate a “send buffer” and an MSS value. It will then use the source/destination IP addresses and TCP ports to build a socket for this connection and will append it with these parameters to a TCB state block.
- The TCB state for this connection will be “LISTEN”. Once the TCP process the SYN packet, it will transition to “SYN_RECEIVED”. The server will strip the SEQ number, RWIN and MSS values off the SYN packet and store them in the TCB state block for this connection.
- TCP will then reply with a TCP packet setting the SYN and ACK flags on. It will also send its Sequence Number, RWIN and MSS along.
- Applying this on the figure, we can see that the server sent back a TCP SYN/ACK packet with RWIN value of 5792 telling the client that this is the maximum amount of data I can accept without acknowledgement, and you can send these bytes divided into segments, each with 1440 bytes (MSS). The Sequence Number value is 0 and the ACK is 1.
Back to the client, the following sequence of events will happen:
- The client will receive a TCP packet over the socket, and because this socket is bound to a TCB state block, the client will take the “RWIN” and MSS values received from the SYN/ACK packet and will update its TCB with the server’s value.
- TCB will hold now the client own RWIN, MSS, Sequence number values and the neighbor RWIN, MSS and Sequence numbers. The TCP on the client will also calculate the route-trip time that it took the server to reply with an ACK packet, and will store this RTD value in the TCB state block.
- The last step is the client sending a TCP ACK packet. Right after sending the ACK packet, the TCB state will transition from “SYN_SENT” to “ESTABLISHED”.
- The server will receive the TCP ACK from the client, update the RWIN value of the client in the TCB state table, calculate the RTD that the client took to reply with an ACK packet and update its timers. The TCB state will transition from “SYN_RECEIVED” to “ESTABLISHED”
One important note to mention is that the SEQ/ACK numbers provided in this example and used by the Wireshark are relative. TCP implementations will never use an ISN with “0” value because of security concerns (mostly, the old TCP Sequence number prediction attack). Again, the real ISN might be any 32-bit number but not “0”.
The Wireshark is showing a parameter called “Calculated window size”, this is not a parameter which exists in the actual TCP header itself, and this is only a calculated value that the Wireshark is showing you (the user). Calculated window size and window scaling is another topic that will be discussed in further posts.
This is how things work behind the scene for TCP 3-way handshaking. However, these are abstract information, and the process involves many processes between the application stack, the kernel and the TCP stack, but I wanted to keep everything simple as it can be.
In the next post, I will explain the usage of the SEQ and ACK numbers used here, and how they increment to support a reliable delivery of data.
Thanks for your time.