tcpdump es un analizador de paquetes de línea de comandos que captura el tráfico que pasa por una interfaz de red y lo muestra o lo guarda en un fichero .pcap. Está disponible en prácticamente cualquier servidor Linux y es la herramienta más rápida para responder preguntas como "¿llegan las peticiones a mi servidor?" o "¿qué responde realmente el DNS?".

En este tutorial aprenderás a usar tcpdump en Ubuntu 24.04: leer su salida, construir filtros por host, puerto y protocolo, guardar capturas con rotación para abrirlas en Wireshark y aplicar todo ello a casos reales de diagnóstico.

Requisitos previos

Para seguir este tutorial necesitas:

  • Un servidor con Ubuntu 24.04 LTS, por ejemplo un VPS de CubePath.
  • Un usuario no root con privilegios sudo. Capturar tráfico requiere permisos de root.
  • Algo de tráfico que observar: un servidor web, un servicio SSH o simplemente comandos como curl y dig que puedas lanzar desde otra terminal.

Paso 1: Instalar tcpdump e identificar la interfaz

Ubuntu Server suele traer tcpdump instalado. Si no lo está, instálalo desde los repositorios:

sudo apt update
sudo apt install -y tcpdump

Comprueba la versión:

tcpdump --version
tcpdump version 4.99.4
libpcap version 1.10.4 (with TPACKET_V3)
OpenSSL 3.0.13 30 Jan 2024

A continuación identifica la interfaz por la que sale el tráfico. En servidores virtuales suele llamarse eth0, ens3 o ens18:

ip -br address
lo               UNKNOWN        127.0.0.1/8 ::1/128
eth0             UP             203.0.113.10/24 2001:db8::10/64

En este tutorial se usa eth0; sustitúyela por el nombre de tu interfaz. tcpdump -D también lista todas las interfaces en las que se puede capturar, incluida la pseudo interfaz any, que escucha en todas a la vez.

Paso 2: Hacer una primera captura y leer la salida

Captura cinco paquetes en la interfaz principal:

sudo tcpdump -i eth0 -n -c 5

Las opciones hacen lo siguiente:

  • -i eth0: interfaz en la que capturar.
  • -n: no resolver direcciones IP ni puertos a nombres. Sin ella, tcpdump hace consultas DNS por cada dirección, lo que ralentiza la salida y genera tráfico extra que también aparece en la captura.
  • -c 5: parar tras cinco paquetes. Sin -c, la captura sigue hasta que pulses Ctrl+C.

Una línea típica de la salida es esta:

10:42:07.311582 IP 198.51.100.23.51544 > 203.0.113.10.443: Flags [S], seq 2849126381, win 64240, options [mss 1460,sackOK,TS val 1419 ecr 0,nop,wscale 7], length 0

Se lee de izquierda a derecha:

CampoSignificado
10:42:07.311582Hora de captura con microsegundos
IPProtocolo de red (IP6 para IPv6)
198.51.100.23.51544IP y puerto de origen (el puerto es el último número)
203.0.113.10.443IP y puerto de destino
Flags [S]Flags TCP: S SYN, . ACK, P PUSH, F FIN, R RST
length 0Bytes de datos de la capa de aplicación

La línea anterior es un cliente iniciando una conexión HTTPS (un SYN hacia el puerto 443). Al terminar, tcpdump muestra un resumen:

5 packets captured
7 packets received by filter
0 packets dropped by kernel

Si dropped by kernel es mayor que cero, tcpdump no ha podido procesar todo el tráfico. Usa un filtro más específico, como verás en el siguiente paso.

Paso 3: Filtrar el tráfico con expresiones BPF

Sin filtro, en un servidor con actividad la salida es ilegible. tcpdump acepta expresiones de filtro en sintaxis BPF (Berkeley Packet Filter), que el kernel aplica antes de copiar los paquetes, así que además son eficientes. El filtro va al final del comando.

Si estás conectado por SSH, lo primero es excluir tu propia sesión, porque cada línea que tcpdump imprime genera nuevos paquetes SSH que a su vez se capturan:

sudo tcpdump -i eth0 -n not port 22

Filtrar por host y red

Tráfico hacia o desde una dirección concreta:

sudo tcpdump -i eth0 -n host 198.51.100.23

Solo en un sentido, con src o dst:

sudo tcpdump -i eth0 -n src host 198.51.100.23

Toda una subred en notación CIDR:

sudo tcpdump -i eth0 -n net 10.0.0.0/8

Filtrar por puerto y protocolo

Un puerto, en TCP o UDP:

sudo tcpdump -i eth0 -n port 443

Un rango de puertos:

sudo tcpdump -i eth0 -n portrange 8000-8100

Por protocolo, con las palabras clave tcp, udp, icmp, icmp6 o arp:

sudo tcpdump -i eth0 -n icmp

Combinar filtros

Los filtros se combinan con and, or y not. Cuando uses paréntesis, pon toda la expresión entre comillas simples para que la shell no los interprete:

sudo tcpdump -i eth0 -n 'host 198.51.100.23 and (port 80 or port 443)'

Filtrar por flags TCP

Para ver solo intentos de conexión nuevos (paquetes con SYN pero sin ACK), útil para saber quién intenta conectar y a qué puertos:

sudo tcpdump -i eth0 -n 'tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn'

Para ver conexiones rechazadas o cortadas de forma abrupta, filtra los paquetes con RST:

sudo tcpdump -i eth0 -n 'tcp[tcpflags] & tcp-rst != 0'

Paso 4: Ver el contenido de los paquetes

Por defecto tcpdump solo muestra cabeceras. Para ver los datos, -A los imprime en ASCII y -X en hexadecimal y ASCII. Esto solo es legible en protocolos sin cifrar, como HTTP en el puerto 80.

En una terminal, captura el tráfico HTTP local:

sudo tcpdump -i lo -n -A 'tcp port 80 and (tcp[tcpflags] & tcp-push != 0)'

En otra terminal, lanza una petición (necesitas un servidor web escuchando en el puerto 80):

curl -s http://127.0.0.1/ -o /dev/null

En la primera terminal verás la petición en texto claro:

GET / HTTP/1.1
Host: 127.0.0.1
User-Agent: curl/8.5.0
Accept: */*

El filtro tcp-push descarta los paquetes sin datos (SYN, ACK vacíos), lo que deja solo peticiones y respuestas. Para HTTPS no verás el contenido, pero sí el establecimiento de la conexión y el tamaño de cada paquete, que ya permite detectar muchos problemas.

Otras opciones de salida útiles:

  • -v o -vv: más detalle de las cabeceras (TTL, checksum, opciones).
  • -e: muestra también las direcciones MAC de la capa de enlace.
  • -tttt: marca de tiempo con fecha completa, útil para correlacionar con logs.
  • -l: salida con buffer por línea, necesaria para enviar la salida a grep en tiempo real.

Por ejemplo, para extraer las cabeceras Host: que llegan a tu servidor web:

sudo tcpdump -i eth0 -n -l -A 'tcp dst port 80' | grep --line-buffered 'Host:'

Paso 5: Guardar capturas y abrirlas en Wireshark

Para análisis posteriores o para compartir una captura, guárdala en un fichero pcap con -w. En ese modo tcpdump no imprime los paquetes:

sudo tcpdump -i eth0 -n -c 1000 -w /tmp/web.pcap 'port 80 or port 443'
tcpdump: listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes
1000 packets captured

Lee el fichero con -r, aplicando si quieres un filtro distinto al de la captura:

tcpdump -n -r /tmp/web.pcap 'tcp[tcpflags] & tcp-rst != 0'

Para analizarlo en Wireshark, descárgalo a tu equipo con scp:

scp your_user@your_server_ip:/tmp/web.pcap .

Si solo te interesan las cabeceras, limita los bytes que se guardan de cada paquete con -s. Con -s 128 los ficheros son mucho más pequeños y apenas contienen datos de la aplicación:

sudo tcpdump -i eth0 -n -s 128 -w /tmp/headers.pcap

Captura continua con rotación

Para problemas intermitentes, deja tcpdump grabando en un buffer circular: -C cambia de fichero cada cierto tamaño (en millones de bytes) y -W limita el número de ficheros, sobrescribiendo el más antiguo. Este comando mantiene como máximo 10 ficheros de 100 MB:

sudo tcpdump -i eth0 -n -s 256 -C 100 -W 10 -w /tmp/ring.pcap 'not port 22'

tcpdump numera los ficheros como ring.pcap0, ring.pcap1, etc. Cuando el problema se reproduzca, detén la captura con Ctrl+C y analiza los ficheros más recientes. Para que la captura siga activa al cerrar tu sesión SSH, ejecútala dentro de tmux o screen.

Paso 6: Diagnosticar problemas reales

Comprobar si las peticiones llegan al servidor

Si un servicio no responde desde fuera, la primera pregunta es si el tráfico llega. Captura los SYN hacia el puerto del servicio y prueba a conectar desde otro equipo:

sudo tcpdump -i eth0 -n 'tcp dst port 443 and tcp[tcpflags] & tcp-syn != 0'

Interpreta el resultado así:

  • No aparece nada: el tráfico se bloquea antes de llegar al servidor (DNS apunta a otra IP, firewall externo o grupo de seguridad).
  • Aparecen SYN pero ninguna respuesta: el firewall local (sudo ufw status) descarta los paquetes.
  • Aparece un RST como respuesta: el paquete llega, pero ningún proceso escucha en ese puerto. Compruébalo con sudo ss -tlnp.

Depurar la resolución DNS

Captura las consultas y respuestas DNS mientras lanzas una consulta desde otra terminal:

sudo tcpdump -i any -n port 53
dig cubepath.com
11:03:12.114210 lo    In  IP 127.0.0.1.41822 > 127.0.0.53.53: 3321+ [1au] A? cubepath.com. (53)
11:03:12.114705 eth0  Out IP 203.0.113.10.35140 > 1.1.1.1.53: 1407+ [1au] A? cubepath.com. (41)
11:03:12.131882 eth0  In  IP 1.1.1.1.53 > 203.0.113.10.35140: 1407 2/0/1 A 104.21.0.1, A 172.67.0.1 (73)

Con la interfaz any se ve el recorrido completo: la aplicación pregunta a systemd-resolved en 127.0.0.53, que a su vez consulta al servidor DNS configurado. A? es la pregunta; 2/0/1 indica dos respuestas, cero registros de autoridad y un registro adicional. Si ves la pregunta pero nunca la respuesta, el problema está en el servidor DNS o en el camino hasta él. Si la respuesta es NXDomain, el nombre no existe.

Detectar escaneos de puertos

Un escaneo se reconoce por muchos SYN desde la misma IP hacia puertos distintos. Captura 1000 SYN entrantes y cuenta las IP de origen:

sudo tcpdump -i eth0 -n -c 1000 'tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn and dst host 203.0.113.10' \
  | awk '{print $3}' | cut -d. -f1-4 | sort | uniq -c | sort -rn | head
    612 198.51.100.77
     41 192.0.2.15
      8 203.0.113.200

Una IP con cientos de SYN en pocos segundos es casi siempre un escáner. Sustituye 203.0.113.10 por la IP pública de tu servidor. Para bloquear este tipo de actividad de forma automática, usa una herramienta como Fail2ban en lugar de un script propio.

Solución de problemas

tcpdump: eth0: You don't have permission to perform this capture on that device. Ejecuta el comando con sudo. Capturar en una interfaz requiere la capacidad CAP_NET_RAW.

tcpdump: /var/log/capture.pcap: Permission denied al usar -w. tcpdump escribe como el usuario tcpdump y AppArmor restringe las rutas. Guarda la captura en /tmp o en tu directorio personal y muévela después.

La captura no muestra nada. Comprueba que usas la interfaz correcta con ip -br address y prueba con -i any. Si capturas tráfico entre procesos del mismo servidor, está en la interfaz lo, no en eth0.

packets dropped by kernel es alto. tcpdump no procesa los paquetes al ritmo al que llegan. Añade un filtro más específico, usa -n para evitar resoluciones DNS, reduce -s y escribe en un fichero con -w en lugar de imprimir en pantalla.

Conclusión

Ya sabes capturar tráfico con tcpdump, leer su salida, filtrar por host, puerto y flags TCP, guardar capturas con rotación y usar todo ello para diagnosticar conectividad, DNS y escaneos. Como siguientes pasos, puedes abrir tus capturas en Wireshark para seguir flujos TCP completos, usar tshark para analizar ficheros pcap desde la línea de comandos o consultar man pcap-filter para conocer toda la sintaxis de filtros BPF.