What is tcpdump?
When you write a TCP/IP application, you often need to see exactly what packets are flying over the network โ are they arriving? In what order? With what flags? That is exactly what tcpdump does. It is a command-line tool that captures network packets and prints them in a human-readable format so you can debug connections, verify handshakes, and spot problems.
Wireshark is the graphical alternative that does the same job but with a point-and-click interface. It was formerly called Ethereal and is available at http://www.wireshark.org/.
For every TCP segment captured, tcpdump prints one line like this:
src > dst: flags data-seqno ack window urg <options>
Here is what each part means:
| Field | Meaning | Example |
|---|---|---|
src |
Source IP address and port | pukaki.60391 |
dst |
Destination IP address and port | tekapo.55555 |
flags |
TCP control bits โ S=SYN, F=FIN, P=PSH, R=RST, E=ECE, C=CWR, dot(.)=ACK only | S or P or . |
data-seqno |
Range of sequence numbers covered by bytes in this packet. By default shown relative to the first byte seen; use -S for absolute values. |
1:17(16) means bytes 1โ17, size 16 |
ack |
Next sequence number expected from the other side | ack 17 |
window |
Receive buffer space available โ tells sender how much data can be sent before blocking | win 5840 |
urg |
Offset of urgent data in the segment (rare) | urg 0 |
options |
TCP option fields (timestamps, MSS, etc.) | omitted in examples |
Note: src, dst, and flags are always shown. The rest appear only when relevant to that segment.
The most common invocation to filter by port number:
$ tcpdump -t -N 'port 55555'
Option breakdown:
-tโ suppress timestamp, keeps output clean-Nโ show hostnames without the domain part (e.g.,pukakiinstead ofpukaki.example.com)'port 55555'โ Berkeley Packet Filter (BPF) expression that captures only traffic on port 55555-Sโ show absolute sequence numbers instead of relative ones
You can also capture on a specific interface:
$ sudo tcpdump -i eth0 -t -N 'port 55555'
Before any data flows, TCP performs a three-way handshake to establish the connection. Here is what tcpdump shows for that exchange between client pukaki and server tekapo on port 55555:
IP pukaki.60391 > tekapo.55555: S 3412991013:3412991013(0) win 5840
IP tekapo.55555 > pukaki.60391: S 1149562427:1149562427(0) ack 3412991014 win 5792
IP pukaki.60391 > tekapo.55555: . ack 1 win 5840
SYN+ACK
Notice:
- Line 1: Client sends
S(SYN) with its initial sequence number, zero data bytes(0). - Line 2: Server replies with
S(SYN) + acknowledges client’s seq (ack 3412991014= client seq + 1). - Line 3: Client sends a plain ACK (
.). The sequence numbers are now shown relative โack 1means the first expected byte from server.
After the handshake, the client sends two messages (16 bytes, then 32 bytes). The server replies with 4-byte acknowledgements each time:
IP pukaki.60391 > tekapo.55555: P 1:17(16) ack 1 win 5840
IP tekapo.55555 > pukaki.60391: . ack 17 win 1448
IP tekapo.55555 > pukaki.60391: P 1:5(4) ack 17 win 1448
IP pukaki.60391 > tekapo.55555: . ack 5 win 5840
IP pukaki.60391 > tekapo.55555: P 17:49(32) ack 5 win 5840
IP tekapo.55555 > pukaki.60391: . ack 49 win 1448
IP tekapo.55555 > pukaki.60391: P 5:9(4) ack 49 win 1448
IP pukaki.60391 > tekapo.55555: . ack 9 win 5840
How to read P 1:17(16):
Pโ PSH flag is set, meaning the sender wants the receiver to deliver the data immediately to the application.1:17โ Sequence numbers 1 through 17 (relative).(16)โ 16 bytes of payload.
Each data segment gets an ACK (.) from the other side confirming receipt. The server’s receive window shrinks from 5792 to 1448 as it processes data.
Closing a TCP connection takes four segments, not three, because each side independently closes its half:
IP pukaki.60391 > tekapo.55555: F 49:49(0) ack 9 win 5840
IP tekapo.55555 > pukaki.60391: . ack 50 win 1448
IP tekapo.55555 > pukaki.60391: F 9:9(0) ack 50 win 1448
IP pukaki.60391 > tekapo.55555: . ack 10 win 5840
ACK (ack 50)
FIN (seq=9)
Notice the client FIN goes from seq 49 to 49 with zero bytes โ the FIN itself consumes one sequence number. So the server ACKs with ack 50. Similarly, the server FIN at seq 9 gets ACKed by client as ack 10.
Here is a minimal TCP server in C. Run it, then use tcpdump to watch the handshake:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#define PORT 55555
#define BUF_SIZE 256
int main(void)
{
int sfd, cfd;
struct sockaddr_in addr;
char buf[BUF_SIZE];
ssize_t nr;
/* 1. Create TCP socket */
sfd = socket(AF_INET, SOCK_STREAM, 0);
if (sfd == -1) { perror("socket"); exit(EXIT_FAILURE); }
/* 2. Bind to port 55555 on all interfaces */
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sfd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
perror("bind"); exit(EXIT_FAILURE);
}
/* 3. Listen for connections */
if (listen(sfd, 5) == -1) { perror("listen"); exit(EXIT_FAILURE); }
printf("Server listening on port %d\n", PORT);
printf("In another terminal run:\n");
printf(" sudo tcpdump -t -N 'port %d'\n\n", PORT);
/* 4. Accept one connection */
cfd = accept(sfd, NULL, NULL);
if (cfd == -1) { perror("accept"); exit(EXIT_FAILURE); }
printf("Client connected!\n");
/* 5. Echo data back */
while ((nr = read(cfd, buf, BUF_SIZE)) > 0) {
printf("Received %zd bytes\n", nr);
if (write(cfd, buf, nr) != nr) {
fprintf(stderr, "Partial write\n");
}
}
close(cfd);
close(sfd);
return 0;
}
Compile and run:
$ gcc -o tcp_server tcp_server.c
$ ./tcp_server
In another terminal, start tcpdump before connecting a client:
$ sudo tcpdump -t -N 'port 55555'
Connect with netcat to generate traffic:
$ echo "Hello World" | nc localhost 55555
You will see SYN, SYN-ACK, ACK, PSH, FIN segments in tcpdump output.
Q1. What does the dot (.) in tcpdump flags mean?
The dot means only the ACK bit is set in the TCP segment โ no SYN, no FIN, no data push. It is a pure acknowledgement.
Q2. In the tcpdump line P 1:17(16), what does each part represent?
P = PSH flag; 1:17 = relative sequence range; (16) = 16 bytes of data payload.
Q3. Why does a TCP connection need three segments to open but four to close?
Opening is done together โ the server combines SYN and ACK in one segment. Closing requires each side to separately send a FIN and receive an ACK because the two halves of the connection are independent; the server may still have data to send after the client closes its half.
Q4. What does the -S option in tcpdump do?
By default, tcpdump shows relative sequence numbers starting from 0. The -S option forces absolute sequence numbers as negotiated in the SYN segment.
Q5. What is the difference between tcpdump and Wireshark?
Both capture and decode network packets. tcpdump is a command-line tool suited for servers and automation. Wireshark provides a graphical interface with colour-coded protocol dissection and interactive filtering, which is better for interactive debugging on a desktop.
Q6. What does the win field in tcpdump output represent?
It shows the receive window size โ the number of bytes the sender of that segment is willing to accept before getting an acknowledgement. It is how TCP implements flow control.
Q7. What BPF filter would you use to capture only HTTP traffic?
$ sudo tcpdump -t -N 'tcp port 80'
You can also combine filters: 'host 192.168.1.5 and port 80'.
