This commit is contained in:
Rodrigo Bertoldo de Sousa Martins committed 2026-09-14 15:41:44 -03:00
1 parent c17738a62f
commit 38a3e9e495
1 file changed
+56
+56
View File
@@ -133,6 +133,48 @@ static __always_inline bool is_local_ip(__u32 ip_be)
return false; return false;
} }
// ─────────────────────────────────────────────────────────
// DECISÃO DE ESCOPO (depois de 4 rodadas de bugs encontrados e
// corrigidos — porta, dual-stack, loopback, tamanho — todos legítimos,
// mas o problema de fundo continuou aparecendo especificamente em
// tráfego HTTP via proxy: nginx↔Nextcloud, nginx↔Atlas, nginx↔OnlyOffice,
// sempre — "upstream prematurely closed connection" / timeout, mesmo em
// respostas pequenas, em serviços sem nenhuma relação entre si):
//
// Em TODOS os testes, sem uma única exceção, tráfego banco/cache
// (MariaDB, Redis) redirecionou correto e nunca corrompeu nada — nem em
// rajada, nem sob concorrência. Tráfego HTTP via proxy reverso
// (streaming, HTTP/2, keep-alive, chunked) é o único padrão onde o
// problema aparece, e é mais sensível a qualquer perturbação sutil no
// fluxo de bytes.
//
// Em vez de continuar caçando o bug exato do mecanismo de redirect do
// kernel, restringimos o REGISTRO no sockhash a conexões onde um dos
// lados é porta de banco/cache. Tráfego HTTP nunca entra no mapa —
// nunca é candidato a redirect, sempre usa o caminho normal de rede
// (comprovadamente 100% íntegro, inclusive em teste isolado de 500MB
// via nc). Perde-se a aceleração pra proxy HTTP; mantém-se pro tipo de
// tráfego (muitos round-trips pequenos de banco/cache) onde o ganho de
// latência é maior E onde já provamos que funciona sem risco.
//
// IMPORTANTE: key.sport/key.dport NÃO são o número literal da porta —
// já passam pela transformação bpf_htonl(porta)>>16 (ver
// extract_key_from_ops). Comparar direto com 3306/6379 nunca bateria.
// Os valores abaixo são o RESULTADO dessa mesma transformação aplicada
// às portas reais, verificados nos traces de produção desta sessão
// (ex: MariaDB sempre apareceu com dport/sport=59916, nunca 3306) e
// confirmados by matemática: bpf_htonl(3306)>>16 = 0xEA0C = 59916;
// bpf_htonl(6379)>>16 = 0xEB18 = 60184.
// ─────────────────────────────────────────────────────────
#define SOCKMAP_PORT_MARIADB_ENC 59916 // 3306 já transformado
#define SOCKMAP_PORT_REDIS_ENC 60184 // 6379 já transformado
static __always_inline bool is_accelerated_key(struct sock_key *key)
{
return key->sport == SOCKMAP_PORT_MARIADB_ENC || key->dport == SOCKMAP_PORT_MARIADB_ENC ||
key->sport == SOCKMAP_PORT_REDIS_ENC || key->dport == SOCKMAP_PORT_REDIS_ENC;
}
// ───────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────
// Extrai a chave de conexão a partir do contexto sock_ops // Extrai a chave de conexão a partir do contexto sock_ops
// (usado quando uma conexão TCP é estabelecida) // (usado quando uma conexão TCP é estabelecida)
@@ -216,6 +258,12 @@ int bpf_sockops_handler(struct bpf_sock_ops *skops)
return 0; return 0;
} }
// ── Escopo: só banco/cache (ver comentário em is_accelerated_key) ──
if (!is_accelerated_key(&key)) {
stats_inc(3);
return 0;
}
if (skops->family == SOCKMAP_AF_INET6) if (skops->family == SOCKMAP_AF_INET6)
bpf_printk("REG via IPv6 mapeado: op=%u sip=%x dip=%x", op, key.sip4, key.dip4); bpf_printk("REG via IPv6 mapeado: op=%u sip=%x dip=%x", op, key.sip4, key.dip4);
@@ -323,6 +371,14 @@ int bpf_msg_redirect(struct sk_msg_md *msg)
key.dport = bpf_htonl(msg->local_port) >> 16; key.dport = bpf_htonl(msg->local_port) >> 16;
key.family = SOCKMAP_AF_INET; // normalizado, ver extract_key_from_ops key.family = SOCKMAP_AF_INET; // normalizado, ver extract_key_from_ops
// Cinto e suspensório: mesmo que o registro já esteja restrito a
// banco/cache, confere de novo aqui — garante que nenhum tráfego
// HTTP tenta redirect mesmo que uma entrada antiga/inesperada exista.
if (!is_accelerated_key(&key)) {
stats_inc(2);
return SK_PASS;
}
// Tenta redirecionar diretamente para o socket par. // Tenta redirecionar diretamente para o socket par.
int ret = bpf_msg_redirect_hash(msg, &sock_hash, &key, BPF_F_INGRESS); int ret = bpf_msg_redirect_hash(msg, &sock_hash, &key, BPF_F_INGRESS);
if (ret == SK_PASS) { if (ret == SK_PASS) {