This commit is contained in:
rodrigo committed 2025-02-28 20:43:33 -03:00
1 parent c35a244d40
commit 0a94f772da
1 file changed
+100 -75
+100 -75
View File
@@ -53,59 +53,77 @@ static __always_inline void update_stats(__u64 *stat_counter) {
} }
} }
// Função para ajustar TCP MSS - corrigido tipos de ponteiro // Função para ajustar TCP MSS - totalmente reescrita para maior simplicidade
static __always_inline int adjust_tcp_mss(struct tcphdr *tcp, void *data_end_ptr, __u16 max_mss) { static __always_inline int adjust_tcp_mss(struct tcphdr *tcp, void *data_end, __u16 max_mss) {
void *tcp_end = (void *)tcp + sizeof(struct tcphdr); // Verificação básica do cabeçalho TCP
if (tcp_end > data_end_ptr) if ((void *)(tcp + 1) > data_end)
return 0; return 0;
if (!tcp->syn) // Ajustamos MSS apenas em pacotes SYN
return 0; // Ajustamos MSS apenas em pacotes SYN if (!tcp->syn || tcp->ack)
return 0;
__u8 tcp_hdr_len = tcp->doff * 4; __u8 tcp_hdr_len = tcp->doff * 4;
__u8 *tcp_opt_ptr = (__u8 *)tcp + sizeof(struct tcphdr); if (tcp_hdr_len <= sizeof(struct tcphdr))
__u8 *tcp_opt_end = (__u8 *)tcp + tcp_hdr_len; return 0; // Sem opções TCP
// Corrigido: cast explícito para comparação de tipos de ponteiro // Verificar se todo o cabeçalho está acessível
if ((void *)tcp_opt_end > data_end_ptr) void *tcp_end = (void *)tcp + tcp_hdr_len;
if (tcp_end > data_end)
return 0; return 0;
// Procurar opção MSS (kind=2, len=4) nas opções TCP __u8 *opt_ptr = (__u8 *)(tcp + 1);
#pragma unroll 4 // Limite de desenrolamento para evitar erros __u8 *tcp_options_end = (__u8 *)tcp_end;
for (int i = 0; i < 40 && tcp_opt_ptr + 1 < tcp_opt_end; i += tcp_opt_ptr[1]) {
// Corrigido: verificações de limites com cast explícito // Loop simplificado com controle estrito de limites
if ((void *)(tcp_opt_ptr + 2) > data_end_ptr || (tcp_opt_ptr + 2) > tcp_opt_end) #pragma unroll 4
for (int i = 0; i < 4 && opt_ptr < tcp_options_end; i++) {
// Verificar espaço para o tipo da opção
if (opt_ptr + 1 > tcp_options_end || (void *)(opt_ptr + 1) > data_end)
break; break;
if (tcp_opt_ptr[0] == 2 && tcp_opt_ptr[1] == 4) { // MSS option // Verificar tipo da opção
// Corrigido: verificações de limites com cast explícito if (*opt_ptr == 0) // End of options
if ((void *)(tcp_opt_ptr + 4) > data_end_ptr || (tcp_opt_ptr + 4) > tcp_opt_end) break;
break;
// Extrair valor MSS atual (network byte order) if (*opt_ptr == 1) { // NOP
__u16 *mss_ptr = (__u16 *)(tcp_opt_ptr + 2); opt_ptr += 1;
__u16 current_mss = bpf_ntohs(*mss_ptr); continue;
}
// Ajustar MSS se necessário // Verificar espaço para o comprimento
if (current_mss > max_mss) { if (opt_ptr + 2 > tcp_options_end || (void *)(opt_ptr + 2) > data_end)
*mss_ptr = bpf_htons(max_mss); break;
__u32 zero = 0;
struct mtu_stats *stats = bpf_map_lookup_elem(&mtu_stats_map, &zero); __u8 opt_len = *(opt_ptr + 1);
if (stats) { if (opt_len < 2) // Comprimento inválido
stats->mss_adjusted++; break;
// Verificar se a opção completa está no buffer
if (opt_ptr + opt_len > tcp_options_end || (void *)(opt_ptr + opt_len) > data_end)
break;
// Verificar se é a opção MSS
if (*opt_ptr == 2 && opt_len == 4) {
// Temos espaço para o valor de MSS? (2 bytes após cabeçalho da opção)
if (opt_ptr + 4 <= tcp_options_end && (void *)(opt_ptr + 4) <= data_end) {
__u16 *mss_ptr = (__u16 *)(opt_ptr + 2);
__u16 current_mss = bpf_ntohs(*mss_ptr);
if (current_mss > max_mss) {
*mss_ptr = bpf_htons(max_mss);
__u32 key = 0;
struct mtu_stats *stats = bpf_map_lookup_elem(&mtu_stats_map, &key);
if (stats)
stats->mss_adjusted++;
return 1;
} }
return 1;
} }
break; break;
} }
if (tcp_opt_ptr[0] == 0) // End of options // Avançar para próxima opção
break; opt_ptr += opt_len;
if (tcp_opt_ptr[1] < 2) // Opções malformadas, prevenir loop infinito
break;
tcp_opt_ptr += tcp_opt_ptr[1];
} }
return 0; return 0;
@@ -136,82 +154,89 @@ static __always_inline int send_icmp_frag_needed(struct iphdr *iph, __u16 mtu) {
return XDP_ABORTED; return XDP_ABORTED;
} }
// Programa XDP principal para otimização de pacotes WireGuard - simplificado e corrigido // Programa XDP principal - simplificado
SEC("xdp") SEC("xdp")
int xdp_wg_optimizer(struct xdp_md *ctx) { int xdp_wg_optimizer(struct xdp_md *ctx) {
void *data_end = (void *)(long)ctx->data_end; void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data; void *data = (void *)(long)ctx->data;
__u32 zero = 0; __u32 key = 0;
// Inicializar contadores // Incrementar estatística de pacotes totais
struct mtu_stats *stats = bpf_map_lookup_elem(&mtu_stats_map, &zero); struct mtu_stats *stats = bpf_map_lookup_elem(&mtu_stats_map, &key);
if (stats) { if (stats)
stats->total_packets++; stats->total_packets++;
}
// Verificar tamanho mínimo para cabeçalho Ethernet + IP // Verificação básica de limites
if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) > data_end) if (data + sizeof(struct ethhdr) > data_end)
return XDP_PASS; return XDP_PASS;
struct ethhdr *eth = data; struct ethhdr *eth = data;
// Processamos apenas tráfego IPv4 // Filtrar apenas pacotes IPv4
if (eth->h_proto != bpf_htons(ETH_P_IP)) if (eth->h_proto != bpf_htons(ETH_P_IP))
return XDP_PASS; return XDP_PASS;
struct iphdr *iph = (void*)(eth + 1); if ((void *)(eth + 1) + sizeof(struct iphdr) > data_end)
// Verificar se o cabeçalho IP é válido
if ((void*)(iph + 1) > data_end)
return XDP_PASS; return XDP_PASS;
struct iphdr *iph = (void *)(eth + 1);
// Verificar cabeçalho IP
if ((void *)(iph + 1) > data_end || iph->version != 4)
return XDP_PASS;
// Verificação de MTU
__u16 tot_len = bpf_ntohs(iph->tot_len); __u16 tot_len = bpf_ntohs(iph->tot_len);
__u16 ip_hdr_len = iph->ihl * 4;
// 1. Verificação de MTU - pacote maior que o MTU do WireGuard?
if (tot_len > MAX_WG_MTU) { if (tot_len > MAX_WG_MTU) {
if (stats) { // Atualizar estatísticas
if (stats)
stats->oversized_packets++; stats->oversized_packets++;
}
// Verificar se podemos fragmentar (sem flag DF) ou se precisamos sinalizar PMTUD // Verificar flag DF
__u16 frag_off = bpf_ntohs(iph->frag_off); __u16 frag_off = bpf_ntohs(iph->frag_off);
if (frag_off & 0x4000) {
// Don't Fragment está ativo, registrar o MTU para este destino
__u32 dest_ip = iph->daddr;
__u16 mtu = MAX_WG_MTU;
bpf_map_update_elem(&path_mtu_map, &dest_ip, &mtu, BPF_ANY);
if (frag_off & 0x4000) { // Don't Fragment está ativo // Atualizar estatísticas
return send_icmp_frag_needed(iph, MAX_WG_MTU); if (stats)
stats->pmtu_triggered++;
return XDP_ABORTED; // Sinalizar para enviar ICMP Fragmentation Needed
} else { } else {
// Pacote pode ser fragmentado, deixar para o kernel // Pacote pode ser fragmentado
if (stats) { if (stats)
stats->fragmented++; stats->fragmented++;
}
return XDP_PASS;
} }
} }
// 2. Otimização TCP MSS para sessões TCP novas // Ajustar MSS para pacotes TCP
if (iph->protocol == IPPROTO_TCP) { if (iph->protocol == IPPROTO_TCP) {
// Verificar se temos cabeçalho TCP completo __u8 ihl = iph->ihl * 4; // IP header length
void *tcp_start = (void*)iph + ip_hdr_len; void *tcp_ptr = (void *)iph + ihl;
struct tcphdr *tcp = tcp_start;
if ((void*)(tcp + 1) <= data_end) { // Verificar se temos espaço para o cabeçalho TCP
if (tcp_ptr + sizeof(struct tcphdr) <= data_end) {
struct tcphdr *tcp = tcp_ptr;
adjust_tcp_mss(tcp, data_end, MSS_CLAMPING_VALUE); adjust_tcp_mss(tcp, data_end, MSS_CLAMPING_VALUE);
} }
} }
// 3. Para pacotes destinados a hosts com MTU conhecidos, verificar se precisa sinalizar PMTU // Verificar MTUs conhecidos
__u32 dest_ip = iph->daddr; __u16 *known_mtu = bpf_map_lookup_elem(&path_mtu_map, &iph->daddr);
__u16 *known_mtu = bpf_map_lookup_elem(&path_mtu_map, &dest_ip);
if (known_mtu && tot_len > *known_mtu) { if (known_mtu && tot_len > *known_mtu) {
// Pacote excede MTU já conhecido para este destino
__u16 frag_off = bpf_ntohs(iph->frag_off); __u16 frag_off = bpf_ntohs(iph->frag_off);
if (frag_off & 0x4000) { // DF bit set if (frag_off & 0x4000) {
return send_icmp_frag_needed(iph, *known_mtu); // Don't Fragment está ativo, não pode passar pelo tunnel
if (stats)
stats->pmtu_triggered++;
return XDP_ABORTED;
} }
} }
// O pacote está dentro dos limites, deixar prosseguir // Permitir o pacote
return XDP_PASS; return XDP_PASS;
} }