A captured TCP SYN has a data offset of 10; how long is its header, and what do its option bytes typically carry?
answer
- count 32-bit words, not bytes
- fixed part is five words
- options cap at forty bytes
- kinds 2, 4, 8 and 3
- NOP pads to a boundary
basics
~10 sData offset counts 32-bit words, so 10 means a 40-byte header: 20 fixed bytes plus 20 bytes of options, typically MSS (4), SACK-permitted (2), timestamps (10), one NOP and window scale (3).
solid answer
~50 sThe TCP data offset is a 4-bit count of 32-bit words, so it runs from 5 (a 20-byte header with no options) to 15 (60 bytes), which caps options at 40 bytes. A value of 10 means a 40-byte header with 20 bytes of options. In a SYN those 20 bytes typically hold `MSS` (kind 2, 4 bytes), `SACK-permitted` (kind 4, 2 bytes), `Timestamps` (kind 8, 10 bytes) and `Window Scale` (kind 3, 3 bytes), plus one `NOP` (kind 1) as padding: 4 + 2 + 10 + 3 + 1 = 20. Window scale and timestamps take effect only if the SYN-ACK carries them too, SACK-permitted grants the peer permission to send SACK blocks, and MSS is a one-way announcement. Two more traps in the same SYN: its window field is never scaled, and its sequence number is the initial sequence number, not a data byte.
code
pseudocode · 15 linesoffset_words = header[12] >> 4 # high 4 bits of byte 12
header_len = offset_words * 4 # 20..60 bytes
i = 20 # options start after fixed part
while i < header_len:
kind = header[i]
if kind == 0: break # End of Option List
if kind == 1: # No-Operation, one byte
i = i + 1
continue
if i + 1 >= header_len: error("truncated option")
length = header[i + 1] # counts kind and length bytes
if length < 2 or i + length > header_len:
error("illegal option length")
handle_option(kind, header[i + 2 : i + length])
i = i + lengthgo deeper
Remember that the fixed TCP header is 20 bytes and that options come after it, up to a length the header itself declares.
Turn a data offset into bytes, name the options a SYN carries with their sizes, and say which of them are offers that need the SYN-ACK to agree.
Read a raw SYN in a capture confidently, including the unscaled window, the ISN, ECN-setup flags and an options list that does not align to word boundaries.
Explain how the fixed 40-byte options ceiling constrains TCP's evolution, and why new extensions must negotiate in the SYN or live without option space.
## The fixed 20 bytes Every TCP header begins with five 32-bit words that are always present: | Field | Size | What it holds | |---|---|---| | Source port, destination port | 16 bits each | The two endpoints' ports | | Sequence number | 32 bits | Number of the first data byte; in a `SYN`, the **initial sequence number** (ISN) | | Acknowledgment number | 32 bits | Next sequence number expected; meaningful only when `ACK` is set | | Data offset | 4 bits | Header length in **32-bit words** | | Reserved | 4 bits | Must be zero when sent | | Control bits | 8 bits | `CWR`, `ECE`, `URG`, `ACK`, `PSH`, `RST`, `SYN`, `FIN` | | Window | 16 bits | Bytes the sender of this segment is willing to accept | | Checksum | 16 bits | Covers a pseudo-header, the TCP header including options, and the data | | Urgent pointer | 16 bits | Meaningful only when `URG` is set | That is 20 bytes. Anything after it, up to the length the data offset declares, is **options**. ## Data offset arithmetic The field is only 4 bits wide and counts words, not bytes. Reading it takes three steps: 1. Take the value: here, 10. 2. Multiply by 4 to get the header length in bytes: 40. 3. Subtract the fixed 20 bytes to get the options area: 20. Because the header must contain the five fixed words, the smallest legal value is **5** (20 bytes, no options). Because 4 bits top out at 15, the largest is **15** (60 bytes), so **options can never exceed 40 bytes**. RFC 9293 writes this as `size(Options) == (DOffset-5)*32` bits, "present only when DOffset > 5", and notes the header is always a whole number of 32-bit words, which is why padding exists. ## Decoding the options in a typical SYN Options are a list. Two kinds are a single byte: **End of Option List** (kind 0) and **No-Operation** (kind 1). Every other option is kind, length, data, where the length counts the kind and length bytes too. | Option | Kind | Length | Where it may appear | |---|---|---|---| | Maximum Segment Size (`MSS`) | 2 | 4 | Only in segments with `SYN` set | | Window Scale (`WS`) | 3 | 3 | Only in `SYN` segments; ignored elsewhere | | `SACK-permitted` | 4 | 2 | Only in `SYN` segments | | Timestamps (`TSval`, `TSecr`) | 8 | 10 | Offered in the `SYN`; in every non-`RST` segment once both sides sent it | | No-Operation (`NOP`) | 1 | 1 | Anywhere, as alignment padding | A common layout of a 20-byte SYN options area is `MSS`, `SACK-permitted`, `Timestamps`, `NOP`, `Window Scale`: 4 + 2 + 10 + 1 + 3 = 20. The order is the implementation's choice; receivers MUST handle options that do not start on a word boundary. In a `SYN` the timestamps option's echo field (`TSecr`) SHOULD be zero, since there is nothing to echo yet. ## Offers versus announcements The `SYN` carries two different kinds of option: - **Offers that need an answer.** Window scale and timestamps are in effect only if the `SYN-ACK` carries them too (RFC 7323). A TCP may send SACK blocks only if its peer sent `SACK-permitted` (RFC 2018). - **Announcements.** `MSS` states the largest segment the sender can receive. The peer announces its own value; nothing is agreed. ## Other fields worth reading in the same SYN - **Sequence number** is the ISN, and the first data byte will be ISN+1. - **Acknowledgment number** is not significant, because `ACK` is off in a first `SYN`. - **Window** is **never scaled** in a `SYN` or `SYN-ACK` (RFC 7323), even when a window scale option sits a few bytes away. - **`ECE` and `CWR` both set** make it an ECN-setup SYN (RFC 3168). ## Why 40 bytes is tight The cap shapes what later segments can carry. RFC 2018 computes a SACK option with *n* blocks as 8*n*+2 bytes, so 40 bytes fit at most 4 blocks, and only 3 when the 10-byte timestamps option plus 2 bytes of padding is present. How SACK blocks are used is a separate topic; the arithmetic belongs to the header.
- Why can a TCP SACK option carry at most three blocks on a connection that also uses timestamps?Options are capped at 40 bytes by the 4-bit data offset. RFC 2018 sizes a SACK option at 8n+2 bytes for n blocks, so four blocks (34 bytes) fit alone. The timestamps option takes 10 bytes plus 2 bytes of padding, leaving 28, and three blocks need 26, so three is the ceiling.
- What must a TCP receiver do with an option kind it does not implement?RFC 9293 says it MUST ignore it without error, provided the option has a length field, which every option except End of Option List and No-Operation must have. That rule is what lets new options be deployed. A receiver MUST also be prepared for an illegal length such as zero; the suggested handling is to reset the connection and log the cause.
saying these in an interview costs you the question
- A data offset of 10 means a 10-byte TCP header
- TCP options can grow the header as large as the segment needs
- The window value in a SYN is already scaled by the offered factor
- A SYN's sequence number is the number of its first data byte
- The SYN-ACK must repeat the MSS value the client offered