H3AD-REF / REFERENCES / PACKET STRUCTURE

Packets.
Byte By Byte, No Wireshark Required.

A static reference for the four headers you end up hand-parsing most often: Ethernet, IPv4, TCP, and UDP. Each one is laid out here in wire order with byte offsets, so you can read a hex dump cold and know what you're looking at before you ever open a capture tool. Once you do open one, the same fields (tcp.flags, ip.ttl, and the rest) are what the Wireshark Display Filters cheatsheet filters on.

Ethernet Header

The first 14 bytes of any raw frame, fixed length, no exceptions. Everything else in this reference sits on top of it.

Ethernet II Header (14 bytes, fixed)

Frame offset 0: the very first byte captured
├── Destination MAC  6 bytes  offset 0–5
├── Source MAC       6 bytes  offset 6–11
└── EtherType        2 bytes  offset 12–13
    // tells the next parser what sits inside the payload

Common EtherType values
├── 0x0800  IPv4
├── 0x0806  ARP
└── 0x86DD  IPv6
    // there's no length field here: Ethernet doesn't say how big the payload is, IP's Total Length does that job instead

IP Header (IPv4)

Starts right where Ethernet ends, at offset 14. Minimum 20 bytes, longer only when options are present.

IPv4 Header (20 bytes minimum, up to 60 with options)

Frame offset 14: first byte right after the Ethernet header
├── Version / IHL            1 byte   offset 14
│   └── high nibble = version (4 for IPv4), low nibble = IHL, header length in 4-byte words
├── Type of Service          1 byte   offset 15
├── Total Length             2 bytes  offset 16–17
│   └── // whole IP packet, header plus payload, in bytes
├── Identification           2 bytes  offset 18–19
├── Flags / Fragment Offset  2 bytes  offset 20–21
│   └── 3 flag bits (reserved, DF, MF) and a 13-bit fragment offset packed into the same two bytes
├── TTL                      1 byte   offset 22
├── Protocol                 1 byte   offset 23
│   └── 6 = TCP, 17 = UDP, 1 = ICMP
├── Header Checksum           2 bytes  offset 24–25
├── Source IP                 4 bytes  offset 26–29
└── Destination IP            4 bytes  offset 30–33
    // IHL = 5 (no options) means this header is exactly 20 bytes, offsets 14 through 33

TCP Header

The connection-state header. Minimum 20 bytes, and the offsets below assume a 20-byte IP header ahead of it with no options.

TCP Header (20 bytes minimum, up to 60 with options)

Frame offset 34: right after a 20-byte IP header
├── Source Port              2 bytes  offset 34–35
├── Destination Port         2 bytes  offset 36–37
├── Sequence Number          4 bytes  offset 38–41
├── Acknowledgment Number    4 bytes  offset 42–45
├── Data Offset / Flags      2 bytes  offset 46–47
│   └── high nibble = data offset, header length in 4-byte words; low bits carry the flags:
│       SYN, ACK, FIN, RST, PSH, URG
├── Window                   2 bytes  offset 48–49
├── Checksum                 2 bytes  offset 50–51
└── Urgent Pointer           2 bytes  offset 52–53
    // a bare SYN sets only that bit with ACK=0 and no data; a SYN/ACK sets both bits in the same flags byte

UDP Header

Eight bytes, always. No sequence numbers, no acknowledgment, no state to track between packets.

UDP Header (8 bytes, fixed, RFC 768)

Frame offset varies: same starting point TCP would occupy, right after the IP header
├── Source Port       2 bytes
├── Destination Port  2 bytes
├── Length            2 bytes
│   └── // UDP header plus payload, in bytes, the same job IP's Total Length does one layer up
└── Checksum          2 bytes

No sequence number, no acknowledgment number, no flags
    // deliberately simpler than TCP: 8 bytes total, and nothing here tracks connection state

Reading It By Hand

The practical payoff of knowing this layout: finding a header in a raw hex dump with nothing but a byte counter.

BY HAND

Finding the TCP Header In A Hex Dump

No packet capture tool, just arithmetic on the bytes in front of you
Byte 0 of a raw frame is always the first byte of the destination MAC, and the Ethernet header is a fixed 14 bytes, so the IP header starts at offset 14 (0x0E) every single time. From there the math depends on one nibble: read the byte sitting at offset 14, take its low nibble, that's the IHL, and multiply it by 4. That product is the IP header's real length in bytes. Add it to 14 and you land on the first byte of whatever transport header comes next. With no IP options, IHL is 5, the IP header runs exactly 20 bytes, and TCP or UDP starts at offset 34 (0x22). Any IP options push that starting offset further out, so checking the IHL nibble first is what keeps a hand count from landing you three bytes into someone else's field.