Monitorizar tráfico saliente y entrante de una web guía práctica con Python y alternativas reales

Monitorizar tráfico saliente y entrante de una web: guía práctica con Python y alternativas reales

Monitorizar el tráfico de red de una web es una tarea habitual tanto en administración de sistemas como en laboratorios de ciberseguridad. Saber cuántos bytes entran y salen, qué protocolos se usan y desde qué IPs se conectan los clientes es información valiosa para detectar anomalías, dimensionar infraestructura o depurar problemas de conectividad.

En este artículo veremos cómo hacerlo con Python y Scapy, una de las bibliotecas más didácticas para manipular paquetes. Pero también seremos honestos sobre sus limitaciones: Scapy es excelente para aprender y para scripts puntuales, pero no es la herramienta adecuada para monitorización continua en producción. Al final del artículo encontrarás alternativas más robustas.

Si quieres profundizar en ciberseguridad desde una perspectiva más amplia, tienes nuestra guía completa de ciberseguridad.


1. ¿Dónde se ejecuta este script? La pregunta que hay que responder primero

Antes de escribir una sola línea de código, hay que tener claro un concepto que suele generar confusión: Scapy captura paquetes de la interfaz de red de la máquina donde se ejecuta. No es un monitor remoto. No «ve» internet de forma mágica. No existe una opción para poner una URL y que capture el tráfico de esa web desde fuera.

Por tanto, el script debe ejecutarse en:

  • Tu ordenador personal (Windows, Linux o macOS), si quieres ver el tráfico que genera tu propia navegación hacia una web.
  • Tu servidor, si quieres monitorizar el tráfico que entra y sale de ese servidor.

¿Se puede ejecutar desde Visual Studio Code?

Sí, pero con matices importantes:

  1. VS Code es solo el editor. El script se ejecuta en la terminal integrada o en una terminal externa, sobre tu sistema operativo real.
  2. Necesitas permisos de administrador. Scapy requiere acceso crudo a la red. En Linux necesitas sudo. En Windows, ejecutar la terminal como Administrador y tener Npcap instalado. Sin esto, sniff() fallará.
  3. El entorno virtual y los permisos no se llevan bien. Si usas un venv (recomendado), al ejecutar con sudo el intérprete de Python del venv no se carga automáticamente. La solución es: sudo env "PATH=$PATH" python tu_script.py.
  4. Si usas WSL, puedes ejecutar VS Code conectado a WSL y lanzar el script con sudo desde la terminal de WSL.

¿Captura todo el tráfico o solo el de una URL?

Depende del filtro que uses:

  • Si usas sniff(filter="tcp port 80"): capturas todo el tráfico HTTP de tu máquina, no solo el de una web concreta. Verás peticiones a cualquier sitio.
  • Si usas sniff(filter="host 93.184.216.34"): capturas solo el tráfico hacia/desde esa IP. Pero ojo: si la web usa CDN, esa IP puede no ser la única, y el tráfico a otros recursos de la misma web puede ir a otras IPs.
  • El script de este artículo resuelve la URL a una IP con socket.gethostbyname() y luego filtra por esa IP. Eso reduce el tráfico, pero no lo limita perfectamente a «esa web», porque una página carga recursos de múltiples dominios.

En resumen: el script no «monitoriza una URL» de forma remota. Monitoriza el tráfico de tu máquina que coincide con la IP de esa URL. Si quieres monitorizar el tráfico de un servidor, ejecuta el script en el servidor.


2. Requisitos previos

Antes de ejecutar los ejemplos necesitas:

  • Python 3.7 o superior. Scapy 2.5+ requiere Python 3.7+. Python 2 está obsoleto desde 2020 y no recibe parches de seguridad.
  • Scapy instalado: pip install scapy
  • Permisos de captura. En Linux necesitas sudo o la capability CAP_NET_RAW. En Windows, Npcap y terminal como Administrador.
  • Un entorno controlado. Monitoriza solo tu propio servidor o tu propia máquina. Interceptar tráfico ajeno sin autorización es ilegal en la mayoría de jurisdicciones.

3. El error conceptual más común: ¿qué es «entrante» y qué es «saliente»?

Un paquete con puerto destino 80 no siempre es «entrante». Depende de dónde estés capturando:

  • Si capturas en el cliente (tu navegador): los paquetes con dport=80/443 son salientes (tú envías la petición), y los que tienen sport=80/443 son entrantes (el servidor responde).
  • Si capturas en el servidor: es al revés. Los paquetes con dport=80/443 son entrantes (el cliente te envía la petición), y los que tienen sport=80/443 son salientes (tu respuesta).

El código original de esta entrada confundía ambos casos. En los ejemplos siguientes, asumiremos que capturas en el cliente (tu máquina), que es el escenario más habitual para quien quiere entender el tráfico que genera una web.


4. Captura básica con Scapy (solo HTTP, puerto 80)

Este primer ejemplo es deliberadamente simple para que veas la mecánica. Captura tráfico HTTP clásico y distingue dirección desde el punto de vista del cliente.

from scapy.all import sniff, TCP, IP

def analizar_paquete(pkt):
    if pkt.haslayer(TCP) and pkt.haslayer(IP):
        tcp = pkt[TCP]
        ip = pkt[IP]

        # Desde el punto de vista del CLIENTE (tu máquina)
        if tcp.dport == 80:
            print(f"[SALIENTE] {ip.src} -> {ip.dst}:{tcp.dport}  flags={tcp.flags}")
        elif tcp.sport == 80:
            print(f"[ENTRANTE] {ip.src}:{tcp.sport} -> {ip.dst}  flags={tcp.flags}")

# store=0 evita acumular paquetes en memoria (importante en capturas largas)
sniff(filter="tcp port 80", prn=analizar_paquete, store=0)

Qué hace bien este código:

  • Usa store=0 para no consumir RAM innecesariamente.
  • Distingue dirección según el puerto, asumiendo captura en el cliente.
  • El filtro BPF tcp port 80 es correcto y eficiente (se ejecuta en el kernel).

Limitación: solo captura HTTP. En 2026, casi todo es HTTPS (puerto 443). El contenido estará cifrado, pero sí podrás ver los metadatos: IPs, puertos, tamaño de paquetes y frecuencia. Eso sigue siendo útil para monitorización de volumen.


5. Captura para una web concreta (HTTP y HTTPS)

Si quieres filtrar por la IP de una web específica, puedes resolver el dominio y usar un filtro BPF más preciso.

import socket
from scapy.all import sniff, TCP, IP

def monitorizar_web(url):
    try:
        ip = socket.gethostbyname(url)
        print(f"Resolviendo {url} -> {ip}")
        print("Capturando tráfico hacia/desde esa IP (Ctrl+C para detener)...\n")
    except socket.gaierror:
        print(f"No se pudo resolver: {url}")
        return

    def callback(pkt):
        if pkt.haslayer(TCP) and pkt.haslayer(IP):
            tcp = pkt[TCP]
            if tcp.dport in (80, 443):
                print(f"[SALIENTE] -> {ip}:{tcp.dport}  len={len(pkt)} bytes")
            elif tcp.sport in (80, 443):
                print(f"[ENTRANTE] <- {ip}:{tcp.sport}  len={len(pkt)} bytes")

    # Filtro BPF con paréntesis para evitar ambigüedad de precedencia
    sniff(filter=f"host {ip} and (tcp port 80 or tcp port 443)",
          prn=callback, store=0)

# Ejecutar en TU máquina (Linux: sudo env "PATH=$PATH" python script.py)
monitorizar_web("ejemplo.com")

Nota sobre el filtro BPF: la expresión host X and (tcp port 80 or tcp port 443) usa paréntesis para evitar problemas de precedencia. La sintaxis BPF es la misma que usa tcpdump.

Importante sobre CDN: si la web usa una CDN (Cloudflare, Akamai, etc.), gethostbyname devuelve una sola IP de las muchas posibles. El script capturará solo el tráfico hacia esa IP concreta. Para una captura más completa, podrías resolver todas las IPs del dominio con socket.getaddrinfo() y construir un filtro con varias IPs, o simplemente capturar todo el tráfico y filtrar por dominio en el callback (menos eficiente).


6. ¿Y HTTP/3? El tráfico web ya no es solo TCP

HTTP/3 usa QUIC sobre UDP (normalmente puerto 443). Si solo filtras TCP, te pierdes una parte creciente del tráfico web moderno. Sin embargo, QUIC está cifrado por diseño, así que no podrás ver nada más allá de los metadatos (IPs, puertos, tamaño).

Si quieres incluir HTTP/3 en tu monitorización:

sniff(filter=f"host {ip} and (tcp port 80 or tcp port 443 or udp port 443)",
      prn=callback, store=0)

Pero ten en cuenta: el callback anterior solo procesa TCP. Para UDP necesitarías una rama adicional. Y aunque la proceses, el contenido de QUIC está cifrado y Scapy no puede descifrarlo sin las claves TLS.

Conclusión práctica: para monitorización de tráfico web real, Scapy te da volumen y metadatos, no contenido. Si necesitas contenido (URLs, payloads), necesitas otra aproximación (logs del servidor, proxies, o instrumentación de la aplicación).


7. Limitaciones reales de Scapy para monitorización

Scapy es una biblioteca excelente para aprender, prototipar y hacer análisis puntuales. Pero para monitorización continua en producción tiene problemas:

LimitaciónImplicación
RendimientoScapy procesa paquetes en Python puro. En redes con mucho tráfico, pierde paquetes o consume CPU excesiva.
Sin persistenciaEl código de ejemplo imprime en consola. Para métricas necesitas escribir a un fichero, base de datos o sistema de observabilidad.
CifradoHTTPS y HTTP/3 cifran el contenido. Solo ves metadatos.
ComplejidadReimplementar contadores, agregaciones y alertas que otras herramientas ya dan hechas no tiene sentido.

Alternativas profesionales:

  • tcpdump + análisis posterior: captura a fichero PCAP con filtros BPF eficientes (en C, no en Python) y analiza después.
  • iftop, nload, vnstat: monitorización de ancho de banda en tiempo real desde la terminal, sin escribir código.
  • Prometheus + Grafana + node_exporter: el estándar de facto para observabilidad de servidores. node_exporter expone métricas de red (node_network_receive_bytes_total, node_network_transmit_bytes_total) que puedes graficar y alertar.
  • Netdata: monitorización todo-en-uno con dashboards de red listos para usar.
  • Wireshark: para análisis forense y depuración profunda de paquetes.

Si tu objetivo es monitorizar un servidor Linux, revisa también nuestra guía de optimización de rendimiento de servidores Linux, donde tratamos métricas de red en contexto.


8. Consideraciones legales y éticas

Monitorizar tráfico de red es legal en tu propia infraestructura o en entornos de laboratorio controlados. No es legal interceptar tráfico de terceros sin autorización expresa. Los ejemplos de este artículo están pensados para:

  • Monitorizar tu propio servidor web.
  • Analizar el tráfico que genera tu propia máquina.
  • Laboratorios de ciberseguridad con máquinas virtuales aisladas.

Si necesitas un entorno de pruebas, cualquier hipervisor moderno te sirve. Tenemos guías específicas de Proxmox y de VirtualBox si quieres montar tu lab.


Conclusión

Scapy te permite entender cómo funciona la captura de paquetes y escribir scripts de monitorización en pocas líneas. Es una herramienta valiosa para aprender y para tareas puntuales. Pero si tu objetivo es monitorizar una web en producción, invierte el tiempo en tcpdump para capturas puntuales y en un stack de observabilidad (Prometheus + Grafana o Netdata) para monitorización continua.

Y recuerda: el script se ejecuta en la máquina que captura, no «en la URL». Si quieres ver el tráfico de tu servidor, ejecútalo en el servidor. Si quieres ver el tráfico que genera tu navegador, ejecútalo en tu ordenador. Y en 2026, el tráfico web es mayoritariamente HTTPS y cada vez más HTTP/3: monitorizar solo el puerto 80 es mirar una parte cada vez más pequeña de la realidad.


Caso practico:

1. Conéctate al servidor y crea el directorio

# Conéctate por SSH a tu servidor
ssh usuario@tu-servidor

# Crea un directorio para el proyecto
mkdir -p ~/monitor-trafico
cd ~/monitor-trafico
Conéctate al servidor y crea el directorio

2. Crea y activa el entorno virtual (venv)

# Crear el entorno virtual
python3 -m venv venv

# Activarlo
source venv/bin/activate

Verás que el prompt cambia y aparece (venv).

3. Instala Scapy

pip install --upgrade pip
pip install scapy
Instala Scapy

4. Crea el archivo Python

nano monitor.py

Pega este código (versión mejorada del artículo, pensada para servidor):

#!/usr/bin/env python3
"""
Monitor de tráfico entrante/saliente en un servidor
Ejecutar con: sudo env "PATH=$PATH" python monitor.py
"""

from scapy.all import sniff, TCP, IP, UDP
import socket
from collections import defaultdict
from datetime import datetime

# Contadores simples
stats = defaultdict(lambda: {"paquetes": 0, "bytes": 0})

def analizar_paquete(pkt):
    if not (pkt.haslayer(IP) and (pkt.haslayer(TCP) or pkt.haslayer(UDP))):
        return

    ip = pkt[IP]
    proto = "TCP" if pkt.haslayer(TCP) else "UDP"
    capa = pkt[TCP] if proto == "TCP" else pkt[UDP]

    # En el SERVIDOR:
    # - dport 80/443 → ENTRANTE (cliente nos habla)
    # - sport 80/443 → SALIENTE (nosotros respondemos)
    if capa.dport in (80, 443):
        direccion = "ENTRANTE"
        clave = f"{direccion} {ip.src} → {ip.dst}:{capa.dport}"
    elif capa.sport in (80, 443):
        direccion = "SALIENTE"
        clave = f"{direccion} {ip.src}:{capa.sport} → {ip.dst}"
    else:
        return  # Ignoramos otros puertos

    tamaño = len(pkt)
    stats[clave]["paquetes"] += 1
    stats[clave]["bytes"] += tamaño

    # Imprimir en tiempo real (puedes comentar esta línea si quieres menos ruido)
    print(f"[{datetime.now().strftime('%H:%M:%S')}] [{direccion}] {proto} "
          f"{ip.src}:{capa.sport} → {ip.dst}:{capa.dport}  {tamaño} bytes  flags={getattr(capa, 'flags', '-')}")

def mostrar_resumen():
    print("\n" + "="*70)
    print("RESUMEN DE TRÁFICO")
    print("="*70)
    for clave, datos in sorted(stats.items(), key=lambda x: x[1]["bytes"], reverse=True):
        print(f"{clave}")
        print(f"   Paquetes: {datos['paquetes']:,}  |  Bytes: {datos['bytes']:,}")
    print("="*70)

if __name__ == "__main__":
    print("Iniciando captura de tráfico en el servidor...")
    print("Filtro: host local + puertos 80 y 443 (HTTP/HTTPS)")
    print("Pulsa Ctrl+C para detener y ver el resumen\n")

    try:
        # Captura todo el tráfico de los puertos web del servidor
        # store=0 → no guarda los paquetes en memoria (importante)
        sniff(
            filter="tcp port 80 or tcp port 443 or udp port 443",
            prn=analizar_paquete,
            store=0
        )
    except KeyboardInterrupt:
        mostrar_resumen()
        print("\nCaptura detenida.")

Guarda el archivo (Ctrl+O → Enter → Ctrl+X en nano).

Crea el archivo Python

5. Ejecutar el script (importante: con permisos)

Scapy necesita privilegios de red. No ejecutes solo python monitor.py.

Hazlo así:

# Con el venv activado:
sudo env "PATH=$PATH" python monitor.py

La parte env «PATH=$PATH» es clave para que use el Python del entorno virtual y no el del sistema.

Ejecutar el script (importante con permisos)

Resumen rápido de comandos

mkdir -p ~/monitor-trafico && cd ~/monitor-trafico
python3 -m venv venv
source venv/bin/activate
pip install scapy
nano monitor.py          # pegas el código
sudo env "PATH=$PATH" python monitor.py

Monitorizar tráfico saliente y entrante de una web con Python caso real

Notas importantes:

  • El script está pensado para ejecutarse en el servidor (punto de vista del servidor: dport = entrante).
  • Solo verás metadatos (IPs, puertos, tamaño, flags). El contenido HTTPS está cifrado.
  • Para producción real se recomienda herramientas más robustas (vnstat, nload, Prometheus + node_exporter, Netdata, etc.), porque Scapy no es ideal para monitorización continua.

Deja un comentario