tcpdump can show you what’s actually happening on the wire for HTTP, but it’s a bit like trying to read a novel through a tiny peephole if you don’t know what to look for.

Here’s a live capture of a simple HTTP GET request and its response, and then we’ll break down how to make sense of it.

# On the server where the web server is running, or on a machine that can see the traffic
# We'll filter for traffic to/from port 80 (HTTP) on a specific IP address
# Replace 192.168.1.100 with your server's IP
sudo tcpdump -i eth0 host 192.168.1.100 and port 80 -A -vvv

Now, from another machine, run curl http://192.168.1.100 (or just hit that URL in a browser).

You’ll see output like this (simplified and annotated):

10:30:01.123456 IP (tos 0x0, ttl 64, id 12345, offset 0, flags [DF], proto TCP (6) (len 60)
    192.168.1.50.54321 > 192.168.1.100.80: Flags [S], seq 1234567890, win 29200, options [mss 1460,sackOK,TS val 1234567 ecr 0,nop,wscale 7], length 0

10:30:01.123500 IP (tos 0x0, ttl 64, id 54321, offset 0, flags [DF], proto TCP (6) (len 60)
    192.168.1.100.80 > 192.168.1.50.54321: Flags [S.], seq 987654321, ack 1234567891, win 28960, options [mss 1460,sackOK,TS val 9876543 ecr 1234567,wscale 7], length 0
    E.. ....@.@. .... ....@. . ....P. .... .... .... .).... .)... ...

10:30:01.123550 IP (tos 0x0, ttl 64, id 12346, offset 0, flags [DF], proto TCP (6) (len 52)
    192.168.1.50.54321 > 192.168.1.100.80: Flags [.], ack 1, win 228, options [nop,nop,TS val 1234570 ecr 9876543], length 0
    E.. ....@.@. .... ....@. . ....P. .... .... .... .... .... .... ....

10:30:01.123600 IP (tos 0x0, ttl 64, id 12347, offset 0, flags [DF], proto TCP (6) (len 380)
    192.168.1.50.54321 > 192.168.1.100.80: Flags [P.], seq 1:337, ack 1, win 228, options [nop,nop,TS val 1234570 ecr 9876543], length 336: HTTP: GET / HTTP/1.1
    Host: 192.168.1.100
    User-Agent: curl/7.68.0
    Accept: */*

10:30:01.123700 IP (tos 0x0, ttl 64, id 54322, offset 0, flags [DF], proto TCP (6) (len 1514)
    192.168.1.100.80 > 192.168.1.50.54321: Flags [.], ack 337, win 245, options [nop,nop,TS val 9876550 ecr 1234570], length 1454: HTTP: HTTP/1.1 200 OK
    Content-Type: text/html; charset=UTF-8
    Content-Length: 1000
    Date: Mon, 01 Jan 2024 10:30:01 GMT
    Server: Apache/2.4.41 (Ubuntu)

    <!DOCTYPE html>
    <html>
    <head>
    <title>Test Page</title>
    </head>
    <body>
    <h1>Hello, World!</h1>
    </body>
    </html>
    ... (rest of HTML)
    E.. ....@.@. .... ....@. . ....P. .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... .... ........")

This output contains the magic: the `E..` lines are the ASCII representation (`-A`), and the rest is the header information.

**The TCP Handshake (First few lines):**

*   **SYN (`S`)**: The client (your `curl` command, IP `192.168.1.50`) initiates the connection by sending a SYN packet. This is like saying, "Hey, I want to talk."
*   **SYN-ACK (`S.`)**: The server (`192.168.1.100`) responds with a SYN-ACK, acknowledging the client's request and sending its own SYN. This is like saying, "Okay, I hear you, and I'm ready too."
*   **ACK (`.`)**: The client sends a final ACK to confirm the connection is established. This is the "three-way handshake" completing.

**The HTTP Request and Response:**

*   **`Flags [P.]` (Packet with Push and ACK)**: This is the client sending the actual HTTP request data. The `P` flag means "Push" – send the data now. The `.` is an ACK for the server's SYN-ACK.
    *   `GET / HTTP/1.1`: The HTTP method, the path requested (root `/`), and the HTTP version.
    *   `Host: 192.168.1.100`: Essential for virtual hosting.
    *   `User-Agent`, `Accept`: Other headers providing client information.
*   **`Flags [.]` (Packet with ACK)**: The server acknowledges receipt of the HTTP request.
*   **`Flags [P.]` (Packet with Push and ACK)**: This is the server sending the HTTP response data.
    *   `HTTP/1.1 200 OK`: The HTTP status line. `200 OK` is a success code.
    *   `Content-Type`, `Content-Length`, `Date`, `Server`: Response headers.
    *   The rest of the data is the HTML body of the page.

**The "Why" and "How" of `tcpdump` for HTTP:**

`tcpdump` operates at the network interface level. It doesn't understand HTTP intrinsically; it sees raw packets. The magic happens when you combine `tcpdump`'s packet capture capabilities with its ability to interpret TCP/IP headers and, with the `-A` flag, display the *payload* of packets as ASCII.

For HTTP, this means you're seeing:

1.  **TCP connection establishment**: The SYN, SYN-ACK, ACK packets that form the foundation of the communication.
2.  **HTTP request**: The raw bytes of your `GET` or `POST` request, including headers and any body.
3.  **HTTP response**: The raw bytes of the server's `200 OK`, `404 Not Found`, etc., along with its headers and body.

**Levers You Control:**

*   **`-i interface`**: Specifies which network interface to listen on (e.g., `eth0`, `en0`, `any`). `any` can be useful but might capture more than you want.
*   **`host <IP_address>`**: Filters traffic to or from a specific IP address. Crucial for isolating your server.
*   **`port <port_number>`**: Filters traffic to or from a specific TCP/UDP port. Use `port 80` for HTTP, `port 443` for HTTPS (though HTTPS payload will be encrypted).
*   **`-A`**: ASCII output. This is what makes HTTP readable. Without it, you'd see hex dumps of the payload.
*   **`-vvv`**: Very verbose output. Shows more packet details like TTL, TOS, IP ID, and TCP sequence/acknowledgement numbers, which are invaluable for diagnosing connection issues.
*   **`expr` (filter expression)**: You can combine `host`, `port`, and other primitives with `and`, `or`, `not` to create very specific filters. For example, `tcpdump -i eth0 host 192.168.1.100 and port 80 and 'tcp[tcpflags] & tcp-syn != 0'` would show only SYN packets.

**The One Thing Most People Don't Know:**

When you see `tcp[tcpflags] & tcp-syn != 0` in a filter, `tcpflags` is a special keyword that accesses the TCP flags byte. The bitwise AND (`&`) operation with `tcp-syn` (which is a predefined value representing the SYN flag bit) effectively isolates the SYN flag. If the result is non-zero, it means the SYN flag was set in that packet. This is fundamental to understanding how to filter by specific TCP states.

The next step is often dealing with encrypted traffic, which means diving into SSL/TLS handshake analysis or using `wireshark` with session keys.

Want structured learning?

Take the full Tcpdump course →