Este artículo fue publicado originalmente en go2linux.org. El dominio ya no me pertenece, pero soy el autor original. Lo republico aquí en garron.me con correcciones y mejoras.
tcpdump es el sniffer de paquetes clásico de Linux. Imprime una línea por cada paquete que pasa por una interfaz de red, o guarda los paquetes en un archivo para analizarlos después.
Hace años, como parte de mi trabajo, tuve que ayudar a implementar VLANs en un hub satelital. Necesitábamos comprobar si las etiquetas VLAN estaban presentes en las tramas Ethernet, y teníamos dos sniffers: un analizador profesional Fluke y mi laptop IBM T30 con tcpdump. El Fluke encontró las tramas etiquetadas y las no etiquetadas, y la laptop también, por una fracción del costo.
Instalación
Normalmente ya está instalado. Si no:
sudo apt install tcpdump # Debian, Ubuntu
sudo dnf install tcpdump # Fedora, RHEL
sudo pacman -S tcpdump # Arch
Capturar paquetes requiere root, así que todos los ejemplos usan sudo.
Elegir la interfaz
Lista las interfaces en las que tcpdump puede capturar:
sudo tcpdump -D
Luego captura en una de ellas con -i:
sudo tcpdump -i enp3s0
Nombres como eth0 son raros hoy; ip -br link muestra los nombres en tu equipo. Para escuchar en todas las interfaces a la vez usa la pseudointerfaz any:
sudo tcpdump -i any
Las capturas en any no se hacen en modo promiscuo, así que solo ves el tráfico dirigido al equipo o enviado por él.
Presiona Ctrl+C para detenerlo. tcpdump informa entonces cuántos paquetes capturó y cuántos descartó el kernel.
Opciones que usarás siempre
sudo tcpdump -i enp3s0 -nn -c 20
-nno resuelve las direcciones IP a nombres. Sin esta opcióntcpdumphace consultas DNS, lo que es lento y agrega su propio tráfico a la captura.-nntampoco traduce los números de puerto, así que ves443en lugar dehttps.-c 20se detiene después de 20 paquetes.
Una línea de salida se ve así:
12:01:15.123456 IP 192.0.2.10.51514 > 198.51.100.7.443: Flags [S], seq 1234567890, win 64240, length 0
Es la marca de tiempo, el protocolo, dirección y puerto de origen, dirección y puerto de destino, las banderas TCP (S es SYN, . es ACK, P es PUSH, F es FIN, R es RST) y el tamaño de los datos.
Filtros de captura
Sin un filtro lo recibes todo, y en un servidor con tráfico eso no sirve de nada. Agrega una expresión de filtro al final del comando.
Por host:
sudo tcpdump -i enp3s0 -nn host 192.0.2.10
sudo tcpdump -i enp3s0 -nn src 192.0.2.10
sudo tcpdump -i enp3s0 -nn dst 192.0.2.10
Por red:
sudo tcpdump -i enp3s0 -nn net 192.0.2.0/24
Por puerto o rango de puertos:
sudo tcpdump -i enp3s0 -nn port 53
sudo tcpdump -i enp3s0 -nn portrange 8000-8100
Por protocolo:
sudo tcpdump -i enp3s0 -nn icmp
sudo tcpdump -i enp3s0 -nn udp
sudo tcpdump -i enp3s0 -nn arp
Combínalos con and, or y not. Pon la expresión entre comillas simples cuando tenga paréntesis, para que el shell no los interprete:
sudo tcpdump -i enp3s0 -nn 'host 192.0.2.10 and (port 80 or port 443)'
Cuando estás conectado por SSH, tu propia sesión inunda la salida. Exclúyela:
sudo tcpdump -i enp3s0 -nn not port 22
Hay más ejemplos de este tipo en Excluyendo puertos o IPs de la salida de tcpdump.
Solo los paquetes que abren conexiones TCP nuevas (SYN sin ACK):
sudo tcpdump -i enp3s0 -nn 'tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn'
Ver el contenido de los paquetes
-A imprime el contenido como texto, suficiente para protocolos en texto plano como HTTP o SMTP:
sudo tcpdump -i enp3s0 -nn -A port 80
-X lo imprime en hexadecimal y texto lado a lado. El tráfico cifrado (HTTPS, SSH) solo muestra ruido, como debe ser.
Guardar en un archivo y leerlo después
-w escribe los paquetes en bruto en un archivo en lugar de imprimirlos:
sudo tcpdump -i enp3s0 -nn -w captura.pcap port 443
Lee el archivo después con -r. Los filtros también funcionan aquí, así que puedes capturar de forma amplia y afinar después:
tcpdump -nn -r captura.pcap
tcpdump -nn -r captura.pcap host 192.0.2.10
El mismo archivo se abre en Wireshark, que es la forma cómoda de seguir un flujo TCP o decodificar un protocolo. La versión original de este artículo recomendaba Ethereal; ese proyecto pasó a llamarse Wireshark en 2006.
En algunas distribuciones tcpdump abandona los privilegios de root y pasa a un usuario sin privilegios después de abrir la interfaz, y entonces no puede escribir en tu directorio personal. Si obtienes Permission denied en el archivo de salida, escribe en /tmp o agrega -Z root.
Capturas largas: rotar los archivos
Para dejar una captura corriendo mientras esperas que aparezca un problema, limita el tamaño de cada archivo con -C (en millones de bytes) y la cantidad de archivos con -W. Cuando el último archivo se llena, tcpdump sobrescribe el primero:
sudo tcpdump -i enp3s0 -nn -w traza.pcap -C 100 -W 10
Eso ocupa como máximo 1 GB en disco. Para rotar por tiempo, usa -G con un nombre de archivo que contenga campos de strftime:
sudo tcpdump -i enp3s0 -nn -w 'traza-%Y%m%d-%H%M.pcap' -G 3600
Ver etiquetas VLAN
Este es el caso de la historia de arriba. -e imprime la cabecera de nivel de enlace, que incluye la etiqueta 802.1Q, y el filtro vlan deja solo las tramas etiquetadas:
sudo tcpdump -i enp3s0 -e -nn vlan
12:01:15.123456 00:11:22:33:44:55 > 66:77:88:99:aa:bb, ethertype 802.1Q (0x8100), length 102: vlan 100, p 0, ethertype IPv4 (0x0800), 192.0.2.10 > 192.0.2.1: ICMP echo request, id 1, seq 1, length 64
Para una sola VLAN:
sudo tcpdump -i enp3s0 -e -nn vlan 100
Captura en la interfaz física. En una subinterfaz VLAN como enp3s0.100 el kernel ya quitó la etiqueta.
Enviar la salida a otro comando
tcpdump almacena su salida en un búfer cuando no escribe en una terminal. Agrega -l para que la envíe línea por línea cuando la pasas a otro comando:
sudo tcpdump -i enp3s0 -nn -l port 53 | grep example.com
Ejemplos prácticos
Consultas DNS que salen del equipo:
sudo tcpdump -i any -nn udp port 53
Comprobar si los paquetes de un cliente llegan al servidor:
sudo tcpdump -i enp3s0 -nn host 192.0.2.10 and port 443
Peticiones y respuestas de ping:
sudo tcpdump -i enp3s0 -nn icmp
Tráfico DHCP:
sudo tcpdump -i enp3s0 -nn port 67 or port 68
Ver también
man tcpdump — referencia completa. man pcap-filter — la sintaxis completa de los filtros.