Guides

tcpdump command: examples, filters, pcap rotation and Wireshark over SSH

tcpdump examples tested on Linux: capture a port or host, filter syntax, save and rotate pcap files, spot SYN floods, stream to Wireshark over SSH.

Published ~13 min read
On this page

tcpdump prints the packets that cross a network interface, one line per packet, and can save them to a file for Wireshark. On a server it answers questions no log can: is the request reaching the machine at all, who is opening connections to port 443, which DNS server the box really asks, and who sends the reset. The outputs marked as real were captured on a Debian 12 server with tcpdump 4.99.3, on the loopback interface against our own test services; the eth0 recipes use the same flags.

Short answer

  • Watch one port: sudo tcpdump -i eth0 -nn port 443. Stop with Ctrl+C.
  • Save for Wireshark: sudo tcpdump -i eth0 -nn -w web.pcap port 443, read it back with tcpdump -nn -r web.pcap.
  • Quote filters with parentheses: sudo tcpdump -i eth0 -nn 'host 203.0.113.7 and (port 80 or port 443)'

Key facts

Package
tcpdump (apt, dnf, apk, pacman)
Needs
root, or CAP_NET_RAW, to capture
Default snapshot length
262144 bytestcpdump 4.99
Filter syntax
man 7 pcap-filter
Stops on
Ctrl+C, or after -c N packets
File format
.pcap, opens in Wireshark

Install tcpdump and pick the interface

install
sudo apt install tcpdump        # Debian, Ubuntu
sudo dnf install tcpdump        # Rocky, AlmaLinux, Fedora
sudo apk add tcpdump            # Alpine
sudo pacman -S tcpdump          # Arch
tcpdump --version

Without -i, tcpdump picks the lowest numbered interface that is up, loopback excluded. That guess is usually right on a VPS with one network card, but name it anyway, so a script does the same on every server. tcpdump -D lists what it can capture on:

Real output · sudo tcpdump -D, Debian 12 (first three lines)
1.eth0 [Up, Running, Connected]
2.any (Pseudo-device that captures on all interfaces) [Up, Running]
3.lo [Up, Running, Loopback]
  • eth0, ens3, ens18, enp1s0: the public network card. The name depends on the image and the hypervisor; ip -br addr shows which one holds your public IP.
  • any: every interface at once, including loopback and Docker bridges. The man page notes that it never runs in promiscuous mode, and each line gains two columns: the interface and the direction (In or Out).
  • lo: traffic between programs on the same server, such as nginx talking to an app on 127.0.0.1:3000 or lookups to the local DNS stub.
Real output, trimmed to 1 of 3 packets · -i any adds interface and direction
$ sudo tcpdump -i any -nn -c 3 port 18080
tcpdump: data link type LINUX_SLL2
listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
03:15:59.257627 lo    In  IP 127.0.0.1.46466 > 127.0.0.1.18080: Flags [S], seq 120644302, win 65495, options [mss 65495,sackOK,TS val 2437651709 ecr 0,nop,wscale 7], length 0

How to read tcpdump output

This is one complete HTTP request, captured with sudo tcpdump -i lo -nn -c 10 port 18080 while curl fetched a page from a test server on port 18080. It is trimmed to fit the page: the TCP options and the first line (tcpdump: verbose output suppressed, use -v[v]... for full protocol decode) were cut.

Real output, trimmed · one curl request, Debian 12, tcpdump 4.99.3
listening on lo, link-type EN10MB (Ethernet), snapshot length 262144 bytes
03:15:57.068132 IP 127.0.0.1.46446 > 127.0.0.1.18080: Flags [S], seq 1574766054, win 65495, length 0
03:15:57.068146 IP 127.0.0.1.18080 > 127.0.0.1.46446: Flags [S.], seq 2675402100, ack 1574766055, win 65483, length 0
03:15:57.068157 IP 127.0.0.1.46446 > 127.0.0.1.18080: Flags [.], ack 1, win 512, length 0
03:15:57.068190 IP 127.0.0.1.46446 > 127.0.0.1.18080: Flags [P.], seq 1:77, ack 1, win 512, length 76
03:15:57.068194 IP 127.0.0.1.18080 > 127.0.0.1.46446: Flags [.], ack 77, win 511, length 0
03:15:57.070098 IP 127.0.0.1.18080 > 127.0.0.1.46446: Flags [P.], seq 1:185, ack 77, win 512, length 184
03:15:57.070107 IP 127.0.0.1.46446 > 127.0.0.1.18080: Flags [.], ack 185, win 511, length 0
03:15:57.070134 IP 127.0.0.1.18080 > 127.0.0.1.46446: Flags [P.], seq 185:191, ack 77, win 512, length 6
03:15:57.070136 IP 127.0.0.1.46446 > 127.0.0.1.18080: Flags [.], ack 191, win 511, length 0
03:15:57.070164 IP 127.0.0.1.46446 > 127.0.0.1.18080: Flags [F.], seq 77, ack 191, win 512, length 0
10 packets captured
26 packets received by filter
0 packets dropped by kernel
  • Timestamp, then IP (or IP6, ARP).
  • 127.0.0.1.46446 > 127.0.0.1.18080: source address and port, then destination. The last dot-separated number is the port, also for IPv6 addresses.
  • Flags: S SYN, F FIN, P PUSH (data), R RST, and a dot for ACK. [S], [S.], [.] is the three-way handshake; [P.] carries data; [F.] starts the close.
  • seq 1:77 and length 76: this packet carries bytes 1 to 76 of the client’s stream (the HTTP request). After the handshake, tcpdump prints sequence numbers relative to the start; add -S for the real ones. If the capture starts in the middle of a connection, it never sees the start and prints the large absolute numbers instead.
  • The three counters at the end: captured is what tcpdump processed, and the meaning of received by filter depends on the OS (here it was higher than captured). Only dropped by kernel tells you about lost packets: it must be 0, or you are missing some.

The handshake itself, retransmissions and what a refused or dropped SYN looks like are explained in what TCP is and how the handshake works.

Options that change the output

OptionWhat it does
-nNo DNS lookups and no port names. In tcpdump 4.99, -n and -nn printed identical lines in our test; -nn is still the habit and harmless.
-c 100Stop after 100 packets.
-v, -vv, -vvvMore detail: TTL, IP ID, total length, full DNS answers.
-ttttDate and time on each line (2026-11-02 03:17:32.731853).
-APayload as ASCII. Readable for HTTP, SMTP and DNS names.
-XPayload as hex and ASCII side by side.
-eLink-layer header: MAC addresses.
-lLine-buffered output, needed when you pipe into grep or awk and want lines right away.
-qShorter lines with less protocol detail.
-s 128Keep only the first 128 bytes of each packet (default 262144).
-#Number each packet, like Wireshark's No. column.

Without -n, the same DNS packet read back from our capture file printed localhost.37266 and 127.0.0.53.domain instead of numbers. On a busy server the reverse lookups also slow tcpdump down, which is one of the causes of dropped packets.

tcpdump filters: host, net, port, protocol

Everything after the options is the filter, written in the libpcap filter language (man 7 pcap-filter). The kernel applies it before tcpdump sees a packet, so a tight filter is also the cheapest way to avoid drops. Put the whole filter in single quotes.

CaptureFilter
To or from one addresshost 203.0.113.7
Only from, or only to, an addresssrc host 203.0.113.7 / dst host 203.0.113.7
A whole subnetnet 198.51.100.0/24
One port, TCP or UDPport 443
Only the destination porttcp dst port 443
A port rangeportrange 8000-8100
By protocoltcp / udp / icmp / icmp6 / arp / ip6
Two portsport 80 or port 443
Everything except SSHnot port 22
One client on the web portshost 203.0.113.7 and (port 80 or port 443)
Packets of 1000 bytes or moregreater 1000
New TCP connections only (SYN without ACK)tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn
Resets onlytcp[tcpflags] & tcp-rst != 0
Ping requests and repliesicmp[icmptype] == icmp-echo or icmp[icmptype] == icmp-echoreply

Three rules from the man page that explain most surprises:

  • not binds tightest, and and and or have equal precedence, read left to right. not host a and b means not host a and host b, not not (a or b). Use parentheses whenever you mix them.
  • A missing keyword repeats the last one. port 80 or 443 is read as port 80 or port 443.
  • Byte offsets such as tcp[13] or tcp[tcpflags] only match IPv4 in libpcap 1.10 (Debian 12): the BUGS section says arithmetic on transport headers ignores IPv6 packets. A SYN filter therefore silently misses IPv6 clients. In our test, 'ip6 and tcp[tcpflags] & tcp-syn != 0' stopped at once with tcpdump: expression rejects all packets.

For IPv6, read the flags from the IPv6 header instead. The IPv6 header is 40 bytes and the TCP flags are byte 13 of the TCP header, so a new connection (SYN set, ACK clear) is:

new TCP connections over IPv6
sudo tcpdump -i eth0 -nn 'ip6 and tcp dst port 443 and ip6[40+13] & 0x12 == 0x02'

It only works when TCP follows the IPv6 header directly. Packets with extension headers in between are not matched at all, which is rare for normal web traffic. In our test it caught the SYN of a curl to [::1] and nothing else.

Only incoming or only outgoing: -Q

-Q in keeps only the packets the interface receives, -Q out only the ones it sends; without -Q you get both. On a server with several addresses that is simpler than writing every address into dst host: sudo tcpdump -i eth0 -nn -Q in 'tcp port 443' shows only what clients send. The man page says the option is not available on every platform; on Linux, tcpdump 4.99.3 accepted it, also together with -i any.

Test a filter, or keep it in a file

To check a filter without capturing, compile it with -d. This needs no root and no capture file: tcpdump -d 'tcp dst port 443' as a normal user printed Warning: assuming Ethernet and the BPF program in our test, or the syntax error when the filter is wrong. Add -r web.pcap to compile it for the exact link type of a capture file.

Long filters can live in a file: -F filter.txt reads the expression from it, and per the man page a filter on the command line is then ignored. Keep the file in your home directory or under /tmp, because the AppArmor profile described in the errors below blocks reads from most other places.

Save, rotate and read pcap files

write and read
sudo tcpdump -i eth0 -nn -w web.pcap port 443          # write raw packets, print nothing
sudo tcpdump -i eth0 -nn -w web.pcap --print port 443  # write and show them at the same time
tcpdump -nn -r web.pcap                                # read back, no root needed
tcpdump -nn -r web.pcap 'tcp[tcpflags] & tcp-rst != 0' # read back with a filter
tcpdump --count -r web.pcap 'tcp[tcpflags] & tcp-syn != 0'   # only count matches

-w stores whole packets, not the text lines, so you can filter the file again later in tcpdump or Wireshark. The output is buffered: another program reading the file while the capture runs sees nothing for a while, unless you add -U.

Rotate captures with -C, -G and -W

rotation
# ring buffer by size: at most 10 files of about 100 MB, oldest overwritten
sudo tcpdump -i eth0 -nn -C 100 -W 10 -w /var/tmp/pcap/ring.pcap port 443

# one file per hour, names from strftime, compressed after each rotation
sudo tcpdump -i eth0 -nn -G 3600 -w '/var/tmp/pcap/web-%Y%m%d-%H%M.pcap' -z gzip port 443

What the man page says, and what our test showed:

  • -C counts millions of bytes (1,000,000, not 1,048,576), and checks the size before each write, so files end slightly above it. With -C 1 -W 3, our capture produced ring.pcap0, ring.pcap1 and ring.pcap2, and kept writing in a circle.
  • -G with -W is not a ring. tcpdump stops after that many files. Our -G 2 -W 3 test ended with Maximum file limit reached: 3 and exit code 0 after six seconds. For an always-on hourly capture, leave out -W and delete old files with a timer, for example find /var/tmp/pcap -name 'web-*' -mmin +1440 -delete.
  • -G without a time format in the name overwrites the same file every period. With both -C and -G, the man page says -W is ignored.

tcpdump examples for servers

Replace eth0 with your interface. Each recipe is safe to run on a production server: none of them changes anything, and the filters keep the volume small.

Who is opening connections to port 443?

top sources of new HTTPS connections (IPv4)
sudo tcpdump -i eth0 -nn -l -c 2000 \
  'tcp dst port 443 and tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn' 2>/dev/null |
  awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | sort -rn | head -20

Only the first packet of each connection matches, so the count is connections, not traffic. Field $3 is the source in the normal output; with -i any, the interface and direction columns push it to $5. The cut drops the port, which only works for IPv4 addresses, and the flag filter is IPv4 only anyway (see the rules above). For IPv6 clients, swap in the ip6[40+13] filter from that section and replace the cut with sed 's/\.[0-9]*$//', which strips the port from both address types.

Spot a SYN flood

SYN rate and half-open connections
# new connection attempts in 10 seconds
sudo timeout 10 tcpdump -i eth0 -nn 'tcp dst port 443 and tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn' 2>/dev/null | wc -l
# the same for IPv6 clients
sudo timeout 10 tcpdump -i eth0 -nn 'ip6 and tcp dst port 443 and ip6[40+13] & 0x12 == 0x02' 2>/dev/null | wc -l

# handshakes the server answered but the client never completed
ss -Htn state syn-recv '( sport = :443 )' | wc -l
ss -Htn state established '( sport = :443 )' | wc -l

On a healthy server syn-recv is close to 0, because real clients answer the SYN-ACK within milliseconds. The SYN count has no universal normal value: run the same 10-second count in a quiet hour and keep it as your baseline. A flood shows a SYN rate far above that baseline, a syn-recv count that stays high, and few completed handshakes, often from random, spoofed source addresses, so the per-source list above stays flat instead of showing one attacker. With net.ipv4.tcp_syncookies=1 (the kernel default, also on our Debian 12 host), syn-recv stops growing at the size of the SYN backlog: the kernel answers further SYNs with cookies instead of storing them, and logs a line containing Possible SYN flooding on port. A flat syn-recv count is therefore no sign that the flood has stopped. Background on the attack types is in what a DDoS attack is.

Watch DNS queries

DNS lookups from this server
sudo tcpdump -i any -nn -l 'port 53'
Real output · dig @127.0.0.53 example.net, captured on lo
03:17:32.731853 IP 127.0.0.1.37266 > 127.0.0.53.53: 51342+ [1au] A? example.net. (52)
03:17:32.734063 IP 127.0.0.53.53 > 127.0.0.1.37266: 51342 2/0/1 A 172.66.175.59, A 104.20.21.8 (72)

51342 is the query ID that pairs question and answer, + means recursion desired, A? the record type asked for, and (52) the DNS message length. In the answer, 2/0/1 counts answer, authority and additional records. The [1au] on the query is its one additional record, the EDNS option. Use -i any on Ubuntu and Debian with systemd-resolved: programs ask the stub on 127.0.0.53 over loopback, and only the stub’s own queries leave through eth0. Filter on port 53, not udp port 53, because large answers retry over TCP.

See which sites are requested (HTTP Host and HTTPS SNI)

plain HTTP: the Host header
sudo tcpdump -i eth0 -nn -l -A 'tcp dst port 80' | grep -a -i '^Host:'
HTTPS: the server name in the TLS ClientHello
sudo tcpdump -i eth0 -nn -A -c 20 \
  'tcp dst port 443 and tcp[((tcp[12] & 0xf0) >> 2)] = 0x16'

HTTPS encrypts the Host header, but the name the browser asks for travels in clear text in the first TLS message, the ClientHello. The filter reads the TCP header length, jumps to the first payload byte and keeps packets where it is 0x16, a TLS handshake record. In our test (openssl s_client over loopback, a 517-byte ClientHello in one packet), -A on that packet showed the test name shop.example in the ASCII column. Where it falls short:

  • Large ClientHellos from current browsers. Chrome and Firefox now send a post-quantum key share (X25519MLKEM768), which makes the ClientHello about 1.8 KB. On eth0 with a 1500-byte MTU it spans two TCP segments, and Chrome shuffles the order of its extensions, so the server name can land in the second segment. That segment does not start with 0x16, and the filter does not show it. The reliable route is a pcap file and tshark -r web.pcap -Y tls.handshake.extensions_server_name -T fields -e tls.handshake.extensions_server_name, which reassembles the segments first.
  • Encrypted Client Hello (ECH). The name in clear text is only the outer public name, for example the ECH name of the CDN, not the real site.
  • IPv4 only. Like the flag filters, the tcp[...] offsets do not match IPv6 packets.
  • HTTP/3 runs over UDP 443, which a tcp filter never sees.

Find out who sends a reset

sudo tcpdump -i any -nn 'tcp port 443 and tcp[tcpflags] & tcp-rst != 0' shows every RST on the port, with the side that sent it. How to read the result when a browser reports a reset is in ERR_CONNECTION_RESET for site owners.

Capture for a fixed time

60 seconds, then stop
sudo timeout 60 tcpdump -i eth0 -nn -w /var/tmp/pcap/minute.pcap 'port 443'

timeout sends SIGTERM, on which tcpdump closes the file cleanly and prints its counters, so a cron job or a support script cannot leave a capture running forever.

Capture a Docker container’s traffic

Docker bridge, or one container
# all containers on Docker's default bridge network
sudo tcpdump -i docker0 -nn port 80

# one container, inside its network namespace (eth0 is the container's interface)
sudo nsenter -t "$(docker inspect -f '{{.State.Pid}}' CONTAINER)" -n tcpdump -i eth0 -nn port 80
  • docker0 is the default bridge. Containers on a network you created with docker network create sit on a br- bridge instead, and every container also has its own veth interface on the host; ip -br link lists them.
  • nsenter -n enters only the container’s network namespace. tcpdump, its filter and the -w path all come from the host, so the image needs no tcpdump.
  • Addresses: on docker0 and inside the container you see the container’s private address; on the host’s eth0 the same traffic appears after Docker’s NAT, with the host’s public address.

Capture remotely and open it in Wireshark

Two ways. The simple one: write a file on the server, copy it home, open it.

file, then copy
# on the server
sudo tcpdump -i eth0 -nn -c 5000 -w /var/tmp/pcap/web.pcap 'port 443'
# on your PC
scp root@203.0.113.10:/var/tmp/pcap/web.pcap .

The live one: run tcpdump over SSH, write the packets to standard output and let Wireshark read them from standard input.

live stream into Wireshark (Linux, macOS)
ssh root@203.0.113.10 "tcpdump -i eth0 -U -w - 'not port 22'" | wireshark -k -i -
  • not port 22 keeps your own SSH session out. Without it, every captured packet travels back over SSH, which creates new packets to capture, and the stream feeds itself. If SSH runs on another port, exclude that one, or narrow it to your session with not (host YOUR_IP and port 22).
  • -w - and -U: raw packets to standard output, flushed after each packet so Wireshark shows them as they arrive. We tested the same pipe locally into tcpdump -r -.
  • -k -i -: per the Wireshark manual, start capturing at once and read pcap data from standard input.
  • Not root on the server? Use sudo tcpdump with a sudo rule that needs no password. Do not add ssh -t to answer a password prompt: a terminal rewrites line endings and corrupts the binary stream.
  • Windows: run the same pipe from cmd.exe with the full path to Wireshark.exe. Windows PowerShell 5.1 pipes between programs as text and breaks the pcap data.

If the server uses another SSH port, user or key, put them in a Host block of your SSH config file and the pipe stays a one-liner.

tcpdump vs Wireshark vs ss

tcpdumpWiresharkss
Runs on a headless serverYesNoYes
Shows individual packetsYesYesNo
Shows sockets and the owning processNoNoYes
Decodes protocols in depth (TLS, HTTP/2, QUIC)Headers and common protocolsYesNo
Writes capture files.pcap.pcapng by default, .pcapNo
Rights neededRoot, or CAP_NET_RAW, to captureCapture rights (root, or the wireshark group on Linux)Only to see other users' processes
From the tcpdump, pcap-filter and ss man pages (Debian 12) and the Wireshark manual, checked 02.11.2026. On Linux, Wireshark captures through dumpcap, which members of the wireshark group may run.

In practice they work together. ss answers “what is listening and who is connected right now” without touching packets, which is the first step in checking open ports on Linux. tcpdump captures on the server, where there is no screen. Wireshark, or its command-line twin tshark, analyses the file afterwards: following a TCP stream, decrypting your own TLS sessions with a key log, graphing retransmissions.

tcpdump errors and fixes

Symptom, cause, fix

  1. Symptom: tcpdump: eth0: You don't have permission to perform this capture on that device
    (socket: Operation not permitted)

    Cause
    You ran it as a normal user. Capturing needs root or CAP_NET_RAW.
    Fix
    Run it with sudo. Reading a saved file with -r needs no root. To capture without sudo, see the note below.
  2. Symptom: tcpdump: eth9: No such device exists

    Cause
    The interface has another name on this machine.
    Fix
    List the names with tcpdump -D or ip -br link.
  3. Symptom: tcpdump: can't parse filter expression: syntax error

    Cause
    A typo in the filter, such as prot instead of port, or a missing and.
    Fix
    Check each keyword against man 7 pcap-filter and test it with tcpdump -d.
  4. Symptom: bash: syntax error near unexpected token `('

    Cause
    The shell saw the parentheses of an unquoted filter.
    Fix
    Put the whole filter in single quotes.
  5. Symptom: tcpdump: /var/tmp/pcap/web-20261102-0317.pcap: Permission denied

    Cause
    It appears at the first rotation, after the first file was written, and tcpdump exits with code 1. tcpdump runs as the user tcpdump after opening the first file and cannot create files in a root-only directory.
    Fix
    Capture into a directory owned by tcpdump (sudo install -d -o tcpdump -g tcpdump /var/tmp/pcap), or add -Z root.
  6. Symptom: tcpdump: /srv/capture.txt: Permission denied, even with sudo

    Cause
    Debian 12 and Ubuntu ship an enforcing AppArmor profile for tcpdump, /etc/apparmor.d/usr.bin.tcpdump. Outside /tmp, /var/tmp and your home directory, -w may only write files ending in .pcap, .cap or .pcap plus digits; .txt and .pcapng are refused. Read from the profile file on our Debian 12 host (aa-status lists tcpdump in enforce mode), not reproduced.
    Fix
    Name the file .pcap (ring buffer files such as ring.pcap0 still match), or write under /var/tmp. That is why the recipes here use /var/tmp/pcap and .pcap names.
  7. Symptom: N packets dropped by kernel is above 0

    Cause
    tcpdump could not keep up. In our test, three 3 MB downloads over loopback dropped 113 packets while writing to a file.
    Fix
    Add -nn, write with -w instead of printing, narrow the filter, cut payload with -s 128, or raise the buffer with -B 8192 (KiB).
  8. Symptom: cksum 0xfe30 (incorrect -> 0xfa53) on your own outgoing packets (with -v)

    Cause
    The checksum is filled in after tcpdump sees the packet: by the network card (checksum offload), and on loopback not at all. In our test, the SYN that curl sent over lo showed this, the RST that answered it showed correct.
    Fix
    Ignore it, or skip the check with -K. The man page says that otherwise all outgoing TCP checksums will be flagged as bad on such interfaces.

Capture without sudo (setcap), and its risk

let one group capture without sudo
sudo groupadd pcap
sudo usermod -aG pcap YOUR_USER
sudo chgrp pcap /usr/bin/tcpdump
sudo chmod 750 /usr/bin/tcpdump
sudo setcap cap_net_raw,cap_net_admin=eip /usr/bin/tcpdump   # last: chgrp removes file capabilities

How we tested

OS image
Debian 12
Versions
tcpdump 4.99.3libpcap 1.10.3iproute2 6.1.0curl 7.88.1
Tested on
Method
Captures on the loopback interface only, against test services bound to 127.0.0.1 and ::1 (an HTTP server on port 18080, a TLS server with a throwaway certificate on 18443, curl to a closed port for the checksum, -Q and IPv6 checks) and two lookups through the systemd-resolved stub. Output formats, rotation file names, the -Z permission failure and the dropped-packet count come from those runs, and so does every error text above, except the AppArmor row, which is read from the profile file.
Not tested
The live stream into the Wireshark GUI (the pipe was tested into tcpdump -r -), tshark, Docker and nsenter, setcap, the AppArmor denial, captures on a real network card and a real SYN flood.

tcpdump needs root on the machine it captures on, which a shared web host does not give you. Every Standard KVM VPS comes with full root and a VNC console in the panel, so a capture that floods your SSH session can still be stopped from the console in your browser.

Frequently asked

How do I capture traffic on a specific port with tcpdump?

Run sudo tcpdump -i eth0 -nn port 443, replacing eth0 with your interface and 443 with the port. port matches TCP and UDP in both directions; use tcp dst port 443 for only incoming TCP, or 'port 80 or port 443' in single quotes for two ports. Stop with Ctrl+C or add -c 100.

How do I save tcpdump output to a file and open it in Wireshark?

Use -w: sudo tcpdump -i eth0 -nn -w capture.pcap port 443 writes raw packets instead of text. Read it back with tcpdump -nn -r capture.pcap, or copy the file to your PC and open it in Wireshark. Add --print to see packets on screen while they are written.

What does tcpdump -i any do?

It captures on all interfaces at once, including loopback and Docker bridges, in Linux cooked mode. Each line gains the interface name and the direction (In or Out), and the man page notes that captures on any are never in promiscuous mode. Use it when you do not know which interface the traffic takes.

How do I rotate tcpdump capture files?

Use -C 100 -W 10 for a ring of ten files of about 100 MB each (the oldest is overwritten), or -G 3600 with a strftime name such as web-%Y%m%d-%H%M.pcap for one file per hour. Note that -G with -W stops after that many files instead of overwriting, so delete old hourly files with a timer.

What is the difference between tcpdump and Wireshark?

tcpdump is a command-line capture tool that runs on headless servers and writes pcap files. Wireshark is a graphical analyser that decodes far more protocols, follows TCP streams and graphs problems. A common workflow is to capture with tcpdump on the server and analyse the file in Wireshark, or stream it live over SSH.

Related articles

All guides