From dd38ec9f0ea2cf1ea37fada39b18b16ae770eb5c Mon Sep 17 00:00:00 2001 From: Rodrigo Martins Date: Wed, 26 Feb 2025 19:21:42 -0300 Subject: [PATCH] commit --- xdp_ddos_filter copy 2.c | 323 +++++++++++++++++++++++++++++++ xdp_ddos_filter.c | 405 +++++++++++++++++---------------------- 2 files changed, 502 insertions(+), 226 deletions(-) create mode 100644 xdp_ddos_filter copy 2.c diff --git a/xdp_ddos_filter copy 2.c b/xdp_ddos_filter copy 2.c new file mode 100644 index 0000000..62a5dca --- /dev/null +++ b/xdp_ddos_filter copy 2.c @@ -0,0 +1,323 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_HIGH_PRIORITY_PACKETS_PER_SECOND 2000 // Limite de pacotes por segundo para alta prioridade +#define MAX_LOW_PRIORITY_PACKETS_PER_SECOND 500 // Limite de pacotes por segundo para baixa prioridade +#define MAX_PACKETS_PER_IP 60000 // Limite de pacotes por IP antes de bloquear +#define MAX_ICMP_PACKETS_PER_IP 50 // Limite de pacotes ICMP por IP antes de bloquear +#define MAX_SYN_PACKETS_PER_IP 100 // Limite de pacotes SYN por IP antes de bloquear +#define TIMEOUT_SEC 1 // Tempo para expiração do contador (em segundos) + +// Estrutura para armazenar contagem de pacotes e o último timestamp visto para um IP +struct ip_stats { + __u64 pkt_count; // Contador de pacotes + __u64 icmp_count; // Contador de pacotes ICMP + __u64 syn_count; // Contador de pacotes SYN + __u64 last_seen; // Timestamp do último pacote + __u64 high_priority_count; // Contador de pacotes de alta prioridade + __u64 low_priority_count; // Contador de pacotes de baixa prioridade +}; + +// Estruturas para NAT +struct nat_entry { + __u32 new_ip; // IP de destino após NAT + __u16 new_port; // Porta de destino após NAT + __u16 proto; // Protocolo (TCP/UDP) +} __attribute__((aligned(8))); + +// Modificar mapa DNAT para usar porta como chave +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 10000); + __type(key, __u16); // Porta de destino + __type(value, struct nat_entry); // Nova configuração +} dnat_map SEC(".maps"); + +struct masquerade_key { + __u32 src_ip; // IP de origem + __u32 dst_ip; // IP de destino + __u16 dst_port; // Porta de destino + __u16 proto; // Protocolo +} __attribute__((aligned(8))); + +// Mapa de hash para armazenar estatísticas de IPs +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 100000); // Número máximo de entradas no mapa + __type(key, __u32); // Tipo da chave (endereço IP) + __type(value, struct ip_stats); // Tipo do valor (estatísticas do IP) +} ddos_map SEC(".maps"); + +// Mapa de hash para armazenar a blacklist +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 100000); // Número máximo de entradas no mapa + __type(key, __u32); // Tipo da chave (endereço IP) + __type(value, __u32); // Tipo do valor (dummy value) +} blacklist_map SEC(".maps"); + +// Mapas adicionais para NAT +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 10000); + __type(key, struct masquerade_key); + __type(value, __u32); // IP mascarado +} masquerade_map SEC(".maps"); + +// Adicionar estrutura para SNAT +struct snat_entry { + __u32 new_ip; // IP após NAT + __u16 new_port; // Porta após NAT +} __attribute__((aligned(8))); + +// Adicionar mapa para SNAT +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 10000); + __type(key, struct masquerade_key); + __type(value, struct snat_entry); +} snat_map SEC(".maps"); + +// Lista de permissões estática (whitelist) de IPs confiáveis +const __u32 whitelist[] = { + 0x0A000001, // 10.0.0.1 + 0x0A630101, // 192.168.0.1 + 0x0a630102, + 0x0a630104 +}; + +// Adicionar mapa para interface de redirecionamento +struct { + __uint(type, BPF_MAP_TYPE_XSKMAP); + __uint(max_entries, 1); + __type(key, int); + __type(value, int); +} xsks_map SEC(".maps"); + +// Função auxiliar para obter o timestamp atual em nanossegundos +static __inline __u64 get_time_ns(void) { + return bpf_ktime_get_ns(); +} + +// Função para verificar se o IP está na lista de permissões +static __inline int is_whitelisted(__u32 ip) { + int i; + for (i = 0; i < sizeof(whitelist) / sizeof(whitelist[0]); i++) { + if (ip == whitelist[i]) { + return 1; + } + } + return 0; +} + +// Função para verificar se o IP está na lista negra +static __inline int is_blacklisted(__u32 ip) { + __u32 *value = bpf_map_lookup_elem(&blacklist_map, &ip); + return value != NULL; +} + +// Função para verificar se a porta é de alta prioridade +static __inline int is_high_priority_port(__u16 port) { + return (port == 80 || port == 443 || port == 32100 || port == 32400); +} + +// Função para verificar se a porta é de baixa prioridade +static __inline int is_low_priority_port(__u16 port) { + return !is_high_priority_port(port); +} + +// Função para verificar se a porta deve ser filtrada +static __inline int is_filtered_port(__u16 port) { + // Intervalo de portas 1-1024 + if (port >= 1 && port <= 1024) { + return 1; + } + // Portas específicas + if (port == 8117 || port == 8085 || port == 8086 || port == 32100 || port == 32400) { + return 1; + } + return 0; +} + +// Função para verificar se o pacote é destinado ao servidor e deve ser filtrado +static __inline int is_destined_to_server(struct iphdr *ip, void *data_end) { + if (ip->protocol == IPPROTO_TCP) { + struct tcphdr *tcp = (void *)(ip + 1); + if ((void *)(tcp + 1) > data_end) + return 0; + // Verifique se a porta está na lista de portas a serem filtradas + __u16 dest_port = __constant_ntohs(tcp->dest); + if (is_filtered_port(dest_port)) { + return 1; + } + } else if (ip->protocol == IPPROTO_UDP) { + struct udphdr *udp = (void *)(ip + 1); + if ((void *)(udp + 1) > data_end) + return 0; + // Verifique se a porta está na lista de portas a serem filtradas + __u16 dest_port = __constant_ntohs(udp->dest); + if (is_filtered_port(dest_port)) { + return 1; + } + } else if (ip->protocol == IPPROTO_ICMP) { + return 1; + } + return 0; +} + +// Programa principal XDP +SEC("xdp") +int xdp_ddos_filter(struct xdp_md *ctx) { + void *data_end = (void *)(long)ctx->data_end; + void *data = (void *)(long)ctx->data; + + struct ethhdr *eth = data; + if ((void *)(eth + 1) > data_end) + return XDP_PASS; + + // Verifica se é um pacote IP + if (eth->h_proto != __constant_htons(ETH_P_IP)) + return XDP_PASS; + + struct iphdr *ip = (void *)(eth + 1); + if ((void *)(ip + 1) > data_end) + return XDP_PASS; + + // Verifica se o cabeçalho IP é válido + if (ip->ihl != 5 || ip->version != 4) + return XDP_PASS; + + // Verifica se o IP está na lista de permissões + __u32 src_ip = ip->saddr; + if (is_whitelisted(src_ip)) { + return XDP_PASS; + } + + // Verifica se o IP está na lista negra + if (is_blacklisted(src_ip)) { + return XDP_DROP; + } + + // Verifica se o pacote é destinado ao servidor e deve ser filtrado + if (!is_destined_to_server(ip, data_end)) + return XDP_PASS; + + __u16 dest_port = 0; + struct tcphdr *tcp = NULL; + + // Verifica se é um pacote TCP ou UDP + if (ip->protocol == IPPROTO_TCP) { + tcp = (void *)(ip + 1); + if ((void *)(tcp + 1) > data_end) + return XDP_PASS; + dest_port = __constant_ntohs(tcp->dest); + + // Verifica se é um pacote SYN + if (tcp->syn && !tcp->ack) { + // Consulta o mapa para verificar se o IP já está registrado + struct ip_stats *entry = bpf_map_lookup_elem(&ddos_map, &src_ip); + + if (entry) { + __u64 now = get_time_ns(); + + // Reinicia o contador se o tempo decorrido for maior que um segundo + if ((now - entry->last_seen) > TIMEOUT_SEC * 1000000000ULL) { + entry->syn_count = 0; + entry->last_seen = now; + } + + // Incrementa o contador de pacotes SYN + entry->syn_count++; + entry->last_seen = now; + + // Bloqueia o tráfego se o limite de pacotes SYN for excedido + if (entry->syn_count > MAX_SYN_PACKETS_PER_IP) { + return XDP_DROP; + } + } else { + // Adiciona um novo IP ao mapa + struct ip_stats new_entry = { + .syn_count = 1, + .last_seen = get_time_ns() + }; + bpf_map_update_elem(&ddos_map, &src_ip, &new_entry, BPF_ANY); + } + } + } else if (ip->protocol == IPPROTO_UDP) { + struct udphdr *udp = (void *)(ip + 1); + if ((void *)(udp + 1) > data_end) + return XDP_PASS; + dest_port = __constant_ntohs(udp->dest); + } + + // Consulta o mapa para verificar se o IP já está registrado + struct ip_stats *entry = bpf_map_lookup_elem(&ddos_map, &src_ip); + + if (entry) { + __u64 now = get_time_ns(); + + // Reinicia o contador se o tempo decorrido for maior que um segundo + if ((now - entry->last_seen) > TIMEOUT_SEC * 1000000000ULL) { + entry->pkt_count = 0; + entry->icmp_count = 0; + entry->syn_count = 0; + entry->high_priority_count = 0; + entry->low_priority_count = 0; + entry->last_seen = now; + } + + // Rate limiting para pacotes de alta prioridade + if (is_high_priority_port(dest_port)) { + entry->high_priority_count++; + if (entry->high_priority_count > MAX_HIGH_PRIORITY_PACKETS_PER_SECOND) { + return XDP_DROP; + } + } + + // Rate limiting para pacotes de baixa prioridade + if (is_low_priority_port(dest_port)) { + entry->low_priority_count++; + if (entry->low_priority_count > MAX_LOW_PRIORITY_PACKETS_PER_SECOND) { + return XDP_DROP; + } + } + + // Incrementa o contador de pacotes + entry->pkt_count++; + entry->last_seen = now; + + // Filtra pacotes ICMP + if (ip->protocol == IPPROTO_ICMP) { + entry->icmp_count++; + if (entry->icmp_count > MAX_ICMP_PACKETS_PER_IP) { + return XDP_DROP; + } + } + + // Bloqueia o tráfego se o limite de pacotes for excedido + if (entry->pkt_count > MAX_PACKETS_PER_IP) { + return XDP_DROP; + } + } else { + // Adiciona um novo IP ao mapa + struct ip_stats new_entry = { + .pkt_count = 1, + .icmp_count = (ip->protocol == IPPROTO_ICMP) ? 1 : 0, + .syn_count = (ip->protocol == IPPROTO_TCP && tcp && tcp->syn && !tcp->ack) ? 1 : 0, + .last_seen = get_time_ns(), + .high_priority_count = is_high_priority_port(dest_port) ? 1 : 0, + .low_priority_count = is_low_priority_port(dest_port) ? 1 : 0 + }; + bpf_map_update_elem(&ddos_map, &src_ip, &new_entry, BPF_ANY); + } + + return XDP_PASS; +} + +char __license[] SEC("license") = "GPL"; \ No newline at end of file diff --git a/xdp_ddos_filter.c b/xdp_ddos_filter.c index 62a5dca..f32e969 100644 --- a/xdp_ddos_filter.c +++ b/xdp_ddos_filter.c @@ -7,92 +7,45 @@ #include #include -#define MAX_HIGH_PRIORITY_PACKETS_PER_SECOND 2000 // Limite de pacotes por segundo para alta prioridade -#define MAX_LOW_PRIORITY_PACKETS_PER_SECOND 500 // Limite de pacotes por segundo para baixa prioridade -#define MAX_PACKETS_PER_IP 60000 // Limite de pacotes por IP antes de bloquear -#define MAX_ICMP_PACKETS_PER_IP 50 // Limite de pacotes ICMP por IP antes de bloquear -#define MAX_SYN_PACKETS_PER_IP 100 // Limite de pacotes SYN por IP antes de bloquear -#define TIMEOUT_SEC 1 // Tempo para expiração do contador (em segundos) +// Otimização: melhorar constantes para ajuste fino +#define MAX_HIGH_PRIORITY_PACKETS_PER_SECOND 2000 +#define MAX_LOW_PRIORITY_PACKETS_PER_SECOND 500 +#define MAX_PACKETS_PER_IP 60000 +#define MAX_ICMP_PACKETS_PER_IP 50 +#define MAX_SYN_PACKETS_PER_IP 100 +#define TIMEOUT_SEC 1 +#define PACKET_COST 1 // Custo padrão por pacote +#define HIGH_PRIO_TOKEN_RATE 2000 // Tokens/segundo para alta prioridade +#define LOW_PRIO_TOKEN_RATE 500 // Tokens/segundo para baixa prioridade +#define MAX_TOKENS 2000 // Máximo de tokens acumulados -// Estrutura para armazenar contagem de pacotes e o último timestamp visto para um IP +// Otimização: estrutura de dados mais compacta para reduzir acessos de memória struct ip_stats { - __u64 pkt_count; // Contador de pacotes - __u64 icmp_count; // Contador de pacotes ICMP - __u64 syn_count; // Contador de pacotes SYN - __u64 last_seen; // Timestamp do último pacote - __u64 high_priority_count; // Contador de pacotes de alta prioridade - __u64 low_priority_count; // Contador de pacotes de baixa prioridade -}; + __u32 pkt_count; // Contador de pacotes total + __u32 last_seen; // Último timestamp em segundos (não nanossegundos) + __u16 icmp_count; // Contador ICMP (reduzido para 16 bits) + __u16 syn_count; // Contador SYN (reduzido para 16 bits) + __u16 high_prio_tokens; // Tokens disponíveis para alta prioridade + __u16 low_prio_tokens; // Tokens disponíveis para baixa prioridade +} __attribute__((packed)); -// Estruturas para NAT -struct nat_entry { - __u32 new_ip; // IP de destino após NAT - __u16 new_port; // Porta de destino após NAT - __u16 proto; // Protocolo (TCP/UDP) -} __attribute__((aligned(8))); - -// Modificar mapa DNAT para usar porta como chave +// Otimização: usar PERCPU map para evitar contenção e locks struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, 10000); - __type(key, __u16); // Porta de destino - __type(value, struct nat_entry); // Nova configuração -} dnat_map SEC(".maps"); - -struct masquerade_key { - __u32 src_ip; // IP de origem - __u32 dst_ip; // IP de destino - __u16 dst_port; // Porta de destino - __u16 proto; // Protocolo -} __attribute__((aligned(8))); - -// Mapa de hash para armazenar estatísticas de IPs -struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, 100000); // Número máximo de entradas no mapa - __type(key, __u32); // Tipo da chave (endereço IP) - __type(value, struct ip_stats); // Tipo do valor (estatísticas do IP) + __uint(type, BPF_MAP_TYPE_PERCPU_HASH); + __uint(max_entries, 100000); + __type(key, __u32); // IP address + __type(value, struct ip_stats); } ddos_map SEC(".maps"); -// Mapa de hash para armazenar a blacklist +// Otimização: usar LRU para blacklist para evitar crescimento infinito struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, 100000); // Número máximo de entradas no mapa - __type(key, __u32); // Tipo da chave (endereço IP) - __type(value, __u32); // Tipo do valor (dummy value) + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(max_entries, 100000); + __type(key, __u32); + __type(value, __u32); } blacklist_map SEC(".maps"); -// Mapas adicionais para NAT -struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, 10000); - __type(key, struct masquerade_key); - __type(value, __u32); // IP mascarado -} masquerade_map SEC(".maps"); - -// Adicionar estrutura para SNAT -struct snat_entry { - __u32 new_ip; // IP após NAT - __u16 new_port; // Porta após NAT -} __attribute__((aligned(8))); - -// Adicionar mapa para SNAT -struct { - __uint(type, BPF_MAP_TYPE_HASH); - __uint(max_entries, 10000); - __type(key, struct masquerade_key); - __type(value, struct snat_entry); -} snat_map SEC(".maps"); - -// Lista de permissões estática (whitelist) de IPs confiáveis -const __u32 whitelist[] = { - 0x0A000001, // 10.0.0.1 - 0x0A630101, // 192.168.0.1 - 0x0a630102, - 0x0a630104 -}; - -// Adicionar mapa para interface de redirecionamento +// Mapa para interface de redirecionamento struct { __uint(type, BPF_MAP_TYPE_XSKMAP); __uint(max_entries, 1); @@ -100,15 +53,23 @@ struct { __type(value, int); } xsks_map SEC(".maps"); -// Função auxiliar para obter o timestamp atual em nanossegundos -static __inline __u64 get_time_ns(void) { - return bpf_ktime_get_ns(); +// Otimização: usar lista de permissões fixa e compacta +static const __u32 whitelist[] = { + 0x0A000001, // 10.0.0.1 + 0x0A630101, // 10.99.1.1 + 0x0a630102, // 10.99.1.2 + 0x0a630104 // 10.99.1.4 +}; + +// Otimização: função inline para obter o timestamp em segundos em vez de nanossegundos +static __always_inline __u32 get_time_sec(void) { + return bpf_ktime_get_ns() / 1000000000; } -// Função para verificar se o IP está na lista de permissões -static __inline int is_whitelisted(__u32 ip) { - int i; - for (i = 0; i < sizeof(whitelist) / sizeof(whitelist[0]); i++) { +// Otimização: usar always_inline e __builtin_expect para funções críticas +static __always_inline int is_whitelisted(__u32 ip) { + #pragma unroll + for (int i = 0; i < sizeof(whitelist) / sizeof(whitelist[0]); i++) { if (ip == whitelist[i]) { return 1; } @@ -116,59 +77,41 @@ static __inline int is_whitelisted(__u32 ip) { return 0; } -// Função para verificar se o IP está na lista negra -static __inline int is_blacklisted(__u32 ip) { - __u32 *value = bpf_map_lookup_elem(&blacklist_map, &ip); - return value != NULL; +static __always_inline int is_blacklisted(__u32 ip) { + return bpf_map_lookup_elem(&blacklist_map, &ip) != NULL; } -// Função para verificar se a porta é de alta prioridade -static __inline int is_high_priority_port(__u16 port) { - return (port == 80 || port == 443 || port == 32100 || port == 32400); -} - -// Função para verificar se a porta é de baixa prioridade -static __inline int is_low_priority_port(__u16 port) { - return !is_high_priority_port(port); -} - -// Função para verificar se a porta deve ser filtrada -static __inline int is_filtered_port(__u16 port) { - // Intervalo de portas 1-1024 - if (port >= 1 && port <= 1024) { - return 1; +// Otimização: usar switch-case em vez de verificações múltiplas para portas +static __always_inline int get_port_priority(__u16 port) { + switch (port) { + case 80: // HTTP + case 443: // HTTPS + case 32100: // Serviço de alta prioridade 1 + case 32400: // Serviço de alta prioridade 2 + return 2; // Alta prioridade + case 22: // SSH + case 25: // SMTP + case 53: // DNS + return 1; // Média prioridade + default: + return 0; // Baixa prioridade } - // Portas específicas - if (port == 8117 || port == 8085 || port == 8086 || port == 32100 || port == 32400) { - return 1; - } - return 0; } -// Função para verificar se o pacote é destinado ao servidor e deve ser filtrado -static __inline int is_destined_to_server(struct iphdr *ip, void *data_end) { - if (ip->protocol == IPPROTO_TCP) { - struct tcphdr *tcp = (void *)(ip + 1); - if ((void *)(tcp + 1) > data_end) - return 0; - // Verifique se a porta está na lista de portas a serem filtradas - __u16 dest_port = __constant_ntohs(tcp->dest); - if (is_filtered_port(dest_port)) { +// Otimização: função de verificação de porta mais eficiente +static __always_inline int is_filtered_port(__u16 port) { + // Portas importantes usam verificação direta + switch (port) { + case 8117: + case 8085: + case 8086: + case 32100: + case 32400: return 1; - } - } else if (ip->protocol == IPPROTO_UDP) { - struct udphdr *udp = (void *)(ip + 1); - if ((void *)(udp + 1) > data_end) - return 0; - // Verifique se a porta está na lista de portas a serem filtradas - __u16 dest_port = __constant_ntohs(udp->dest); - if (is_filtered_port(dest_port)) { - return 1; - } - } else if (ip->protocol == IPPROTO_ICMP) { - return 1; + default: + // Verificação de intervalo apenas para outras portas + return (port <= 1024); } - return 0; } // Programa principal XDP @@ -176,148 +119,158 @@ SEC("xdp") int xdp_ddos_filter(struct xdp_md *ctx) { void *data_end = (void *)(long)ctx->data_end; void *data = (void *)(long)ctx->data; - - struct ethhdr *eth = data; - if ((void *)(eth + 1) > data_end) + + // Otimização: early return para pacotes muito pequenos + if (__builtin_expect(data + sizeof(struct ethhdr) + sizeof(struct iphdr) > data_end, 0)) return XDP_PASS; - // Verifica se é um pacote IP - if (eth->h_proto != __constant_htons(ETH_P_IP)) + struct ethhdr *eth = data; + + // Otimização: early return para pacotes não-IP + if (__builtin_expect(eth->h_proto != __constant_htons(ETH_P_IP), 0)) return XDP_PASS; struct iphdr *ip = (void *)(eth + 1); - if ((void *)(ip + 1) > data_end) + + // Otimização: verificar o cabeçalho IP de forma mais eficiente + if (__builtin_expect((void *)(ip + 1) > data_end || + ip->ihl != 5 || + ip->version != 4, 0)) return XDP_PASS; - // Verifica se o cabeçalho IP é válido - if (ip->ihl != 5 || ip->version != 4) - return XDP_PASS; - - // Verifica se o IP está na lista de permissões + // Otimização: early return para IPs na whitelist __u32 src_ip = ip->saddr; - if (is_whitelisted(src_ip)) { + if (__builtin_expect(is_whitelisted(src_ip), 0)) { return XDP_PASS; } - // Verifica se o IP está na lista negra - if (is_blacklisted(src_ip)) { + // Otimização: early drop para IPs bloqueados + if (__builtin_expect(is_blacklisted(src_ip), 0)) { return XDP_DROP; } - // Verifica se o pacote é destinado ao servidor e deve ser filtrado - if (!is_destined_to_server(ip, data_end)) - return XDP_PASS; - + // Identificar protocolo e porta para classificação __u16 dest_port = 0; - struct tcphdr *tcp = NULL; + int is_syn = 0; + int is_icmp = 0; - // Verifica se é um pacote TCP ou UDP if (ip->protocol == IPPROTO_TCP) { - tcp = (void *)(ip + 1); - if ((void *)(tcp + 1) > data_end) + struct tcphdr *tcp = (void *)(ip + 1); + if (__builtin_expect((void *)(tcp + 1) > data_end, 0)) return XDP_PASS; + dest_port = __constant_ntohs(tcp->dest); - - // Verifica se é um pacote SYN - if (tcp->syn && !tcp->ack) { - // Consulta o mapa para verificar se o IP já está registrado - struct ip_stats *entry = bpf_map_lookup_elem(&ddos_map, &src_ip); - - if (entry) { - __u64 now = get_time_ns(); - - // Reinicia o contador se o tempo decorrido for maior que um segundo - if ((now - entry->last_seen) > TIMEOUT_SEC * 1000000000ULL) { - entry->syn_count = 0; - entry->last_seen = now; - } - - // Incrementa o contador de pacotes SYN - entry->syn_count++; - entry->last_seen = now; - - // Bloqueia o tráfego se o limite de pacotes SYN for excedido - if (entry->syn_count > MAX_SYN_PACKETS_PER_IP) { - return XDP_DROP; - } - } else { - // Adiciona um novo IP ao mapa - struct ip_stats new_entry = { - .syn_count = 1, - .last_seen = get_time_ns() - }; - bpf_map_update_elem(&ddos_map, &src_ip, &new_entry, BPF_ANY); - } - } + is_syn = tcp->syn && !tcp->ack; + } else if (ip->protocol == IPPROTO_UDP) { struct udphdr *udp = (void *)(ip + 1); - if ((void *)(udp + 1) > data_end) + if (__builtin_expect((void *)(udp + 1) > data_end, 0)) return XDP_PASS; + dest_port = __constant_ntohs(udp->dest); + + } else if (ip->protocol == IPPROTO_ICMP) { + is_icmp = 1; + } else { + // Outros protocolos passam sem filtro adicional + return XDP_PASS; } - // Consulta o mapa para verificar se o IP já está registrado + // Otimização: early return se não for para portas filtradas + if (__builtin_expect(!is_filtered_port(dest_port) && !is_icmp, 1)) + return XDP_PASS; + + // Prioridade do pacote com base na porta + int priority = get_port_priority(dest_port); + + // Obter estatísticas atuais do IP struct ip_stats *entry = bpf_map_lookup_elem(&ddos_map, &src_ip); - + __u32 now = get_time_sec(); + if (entry) { - __u64 now = get_time_ns(); - - // Reinicia o contador se o tempo decorrido for maior que um segundo - if ((now - entry->last_seen) > TIMEOUT_SEC * 1000000000ULL) { - entry->pkt_count = 0; - entry->icmp_count = 0; - entry->syn_count = 0; - entry->high_priority_count = 0; - entry->low_priority_count = 0; - entry->last_seen = now; + // Otimização: cálculo de tempo decorrido mais eficiente + __u32 elapsed = 0; + if (__builtin_expect(now > entry->last_seen, 1)) { + elapsed = now - entry->last_seen; } - // Rate limiting para pacotes de alta prioridade - if (is_high_priority_port(dest_port)) { - entry->high_priority_count++; - if (entry->high_priority_count > MAX_HIGH_PRIORITY_PACKETS_PER_SECOND) { - return XDP_DROP; + // Implementação de token bucket para cada prioridade + if (elapsed > 0) { + // Adicionar tokens baseado no tempo decorrido, limitado ao máximo + __u16 new_high_tokens = entry->high_prio_tokens + (HIGH_PRIO_TOKEN_RATE * elapsed); + entry->high_prio_tokens = new_high_tokens > MAX_TOKENS ? MAX_TOKENS : new_high_tokens; + + __u16 new_low_tokens = entry->low_prio_tokens + (LOW_PRIO_TOKEN_RATE * elapsed); + entry->low_prio_tokens = new_low_tokens > MAX_TOKENS ? MAX_TOKENS : new_low_tokens; + + // Resetar contadores específicos de protocolo após 1 segundo + if (elapsed >= TIMEOUT_SEC) { + entry->icmp_count = 0; + entry->syn_count = 0; } } - // Rate limiting para pacotes de baixa prioridade - if (is_low_priority_port(dest_port)) { - entry->low_priority_count++; - if (entry->low_priority_count > MAX_LOW_PRIORITY_PACKETS_PER_SECOND) { - return XDP_DROP; - } - } - - // Incrementa o contador de pacotes - entry->pkt_count++; + // Atualizar o último timestamp visto entry->last_seen = now; - - // Filtra pacotes ICMP - if (ip->protocol == IPPROTO_ICMP) { + + // Atualizar contadores específicos + entry->pkt_count++; + + if (is_icmp) { entry->icmp_count++; - if (entry->icmp_count > MAX_ICMP_PACKETS_PER_IP) { + if (__builtin_expect(entry->icmp_count > MAX_ICMP_PACKETS_PER_IP, 0)) { + __u32 one = 1; + bpf_map_update_elem(&blacklist_map, &src_ip, &one, BPF_ANY); + return XDP_DROP; + } + } + + if (is_syn) { + entry->syn_count++; + if (__builtin_expect(entry->syn_count > MAX_SYN_PACKETS_PER_IP, 0)) { + __u32 one = 1; + bpf_map_update_elem(&blacklist_map, &src_ip, &one, BPF_ANY); return XDP_DROP; } } - // Bloqueia o tráfego se o limite de pacotes for excedido - if (entry->pkt_count > MAX_PACKETS_PER_IP) { + // Otimização: verificação total de pacotes + if (__builtin_expect(entry->pkt_count > MAX_PACKETS_PER_IP, 0)) { + __u32 one = 1; + bpf_map_update_elem(&blacklist_map, &src_ip, &one, BPF_ANY); return XDP_DROP; } + + // Verificar tokens disponíveis com base na prioridade + if (priority == 2) { // Alta prioridade + if (entry->high_prio_tokens >= PACKET_COST) { + entry->high_prio_tokens -= PACKET_COST; + return XDP_PASS; + } + } else { // Média e baixa prioridade + if (entry->low_prio_tokens >= PACKET_COST) { + entry->low_prio_tokens -= PACKET_COST; + return XDP_PASS; + } + } + + // Sem tokens disponíveis para esta prioridade, descartar + return XDP_DROP; + } else { - // Adiciona um novo IP ao mapa + // Primeira vez que vemos este IP, inicializar com valores generosos struct ip_stats new_entry = { .pkt_count = 1, - .icmp_count = (ip->protocol == IPPROTO_ICMP) ? 1 : 0, - .syn_count = (ip->protocol == IPPROTO_TCP && tcp && tcp->syn && !tcp->ack) ? 1 : 0, - .last_seen = get_time_ns(), - .high_priority_count = is_high_priority_port(dest_port) ? 1 : 0, - .low_priority_count = is_low_priority_port(dest_port) ? 1 : 0 + .last_seen = now, + .icmp_count = is_icmp ? 1 : 0, + .syn_count = is_syn ? 1 : 0, + .high_prio_tokens = MAX_TOKENS - PACKET_COST, + .low_prio_tokens = MAX_TOKENS - PACKET_COST }; + bpf_map_update_elem(&ddos_map, &src_ip, &new_entry, BPF_ANY); + return XDP_PASS; } - - return XDP_PASS; } char __license[] SEC("license") = "GPL"; \ No newline at end of file