Packets#
Packet anatomy#
Each higher layer’s data becomes the payload of the layer below it, prefixed with that layer’s header. The wire bytes are the result of this encapsulation; at the receiver, each layer strips its header and hands the rest up.
A 1500-byte Ethernet frame carrying a TCP / HTTP payload looks like:
flowchart LR
E["Eth header<br/>(14 B)"] --> I["IP hdr<br/>(20 B)"] --> T["TCP hdr<br/>(20 B)"] --> H["HTTP headers"] --> P["application payload<br/>(HTML, JSON, ...)"] --> F["FCS<br/>(4 B)"]
L2 frame: up to 1500 B (MTU), measured from the Ethernet header through the FCS.
The wrapping rule:
L2 frame = Ethernet header + L3 packet + FCS
L3 packet = IP header + L4 segment / datagram
L4 segment = TCP / UDP header + L7 payload
L7 payload = HTTP, DNS, TLS-encrypted application data
Ethernet frame (L2)#
packet-beta
0-47: "Destination MAC (48 bits)"
48-95: "Source MAC (48 bits)"
96-111: "EtherType"
Field |
Bytes |
Meaning |
|---|---|---|
Preamble |
7 |
Sync pattern (only on the wire; NIC strips it) |
SFD |
1 |
Start-of-frame delimiter |
Dest MAC |
6 |
Destination MAC ( |
Src MAC |
6 |
Source MAC |
802.1Q tag |
4 |
Optional VLAN tag (PCP, DEI, VID); appears only when used |
EtherType |
2 |
Payload type: |
Payload |
46-1500 |
L3 packet |
FCS |
4 |
Frame check sequence (CRC-32) |
IPv4 header#
20 bytes minimum, up to 60 with options.
packet-beta
0-3: "Ver"
4-7: "IHL"
8-15: "DSCP/ECN"
16-31: "Total Length"
32-47: "Identification"
48-50: "Flags"
51-63: "Fragment Offset"
64-71: "TTL"
72-79: "Protocol"
80-95: "Header Checksum"
96-127: "Source Address"
128-159: "Destination Address"
Field |
Bits |
Meaning |
|---|---|---|
Version |
4 |
|
IHL |
4 |
Header length in 32-bit words ( |
DSCP / ECN |
8 |
Differentiated services + congestion notification |
Total Length |
16 |
Header + payload, in bytes |
Identification |
16 |
Fragment ID |
Flags |
3 |
DF (don’t fragment), MF (more fragments) |
Fragment Offset |
13 |
Offset of this fragment in 8-byte units |
TTL |
8 |
Hop counter; routers decrement; 0 → drop + ICMP “time exceeded” |
Protocol |
8 |
L4 type: |
Header Checksum |
16 |
Recomputed at every hop (TTL changes) |
Source Addr |
32 |
Sender IP |
Destination Addr |
32 |
Receiver IP |
Options |
0-40 |
Rare (record-route, source-route, timestamp) |
IPv6 header#
40 bytes fixed, no inline options. Extensions are chained via the Next Header field.
packet-beta
0-3: "Ver"
4-11: "Traffic Class"
12-31: "Flow Label"
32-47: "Payload Length"
48-55: "Next Header"
56-63: "Hop Limit"
64-191: "Source Address (128 bits)"
192-319: "Destination Address (128 bits)"
Field |
Bits |
Meaning |
|---|---|---|
Version |
4 |
|
Traffic Class |
8 |
DSCP / ECN (same semantics as IPv4) |
Flow Label |
20 |
Hint for ECMP / per-flow scheduling |
Payload Length |
16 |
Bytes after this header |
Next Header |
8 |
L4 type or extension header ( |
Hop Limit |
8 |
Same role as IPv4 TTL |
Source Addr |
128 |
Sender |
Destination Addr |
128 |
Receiver |
TCP header#
20 bytes minimum, up to 60 with options. Options carry MSS, window scale, SACK permission, and timestamps.
packet-beta
0-15: "Source Port"
16-31: "Destination Port"
32-63: "Sequence Number"
64-95: "Acknowledgment Number"
96-99: "Data Offset"
100-103: "Reserved"
104-104: "C"
105-105: "E"
106-106: "U"
107-107: "A"
108-108: "P"
109-109: "R"
110-110: "S"
111-111: "F"
112-127: "Window Size"
128-143: "Checksum"
144-159: "Urgent Pointer"
Field |
Bits |
Meaning |
|---|---|---|
Source Port |
16 |
Sender port |
Destination Port |
16 |
Receiver port |
Sequence Number |
32 |
Byte position of the first data byte in this segment |
Acknowledgment Num |
32 |
Next byte the sender expects to receive |
Data Offset |
4 |
Header length in 32-bit words ( |
Reserved |
4 |
Must be 0 |
Flags |
8 |
|
Window Size |
16 |
Bytes the sender will accept (scaled by an option) |
Checksum |
16 |
Pseudo-header + segment |
Urgent Pointer |
16 |
Used with |
Options |
0-40 |
MSS, SACK, window scale, timestamp |
UDP header#
8 bytes; UDP is intentionally minimal.
packet-beta
0-15: "Source Port"
16-31: "Destination Port"
32-47: "Length"
48-63: "Checksum"
Field |
Bits |
Meaning |
|---|---|---|
Source Port |
16 |
Sender |
Destination Port |
16 |
Receiver |
Length |
16 |
Header + payload, in bytes |
Checksum |
16 |
Pseudo-header + datagram (optional on IPv4, required on IPv6) |
Crafting packets#
Send hand-built frames to exercise the TCP state machine, test firewall rules, reproduce a bug, or fingerprint a remote stack. Reads straight off the field tables above: pick the protocol, fill the fields, send.
Tool |
Strength |
|---|---|
|
Python library; build any packet field by field, the gold standard |
|
CLI packet generator; quick TCP / UDP / ICMP probes with custom flags |
|
Bundled with |
|
Older CLI; layer-by-layer assembly |
|
Replay a captured |
|
L2 protocol abuser (CDP, STP, DHCP, ARP) |
|
Lightweight CLI generator / sniffer |
Scapy, Python REPL or script. Build by stacking layers with /:
from scapy.all import *
# 1. Single TCP SYN to port 22
syn = IP(dst="1.2.3.4") / TCP(dport=22, flags="S")
ans, unans = sr(syn, timeout=2)
# 2. Spoof source IP
send(IP(src="10.0.0.1", dst="1.2.3.4") / ICMP())
# 3. Layer-by-layer DNS query at L2
pkt = (Ether(dst="ff:ff:ff:ff:ff:ff")
/ IP(dst="192.0.2.1")
/ UDP(dport=53)
/ DNS(rd=1, qd=DNSQR(qname="example.com")))
sendp(pkt, iface="eth0")
# 4. Read a pcap, mutate, replay
pkts = rdpcap("capture.pcap")
for p in pkts:
if IP in p:
p[IP].src = "10.10.10.10"
wrpcap("forged.pcap", pkts)
hping3, one-liners for quick probing:
$ sudo hping3 -S -p 22 -c 3 1.2.3.4 # 3 SYN packets to :22
$ sudo hping3 -A -p 80 1.2.3.4 # ACK probe (firewall fingerprint)
$ sudo hping3 -2 -p 53 1.2.3.4 # UDP probe
$ sudo hping3 -1 1.2.3.4 # ICMP echo
$ sudo hping3 -S -p 80 --spoof 10.0.0.99 1.2.3.4 # spoofed source
$ sudo hping3 --flood -S -p 80 1.2.3.4 # flood (lab use only)
nping, the nmap suite’s packet generator:
$ sudo nping --tcp -p 22 --flags syn,ack 1.2.3.4
$ sudo nping --udp -p 53 --data-string 'probe' 1.2.3.4
$ sudo nping --icmp --icmp-type echo-request 1.2.3.4
tcpreplay, push an existing capture back onto the wire:
$ sudo tcpreplay -i eth0 capture.pcap
$ sudo tcpreplay -i eth0 --topspeed capture.pcap
$ sudo tcprewrite --infile=in.pcap --outfile=out.pcap \
--srcipmap=10.0.0.0/8:172.16.0.0/16
Warning
Crafting, spoofing, or flooding traffic against systems you do not own is unauthorized network activity. Use isolated lab networks, your own infrastructure, or an explicit pentest engagement.
Inspecting on the wire#
$ sudo tcpdump -i eth0 -nn host 1.2.3.4 and port 443
$ sudo tcpdump -i eth0 -w capture.pcap # save to disk
$ sudo tcpdump -r capture.pcap -X # hexdump from a pcap
$ sudo tshark -i eth0 -Y 'http.request' # Wireshark display filter
$ wireshark capture.pcap # GUI
See also: man 8 tcpdump, man 1 wireshark, RFC 791 (IPv4), RFC 793 (TCP), RFC 768 (UDP), RFC 8200 (IPv6), RFC 826 (ARP).