diff --git a/xdp_wg_mtu_optimizer.c b/xdp_wg_mtu_optimizer.c index 213f09d..1baa350 100644 --- a/xdp_wg_mtu_optimizer.c +++ b/xdp_wg_mtu_optimizer.c @@ -53,59 +53,77 @@ static __always_inline void update_stats(__u64 *stat_counter) { } } -// Função para ajustar TCP MSS - corrigido tipos de ponteiro -static __always_inline int adjust_tcp_mss(struct tcphdr *tcp, void *data_end_ptr, __u16 max_mss) { - void *tcp_end = (void *)tcp + sizeof(struct tcphdr); - if (tcp_end > data_end_ptr) +// Função para ajustar TCP MSS - totalmente reescrita para maior simplicidade +static __always_inline int adjust_tcp_mss(struct tcphdr *tcp, void *data_end, __u16 max_mss) { + // Verificação básica do cabeçalho TCP + if ((void *)(tcp + 1) > data_end) return 0; - if (!tcp->syn) - return 0; // Ajustamos MSS apenas em pacotes SYN + // Ajustamos MSS apenas em pacotes SYN + if (!tcp->syn || tcp->ack) + return 0; __u8 tcp_hdr_len = tcp->doff * 4; - __u8 *tcp_opt_ptr = (__u8 *)tcp + sizeof(struct tcphdr); - __u8 *tcp_opt_end = (__u8 *)tcp + tcp_hdr_len; + if (tcp_hdr_len <= sizeof(struct tcphdr)) + return 0; // Sem opções TCP - // Corrigido: cast explícito para comparação de tipos de ponteiro - if ((void *)tcp_opt_end > data_end_ptr) + // Verificar se todo o cabeçalho está acessível + void *tcp_end = (void *)tcp + tcp_hdr_len; + if (tcp_end > data_end) return 0; - // Procurar opção MSS (kind=2, len=4) nas opções TCP - #pragma unroll 4 // Limite de desenrolamento para evitar erros - 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 - if ((void *)(tcp_opt_ptr + 2) > data_end_ptr || (tcp_opt_ptr + 2) > tcp_opt_end) + __u8 *opt_ptr = (__u8 *)(tcp + 1); + __u8 *tcp_options_end = (__u8 *)tcp_end; + + // Loop simplificado com controle estrito de limites + #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; - if (tcp_opt_ptr[0] == 2 && tcp_opt_ptr[1] == 4) { // MSS option - // Corrigido: verificações de limites com cast explícito - if ((void *)(tcp_opt_ptr + 4) > data_end_ptr || (tcp_opt_ptr + 4) > tcp_opt_end) - break; + // Verificar tipo da opção + if (*opt_ptr == 0) // End of options + break; - // Extrair valor MSS atual (network byte order) - __u16 *mss_ptr = (__u16 *)(tcp_opt_ptr + 2); - __u16 current_mss = bpf_ntohs(*mss_ptr); + if (*opt_ptr == 1) { // NOP + opt_ptr += 1; + continue; + } + + // Verificar espaço para o comprimento + if (opt_ptr + 2 > tcp_options_end || (void *)(opt_ptr + 2) > data_end) + break; - // Ajustar MSS se necessário - if (current_mss > max_mss) { - *mss_ptr = bpf_htons(max_mss); - __u32 zero = 0; - struct mtu_stats *stats = bpf_map_lookup_elem(&mtu_stats_map, &zero); - if (stats) { - stats->mss_adjusted++; + __u8 opt_len = *(opt_ptr + 1); + if (opt_len < 2) // Comprimento inválido + 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; } - if (tcp_opt_ptr[0] == 0) // End of options - break; - - if (tcp_opt_ptr[1] < 2) // Opções malformadas, prevenir loop infinito - break; - - tcp_opt_ptr += tcp_opt_ptr[1]; + // Avançar para próxima opção + opt_ptr += opt_len; } return 0; @@ -136,82 +154,89 @@ static __always_inline int send_icmp_frag_needed(struct iphdr *iph, __u16 mtu) { return XDP_ABORTED; } -// Programa XDP principal para otimização de pacotes WireGuard - simplificado e corrigido +// Programa XDP principal - simplificado SEC("xdp") int xdp_wg_optimizer(struct xdp_md *ctx) { void *data_end = (void *)(long)ctx->data_end; void *data = (void *)(long)ctx->data; - __u32 zero = 0; + __u32 key = 0; - // Inicializar contadores - struct mtu_stats *stats = bpf_map_lookup_elem(&mtu_stats_map, &zero); - if (stats) { + // Incrementar estatística de pacotes totais + struct mtu_stats *stats = bpf_map_lookup_elem(&mtu_stats_map, &key); + if (stats) stats->total_packets++; - } - // Verificar tamanho mínimo para cabeçalho Ethernet + IP - if (data + sizeof(struct ethhdr) + sizeof(struct iphdr) > data_end) + // Verificação básica de limites + if (data + sizeof(struct ethhdr) > data_end) return XDP_PASS; - + struct ethhdr *eth = data; - // Processamos apenas tráfego IPv4 + // Filtrar apenas pacotes IPv4 if (eth->h_proto != bpf_htons(ETH_P_IP)) return XDP_PASS; - - struct iphdr *iph = (void*)(eth + 1); - // Verificar se o cabeçalho IP é válido - if ((void*)(iph + 1) > data_end) + if ((void *)(eth + 1) + sizeof(struct iphdr) > data_end) return XDP_PASS; - __u16 tot_len = bpf_ntohs(iph->tot_len); - __u16 ip_hdr_len = iph->ihl * 4; + struct iphdr *iph = (void *)(eth + 1); - // 1. Verificação de MTU - pacote maior que o MTU do WireGuard? + // 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); if (tot_len > MAX_WG_MTU) { - if (stats) { + // Atualizar estatísticas + if (stats) 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); - - if (frag_off & 0x4000) { // Don't Fragment está ativo - return send_icmp_frag_needed(iph, MAX_WG_MTU); + 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); + + // Atualizar estatísticas + if (stats) + stats->pmtu_triggered++; + + return XDP_ABORTED; // Sinalizar para enviar ICMP Fragmentation Needed } else { - // Pacote pode ser fragmentado, deixar para o kernel - if (stats) { + // Pacote pode ser fragmentado + if (stats) 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) { - // Verificar se temos cabeçalho TCP completo - void *tcp_start = (void*)iph + ip_hdr_len; - struct tcphdr *tcp = tcp_start; + __u8 ihl = iph->ihl * 4; // IP header length + void *tcp_ptr = (void *)iph + ihl; - 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); } } - // 3. Para pacotes destinados a hosts com MTU conhecidos, verificar se precisa sinalizar PMTU - __u32 dest_ip = iph->daddr; - __u16 *known_mtu = bpf_map_lookup_elem(&path_mtu_map, &dest_ip); - + // Verificar MTUs conhecidos + __u16 *known_mtu = bpf_map_lookup_elem(&path_mtu_map, &iph->daddr); if (known_mtu && tot_len > *known_mtu) { - // Pacote excede MTU já conhecido para este destino __u16 frag_off = bpf_ntohs(iph->frag_off); - if (frag_off & 0x4000) { // DF bit set - return send_icmp_frag_needed(iph, *known_mtu); + if (frag_off & 0x4000) { + // 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; }