Commit Graph
6 Commits
Author SHA1 Message Date
SergioandClaude Opus 5 eaa7d02725 el corte, con hora: 93 minutos — y en un servicio que ya autoriza no va límite por tasa
Del `access.log`, sin ambigüedad. La IP del usuario (`45.234.61.160`, autenticada como `sergio`,
2709 peticiones) tuvo tres silencios: **93,2 min (11:59:37 → 13:32:49 UTC)**, 50,1 min (10:44:58 →
11:35:06) y 10,0 min (11:45:06 → 11:55:05). Los tres son el `timeout` de 10 minutos del ban
disparándose una y otra vez: cada vez que volvía, su primera ráfaga lo baneaba de nuevo. El corte
grande terminó exactamente cuando vacié los sets.

🧨 Y LA EXENCIÓN QUE TENÍA NO SERVÍA: la ACL histórica de squid exime `45.234.60.0/24` y él entra
desde `45.234.61.160` — **una red de al lado**. Parecía cubierto y no lo estaba. La pertenencia se
MIDE (`ip in red`), no se deduce del parecido del prefijo.

DECISIÓN DE FONDO: en un servicio que YA AUTORIZA no va límite por tasa. El uso de esta caja es
INTENSIVO —varias sesiones de agente en paralelo, cada una abriendo túneles a la vez— y un límite
calibrado para «una persona normal navegando» no protege de nada: el atacante ajusta su ritmo, el
usuario no puede trabajar más despacio. Squid ya pide usuario y contraseña y tiene su ACL. El ban del
puerto queda apagado (60000/min, ráfaga 1000) y contra un flood queda el tope GLOBAL
`syn_nuevas_por_seg`, que no distingue usuarios ni banea a nadie por ser rápido.

Control tras aplicar: su túnel pasando —`45.234.61.160 … CONNECT api.anthropic.com:443 sergio`— y
`45.234.61.160 ∈ 45.234.60.0/23` comprobado con aritmética de redes, no a ojo.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 13:38:54 +00:00
SergioandClaude Opus 5 618dcfd851 🧨 el cortafuegos baneaba a los usuarios del proxy — y squid nunca se cayó
Preguntaron si el proxy estaba caído. NO lo estaba: el ente llevaba horas corriendo con ↻ 0 y
contestando 407. Lo caído era el ACCESO — el cortafuegos de ayer baneaba a los autorizados.

La prueba en una línea: **154.197.1.2, una IP que está en la ACL de squid (gente con contraseña),
apareció en `@ban4`**, con el contador del ban en 38.246 paquetes tirados.

LA CAUSA NO ES LA TASA, ES LA RÁFAGA: `limit rate over 300/minute burst 5 packets` tolera cinco
conexiones por encima del promedio, y un navegador o un agente detrás de un proxy abre DECENAS de
CONNECT en el mismo instante aunque su promedio sea bajísimo. Y como @ban4 es UN SOLO set consultado
antes que todo, caer por el puerto del proxy te tira también el web y el git.

⚠ El tipo ya traía el campo `rafaga` (default 5) con un comentario que dice «para un servicio web va
alto (100-200)». Otra vez leí el .ron de EJEMPLO y no el TIPO.

Hecho, en orden de urgencia: flush de los sets (servicio restaurado en el acto) · los 21 IPs y 5
redes de la ACL de squid a `confiables` · `rafaga` por servicio según su clientela (ssh 5, git 20,
web 100, proxy 200) · proxy a 1200/min con ban de 60 s, que es red de contención contra un flood y
no control de uso. Control después: CERO autorizados en el set, 24 baneados (escáneres) y tráfico
real pasando —`154.194.14.37 … CONNECT api.deepseek.com:443 sigma`, 298 K tunelados—.

⚠⚠ Y un fallo de método que casi lo tapa: **`nft -f` SUMA a la tabla existente**. Cargué el reglaset
corregido encima del viejo y quedaron 30 reglas con las VIEJAS ADELANTE, así que los `confiables`
nuevos no se evaluaban nunca. Por eso `cortafuegos apply-input` borra la tabla antes de cargar.

La lección: un cortafuegos correcto y uno usable no son lo mismo, y la diferencia NO se ve al
aplicarlo. El control que lo habría cazado es el que no corrí: una ráfaga de conexiones desde una IP
que no esté en `confiables`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 13:33:50 +00:00
SergioandClaude Opus 5 e903f486d9 el enlazador va DENTRO del compilador — /etc/cargo/config.toml es una ruta que cargo no lee
La prueba de la caja recién instalada —`cargo build` en un proyecto nuevo, sin flags ni rutas a
mano— falló con `linker `cc` not found`, y destapó que la pieza que había empaquetado era falsa:
**cargo NO LEE `/etc/cargo/config.toml`**. Sólo lee `$CARGO_HOME/config.toml`, los
`.cargo/config.toml` del proyecto y sus padres, y lo que se le pase con `--config` — que es lo que yo
venía pasando a mano en cada prueba, y por eso «funcionaba».

Y el arreglo no era mover el fichero: **el que enlaza es `rustc`, y rustc no lee la config de
cargo**. Las flags van DENTRO del compilador, en el spec del triple:

· `linker = "ld.lld"` + `linker_flavor = Gnu(Cc::No, Lld::Yes)` — sin esto rustc busca `cc`, que una
  caja takana no tiene.
· `crt_static_default = true` — sin esto enlaza dinámico y pide `-lgcc`, que no existe (la distro se
  construye con zig, que trae compiler-rt).
· `crt_static_allows_dylibs = true` — su pareja obligatoria: sin ella `crt-static` apaga los dylibs
  y con ellos los PROC-MACROS (serde_derive, clap_derive, las 44 recetas `cargo-*` con `derive`).
  El compilador en sí sigue dinámico: el `bootstrap.toml` fija `crt-static = false` para el build, y
  eso gana sobre el default del spec.

⇒ `cargo-config` (receta, árbol y copia en scripts/) se van enteros: un paquete que instala un
fichero que nadie abre es peor que no tenerlo.

Y de paso, `lld21` instala los cuatro alias como SYMLINKS y no como copias: cmake los duplicaba, 5 ×
96 M = 478 M de artefacto para 97 M de enlazador. Ahora 108 M, y `ld.lld` sigue despachando por
`argv[0]`, que es como upstream lo diseñó.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 13:07:56 +00:00
SergioandClaude Opus 5 72ba86c290 la cadena rehecha: llvm21 arreglado, lld enlaza, rust reconstruido — los seis controles pasan
Un cambio de dos líneas en `llvm21` re-selló tres artefactos y los molió la granja sola, en orden,
por dependencia: llvm21 95956a16→bd4a4094, lld21 27be53c1→95a4794b, rust 015a07fb→702094a8.

    llc --version        Stack dump: + segfault   →   LLVM 21.1.2, Optimized build
    opt --version        ídem                     →   LLVM 21.1.2
    ld.lld               «not built with zlib»    →   ENLAZA
    rustc --version                               →   1.97.0 (built from a source tarball)
    --print target-list                           →   x86_64-alpine-linux-musl
    cargo build + correr                          →   0,16 s y el binario habla

La config del sitio pasa a usar `lld` (más rápido); el `ld` de binutils queda documentado como
alternativa que también funciona.

LA REGLA QUE SE GANÓ SU LUGAR: **`link = "static"` en el encabezado decide cosas que la receta no
dice**. Van tres, todas medidas: apagó los threads de openssl, le mintió a libtool, y acá rompió los
registros estáticos de LLVM (`cl::opt`, `TargetRegistry`) porque el `static-pie` descarta sus
constructores globales. Con C++ grande la postura por defecto pasa a ser `dynamic` y medirlo — y el
control no es que selle: es CORRER UNA HERRAMIENTA del artefacto.

Y el corolario de por qué nadie lo vio en meses: el único consumidor de llvm21 era rust, que usa
`llvm-config` y las `.a`, nunca una herramienta. **Un artefacto puede estar roto en todo lo que nadie
usa** — como los 44 `cargo-*` sin cargo y los 23 binarios sin cargador.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 11:19:18 +00:00
SergioandClaude Opus 5 ef1f9252a1 EL TOOLCHAIN COMPILA, ENLAZA Y CORRE — en una caja sin compilador de C
$ cargo build --offline
       Compiling prueba v0.1.0 … Finished in 0.44s
    $ ./target/debug/prueba
    cargo, rustc y ld: los tres nuestros

`cargo` y `rustc` son los que construyó la granja; el enlazador es el `ld` de nuestro `binutils`.

EL MURO 8 SE CERRÓ SIN `lld`. La cadena, que es lo que vale: `-C linker-flavor=ld.lld` → «linker
`lld` not found» (el build con LLVM externo no genera rust-lld); `rust.lld = true` → el bootstrap lo
RECHAZA; `lld21` propio → crasheaba con cualquier entrada; `lld21` con zlib → **no se puede encender
desde ahí**, porque `LLVMConfig.cmake` dice `LLVM_ENABLE_ZLIB 0` y el build standalone lo hereda.

Lo que faltaba NO era un enlazador: era decirle a rustc que enlace en ESTÁTICO. Con `+crt-static`,
rustc usa su propio libunwind/compiler_builtins y deja de pedir `-lgcc` — que es lo que rompía el
intento con `ld`, porque la distro se construye con zig (compiler-rt) y libgcc no existe. Y estático
es el modo natural de musl.

⇒ `scripts/servidor/cargo-config.toml` (instalado en `/etc/cargo/config.toml`) cierra el pendiente
«config del sitio» del §5, con las tres flags y el porqué de cada una.

🧨 Y `lld21` destapó algo que nadie había visto: **las 79 herramientas de `llvm21` están ROTAS**.
`llc --version` crashea igual —también en el worker— porque salen `static-pie` y el enlace estático
descarta los constructores globales de los que dependen `cl::opt` y `TargetRegistry`. Funciona lo
que no los necesita (`llvm-ar`, `llvm-config`) y revienta lo que sí; nadie lo notó porque `rust` usa
`llvm-config` y las `.a`, nunca una herramienta. Queda como deuda DECLARADA: arreglarlo (o encender
zlib) re-hashea `llvm21` y con él `rust`. Hoy no bloquea nada.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-16 04:48:25 +00:00
SergioandClaude Opus 5 24a6dd3b2f el cortafuegos puesto en la caja — y el primer baneado fui yo
`table inet tawasuyu_input` con policy drop, 15 reglas de puerto, y el set `ban4` llenandose solo:
a los pocos minutos, 27 IPs baneadas y paquetes tirados por el contador. El reemplazo de fail2ban
funcionando sobre trafico real, dentro del kernel y sin daemon.

🧨 EL PRIMER BANEADO FUI YO, EN SEGUNDOS. Aplicada la primera version: ssh y https bien, y `http`,
proxy y git-ssh muertos; al minuto la caja entera dejo de contestarme. La causa no es una regla mal
escrita: **el set @ban4 es UNO SOLO para todos los servicios** y `ip saddr @ban4 drop` esta antes
que todo, asi que pasarse de tasa en UN puerto te tira en TODOS — y el `nuevas_por_min: 5` del
puerto de administracion es exactamente lo que me pasa a mi, porque cada comando remoto es una
conexion nueva. Lo devolvio el INTERRUPTOR DE HOMBRE MUERTO (un `nft flush ruleset` programado a
180 s que sólo se desarma si la verificacion externa sale bien). Sin consola serie, esa es la
diferencia entre un susto y un rescue.

⚠ Y el tipo ya lo avisaba: `PoliticaEntrada` tiene un campo `confiables` cuyo comentario describe
palabra por palabra lo que me paso. Copie el .ron de EJEMPLO en vez de leer el TIPO. La cura fue una
linea con el hub y el worker, que se aceptan ANTES de la logica de tasa.

⚠ `nft -c` rechazo 5 reglas antes de aplicar nada: `ct count over N` es CONFIG_NFT_CONNLIMIT y este
kernel no lo trae. Quedan COMENTADAS y no borradas en el fichero que se aplica — lo que la politica
declara y el kernel no puede tiene que verse. El simbolo ya entro a la receta del kernel.

Y para que sobreviva al reinicio, `nftables` declara su [[service]] con `lifecycle = "oneshot"`:
cargar un reglaset no es un daemon, es un acto. Va PRIMERO en el genesis — entre que la red esta y
que las reglas cargan, la caja esta abierta. Probado con `nft flush ruleset` + `arjectl start`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-15 21:56:51 +00:00