first commit
This commit is contained in:
commit
c4cea8c3b3
9 files changed
+2095
No files matched your search
@@ -0,0 +1,283 @@
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/pkt_cls.h>
|
||||
#include <linux/in.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_endian.h>
|
||||
|
||||
// Adicionar definição para ARM64
|
||||
#ifndef __TARGET_ARCH_arm64
|
||||
#define __TARGET_ARCH_arm64
|
||||
#endif
|
||||
|
||||
// Estrutura para regras DNAT
|
||||
struct dnat_rule {
|
||||
__u32 new_ip; // IP destino após NAT
|
||||
__u16 new_port; // Porta destino após NAT
|
||||
};
|
||||
|
||||
// Mapa para regras DNAT baseadas na porta
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 64);
|
||||
__type(key, __u16); // Porta destino
|
||||
__type(value, struct dnat_rule); // Regra DNAT
|
||||
} dnat_port_map SEC(".maps");
|
||||
|
||||
// Mapa para definir redes para SNAT (masquerade)
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 16);
|
||||
__type(key, __u32); // Prefixo de rede (/16)
|
||||
__type(value, __u8); // Flag (1=ativo)
|
||||
} snat_networks SEC(".maps");
|
||||
|
||||
// Mapa para armazenar configurações de hairpinning
|
||||
struct hairpin_key {
|
||||
__u32 dst_ip; // IP destino
|
||||
__u16 dst_port; // Porta destino
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 64);
|
||||
__type(key, struct hairpin_key); // IP e porta destino
|
||||
__type(value, __u8); // Flag (1=ativo)
|
||||
} hairpin_map SEC(".maps");
|
||||
|
||||
// Função para calcular checksum com bounds checking
|
||||
static inline __u16 compute_ip_checksum(struct iphdr *iph) {
|
||||
__u32 csum = 0;
|
||||
__u16 *next_iph_u16 = (__u16 *)iph;
|
||||
|
||||
// IP header sem o campo de checksum (5 words, 10 bytes)
|
||||
#pragma unroll
|
||||
for (int i = 0; i < 10; i++) {
|
||||
csum += *next_iph_u16++;
|
||||
}
|
||||
|
||||
// Fold 32-bit to 16-bit
|
||||
csum = (csum & 0xffff) + (csum >> 16);
|
||||
csum = (csum & 0xffff) + (csum >> 16);
|
||||
|
||||
return ~csum;
|
||||
}
|
||||
|
||||
// Gancho TC para INGRESS (DNAT)
|
||||
SEC("tc_ingress")
|
||||
int nat_ingress_func(struct __sk_buff *skb) {
|
||||
// Cabeçalhos
|
||||
void *data = (void *)(long)skb->data;
|
||||
void *data_end = (void *)(long)skb->data_end;
|
||||
|
||||
// Validação de ethernet
|
||||
struct ethhdr *eth = data;
|
||||
if ((void *)(eth + 1) > data_end)
|
||||
return TC_ACT_OK;
|
||||
|
||||
// Verificar se é IPv4
|
||||
if (eth->h_proto != bpf_htons(ETH_P_IP))
|
||||
return TC_ACT_OK;
|
||||
|
||||
// Validação de cabeçalho IP
|
||||
struct iphdr *ip = (void *)(eth + 1);
|
||||
if ((void *)(ip + 1) > data_end)
|
||||
return TC_ACT_OK;
|
||||
|
||||
// Verificar tamanho do cabeçalho IP
|
||||
if (ip->ihl != 5) // Apenas cabeçalho padrão sem opções
|
||||
return TC_ACT_OK;
|
||||
|
||||
// Depuração - imprimir informações do pacote
|
||||
bpf_printk("INGRESS: IP Source %pI4, Dest %pI4", &ip->saddr, &ip->daddr);
|
||||
|
||||
// DNAT para TCP
|
||||
if (ip->protocol == IPPROTO_TCP) {
|
||||
struct tcphdr *tcp = (void *)(ip + 1);
|
||||
if ((void *)(tcp + 1) > data_end)
|
||||
return TC_ACT_OK;
|
||||
|
||||
__u16 dport = bpf_ntohs(tcp->dest);
|
||||
bpf_printk("INGRESS: TCP port %d", dport);
|
||||
|
||||
// Procurar regra para esta porta
|
||||
struct dnat_rule *rule = bpf_map_lookup_elem(&dnat_port_map, &dport);
|
||||
if (rule) {
|
||||
bpf_printk("Regra encontrada: %d -> %pI4:%d",
|
||||
dport, &rule->new_ip, rule->new_port);
|
||||
|
||||
// Guardar o IP e porta originais
|
||||
__u32 old_ip = ip->daddr;
|
||||
__u16 old_port = tcp->dest;
|
||||
|
||||
// Aplicar a regra DNAT
|
||||
ip->daddr = rule->new_ip;
|
||||
tcp->dest = bpf_htons(rule->new_port);
|
||||
|
||||
// Recalcular checksum IP
|
||||
ip->check = 0;
|
||||
ip->check = compute_ip_checksum(ip);
|
||||
|
||||
// Recalcular checksum TCP (parcialmente)
|
||||
if (tcp->check) {
|
||||
// Primeiro ajustar para o IP de destino alterado
|
||||
__u32 check = ~bpf_ntohs(tcp->check);
|
||||
check += ~bpf_ntohs(old_port) & 0xffff;
|
||||
check += bpf_ntohs(tcp->dest);
|
||||
check += ~((old_ip >> 16) & 0xffff) + ~(old_ip & 0xffff);
|
||||
check += ((ip->daddr >> 16) & 0xffff) + (ip->daddr & 0xffff);
|
||||
|
||||
// Dobrar para obter o checksum final
|
||||
check = (check & 0xffff) + (check >> 16);
|
||||
check = (check & 0xffff) + (check >> 16);
|
||||
tcp->check = bpf_htons(~check);
|
||||
}
|
||||
|
||||
bpf_printk("DNAT aplicado: %pI4:%d -> %pI4:%d",
|
||||
&old_ip, bpf_ntohs(old_port),
|
||||
&ip->daddr, bpf_ntohs(tcp->dest));
|
||||
}
|
||||
}
|
||||
// DNAT para UDP
|
||||
else if (ip->protocol == IPPROTO_UDP) {
|
||||
struct udphdr *udp = (void *)(ip + 1);
|
||||
if ((void *)(udp + 1) > data_end)
|
||||
return TC_ACT_OK;
|
||||
|
||||
__u16 dport = bpf_ntohs(udp->dest);
|
||||
bpf_printk("INGRESS: UDP port %d", dport);
|
||||
|
||||
// Procurar regra para esta porta
|
||||
struct dnat_rule *rule = bpf_map_lookup_elem(&dnat_port_map, &dport);
|
||||
if (rule) {
|
||||
bpf_printk("Regra encontrada: %d -> %pI4:%d",
|
||||
dport, &rule->new_ip, rule->new_port);
|
||||
|
||||
// Guardar o IP e porta originais
|
||||
__u32 old_ip = ip->daddr;
|
||||
__u16 old_port = udp->dest;
|
||||
|
||||
// Aplicar a regra DNAT
|
||||
ip->daddr = rule->new_ip;
|
||||
udp->dest = bpf_htons(rule->new_port);
|
||||
|
||||
// Recalcular checksum IP
|
||||
ip->check = 0;
|
||||
ip->check = compute_ip_checksum(ip);
|
||||
|
||||
// Recalcular checksum UDP (caso exista)
|
||||
if (udp->check) {
|
||||
// Ajuste similar ao do TCP
|
||||
__u32 check = ~bpf_ntohs(udp->check);
|
||||
check += ~bpf_ntohs(old_port) & 0xffff;
|
||||
check += bpf_ntohs(udp->dest);
|
||||
check += ~((old_ip >> 16) & 0xffff) + ~(old_ip & 0xffff);
|
||||
check += ((ip->daddr >> 16) & 0xffff) + (ip->daddr & 0xffff);
|
||||
|
||||
// Dobrar para obter o checksum final
|
||||
check = (check & 0xffff) + (check >> 16);
|
||||
check = (check & 0xffff) + (check >> 16);
|
||||
udp->check = bpf_htons(~check);
|
||||
}
|
||||
|
||||
bpf_printk("DNAT aplicado: %pI4:%d -> %pI4:%d",
|
||||
&old_ip, bpf_ntohs(old_port),
|
||||
&ip->daddr, bpf_ntohs(udp->dest));
|
||||
}
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
// Gancho TC para EGRESS (SNAT/Masquerade)
|
||||
SEC("tc_egress")
|
||||
int nat_egress_func(struct __sk_buff *skb) {
|
||||
// Cabeçalhos
|
||||
void *data = (void *)(long)skb->data;
|
||||
void *data_end = (void *)(long)skb->data_end;
|
||||
|
||||
// Validação de ethernet
|
||||
struct ethhdr *eth = data;
|
||||
if ((void *)(eth + 1) > data_end)
|
||||
return TC_ACT_OK;
|
||||
|
||||
// Verificar se é IPv4
|
||||
if (eth->h_proto != bpf_htons(ETH_P_IP))
|
||||
return TC_ACT_OK;
|
||||
|
||||
// Validação de cabeçalho IP
|
||||
struct iphdr *ip = (void *)(eth + 1);
|
||||
if ((void *)(ip + 1) > data_end)
|
||||
return TC_ACT_OK;
|
||||
|
||||
// Depuração - imprimir informações do pacote
|
||||
bpf_printk("EGRESS: IP Source %pI4, Dest %pI4", &ip->saddr, &ip->daddr);
|
||||
|
||||
// Verificar se o IP de origem está em nossas redes para SNAT/MASQUERADE
|
||||
__u32 src_prefix = ip->saddr & 0xFFFF0000; // /16
|
||||
__u8 *do_snat = bpf_map_lookup_elem(&snat_networks, &src_prefix);
|
||||
|
||||
// Processar SNAT/Masquerade apenas para pacotes de redes internas
|
||||
if (do_snat && *do_snat) {
|
||||
// Guardar o IP original
|
||||
__u32 old_ip = ip->saddr;
|
||||
|
||||
// IP fixo para SNAT: 10.0.0.87
|
||||
__u32 new_ip = 0x5700000A; // 10.0.0.87 em ordem de rede
|
||||
|
||||
bpf_printk("SNAT: Aplicando masquerade para %pI4 -> %pI4",
|
||||
&old_ip, &new_ip);
|
||||
|
||||
// Aplicar SNAT
|
||||
ip->saddr = new_ip;
|
||||
|
||||
// Recalcular checksum IP
|
||||
ip->check = 0;
|
||||
ip->check = compute_ip_checksum(ip);
|
||||
|
||||
// Recalcular checksums L4 (TCP ou UDP)
|
||||
if (ip->protocol == IPPROTO_TCP) {
|
||||
struct tcphdr *tcp = (void *)(ip + 1);
|
||||
if ((void *)(tcp + 1) <= data_end && tcp->check) {
|
||||
// Ajustar checksum TCP para o IP de origem alterado
|
||||
__u32 check = ~bpf_ntohs(tcp->check);
|
||||
check += ~((old_ip >> 16) & 0xffff) + ~(old_ip & 0xffff);
|
||||
check += ((new_ip >> 16) & 0xffff) + (new_ip & 0xffff);
|
||||
|
||||
// Dobrar para obter o checksum final
|
||||
check = (check & 0xffff) + (check >> 16);
|
||||
check = (check & 0xffff) + (check >> 16);
|
||||
tcp->check = bpf_htons(~check);
|
||||
|
||||
bpf_printk("SNAT TCP: porta %d, checksum atualizado",
|
||||
bpf_ntohs(tcp->source));
|
||||
}
|
||||
}
|
||||
else if (ip->protocol == IPPROTO_UDP) {
|
||||
struct udphdr *udp = (void *)(ip + 1);
|
||||
if ((void *)(udp + 1) <= data_end && udp->check) {
|
||||
// Ajustar checksum UDP para o IP de origem alterado
|
||||
__u32 check = ~bpf_ntohs(udp->check);
|
||||
check += ~((old_ip >> 16) & 0xffff) + ~(old_ip & 0xffff);
|
||||
check += ((new_ip >> 16) & 0xffff) + (new_ip & 0xffff);
|
||||
|
||||
// Dobrar para obter o checksum final
|
||||
check = (check & 0xffff) + (check >> 16);
|
||||
check = (check & 0xffff) + (check >> 16);
|
||||
udp->check = bpf_htons(~check);
|
||||
|
||||
bpf_printk("SNAT UDP: porta %d, checksum atualizado",
|
||||
bpf_ntohs(udp->source));
|
||||
}
|
||||
}
|
||||
|
||||
bpf_printk("SNAT concluído: %pI4 -> %pI4", &old_ip, &ip->saddr);
|
||||
}
|
||||
|
||||
return TC_ACT_OK;
|
||||
}
|
||||
|
||||
char __license[] SEC("license") = "GPL";
|
||||
Reference in new issue
Block a user