fixed4337

This commit is contained in:
Rodrigo Bertoldo de Sousa Martins committed 2026-09-14 09:24:18 -03:00
1 parent 0a37f06ce6
commit e97a83c989
2 files changed
+34 -5

No files matched your search

+25 -4
View File
@@ -97,13 +97,30 @@ static __always_inline bool is_local_ip(__u32 ip_be)
// Extrai a chave de conexão a partir do contexto sock_ops
// (usado quando uma conexão TCP é estabelecida)
// ─────────────────────────────────────────────────────────
// BUG CORRIGIDO: o código antigo misturava dois domínios de codificação
// de porta sem converter os dois pro mesmo formato.
// - ops->local_port vem em HOST byte order (puro, ex: 6379)
// - ops->remote_port vem com o valor em network byte order alojado nos
// 16 bits SUPERIORES de um campo de 32 bits — não é um u32 comum em
// network order, então bpf_ntohl() sozinho faz um byte-swap completo
// de 32 bits e produz um número sem relação com a porta real.
// A comparação `sport == local_port do outro lado` só funciona se AMBOS
// os valores estiverem no MESMO domínio. Em vez de tentar decifrar o
// valor "verdadeiro" da porta (o que exigiria confiar numa convenção que
// não dá pra validar sem testar em kernel real), a correção normaliza os
// dois pro domínio de remote_port: extrai remote_port com ">> 16" (sem
// ntohl) e converte local_port PRA esse mesmo domínio com
// "bpf_htonl(local_port) >> 16". Assim os dois lados de uma conexão
// calculam exatamente o mesmo valor pro mesmo par de portas, não importa
// qual seja a codificação exata do kernel — o que importa é que os dois
// membros do par usem a MESMA transformação simétrica.
static __always_inline void
extract_key_from_ops(struct bpf_sock_ops *ops, struct sock_key *key)
{
key->sip4 = ops->local_ip4;
key->dip4 = ops->remote_ip4;
key->sport = ops->local_port; // já em host byte order
key->dport = bpf_ntohl(ops->remote_port); // converter de network para host
key->sport = bpf_htonl(ops->local_port) >> 16;
key->dport = ops->remote_port >> 16;
key->family = ops->family;
}
@@ -201,11 +218,15 @@ int bpf_msg_redirect(struct sk_msg_md *msg)
// Construímos a chave do socket PAR (invertendo src/dst).
// Se A→B enviou dados, queremos encontrar no mapa a entrada
// que B registrou: {sip=B, dip=A, sport=portaB, dport=portaA}
//
// Mesma normalização de porta usada em extract_key_from_ops (mesmo
// domínio dos dois lados): remote_port só com ">> 16", local_port
// convertido pra esse domínio via "bpf_htonl(...) >> 16".
struct sock_key key = {};
key.sip4 = msg->remote_ip4; // IP remoto = IP do par
key.dip4 = msg->local_ip4; // IP local = nosso IP
key.sport = bpf_ntohl(msg->remote_port); // remote_port está em network order
key.dport = msg->local_port; // local_port está em host order
key.sport = msg->remote_port >> 16;
key.dport = bpf_htonl(msg->local_port) >> 16;
key.family = msg->family;
// Tenta redirecionar diretamente para o socket par.