Transmission Control Protocol (TCP) is a connection oriented protocol. Before exchanging data between both sides, a connection is established. TCP Receive Window is a buffer on each side of the TCP connection that temporarily holds incoming data. The size of the window (buffer) is set during TCP 3-way handshaking and can be change later. The sending side can send only that amount of data before it must wait for an acknowledgment from the receiving side.
Assuming we have a TCP client and server application such as below. The client sends a request for a chunk of data and the server responses back. The figure below summarizes TCP receive window.
Step-1: The client sets a buffer for incoming data and advertises the size of the buffer (receive window) to the server.
Step-2: The server sends a chunk of data to the client for processing.
Step-3: The application on the client side processes the packets in the buffer and frees the buffer.
Step-4: The client advertises new buffer (receive window).
Investigating TCP Receive Window in an SSH Traffic
For sake of better understanding, we will capture some traffic between an SSH client and server. The topology will be like below. Both sides will be in the same subnet. I will use two Cisco routers to simulate the client and the server.
The Client Configuration
! hostname Client ! interface FastEthernet0/0 ip address 192.168.1.1 255.255.255.0 duplex full !
The Server Configuration
! hostname Server ! ip domain name test.local ! username celal privilege 15 secret 5 $1$ou9J$yau/b5wgo7C.Zc.Q3giVr. ! interface FastEthernet0/0 ip address 192.168.1.2 255.255.255.0 duplex full ! line vty 0 4 login local transport input ssh !
Step-1: After configuring both side for SSH successfully, start packet capturing between the client and the server.
Step-2: Initiate an SSH connection from the client to the server with “ssh -l celal 192.168.1.2” command and then enter the user’s password.
Step-3: Now, we have the TCP traffic. If you do not have the traffic file, you can download my pcap file from receive_window. As it is seen below, the packets belong to the SSH connection.
Step-4: For sake of simplicity, I will add two more columns. First, I will add “TCP Segment Len” column. Select a TCP packet and find “[TCP Segment Len: X]” field and right click. Next, click “Apply as Column”. Following figure summarizes the steps.
Select “Window:” filed and right click. Do the same steps for this column as well.
After adding both of the column, you should have the result like below.
Step-5: Select the first packet (TCP SYN) and expand the TCP header like below.
The client (192.168.1.1
) advertises it’s receive window (TCP buffer for incoming data) to the server with the size of 4128 bytes.
Step-6: Select the second packet, which is sent by the server to the client and expand the TCP header like below.
The server advertises the same size for the window. The client acknowledges the server with the packet number 3, which does not carry any data.
Step-7: Select packet number 4 and notice it carries 20 bytes of data (payload).
The packet is sent by the server, specifying the server can buffer 4128 bytes in it’s receive window.
Step-8: After receiving 20 bytes of data, the client stores that data in it’s buffer and sends a packet with size of 20 bytes. Remember the client advertised it’s window size as 4128 bytes at the start of the connection and now it is filled the buffer with 20 bytes. The client advertises new window size as 4128-20=4108
bytes. Following output shows the details.
Step-9: With packet number 6-11, client sends 5 packets of size 64 bytes and 1 packet of size 24 bytes. In short, it sends 5*64 +24=344
bytes.
Step-10: After receiving 344 bytes, the server responses back with packet number 12, which contains 344 bytes. When the server receives 344 bytes, it stores that data in the buffer with reducing empty buffer size to 4108-344=3764
bytes. Following figure shows the details.
Step-11: With packet number 13, the client does the same calculation and advertises it’s new window size to the server. The process follows the same patter again and again until one or both sides empties it’s buffer (receive buffer) and advertise a new window size.
TCP window scaling
When the TCP was designed, only 2 bytes reserved for window size, which can be maximum value of 65,535 bytes. Since this can limit some networks throughput, window scaling measure was introduced in RFC 1323. With this mechanism, the receiver is able to advertise a larger window as more resources are allocated for this connection. Basically, window scaling extends the 16-bit window field to 32 bits in length.
A TCP option is used to define window scaling. Both sides (client and server) negotiate window scaling during the establishment of the connection with the first two packets. Following screenshot shows that the client desires to use “window scale of 7
”, which means that window size will be multiplied by 2^7=128
.
Final thoughts
The TCP receive window size is the amount of receive data (in bytes) that can be buffered during a connection. The sending host can send only that amount of data before it must wait for an acknowledgment and window update from the receiving host.
TCP window is used for flow control, which ensures that sender won't overflow receiver's buffer by transmitting too much, too fast.
References
https://docs.microsoft.com/en-us/troubleshoot/windows-server/networking/description-tcp-features
https://www.networkdatapedia.com/post/2016/10/27/practical-tcp-series-the-tcp-window
https://web.eecs.umich.edu/~sugih/courses/eecs489/lectures/30-TCP-Flow+ARQ.pdf
https://packetlife.net/blog/2010/aug/4/tcp-windows-and-window-scaling/