Date created: Friday, January 20, 2012 11:36:48 PM. Last modified: Sunday, May 19, 2024 7:32:20 PM

'tcpdump', 'editcap', & 'ngrep' - Notes




# CLI Args

tcpdump -enlXXS -i eth0 -As 0 -vvv host # -n Don't convert addresses (i.e., host addresses, port numbers, etc.) to names # -m Load SMI MIB module definitions from file module. # This option can be used several times to load several MIB modules into tcpdump # -l Make stdout line buffered. Useful if you want to see the data while capturing it.
# -U Output will be packet-buffered (packets are written to stdout as a whole, rather than new-line buffered). # -X When parsing and printing, in addition to printing the headers of each packet, print the data of each packet (minus its link level header) in hex and ASCII
# - XX When parsing and printing, in addition to printing the headers of each packet, print the data of each packet, including its link level header, in hex and ASCII. # -A Print each packet (minus its link level header) in ASCII
# -e Print the link level header i.e. MAC addresses (compliments -A)
# -S Print absolute rather than relative TCP sequence numbers # -i For specific interface to listen on # -s 0 Snarf [snaplen] bytes of data from each packet rather than the default of 68. # 68 bytes is adequate for IP, ICMP, TCP and UDP but may truncate protocol information from name server and NFS packets.

# It is not possible to capture on multiple specific interfaces, only one specific interface
tcpdump -i eth0
# or all interfaces
tcpdump -i any

# Display and output options

# Display HEX and ASCII
tcpdump -XX

# Display timestamps
tcpdump -tttt

# Display delta from last line/packet
tcpdump -ttt

# Rotate capture file every 10 seconds (file name needs to be unique, can input strftime(3) time format options but only with -G, not with -C)
sudo tcpdump -G 10 -w ./%Y-%m-%d--%H-%M-%S.pcap

# Rotate by file size (-C option appends a count to the file name, files will be called: tcp-port-80.pcap, tcp-port-80.pcap1, tcp-port-80.pcap2 etc.)
sudo tcpdump -i eth10 -s 65535 -w ./tcp-port-80.pcap -C 1G tcp and port 80

# To format for Wireshark limit the snaplen (-s) to 65k
sudo tcpdump -s 65535 -i eth3 -w ./Customer1-2014-04-15-001.pcap

# Run tcpdump remotely over SSH and redirect to local Wireshark
# Note: remote uses need "sudo" without password (or is root) so only god for lab/test
ssh -q root@ "tcpdump -s 0 -U -i eth0 -n -w - "ip and not port 22" | wireshark -k -i -

# Run tcpdump remotely over SSH and save the output to local pcap
ssh -q root@labserver "sudo tcpdump -s 0 -U -i ens1f1 -n -w - 2>/dev/null" > /tmp/labserver.pcap

# To capture a container interface which is exposed to the container host, identify the container interface on the host:
docker compose exec my_container cat /sys/class/net/eth0/iflink

ip link | grep 12
12: veth6bbc99c@if11: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-e560485c9d21 state UP mode DEFAULT group default

sudo tcpdump -i veth6bbc99c

# To capture a container interface which is not exposed to the container host, run tcpdump inside the local container and pipe to Wireshark"
docker compose exec my_container bash -c "tcpdump -s 0 -U -i l3_r0 -n -w - 2>/dev/null" | wireshark -k -i -

# Layer 2/Ethernet

# Include link-layer headers (like MAC address for Ethernet)
tcpdump -e

# Specify a VLAN
tcpdump -i eth1 vlan 801 and host
# QinQ: 100 is outer VLAN, 200 is inner VLAN
tcpdump -i eth1 vlan 100 vlan 200

# Specific Ethertype, e.g. dot1q VLAN tag:
tcpdump -i eth1 ether proto 0x8100
# ARP Ethertype
tcpdump -i eth1 ether proto 0x0806

# Filter by MAC
tcpdump ether dst 00:11:22:33:44:55
tcpdump ether src 00:11:22:33:44:55
tcpdump ether host 00:11:22:33:44:55

# Use -p to NOT enter promiscuous mode, meaning "not for us" traffic isn't captured, multicast and broadcast is still captured
tcpdump -i eth0 -p

# Exclude Ethernet broadcast traffic
tcpdump -i eth0 not ether broadcast

# Capture 802.3 frames with an LLC header
tcpdump -i eth0 llc

# Capture Cisco Discovery Protocol (CDP) frames (off-set to LLC Protocol ID field with CDP protocol ID)
tcpdump -i eth0 llc and ether[20:2] = 0x2000

# Layer 2.5 / STP/PPPoE/MPLS/ISIS

# PPPoE carrying ICMP:
# To match something inside PPPoE, look for a value at an offset within the Ethernet header.
# E.g. 14 byte Ethernet header + 8 byte PPPoE header, next IPv4 follows and the IP protocol ID is at
# the 9th byte (10th offset) within the IPv4 header, so check if the 14+8+9 offset == 1 to match IP protocol 1 for ICMP
tcpdump -i eth1 ether[31] = 1

# To filter for an MPLS VPN conversation (we need Tx and Rx labels)
sudo tcpdump -s 65535 -i eth3 '(mpls 67734) or (mpls 19353)'

sudo tcpdump -s 65535 -i eth3 '(mpls && icmp)'

sudo tcpdump -nlASX -e -vvv -s 0 -i eth3 '(mpls && icmp && host'

sudo tcpdump -nlASX -s 65535 -vvv -i eth3 '(mpls 52634 and (ip and (ip[1] & 0xfc) >> 2 > 0x01) and host and icmp)'

# Remember that when testing for MPLS label stacks, (mpls 123 && mpls 456) will move the the headers pointer along within tcpdump by 8 bytes.
# So for example, using '(mpls 123 && mpls 456) or (mpls 789)' will mean the second check is comparing 789 as the label value for the 2nd label in an alternate stack, it won't check from the bottom of the stack again.

sudo tcpdump -i eth0 ether proto 0x8809 and ether[14] == 1

# ISIS packets:
sudo tcpdump -nlASX -e -vvv -s 0 -i eth1 iso

# Spanning Tree
# "stp" is a shortcut for "ether proto \stp" which needs to be quoted and "stp" needs to be escaped with a backslash
sudo tcpdump -i eth0 stp
# Same as:
sudo tcpdump -i eth0 "ether proto \stp"

# Layer 3/IP/IS-IS

# One can capture multiple address families at the same time:
tcpdump -i eth1 host or host 2001::22

# Once can specify source and or destination address
tcpdump -i eth1 ip6 and src FE80::1 and dst FE80::2

# Listen for a range of clients
tcpdump -i eth2:62 -vvv -n src net

# Capture IPv6 only
sudo tcpdump -i en0 ip6

# Any non-zero TOS/DSCP value
sudo tcpdump -s 65535 -i eth3 ip and ip[1]!=0

# To filter by specific DSCP value
# ip[1] This is IP header byte 1 (starts from 0, so 2nd byte)
# & 0xfc This is to logical AND with a bit mask for the first 6 bits (11111100)
# which are the DSCP bits, last 2 bits are ECN
# >> 2 To bit shift by 2 to compare only DSCP value (first 6 bits) to
# 0xc0, without bit shift you need to compare hex of DSCP + ECN
sudo tcpdump -s 65535 -i eth3 \(ip and \(ip[1] \& 0xfc\) >> 2 \> 0xc0\)
sudo tcpdump -s 65535 -i eth3 \(ip and \ip[1] \& 0xfc \> 0xc0\)
sudo tcpdump -s 65535 -i eth3 \(ip and \ip[1] \& 0xff \> 0xc0\)
sudo tcpdump -s 65535 -i eth3 -w DSCP-elam.pcap host and \(ip and \(ip[1] \& 0xfc\) >> 2 \> 0x0a\)

# This example matched DSCP decimal value 10 (which is AF11),
# matching the entire byte where ECN is 0 and DSCP is 0x0a (10 in decimal)
# is 0101 bit shifted left by 2 bits is 010100 (0x28)
sudo tcpdump -nelASX -s0 -i eth3 \(ip and \(ip[1] \& 0xff\) == 0x28\)

# This will match any DCSP marking, by doing > 0
(ip and (ip[1] & 0xfc) >> 2 > 0x00)

# Look for a specific TTL, which is 9th byte in IPv4 header
tcpdump ip and 'ip[8] == 254'

# This is a shortcut for "iso proto isis"
tcpdump -i eth0 isis

# Off-set to ISO PDU type: Ethernet (14) + LLC (3) == start of ISO header. 5th byte is PDU type.
# 0x11 is "P2P Hello"
tcpdump -i eth0 isis and ether[21] == 17


# Use specific transport protocol and port number; tcpdump -nmlX -i eth0 -As 0 -vvv host and udp port 161

# Capture a range of ports, RADIUS for example
tcpdump -nlASX -s 0 -vvv -i em2 udp portrange 1812-1814 # Exclude a port (like your own SSH session) tcpdump not port 22 tcpdump -i eth1 port not 22 and host
# Capture ICMP only
tcpdump -nmlX -As 0 -vvv icmp
# 0 - Echo Reply
# 3 - Destination Unreachable
# 8 - Echo Request
# 11 - Time Exceeded
# ICMP echo request and reply only
tcpdump -n icmp and 'icmp[0] = 8 and icmp[0] = 0'
tcpdump -n icmp and icmp[icmptype] == icmp-echo and icmp[icmptype] == icmp-echoreply

# Capture ICMPv6 only
tcpdump icmp6
# Unlike ICMP, we can't index the ICMPv6 header to check for a specific type/code.
# Instead we have to index the IPv6 header. ICMPv6 starts 40 bytes into the IPv6 header.
# 128 == Echo Request, 129 == Echo Reply, 135 == Neighbor Solicitation, 136 == Neighbor Solicitation
tcpdump "icmp6 && ip6[40] == 128"
tcpdump "icmp6 and (ip6[40] == 135 and ip6[40] == 136)"

# Capture IGMP
# "igmp" is a shortcut for "ip proto igmp"
tcpdump -i eth0 igmp
# IGMP type is query
tcpdump -i eth0 igmp and igmp[0] == 0x11

# Capture MLD report
# Off-set of 48 because the IPv6 header is followed by an 8 byte hop-by-hop extension header for MLD messages
tcpdump ip6 and src FE80::0200:1 and dst FF02::1 and ip6[48] == 130

# Capture OSPF - IP protocol 89 in decimal / 0x59 in hex
tcpdump ip proto 89
tcpdump ip proto 0x59
tcpdump ip6 proto 89
tcpdump proto ospf
# OSPF message type byte. 1 == Helo
tcpdump proto ospf and ip[21] == 1

# Filtering

# List of protocols which can be filtered directly by name
ah, arp, decnet, esp, ether, fddi, icmp, icmp6, ip, ip6, pim, ppp, radio, rarp, sctp, slip, tcp, tr, udp, wlan
# fddi is actually an alias for ether
# icmp is an abbreviation for ip proto 1
# icmp6 is an abbreviation for ip6 proto 58
# tr and wlan are aliases for ether

# Direction


To capture frames with the Ethernet FCS present (not all NICs support this):

sudo ethtool -K enp0s25 rx-fcs on



# Split a capture file into multipile smaller files, each 100,000 packets long
editcap -c 100000 large-lapture.pcap split-capture.pcap

# Delete a specific packet (packet num. 1000) from a capture file
editcap capture.pcap filtered.pcap 1000

# Delete a range of packets (pacet numbers 100-200) from a capture file
editcap capture.pcap filtered.pcap 100-200

# Delete a list of packets (the same syntax can be used with -r for keeping only the listed packets)
editcap capture.pcap filtered.pcap 1 5 10-20 30-40

# To remove all packets except the given range of packet numbers
editcap -r capture.pcap filtered.pcap 50-99

# Keep only the first 100 packets
editcap -r capture.pcap filtered.pcap 1-100

# Remove the first 30 bytes from all packets in the capture
editcap -C 30 capture.pcap filtered.pcap



# editcap can't merge files but mergecap can...
mergecap -w merged.pcap 10M-1.pcap 10M-2.pcap 10M-3.pcap



# Capture traffic form a specific SIP extension
ngrep -q -t -W byline -d any -w 12345 port 5060 or port 5070

# -q is be quiet (don't print packet reception hash marks)
# -t is print timestamp every time a packet is matched
# -W is set the dump format (normal, byline, single, none)
# Specify an alternate manner for displaying packets, when not in hexadecimal mode.  The byline mode honors embedded line‐feeds, wrapping text only when a linefeed is encountered
# -d is use specified device instead of the pcap default
# -w s word-regex (expression must match as a word)

# Capture HTTP traffic
ngrep -t -W byline -d eth1 tcp and port 80
# or
ngrep src host
# or 
ngrep host

# Capture traffic to/from a specific IP
ngrep -q -t -W byline -d any -w