Networking Fundamentals · intermediate · ~12 min

Reading packet captures with Wireshark

- Open a saved packet capture (pcap) in Wireshark or read it with tcpdump, and understand what the columns mean. - Read the layered headers of a single packet (Ethernet -> IP -> TCP/UDP -> application) and see how encapsulation looks on the wire. - Write display filters (`tcp.port == 80`, `ip.addr == ...`, `http`, `dns`) to isolate the packets you care about out of thousands. - Recognise the TCP three-way handshake and decode the TCP flag bits (SYN, ACK, FIN, RST, PSH, URG). - Use *Follow TCP Stream* to reassemble a scattered conversation into one readable transcript. - Understand the legal and ethical limits of packet capture, and why this course parses fixtures instead of sniffing live traffic.

Overview

A packet capture (often shortened to pcap) is a saved recording of network traffic: every frame that crossed a network interface, byte for byte, timestamped in the order it arrived. Two tools dominate this space. Wireshark is the graphical analyser that decodes each packet into a readable tree of headers. tcpdump is its command-line cousin, used to capture and to do quick filtering on servers where no GUI exists.

Think of a capture as a flight recorder for a network. When something goes wrong, or when you want to understand exactly how a protocol behaves, you stop guessing and look at what actually crossed the wire.

This lesson builds directly on two things you already know. From The TCP/IP and OSI models you learned that data is wrapped in layers: an application message sits inside a transport segment, inside an internet packet, inside a link-layer frame. A packet capture is where you see those layers stacked up, one inside the next. From TCP vs UDP, ports, and the ones to know you learned what ports identify and how TCP differs from UDP. In a capture you watch TCP set up a connection with a handshake, carry data, and tear it down, all visible as individual packets with flags.

In plain terms: you open a file, you filter down to the traffic that matters, you click a packet to expand its layers, and you follow a conversation to read it as text. The terminology (display filter, follow stream, flags, encapsulation) simply names those actions.

Why it matters

Captures are ground truth. Configuration files, logs, and documentation tell you what should happen. A capture tells you what did happen, at the level of individual bytes. When those two disagree, the capture wins.

Concretely, reading captures lets you:

  • Confirm behaviour. Did the client actually send the request? Did the server reset the connection, or did it just never reply? A capture answers this without argument.
  • See cleartext data. Protocols like HTTP, FTP, and Telnet send everything unencrypted. A capture reveals credentials, tokens, and page content in plain view, which is exactly why moving to TLS matters so much.
  • Diagnose performance. Retransmissions, duplicate ACKs, and long gaps between packets show up visually, pointing at packet loss or an overloaded server.
  • Learn real protocols. Reading a real DNS query or TLS handshake teaches you more than any diagram, because you see the exact field values.

For anyone working in networking or security, whether building systems or defending them, reading a capture is a daily, foundational skill. It is the difference between describing a problem and proving it.

Core concepts

1. The layered (encapsulated) view

Definition. Each captured packet is decoded into a stack of headers, one per protocol layer, in the exact order they are nested on the wire.

Plain explanation. When your browser sends a request, the HTTP message is placed inside a TCP segment, which is placed inside an IP packet, which is placed inside an Ethernet frame. Capturing catches the whole frame, and Wireshark unwraps it layer by layer so you can read each header separately.

How it works internally. The bytes are contiguous in memory. Wireshark starts at byte 0, reads the Ethernet header (it knows Ethernet is 14 bytes and the type field says what comes next), advances to the IP header, reads the IP header length to find where TCP starts, reads TCP to find where the payload starts, and so on. This is called dissection.

One Ethernet frame on the wire (bytes left to right):

+-----------+------------------+------------------+-------------------+
| Ethernet  |       IPv4       |       TCP        |   HTTP payload    |
|  header   |      header      |     header       |  "GET / HTTP/1.1" |
| (14 bytes)|   (20+ bytes)    |   (20+ bytes)    |    (variable)     |
+-----------+------------------+------------------+-------------------+
  link          internet          transport          application

Click a layer in Wireshark -> it highlights that slice of bytes.

When to use it. Always, when you need to understand a single packet in detail. Expanding layers is how you read a field's exact value.

When NOT to. When you have thousands of packets and only need the shape of a conversation, expanding every layer is slow. Filter and follow-stream first, then drill in.

Common pitfall. Confusing the link layer address (MAC) with the internet layer address (IP). The MAC only identifies the next hop on the local network and changes at every router; the IP identifies the end host.

Knowledge check: In the frame above, which layer would you expand to find the destination port number, and which to find the destination IP address?

2. Display filters

Definition. A display filter is an expression that hides every packet except the ones matching it. It changes the view, not the capture file.

Plain explanation. A busy capture has thousands of packets. A filter like tcp.port == 80 shows only web traffic on port 80; ip.addr == 10.0.0.5 shows only packets to or from that host.

How it works internally. Wireshark has already dissected every packet, so each field (like tcp.port or http.request.method) is a named value it can test. The filter is evaluated against each packet's dissected fields.

Filter Shows
tcp.port == 443 Traffic on port 443 (HTTPS) in either direction
ip.addr == 10.0.0.5 Any packet to or from 10.0.0.5
http Only packets the HTTP dissector recognised
dns Only DNS queries and responses
tcp.flags.syn == 1 && tcp.flags.ack == 0 Connection-opening SYN packets

When to use it. First thing, on almost every capture, to cut noise down to signal.

When NOT to. Do not confuse a display filter (applied after capture, easy to change) with a capture filter (applied while capturing, uses a different syntax and permanently drops packets). Beginners mix the two up constantly.

Common pitfall. Writing ip.addr != 10.0.0.5 and expecting it to hide all traffic involving that host. Because a packet has two addresses, this expression is true whenever either address is not 10.0.0.5, which is almost always. The correct form is !(ip.addr == 10.0.0.5).

Knowledge check: Predict the result: you type tcp.port = 80 (one equals sign) into the filter bar. What happens, and what did you mean to type?

3. The TCP handshake and flags

Definition. TCP flags are single control bits in the TCP header. The three-way handshake is the fixed SYN, SYN-ACK, ACK exchange that opens every TCP connection.

Plain explanation. Before TCP carries any data, both sides agree to talk. The client sends SYN (synchronise), the server replies SYN-ACK, the client replies ACK. After that, data flows. To close, FIN packets are exchanged; RST is an abrupt "go away".

Three-way handshake:

  Client                         Server
    |------------- SYN ----------->|   "let's talk"
    |<--------- SYN, ACK ----------|   "ok, and let's talk back"
    |------------- ACK ----------->|   "agreed"
    |======== data flows ==========|
    ...
    |------------- FIN ----------->|   "I'm done sending"
    |<------------ ACK ------------|

How it works internally. The flags live in a single byte of the TCP header. Each bit is one flag. A SYN packet has the SYN bit set to 1; a SYN-ACK has both SYN and ACK set. Wireshark decodes this byte and shows [SYN], [SYN, ACK], and so on in the Info column.

Flag Meaning
SYN Start a connection, synchronise sequence numbers
ACK This packet acknowledges received data
FIN Sender has finished sending (graceful close)
RST Reset: abort the connection immediately
PSH Push buffered data to the application now
URG Urgent pointer field is meaningful (rare)

When to use it. Reading the first few packets of any TCP flow tells you whether a connection even got established. No SYN-ACK means the server never accepted.

When NOT to. UDP has no handshake and no flags; do not look for SYN in a DNS-over-UDP capture.

Common pitfall. Assuming an RST means an attack. RSTs are normal: they occur when you connect to a closed port, or when an application closes abruptly. Context matters.

Knowledge check: In your own words, what does it tell you if you see a SYN from the client but the only reply is an RST from the server?

4. Follow stream

Definition. Follow TCP Stream gathers every packet belonging to one connection, sorts them into the correct order, strips the headers, and shows the application data as one continuous transcript.

Plain explanation. A single web request might be split across many packets, interleaved with other conversations. Following the stream reassembles just that one conversation so you can read it top to bottom, with each side's data shown in a different colour.

How it works internally. Wireshark identifies the connection by its four-tuple (source IP, source port, destination IP, destination port), orders packets by TCP sequence number, and concatenates the payloads. This is the single most useful reading tool, and it is exactly what the quiz question refers to.

When to use it. Whenever you want to read content rather than inspect individual packets: an HTTP exchange, an SMTP session, a plaintext login.

When NOT to. For encrypted traffic (TLS), the stream shows ciphertext, not readable content. Following a TLS stream shows you the handshake and then noise.

Common pitfall. Forgetting that following a stream also sets a display filter (tcp.stream == N). After you close the follow window, remember to clear that filter or you will think the rest of the capture vanished.

5. Legality and scope

Definition. Packet capture records other people's data. In most jurisdictions, capturing traffic you are not authorised to capture is illegal (wiretapping / interception).

Plain explanation. Only capture traffic on a host you own, in a lab you control, or on a network where you have written permission. Sniffing a coffee-shop WiFi or a corporate network without authorisation is a crime, not a learning exercise.

Why this course uses fixtures. Live sniffing needs elevated privileges and a real network card, and it tempts learners into grey-area captures. So the matching exercises hand you the same header bytes in a fixed buffer and ask you to parse them, which teaches the exact skill Wireshark uses internally, safely and reproducibly.

Syntax notes

Display filters use field operator value, combined with logical operators. This is Wireshark syntax, not code you compile.

tcp.port == 443              # equality: note the DOUBLE equals
ip.addr == 10.0.0.5          # matches source OR destination
http.request.method == "GET" # string values in quotes
tcp.flags.syn == 1 && tcp.flags.ack == 0   # AND (&&), a bare SYN
dns || http                  # OR (||): show either protocol
!(ip.addr == 10.0.0.5)       # NOT: exclude a host correctly
tcp.stream == 3              # everything in connection #3

Key rules:

  • == not =. A single = is not a valid comparison and the bar turns red.
  • &&, ||, ! (or the words and, or, not) combine expressions.
  • Fields are hierarchical: tcp, then tcp.flags, then tcp.flags.syn. Click any field in a decoded packet and Wireshark shows its filter name in the status bar.

The common tcpdump equivalents (a different, older syntax) for quick command-line work:

tcpdump -r capture.pcap 'tcp port 80'      # read a file, keep port-80 TCP
tcpdump -r capture.pcap 'host 10.0.0.5'    # keep traffic to/from a host
tcpdump -r capture.pcap -c 20 -n           # first 20 packets, no name lookups

Lesson

A packet capture (pcap) is a recording of network traffic. Wireshark (a graphical tool) and tcpdump (a command-line tool) can read and write these files.

Reading captures is how you verify what is actually on the wire, rather than what you assume is happening.

Anatomy of a captured packet

Wireshark shows the protocol layers from top to bottom, the same layers you have already learned:

Frame 12: 74 bytes
Ethernet II   src/dst MAC          ← link
Internet Protocol  src/dst IP      ← internet
Transmission Control Protocol  src/dst port, flags, seq  ← transport
Hypertext Transfer Protocol  GET / ...    ← application

Click any layer and Wireshark highlights its bytes. This makes encapsulation (one protocol wrapped inside another) visible.

Skills that matter

  • Display filters narrow the view to the packets you want: tcp.port == 80, ip.addr == 10.0.0.5, http, dns.
  • Follow stream reassembles a whole TCP conversation into readable text.
  • Spot the handshake: SYN, SYN-ACK, ACK appear at the start of a TCP flow.
  • Read flags: SYN, ACK, FIN, and RST tell you the connection's state.

Legal note

Only capture traffic you are authorised to capture. That means your own host, a lab, or a network you have written permission to test.

Capturing other people's traffic is wiretapping. Every lab in this course uses loopback or static fixtures.

In this course

You will not run a live sniffer here. That requires elevated privileges and a real network card.

Instead, the matching C exercises have you parse the same headers (IPv4, TCP flags, ARP frames) from fixed byte buffers. This is exactly what Wireshark does internally.

Code examples

Because this is a concept lesson (no compiler), the "code" here is a realistic worked reading session: a small text-mode capture summary plus the filters and steps to make sense of it. This mirrors what you would do in Wireshark or with tcpdump on a file called web.pcap.

# 1) List the packets (like Wireshark's packet list, or `tcpdump -r web.pcap -n`)

No.  Time     Source        Dest          Proto  Length  Info
1    0.000000 10.0.0.20:51000 93.184.216.34:80 TCP  74  [SYN] Seq=0
2    0.014200 93.184.216.34:80 10.0.0.20:51000 TCP  74  [SYN, ACK] Seq=0 Ack=1
3    0.014300 10.0.0.20:51000 93.184.216.34:80 TCP  66  [ACK] Seq=1 Ack=1
4    0.014900 10.0.0.20:51000 93.184.216.34:80 HTTP 145 GET / HTTP/1.1
5    0.030100 93.184.216.34:80 10.0.0.20:51000 TCP  66  [ACK] Seq=1 Ack=80
6    0.061500 93.184.216.34:80 10.0.0.20:51000 HTTP 512 HTTP/1.1 200 OK (text/html)
7    0.061700 10.0.0.20:51000 93.184.216.34:80 TCP  66  [ACK] Seq=80 Ack=447
8    0.100000 10.0.0.20:51000 93.184.216.34:80 TCP  66  [FIN, ACK]
9    0.114000 93.184.216.34:80 10.0.0.20:51000 TCP  66  [FIN, ACK]
10   0.114200 10.0.0.20:51000 93.184.216.34:80 TCP  66  [ACK]

# 2) Narrow to just this web conversation
Display filter:  tcp.port == 80

# 3) Expand packet 4 to read its layers (the encapsulated view)
Frame 4: 145 bytes on wire
  Ethernet II   Src: aa:bb:cc:00:11:22  Dst: 00:11:22:33:44:55
  Internet Protocol Version 4   Src: 10.0.0.20  Dst: 93.184.216.34
  Transmission Control Protocol  Src Port: 51000  Dst Port: 80  Flags: [PSH, ACK]
  Hypertext Transfer Protocol
    GET / HTTP/1.1\r\n
    Host: example.com\r\n

# 4) Right-click packet 4 -> Follow -> TCP Stream
(reassembled, client in one colour, server in another)

  GET / HTTP/1.1
  Host: example.com

  HTTP/1.1 200 OK
  Content-Type: text/html
  ...<html>...

What this session does. Packets 1-3 are the three-way handshake (SYN, SYN-ACK, ACK), so we know the connection opened. Packet 4 is the HTTP request; packet 6 is the response. Packets 8-10 close the connection with FIN/ACK. The filter tcp.port == 80 removed unrelated traffic, and Follow TCP Stream reassembled the request and response into readable text.

Expected result. After following the stream you can read the full GET / HTTP/1.1 request and the HTTP/1.1 200 OK response as plain text, because HTTP on port 80 is unencrypted.

Edge cases to note. If the response were HTTPS (port 443), Follow Stream would show a TLS handshake and then ciphertext, unreadable without keys. If packet 2 (SYN-ACK) were missing and you instead saw an RST, the connection never opened. If packets arrived out of order, Wireshark would still reassemble them correctly using sequence numbers.

Line by line

Walking the packet list above, packet by packet:

Pkt Flags / Info What it means
1 [SYN] Seq=0 Client 10.0.0.20 opens a connection from ephemeral port 51000 to the server on port 80. Sequence starts at 0 (Wireshark's relative view).
2 [SYN, ACK] Ack=1 Server accepts. Ack=1 acknowledges the client's SYN (SYN counts as 1 byte).
3 [ACK] Ack=1 Client confirms. Handshake complete; the connection is now established.
4 GET / HTTP/1.1 First data packet. Length 145 is bigger because it carries the HTTP request bytes.
5 [ACK] Ack=80 Server acknowledges 79 bytes of request data (relative ack jumps from 1 to 80).
6 HTTP/1.1 200 OK The response body. Now the client will acknowledge these bytes.
7 [ACK] Ack=447 Client confirms it received the 446 bytes of response.
8-10 FIN, ACK x2 then ACK Graceful shutdown: each side sends FIN, each is acknowledged. Connection closed.

How the values change over time: the Seq and Ack numbers are counters. Each side's Seq counts bytes it has sent; the other side's Ack says "I have received everything up to here." You can watch the client's Ack climb from 1 to 447 as it receives the response, and the server's Ack climb from 1 to 80 as it receives the request. This is TCP's reliability in action: every byte is accounted for.

When you expand packet 4 (step 3 of the session), memory-wise you are looking at one contiguous byte buffer. Wireshark reads the Ethernet header first (14 bytes), sees the type field says IPv4, jumps to the IP header, reads that the payload is TCP, jumps to the TCP header, reads that the destination port is 80 and hands the rest to the HTTP dissector, which finds the GET line. Each "jump" is just an offset added to a pointer into the buffer, which is precisely what the companion C exercises make you do by hand.

Common mistakes

Mistake 1: Using = instead of == in a display filter.

WRONG:   tcp.port = 80
RIGHT:   tcp.port == 80

Why it is wrong: Wireshark's filter language uses == for equality. A single = is not valid; the filter bar turns red and nothing is applied. Recognise it by the red bar and the fact that your packet list did not change.

Mistake 2: Excluding a host with != on an address field.

WRONG:   ip.addr != 10.0.0.5      # still shows almost everything
RIGHT:   !(ip.addr == 10.0.0.5)   # truly hides that host

Why it is wrong: every packet has two addresses. ip.addr != 10.0.0.5 is true whenever either the source or the destination is not that host, which is nearly always. Negate the whole equality instead. This exact trap applies to any field that appears twice in a packet (also tcp.port, eth.addr).

Mistake 3: Confusing a capture filter with a display filter.

Capture filters (BPF syntax, e.g. tcp port 80) are applied while capturing and permanently drop packets. Display filters (e.g. tcp.port == 80) are applied afterward and are reversible. Typing BPF syntax into the display bar, or vice versa, silently fails. Prevent it by remembering: the green bar at the top of the main window is the display filter.

Mistake 4: Trying to read encrypted traffic as text.

Following a TLS stream (port 443) and expecting to see a password. Why it is wrong: TLS encrypts everything after the handshake, so the stream is ciphertext. The fix is to look for cleartext protocols (HTTP, FTP, Telnet) in the lab, and to understand that encryption is exactly what prevents this reading, which is the point of TLS.

Mistake 5: Interpreting every RST as malicious.

An RST simply means "this connection is being aborted." It happens when you hit a closed port, when a firewall rejects you, or when an app crashes. Read the surrounding packets before concluding anything. Prevent misreadings by checking whether a handshake ever completed.

Debugging tips

This is an analysis skill, so "debugging" means your reading of the capture is not making sense. Common situations and how to work through them:

"My filter shows nothing."

  • Check the filter bar colour: red means invalid syntax (often = instead of ==), so fix the expression.
  • Check you did not leave a tcp.stream == N filter set from a previous Follow Stream, clear the bar.
  • Verify the traffic actually exists: type just tcp or ip to confirm packets are present at all.

"I do not see the handshake."

  • The capture may have started after the connection opened. You will see data with no SYN. That is fine; you simply caught the middle.
  • You may be looking at UDP (DNS, QUIC), which has no handshake.

"Follow Stream shows garbage."

  • The traffic is probably encrypted (TLS/HTTPS on port 443). Ciphertext is expected; you cannot read it without keys.
  • Or you followed the wrong stream. Right-click a packet you know is part of the conversation and follow from there.

"The bytes I parse by hand (in the C exercise) do not match Wireshark."

  • Check byte order: network fields are big-endian (most significant byte first). A 16-bit length field 0x00 0x1C is 28, not 7168.
  • Check your offsets: the IP header length (IHL) is variable, so TCP does not always start at byte 34. Read IHL to find the real offset.
  • Check bit numbering when unpacking a flags byte; confirm which bit is the least significant.

Questions to ask when a capture confuses you:

  1. Did a handshake complete? (Look for SYN then SYN-ACK then ACK.)
  2. Which direction is each packet going? (Compare source and destination.)
  3. Is this TCP or UDP? (Flags and handshake only exist for TCP.)
  4. Is the payload cleartext or encrypted? (Port 80 vs 443 is a strong hint.)

Memory safety

This is a concept lesson with no C to compile, but the reading skills here connect directly to memory-safe parsing in the companion C exercises, and that connection is worth making explicit.

When you parse header bytes by hand (as in Parse the fixed fields of a mock IPv4 header or Decode TCP flag byte into individual flags), you are indexing into a byte buffer using offsets you compute from the data itself. That is a classic setting for memory-safety bugs:

  • Bounds. Never read a field without first checking the buffer is long enough. A malicious or truncated packet may claim a 60-byte header in a 20-byte buffer. Always validate length before indexing, or you read out of bounds.
  • Trusting length fields. The IPv4 Total Length and IHL, or a TLS record length, come from the packet and are attacker-controlled. Treat every length as untrusted input: check it against the actual bytes you received before you use it to advance a pointer.
  • Byte order and width. Multi-byte fields are big-endian on the network. Reading them with the host's native width or endianness silently produces wrong values (a subtle logic bug, not a crash, which is worse).
  • Integer overflow. Adding a header length to an offset can overflow if the length is huge; compute offsets in a wide type and range-check them.

The defensive habit: parsers of untrusted network data must be fail-closed. Validate every length and offset against the real buffer size before dereferencing. Historically, packet-parsing code that skipped these checks has been the source of serious vulnerabilities (buffer over-reads that leak memory). Reading captures in Wireshark is safe; writing the parser is where the discipline lives.

Real-world uses

Concrete real-world use. A backend service intermittently times out talking to a database. Logs are inconclusive. An engineer captures traffic on the app server with tcpdump -w db.pcap 'host 10.0.0.9 and port 5432', reproduces the failure, opens the file in Wireshark, filters to the failing connection, and sees the SYN going out with no SYN-ACK coming back, then a retransmit, then a timeout. That single view proves the problem is network reachability (a firewall or routing issue), not the application. The capture turned a day of guessing into a five-minute diagnosis.

Other everyday uses: verifying that a client really upgraded to TLS, confirming a DNS query returned the expected address, spotting a plaintext credential that should never have been sent unencrypted, and measuring how long a server took to respond.

Professional best-practice habits:

  • Capture narrowly. Use a capture filter (host X and port Y) so the file is small and contains only relevant, authorised traffic. Huge captures are hard to read and may sweep up data you should not have.
  • Name and annotate. Save with a descriptive filename and note the scenario. A capture without context is nearly useless a week later.
  • Filter first, drill in second. Reduce to signal, then expand layers, then follow the stream. Do not read raw thousands of packets.
  • Respect scope and law. Only ever capture where you are authorised. Redact or delete sensitive captures when done.
  • Validate untrusted input whenever you write parsing code, never trust a length field from the wire.
Level What it looks like
Beginner Opens a saved pcap, applies one filter, follows a TCP stream, identifies the handshake and reads a cleartext HTTP exchange.
Advanced Writes precise multi-clause filters, reads sequence/ack numbers to spot retransmissions and window issues, uses tcpdump on headless servers, correlates captures with logs, and writes bounds-checked parsers for custom protocols.

Practice tasks

Beginner 1 - Label a handshake. Objective: Given the 10-packet listing in the Code section, identify the three packets that form the TCP three-way handshake and state the flags on each. Requirements: Name the packet numbers and the flag(s) each carries; state at which packet the connection becomes established. Constraints: Use only the listing provided. Hint: The handshake is always SYN, then SYN-ACK, then ACK, at the very start. Concepts: TCP flags, the handshake.

Beginner 2 - Write three filters. Objective: Write Wireshark display filters for three goals. Requirements: (a) show only DNS traffic; (b) show only traffic to or from 192.168.1.50; (c) show only bare SYN packets (SYN set, ACK not set). Example expected answers use the fields dns, ip.addr, tcp.flags.syn, tcp.flags.ack. Constraints: Use display-filter syntax with ==, &&, and correct field names. Hint: A bare SYN is tcp.flags.syn == 1 && tcp.flags.ack == 0. Concepts: Display filters, flags.

Intermediate 1 - Follow the money (bytes). Objective: Using the sequence and acknowledgement numbers in the listing, explain how you can tell the client received the entire HTTP response. Requirements: Reference the specific Seq/Ack values; explain what the final client Ack value proves. Input/output: Point to packet 7 (Ack=447) in your explanation. Constraints: Explain in prose; no tools needed. Hint: An Ack value means "I have received everything up to this byte." Concepts: TCP reliability, sequence/ack numbers.

Intermediate 2 - Spot the failure. Objective: Describe, packet by packet, what a failed connection to a closed port looks like, and contrast it with a filtered (firewalled) port. Requirements: State the flags you would see in each case (closed port vs. silently dropped), and how a capture distinguishes "connection refused" from "no route / dropped". Constraints: Concept answer; reference SYN, RST, and the absence of a reply. Hint: A closed port typically replies with RST; a firewall that drops packets replies with nothing (you see retransmitted SYNs). Concepts: Handshake, flags, RST, diagnosing reachability.

Challenge - Manual offset walk (bridge to the C exercise). Objective: On paper, given a 20-byte IPv4 header where the first byte is 0x45, determine the IP version, the header length in bytes, and the byte offset at which the TCP header begins in the frame (assume a 14-byte Ethernet header before it). Then explain the one bounds check you must perform before reading the TCP source port. Requirements: Show how 0x45 splits into version (high nibble) and IHL (low nibble); convert IHL (in 32-bit words) to bytes; compute the TCP start offset; state the length check. Constraints: No code required, but your reasoning should map directly onto the Parse the fixed fields of a mock IPv4 header exercise. Hint: IHL is measured in 4-byte words, so IHL 5 means a 20-byte IP header. TCP starts at 14 + 20. Before reading a 2-byte port at that offset, confirm the buffer holds at least offset + 2 bytes. Concepts: Encapsulation, header offsets, big-endian fields, bounds checking untrusted input.

Summary

A packet capture (pcap) is a byte-for-byte recording of network traffic; Wireshark reads it graphically and tcpdump on the command line. It is ground truth: what actually crossed the wire, not what you assumed.

The core reading workflow: (1) apply a display filter to cut noise (tcp.port == 80, ip.addr == ..., http, dns), remembering == not = and !(ip.addr == x) to exclude a host; (2) expand a packet's layers to see encapsulation (Ethernet -> IP -> TCP/UDP -> application) and read exact field values; (3) recognise the three-way handshake (SYN, SYN-ACK, ACK) and decode the flags (SYN, ACK, FIN, RST, PSH, URG); (4) Follow TCP Stream to reassemble a scattered conversation into readable text, which only works for cleartext, not TLS.

Common mistakes: = vs ==, misusing != on address fields, confusing capture and display filters, expecting to read encrypted traffic, and treating every RST as an attack.

Remember: only capture traffic you are authorised to capture. And when you write a parser for these headers (the companion C exercises), treat every length and offset from the wire as untrusted, validate against the real buffer size, and respect big-endian byte order. Reading is safe; parsing is where the safety discipline lives.

Practice with these exercises