feat(cybersecurity): auto-commit con 10 cambios

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-02 21:50:23 +02:00
parent 4bbfc127ad
commit f74d0d8e32
10 changed files with 825 additions and 0 deletions
@@ -0,0 +1,65 @@
---
name: rotate_capture_flows
kind: function
lang: py
domain: cybersecurity
version: "1.0.0"
purity: impure
signature: "class Rotator — mitmproxy addon loaded via mitmdump -s"
description: "Addon de mitmproxy que rota el archivo de captura de flows cada N minutos. Crea archivos .mitm con timestamp en el nombre (traffic-YYYYmmdd-HHMMSS.mitm) y abre uno nuevo cuando vence el intervalo de rotacion. La rotacion ocurre en el evento response, por lo que solo sucede cuando hay trafico activo."
tags: [mitmproxy, capture, rotate, proxy, web-proxy, cybersecurity, flows, traffic]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: "error_go_core"
imports: ["mitmproxy.io", "mitmproxy.ctx", "os", "time", "datetime"]
tested: false
tests: []
test_file_path: ""
file_path: "python/functions/cybersecurity/rotate_capture_flows.py"
params:
- name: rotate_min
desc: "Minutos por archivo antes de rotar. Se pasa via --set rotate_min=N al invocar mitmdump. Default: 20."
- name: capture_dir
desc: "Directorio donde se escriben los archivos .mitm rotados. Se pasa via --set capture_dir=/ruta. Default: directorio de trabajo actual."
output: "Archivos .mitm con nombre traffic-<YYYYmmdd-HHMMSS>.mitm en capture_dir, cada uno con los flows HTTP capturados durante una ventana de rotate_min minutos."
---
## Ejemplo
```bash
# Capturar trafico HTTP/S en ventanas de 20 minutos en ~/captures/
mitmdump \
-s python/functions/cybersecurity/rotate_capture_flows.py \
--set rotate_min=20 \
--set capture_dir=/home/enmanuel/captures \
--listen-port 8080
# Ventanas de 5 minutos para analisis rapido
mitmdump \
-s python/functions/cybersecurity/rotate_capture_flows.py \
--set rotate_min=5 \
--set capture_dir=/tmp/proxy_session \
--listen-port 8080
# Leer un archivo capturado con mitmproxy
mitmproxy -r /home/enmanuel/captures/traffic-20260602-143000.mitm
```
## Cuando usarla
Cuando necesites capturar trafico HTTP/S durante periodos largos y quieras trocear las capturas en ventanas de tiempo manejables. Util antes de analizar el comportamiento de red de una aplicacion movil o web durante horas, cuando un unico archivo .mitm de varios GB seria dificil de navegar.
## Gotchas
- La rotacion ocurre en el evento `response`: si no llega ningun flujo completo durante el intervalo, el archivo no rota hasta que llegue el siguiente. El reloj es wall-clock del proceso, no del servidor.
- El archivo anterior se cierra (flush + close) justo antes de abrir el nuevo, por lo que no se pierden flows ya registrados al rotar.
- El addon hace `flush()` despues de cada flujo registrado. Esto garantiza que la captura sobrevive a una muerte abrupta del proceso (SIGKILL, crash, corte de energia): sin el flush, el FlowWriter bufferiza y el `.mitm` queda en 0 bytes si el proceso no llega a ejecutar `done()`. Verificado en smoke test matando con `kill -9` a media captura.
- Los flows que no tienen respuesta (timeouts de servidor, errores de conexion antes de recibir headers) no llegan al evento `response` y por tanto no se escriben en el archivo. Para capturarlos tambien, habria que sobrescribir adicionalmente el hook `error(self, flow)`.
- Requiere mitmproxy >= 10 en el entorno. Instalable con `uv tool install mitmproxy`.
- El directorio `capture_dir` se crea automaticamente con `os.makedirs(..., exist_ok=True)` si no existe.
## Notas
El addon usa la API de opciones de mitmproxy 10+ (`loader.add_option`). En versiones anteriores la API de opciones era distinta. Verificar version con `mitmdump --version` antes de cargar.
@@ -0,0 +1,127 @@
"""mitmproxy addon that rotates the capture file every N minutes.
Load with: mitmdump -s rotate_capture_flows.py --set rotate_min=20 --set capture_dir=/path/to/dir
"""
import os
import time
from datetime import datetime
from mitmproxy import ctx
import mitmproxy.io
class Rotator:
"""Addon that writes flows to a rotating series of .mitm files.
A new file is opened whenever the current one has been open for
at least ``rotate_min`` minutes. The rollover check happens on
every ``response`` event, so the file only rotates when traffic
is actually flowing through the proxy.
"""
def __init__(self) -> None:
self._writer: mitmproxy.io.FlowWriter | None = None
self._fh = None # file handle opened in "wb"
self._opened_at: float = 0.0
self._current_path: str = ""
self._rotate_min: int = 20
self._capture_dir: str = "."
self._exclude: set = set()
# ------------------------------------------------------------------
# mitmproxy lifecycle hooks
# ------------------------------------------------------------------
def load(self, loader) -> None:
"""Register addon options."""
loader.add_option(
name="rotate_min",
typespec=int,
default=20,
help="Minutes per capture file before rolling over.",
)
loader.add_option(
name="capture_dir",
typespec=str,
default=".",
help="Directory where rotating .mitm files are written.",
)
loader.add_option(
name="exclude_hosts",
typespec=str,
default="",
help=(
"Comma-separated hosts or host:port that must never be "
"recorded (e.g. the proxy's own web UI). Flows matching "
"either the host alone or host:port are dropped silently."
),
)
def configure(self, updated) -> None:
"""Read option values and ensure the capture directory exists."""
self._rotate_min = ctx.options.rotate_min
self._capture_dir = ctx.options.capture_dir
self._exclude = {
h.strip() for h in ctx.options.exclude_hosts.split(",") if h.strip()
}
if self._capture_dir:
os.makedirs(self._capture_dir, exist_ok=True)
def response(self, flow) -> None:
"""Called for every completed HTTP response.
Rolls the file over if the rotation interval has elapsed, then
records the flow. Flows whose host (or host:port) is in the
exclude list are dropped without being written.
"""
if self._exclude:
host = flow.request.pretty_host
if host in self._exclude or f"{host}:{flow.request.port}" in self._exclude:
return
now = time.time()
if self._writer is None or (now - self._opened_at) >= self._rotate_min * 60:
self._roll()
self._writer.add(flow)
# Flush after every flow so the capture survives an abrupt kill
# (SIGKILL, crash, power loss). A capture proxy must never lose its
# window of traffic just because the process died without cleanup.
if self._fh is not None:
self._fh.flush()
def done(self) -> None:
"""Clean up when mitmdump shuts down."""
self._close()
# ------------------------------------------------------------------
# Internal helpers
# ------------------------------------------------------------------
def _roll(self) -> None:
"""Close the current file (if any) and open a new one."""
self._close()
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
filename = f"traffic-{timestamp}.mitm"
self._current_path = os.path.join(self._capture_dir, filename)
self._fh = open(self._current_path, "wb")
self._writer = mitmproxy.io.FlowWriter(self._fh)
self._opened_at = time.time()
ctx.log.info(f"rotate_capture_flows: opened new capture file {self._current_path}")
def _close(self) -> None:
"""Flush and close the current writer and file handle."""
if self._fh is not None:
try:
self._fh.flush()
self._fh.close()
except Exception:
pass
finally:
self._fh = None
self._writer = None
addons = [Rotator()]