In what cases do we need TCP packet analysis?
In practice, modern network traffic analysis systems have an extensive database of protocols and ready-made templates for software. This makes it easy to break down transactions into logical parts. Unfortunately, not all business tasks can be solved using mass-produced products, and in every company, there will always be a couple of ‘homemade’ or customized applications. How do you analyze traffic from such applications?
The traffic analyzer’s database does not have information about which bit contains the request code, which code corresponds to the response, etc. In such situations, you have to resort to the basics of network science – TCP analysis. Let’s see what this protocol contains.
TCP is, essentially, a transport layer protocol. It allows establishing a connection between one socket (IP address + port) of the source host and a socket of the destination host. The IP header contains information related to IP addresses, while the TCP header contains information about the port.
TCP Header
TCP headers move through the network to establish, maintain, and terminate TCP connections, as well as to transmit data.
The TCP header contains the following fields:
- Source port (16 bits): The source port is the host’s port from which the request originates.
- Destination port (16 bits): The destination port is the port of the host to which the request is sent.
- Sequence number, SYN (32 bits): The sequence number allows controlling the order of messages.
Each endpoint (source and destination ports) will maintain its unique sequence number for sent messages. When establishing a TCP connection (using a statement with the SYN flag set), an initial sequence number is generated.
It’s not entirely random but contains a specific 32-bit number, ranging from 0 to 4,294,967,295 (or 2 to the power of 32 possible values).
This number corresponds to the time elapsed since the sender system was last rebooted (increased by 1 for every 4 microseconds passed) and is incremented by 64,000 each time a new connection is established.
Since the generated number will be unique for nearly five hours (assuming no connections were established during this time), this approach to selecting sequence numbers avoids random collisions when transmitting data, where multiple packets from different connections might have the same sequence number. Subsequently, when sending subsequent packets, the sequence number value increases by +1 for all packets with the SYN flag, packets with the FIN flag, and for each byte of sent data. This allows the receiving system to process packets in the correct order as they were formed at the sender’s end, rather than in the order they were received. - Acknowledgment number, ACK (32 bits): The acknowledgment number, when a message contains the ACK flag, should correspond to the next sequence number (SYN) that the ACK flag message sender expects to receive from the transmitting system. Thus, sending a single acknowledgment number is capable of confirming the receipt of all bytes of received information up to that point.
- Data offset (4 bits): The data offset, also known as data offset, contains the size of the TCP header, measured in 32-bit segments. The minimum size of the TCP header is five 32-bit segments (a total of 20 bytes), and the maximum is fifteen 32-bit segments (or 60 bytes).
- Reserved (3 bits): Reserved for future use, currently simply filled with zeros. Now, three unused bits remain, while three previously reserved bits are already used as flags.
- Flags (9 bits, flags, or control bits):
NS (1 bit): Nonce Sum. Used to improve the operation of Explicit Congestion Notification (ECN).
CWR (1 bit): Congestion Window Reduced. The sender sets this flag to indicate that a TCP segment was received with the ECE (ECN Congestion Experienced) fieldset. It confirms the receipt of a data packet with the ECE flag from the receiving host. It enables the sender’s Congestion Control mechanism, optimizing the transmission of data packets in congested networks to avoid significant delays caused by packet dropping.
ECE (1 bit): ECN Echo. It serves a dual role depending on the SYN flag’s value. If the SYN flag is set, it indicates that the packet sender supports ECN. If the SYN flag is cleared (SYN=0), and ECE is set, it means that a packet with the CE (Congestion Experienced) flag set was received in the IP header during regular transmission. It serves as an indicator of network congestion (or impending congestion) to the TCP sender.
URG (1 bit): Set if an urgent pointer field is used.
ACK (1 bit): Set when the packet contains an acknowledgment number in the acknowledgment field. All packets after the initial SYN packet will have the ACK flag set.
PSH (1 bit): Makes this packet a PUSH packet. In a typical data transfer flow, the receiving system doesn’t acknowledge the receipt of each packet immediately after receiving it. Instead, the receiving system collects and stores the received data in a buffer for some time until it forwards it to the user’s application. The PUSH packet instructs the receiving system to immediately deliver all previously received data from the buffer to the user’s application and send an acknowledgment.
RST (1 bit): Reset this connection. Sending a packet with the RST flag set informs the immediate termination of the connection. The connection is terminated, and the buffer is cleared. The most common reasons for sending a packet with the RST flag set are in response to a packet received for a closed socket, the user voluntarily terminating the connection (e.g., closing the browser without waiting for a response), or the connection wasn’t properly closed but remained inactive for some time.
SYN (1 bit): Initiates a connection and synchronizes sequence numbers. The first packet sent from each side must have this flag set.
FIN (1 bit): One of the endpoints sends a packet with the FIN flag set to the other endpoint to indicate that all packets have been sent and the connection should be terminated. - Window size (16 bits): The window size indicates the number of bytes of data, starting from the last acknowledgment number, that the sender of this packet is ready to receive. In other words, the sender of this packet informs the other side about the currently available buffer size for receiving data.
- Checksum (16 bits): The checksum is used to check for errors during transmission and/or reception of the sent packet. It is calculated based on the header (all header fields except the checksum itself), the payload (non-service data with the actual information being transmitted), and a pseudo-header (source IP address, destination IP address, protocol number, and TCP segment length, which accounts for both the header and payload lengths).
- Urgent pointer (16 bits): If the URG flag is set, it means that the urgent pointer field contains a numerical value indicating a positive offset from the sequence number in the message, pointing to the last byte of urgent data. After receiving a TCP segment with the URG flag set to ‘1’, the receiving device looks at the urgent pointer field’s value to determine which data in the segment is considered urgent. These urgent data are immediately forwarded to the user’s application, indicating that the sender has marked the data as urgent. The remaining data in the segment, as well as any accumulated data in the receive buffer, are processed in the normal way. This handling of the URG flag in a message differs from the handling of the PSH flag, where, upon receiving it, all data from the buffer, not just the urgent data from the message, is immediately sent to the user’s application.
TCP Message Transmission Mechanism
Before data can be exchanged between two nodes in TCP, unlike UDP, there is a connection establishment stage. Additionally, after all data has been transmitted, there is a connection termination stage. Thus, the execution of each TCP connection can be conditionally divided into three phases:
Connection Initialization
The connection is established using what’s called a TCP three-way handshake. Either party can initiate the connection, but for the sake of simplicity in this article, let’s consider an example where the client initiates a connection with the server.
- Packet #1: The client sends a packet with the SYN flag set and a random number (“R1”) included in the sequence number field.
- Packet #2: Upon receiving packet #1, the server responds with a packet containing the SYN flag set and the ACK flag set. The sequence number field will contain a new random number (“R2”), and the acknowledgment number field will contain the client’s sequence number value incremented by one (i.e., “R1 + 1”). This means it corresponds to the next sequence number that the server expects to receive from the client.
- Packet #3: In response to the SYN packet from the server (packet #2), the client sends a packet with the ACK flag set and an acknowledgment number field value of “R2 + 1.” Similarly, this number corresponds to the next sequence number the client expects to receive from the server.
Data Transmission
After the connection is initialized, the payload (useful data) will flow in both directions of the TCP connection. All packets must include the ACK flag. Other flags, such as PSH or URG, may or may not be set.
Connection Termination
There is no “keep-alive” message type at the TCP level. Therefore, even if a connection becomes inactive at some point, it will continue until the next packet is sent.
In cases where we send an HTTP request over the network, we need to establish a TCP connection immediately. However, in HTTP 1.0, the ability to reuse connections is disabled by default (unless the “keep-alive = close” header is explicitly included in the HTTP header).
This means the TCP connection is automatically closed after receiving the request and sending the response. Since establishing a TCP connection is relatively resource-intensive (it requires additional processor and memory resources and increases network traffic between the server and client, which becomes particularly relevant in secure connections), this leads to increased latency and network congestion. Therefore, in HTTP 1.1, it was decided to keep TCP connections open until one of the parties decides to terminate it.
On the other hand, if connections are not closed after clients receive all the data they need, the server’s resources used to maintain these connections will not be available to other clients. Thus, HTTP servers use timeout intervals to support “keep-alive” functionality for inactive links (which typically lasts only a few seconds, depending on the server’s architecture and configuration), as well as a maximum number of “keep-alive” requests before a session without an active connection is stopped.