Tuesday, October 14, 2025

Demystifying TCP Options

 Demystifying TCP Options and TCP/IP Fingerprinting

The TCP/IP protocol stack carries more information than just source, destination, and payload. Hidden within the TCP header, especially the TCP Options field, lies a rich set of parameters that describe how an operating system’s TCP stack behaves. These subtle patterns—like the order and values of TCP options—form a unique TCP/IP fingerprint, enabling us to identify the client’s OS or device type (Linux, Windows, Android, iOS, etc.) even without user-agent strings or active probes.

Understanding the TCP/IP Stack

The TCP/IP stack defines how data is transmitted over the internet, layer by layer:

  • IP layer: Handles addressing, routing, and fragmentation.
  • TCP layer: Ensures reliable, ordered delivery of packets using sequence numbers, acknowledgments, and flow control.
  • Application layer: Uses TCP sockets for protocols like HTTP, TLS, SMTP, etc.

Each OS implements its own version of the TCP/IP stack—with slightly different default configurations. These subtle differences, observable in packet headers, are what make fingerprinting possible.

When we say TCP/IP stack fingerprinting, we are examining the implementation details of the TCP/IP stack in the OS. Different OSes set defaults differently for TCP header fields, option ordering, and behavior (like how it handles TTL, window size, IP ID, etc.).

TCP Options

TCP has a flexible header, which can include extra parameters called options. They are mostly negotiated during connection setup (SYN/SYN-ACK packets). They allow clients and servers to optimize the connection. Common options include:

a) MSS (Maximum Segment Size)

  • Indicates the largest payload (in bytes) the sender can handle in a single TCP segment.
  • Helps prevent fragmentation at the IP layer.
  • Example: MSS=1460 means each TCP packet can carry up to 1460 bytes of application data.

b) SACK Permitted (Selective Acknowledgment)

  • Allows the receiver to inform the sender which segments were successfully received, even if some were lost.
  • Without SACK, TCP can only acknowledge the highest contiguous sequence number, leading to unnecessary retransmissions.
  • Option flag in SYN/SYN-ACK: SACK Permitted = 1 → OS supports selective acknowledgment.

SACK (Selective Acknowledgment) is a TCP feature that allows the receiver to inform the sender exactly which pieces of data (segments) have arrived successfully, even when some in between were lost.

It improves efficiency during packet loss — especially on high-latency or high-bandwidth networks — by avoiding retransmission of data that was already received.

  • Without SACK (Classic TCP)

    TCP uses a cumulative acknowledgment (ACK):

    • ACK number = “I’ve received all bytes up to this sequence number minus 1.”
    • If packet #3 is lost but #4 and #5 arrive, the receiver cannot say “I got 4 and 5”.
    • It must keep re-ACKing “I got up to #2” → causing duplicate ACKs → sender retransmits #3, #4, #5 unnecessarily.

            Result → Wasted bandwidth and slower recovery.

  • With SACK Enabled

    The receiver can now send a SACK block inside the ACK, like:

          

    • This tells the sender: “I got segments 3000–3500 and 4000–4500, but I’m missing 2000–3000.”
    • The sender only retransmits the missing part.

Negotiation: “SACK Permitted” Option

  • Appears only in SYN and SYN-ACK packets during connection setup.
  • Option Kind = 4, Length = 2  [04][02]
  • It doesn’t enable SACK by itself — it signals that both sides support it.
  • Once both ends advertise SACK Permitted, subsequent ACKs can carry SACK blocks. 

Scenario

Without SACK

With SACK

1 packet lost among 10

Retransmit all after loss

Retransmit only the missing one

Efficiency

Low

High

Throughput recovery

Slow

Fast

Bandwidth use

Wasteful

Optimal

 c) Timestamps (TSval, TSecr)

·       TCP Timestamps are part of the TCP TimeStamp Option (RFC 1323), used for:

o   Round-trip time measurement (RTT)

o   PAWS (Protect Against Wrapped Sequence numbers) to prevent old packets from being interpreted as new

·       Fields:

o   TSval = current timestamp of the sender

o   TSecr = echoed timestamp from the other side (if ACKing a packet)

     TCP Timestamp Option (TSopt):

·       TSval → Timestamp Value

o   This is the current time value of the sender, usually in milliseconds or some clock units.

o   It’s used by the receiver to calculate Round-Trip Time (RTT) for the connection.

·       TSecr → Timestamp Echo Reply

o   This echoes back the TSval received from the other side in the previous packet.

o   Helps the sender measure RTT and is used for PAWS (Protection Against Wrapped Sequence numbers) to detect old/reordered packets.

In short:

·       TSval = “my timestamp right now”

·       TSecr = “your timestamp that I am echoing back”

This 10-byte option is structured as: | Kind=8 (1B) | Length=10 (1B) | TSval (4B) | TSecr (4B) |

It’s part of TCP extensions defined in RFC 1323 for high-speed networks.

What TSecr actually is

·       TSecr = Timestamp Echo Reply

·       It’s a 4-byte value inside the TCP Timestamp option.

·       Its job is to echo back the TSval sent by the other side in a previous TCP packet.

How it helps measure RTT

·       Suppose Client sends TSval = 1000 in a SYN or data packet.

·       Server receives it and responds with TSecr = 1000 (echoing client’s TSval) and its own TSval = 2000.

·       When client receives this response, it knows how long the packet took to travel → Round Trip Time (RTT) can be calculated as: RTT ≈ CurrentTime - TSval_sent

How it helps PAWS (Protection Against Wrapped Sequence numbers)

·       Problem: In high-speed TCP connections, the sequence numbers (32-bit) can “wrap around” quickly.

·       PAWS uses timestamps to ignore old or duplicated packets:

o   If a packet has TSval older than previously seen TSval, it’s considered stale/replayed and discarded.

Simplified analogy

·       TSval = “I sent this packet at time X”

·       TSecr = “I received your packet that had time X”

·       By comparing these, TCP knows:

o   How fast packets are traveling (RTT)

o   Which packets are old or duplicate (PAWS)

 

Explanation:

·       TSval (Timestamp Value) is set by the sender (Client) when sending a packet.

·       TSecr (Timestamp Echo Reply) is set by the receiver (Server) to echo back the sender’s TSval.

·       When the client receives the response, it compares TSecr vs current time to calculate RTT.

·       This also helps PAWS detect old/replayed packets in high-speed connections.

The proper formula in practice is:

·       Client sends packet at TSval = 1000

·       Server receives and responds with TSecr = 1000 (echoed) and TSval_server = 2000

·       When client receives the response, it can calculate RTT ≈ ClientReceiveTime - TSval_sent

        

Key point:

·       The echoed TSecr is used to validate the packet is not stale (PAWS)

·       RTT is measured using local clock difference: ClientReceiveTime - TSval_sent

d) NOP (No-Operation)

·       A 1-byte placeholder used to align TCP options on a 32-bit boundary.

·       TCP requires options to be 4-byte aligned; NOPs act as padding without affecting functionality.

e) Window Scale

·       TCP Window defines how many bytes can be in-flight (unacknowledged) at a time.

·       The window size field in the TCP header is only 16 bits → max 65,535 bytes.

·       Window scaling extends this using a scaling factor (RFC 1323):

o   Window Scale = 7 → multiply the window size by 2^7 = 128

o   Example: TCP header shows Window=16,384 and scale=7 → actual window = 16,384 × 128 = 2,097,152 bytes (~2 MB)

Window Size vs Window Scale (WS)

TCP Window Size

·       Defined in the TCP header: a 16-bit field (0–65535) that tells the sender how many bytes the receiver can accept at the moment.

·       Essentially, it’s the receiver’s buffer space advertised to the sender.

·       Max value without scaling = 65,535 bytes (~64 KB).

Example:

·       A Linux client sends Window Size = 29200 → sender can send up to 29,200 bytes before waiting for ACK.

 Window Scale (WS)

·       Defined in TCP Options, negotiated only during handshake (SYN/SYN-ACK).

·       It’s a multiplicative factor that allows the 16-bit window size to represent a larger buffer.

·       Value = N, scale = 2^N

·       Effective maximum window = Window Size × 2^WS

Example:

·       Window Size = 29200

·       WS = 7 → Effective window = 29200 × 2^7 = 29200 × 128 = 3,737,600 bytes (~3.56 MB)

Key Differences

Feature

Window Size

Window Scale (WS)

Field

TCP header (16-bit)

TCP Option (3 bytes)

Purpose

Advertise receive buffer

Extend window beyond 64 KB limit

Negotiated

Each packet (can vary)

Only during handshake

Maximum without scaling

65,535 bytes

N/A

Maximum with scaling

65,535 × 2^WS

Depends on WS value (0–14)

Affects

Flow control

Flow control for high-speed/long-delay networks

 Example SYN Packet with WS

Window Size: Base buffer advertised by receiver (16-bit field in TCP header).

WS (Window Scale): Multiplier negotiated in SYN/SYN-ACK to expand max buffer beyond 65,535 bytes.

Effective Receive Window: How much data the sender can transmit before waiting for an ACK.

What “before waiting for ACK” means in TCP flow control

In TCP, the sender must not overwhelm the receiver. The receiver advertises a window size (the Window Size field in the TCP header) which tells the sender:  “I can currently accept up to X bytes of data without acknowledgment.”

Example: Linux Client

  • Window Size = 29200 bytes
  • Sender starts transmitting data to the receiver.  

Behavior:

  • Sender can send 29,200 bytes in total without receiving any ACKs.
  • Once those 29,200 bytes are sent, the sender must pause.
  • Sender waits until it receives an ACK from the receiver acknowledging that some or all of the data has been received.
  • As ACKs arrive, the window “slides”, allowing the sender to transmit more bytes.

Why This Matters

  • Prevents buffer overflow on the receiver.
  • Implements flow control in TCP.
  • In high-speed networks, the Window Scale (WS) may be used to allow the sender to transmit much more data before waiting for ACKs.

Visual Example:

“Before waiting for ACK” = the maximum number of bytes the sender can transmit without receiving confirmation that the receiver got the data.

Window Size & Sending Data

Window Size = 29,200 bytes means:

·       The sender can transmit up to 29,200 bytes in total before it must wait for acknowledgments (ACKs) from the receiver.

·       These 29,200 bytes can be sent as multiple TCP segments (chunks), not necessarily as a single large segment.

·       TCP segments are typically smaller than the window (often 1460 bytes if MSS = 1460).

Example (MSS = 1460 bytes)

 Without Window Scaling

  • Window Size = 29,200 bytes
  • Means: the sender can have up to 29,200 bytes “in flight” (sent but not yet ACKed).
  • If it sends 3 segments of 1,460 bytes each → 3 × 1,460 = 4,380 bytes.
    → Still 29,200 − 4,380 = 24,820 bytes of window left to send
    before needing ACKs.
  • Once the receiver ACKs some data, the window slides forward, allowing more data to be sent.

With Window Scaling (WS = 7)

  • WS = 7 → scaling factor = 2⁷ = 128
  • Effective Window = 29,200 × 128 = 3,737,600 bytes
  • That means the sender can have up to 3.7 MB of data in flight before needing ACKs.

With WS = 7, the sender can transmit 3.7 MB worth of TCP segments (in multiple chunks) without waiting for acknowledgments, as long as the total unacknowledged data ≤ 3,737,600 bytes.

f) Option Ordering

  • The order in which TCP options appear in the SYN packet is unique per OS and kernel.
  • Example: Windows may order as [MSS, WS, SACK, TS]; Linux as [MSS, SACK, TS, WS].
  • This ordering is a signature in TCP/IP fingerprinting.

 Why TCP options matter

  • They improve connection efficiency: prevent fragmentation, allow large windows, reduce retransmission overhead.
  • They reveal OS fingerprinting information because each OS sets defaults differently (MSS, WS, TS, option order).
  • Security/monitoring tools use these fields to passively identify the client OS without sending probes.

Quick Example SYN Packet (simplified):

·  This tells the server:

·       Max segment: 1460 bytes

·       Can scale window by 128×

·       Supports selective acknowledgment

·       Includes timestamp for RTT

·  And to a fingerprinting tool, this combination often uniquely identifies the client OS.

 

 

No comments:

Post a Comment