This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
TCP
The Transmission Control Protocol turns IP's lost, duplicated and reordered packets into a reliable, ordered byte stream between two programs. It numbers every byte, has the receiver acknowledge what it got, and resends what's missing. A connection is identified by four values: source address, source port, destination address and destination port.
The header
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Port | Destination Port |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Sequence Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Acknowledgment Number |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Data | |C|E|U|A|P|R|S|F| |
| Offset| Rsrvd |W|C|R|C|S|S|Y|I| Window |
| | |R|E|G|K|H|T|N|N| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Checksum | Urgent Pointer |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Options (0 to 40 bytes) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Offset | Size | Field | Meaning |
|---|---|---|---|
| 0 | 2 | Source Port | The sender's port: random (ephemeral) for a client. |
| 2 | 2 | Destination Port | The service: 80 HTTP, 443 HTTPS, 22 SSH... |
| 4 | 4 | Sequence Number | Number of the first data byte in this segment. Starts at a random value. |
| 8 | 4 | Acknowledgment Number | Next byte expected from the other side (valid when ACK is set). |
| 12 | 4 bits | Data Offset | Header length in 32-bit words: 5 (20 bytes) to 15 (60 bytes). |
| 13 | 8 bits | Flags | SYN opens, FIN closes, RST aborts, ACK acknowledges, PSH "deliver now", URG, plus ECE / CWR for congestion. |
| 14 | 2 | Window | How many bytes the sender of this segment can still receive (scaled by the window scale option). |
| 16 | 2 | Checksum | Covers a pseudo-header (addresses, protocol, length), the header and the data. |
| 18 | 2 | Urgent Pointer | Unused in practice. |
| 20 | 0–40 | Options | MSS, window scale, SACK, timestamps... |
Example: a connection, from opening to closing
curl fetching a small file from 192.0.2.2:8080, as l shows it:
#25 [veth0] 4.968173 192.0.2.1:59682 -> 192.0.2.2:8080 ttl 64 TCP 40 B [SYN]
#26 [veth0] 4.968214 192.0.2.2:8080 -> 192.0.2.1:59682 ttl 64 TCP 40 B [SYN,ACK]
#27 [veth0] 4.968242 192.0.2.1:59682 -> 192.0.2.2:8080 ttl 64 TCP 32 B [ACK]
#28 [veth0] 4.968326 192.0.2.1:59682 -> 192.0.2.2:8080 ttl 64 TCP 119 B [PSH,ACK] [GET]
#29 [veth0] 4.968337 192.0.2.2:8080 -> 192.0.2.1:59682 ttl 64 TCP 32 B [ACK]
#30 [veth0] 4.979895 192.0.2.2:8080 -> 192.0.2.1:59682 ttl 64 TCP 218 B [PSH,ACK] [HTTP 200]
#31 [veth0] 4.979909 192.0.2.1:59682 -> 192.0.2.2:8080 ttl 64 TCP 32 B [ACK]
#32 [veth0] 4.980106 192.0.2.2:8080 -> 192.0.2.1:59682 ttl 64 TCP 61 B [PSH,ACK]
#33 [veth0] 4.980111 192.0.2.1:59682 -> 192.0.2.2:8080 ttl 64 TCP 32 B [ACK]
#34 [veth0] 4.980203 192.0.2.1:59682 -> 192.0.2.2:8080 ttl 64 TCP 32 B [FIN,ACK]
#35 [veth0] 4.980260 192.0.2.2:8080 -> 192.0.2.1:59682 ttl 64 TCP 32 B [FIN,ACK]
#36 [veth0] 4.980266 192.0.2.1:59682 -> 192.0.2.2:8080 ttl 64 TCP 32 B [ACK]
sequenceDiagram
participant C as client 192.0.2.1:59682
participant S as server 192.0.2.2:8080
C->>S: SYN seq=x
S->>C: SYN,ACK seq=y ack=x+1
C->>S: ACK ack=y+1
Note over C,S: connection open (3-way handshake)
C->>S: PSH,ACK "GET /hello.txt" (87 bytes)
S->>C: ACK
S->>C: PSH,ACK HTTP headers (186 bytes)
C->>S: ACK
S->>C: PSH,ACK file (29 bytes)
C->>S: ACK
C->>S: FIN,ACK
S->>C: FIN,ACK
C->>S: ACK
Note over C,S: closed
The sizes in l include the TCP header: 32 bytes for most segments (20 + 12 bytes of timestamp options), 40 for the SYNs. So packet #28 carries 119 − 32 = 87 bytes of HTTP request, and the server sends its 186 bytes of headers (#30) and the 29-byte file (#32) in two segments.
The SYN, byte by byte
0020 e9 22 1f 90 ac 19 e3 e2 00 00 00 00 a0 02
0030 fa f0 84 32 00 00 02 04 05 b4 04 02 08 0a f9 56
0040 4d a7 00 00 00 00 01 03 03 0a
| Bytes | Field | Value |
|---|---|---|
e9 22 |
Source Port | 59682 |
1f 90 |
Destination Port | 8080 |
ac 19 e3 e2 |
Sequence | 2887377890, random |
00 00 00 00 |
Acknowledgment | 0: nothing to acknowledge yet |
a0 |
Data Offset | a = 10 words = 40 bytes |
02 |
Flags | 0000 0010: SYN |
fa f0 |
Window | 64240 |
84 32 |
Checksum | see below |
00 00 |
Urgent | 0 |
02 04 05 b4 |
Option: MSS | max segment size 1460 (1500 − 40 bytes of IP and TCP headers) |
04 02 |
Option: SACK permitted | |
08 0a f9 56 4d a7 00 00 00 00 |
Option: timestamps | the sender's clock, and 0 echoed |
01 |
Option: NOP | padding |
03 03 0a |
Option: window scale | windows are shifted left by 10 (×1024) |
The SYN-ACK answers with its own random sequence number (4145906934) and acknowledges 2887377891, the client's sequence + 1: a SYN counts as one byte.
NetOtter's i for the SYN:
Protocol TCP (6)
TTL 64
TCP header 40 bytes
Ports 59682 -> 8080
Flags SYN
Seq 2887377890
Ack 0
Window 64240
Checksum 0x8432
Urgent 0
Why the checksum looks wrong
0x8432 is not a valid checksum for this segment: the correct one is 0xe95a. Modern network cards compute TCP and UDP checksums in hardware (checksum offload). The system only fills in the pseudo-header's partial sum and leaves the rest to the card. A capture made on the sending machine sees the packet before the card finishes it.
Here, 0x8432 is exactly the sum of the pseudo-header: source, destination, protocol 6 and TCP length 40. The server's SYN-ACK shows 0x8432 too: both ends are on the same machine here, linked by a virtual cable that never computes checksums, so every segment of this capture carries the partial sum. Packets received from a real network card carry real checksums.
In NetOtter
- Parsing:
parse_tcph()(Parsers) reads the fixed fields and honours the Data Offset (soTCP header 40 bytescounts the options), but doesn't decode the options. l: ports and flags ([SYN,ACK]).- Analysis view: well-known ports get names (
:HTTPS). A TLS ClientHello in the first data segment gives the server's name; see Hostname learning. - Filters:
proto tcp,port,portsrc,portdest.
Read more
User guide
- Overview
- Installation
- Getting started
- Command-line options
- Interactive commands
- Display filters
- Analysis view
- Reverse DNS and privacy
- Anomaly detection
- Save files
- Memory and limits
- Troubleshooting
Developer documentation
- Overview
- Building
- Architecture
- OS backends
- Packet parsing
- Packet storage
- Save format
- Hostname learning
- Reverse DNS internals
- Filters and analysis internals
- Anomaly lab
- Coding conventions
- Function explorer
Learning