commit
This commit is contained in:
1 parent
d9412a360d
commit
6081ec0c1c
9 files changed
-1140
No files matched your search
@@ -1,68 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script simplificado para compilar e carregar programas XDP
|
||||
|
||||
# Interface a ser utilizada
|
||||
IFACE=${1:-"enp0s6"}
|
||||
MODE=${2:-"generic"} # generic é mais compatível; native é mais rápido
|
||||
TYPE=${3:-"simple"} # simple ou accelerated
|
||||
|
||||
echo "Compilando e carregando programa XDP"
|
||||
echo "Interface: $IFACE"
|
||||
echo "Modo: $MODE"
|
||||
echo "Tipo: $TYPE"
|
||||
|
||||
# Compilar o programa correto
|
||||
if [ "$TYPE" == "simple" ]; then
|
||||
echo "=== Compilando programa simple_xdp_filter ==="
|
||||
clang -O2 -Wall -target bpf -g -D__TARGET_ARCH_arm64 -c simple_xdp_filter.c -o simple_xdp_filter.o -I/usr/include/bpf -I/usr/include/
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Erro na compilação!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PROG_FILE="simple_xdp_filter.o"
|
||||
else
|
||||
echo "=== Compilando programa xdp_accelerated_nat ==="
|
||||
clang -O2 -Wall -target bpf -g -D__TARGET_ARCH_arm64 -c xdp_accelerated_nat.c -o xdp_accelerated_nat.o -I/usr/include/bpf -I/usr/include/
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Erro na compilação!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PROG_FILE="xdp_accelerated_nat.o"
|
||||
fi
|
||||
|
||||
# Remover qualquer programa XDP existente
|
||||
echo "Removendo programas XDP existentes da interface $IFACE"
|
||||
ip link set dev $IFACE xdp off
|
||||
|
||||
# Carregar o programa
|
||||
echo "Carregando programa $PROG_FILE na interface $IFACE (modo $MODE)..."
|
||||
ip link set dev $IFACE xdp obj $PROG_FILE section xdp mode $MODE
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Erro ao carregar programa XDP."
|
||||
echo "Tentando modo alternativo (skb)..."
|
||||
ip link set dev $IFACE xdp obj $PROG_FILE section xdp mode skb
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Falha também no modo skb."
|
||||
echo "Verifique se seu kernel suporta XDP."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Programa XDP carregado com sucesso!"
|
||||
echo "Verificando status:"
|
||||
ip link show dev $IFACE | grep xdp
|
||||
|
||||
echo "Use 'bpftool map dump' para ver os mapas"
|
||||
|
||||
if [ "$TYPE" == "simple" ]; then
|
||||
# Mostrar estatísticas iniciais
|
||||
echo "Estatísticas iniciais:"
|
||||
bpftool map dump name stats_map
|
||||
fi
|
||||
@@ -1,3 +0,0 @@
|
||||
# Formato: <protocolo> <ip_destino:porta_destino> <novo_ip:nova_porta>
|
||||
tcp 10.0.0.87:80 10.15.0.45:80
|
||||
tcp 10.0.0.87:443 10.15.0.45:443
|
||||
-256
@@ -1,256 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import socket
|
||||
import struct
|
||||
import json
|
||||
import subprocess
|
||||
import argparse
|
||||
import ipaddress
|
||||
import time
|
||||
import re
|
||||
|
||||
def run_cmd(cmd, show_output=False):
|
||||
"""Executa um comando shell e retorna sua saída"""
|
||||
if show_output:
|
||||
print(f"Executando: {cmd}")
|
||||
|
||||
result = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
if result.returncode != 0:
|
||||
print(f"Erro ao executar: {cmd}")
|
||||
print(f"Saída de erro: {result.stderr}")
|
||||
return None
|
||||
return result.stdout.strip()
|
||||
|
||||
def find_map_ids_by_name(map_name):
|
||||
"""Encontra todos os IDs de mapas BPF com um determinado nome"""
|
||||
output = run_cmd("bpftool map list")
|
||||
if not output:
|
||||
return []
|
||||
|
||||
map_ids = []
|
||||
for line in output.split('\n'):
|
||||
if f"name {map_name}" in line:
|
||||
match = re.search(r'^(\d+):', line)
|
||||
if match:
|
||||
map_ids.append(match.group(1))
|
||||
|
||||
return map_ids
|
||||
|
||||
def find_map_id(map_name):
|
||||
"""Encontra o primeiro ID de um mapa BPF pelo nome"""
|
||||
map_ids = find_map_ids_by_name(map_name)
|
||||
return map_ids[0] if map_ids else None
|
||||
|
||||
def clean_old_maps():
|
||||
"""Limpa todos os mapas antigos com nomes relacionados a NAT"""
|
||||
map_names = ["dnat_port_map", "snat_networks", "hairpin_map"]
|
||||
count = 0
|
||||
|
||||
for map_name in map_names:
|
||||
map_ids = find_map_ids_by_name(map_name)
|
||||
for map_id in map_ids:
|
||||
print(f"Limpando mapa antigo: {map_name} (ID: {map_id})")
|
||||
run_cmd(f"bpftool map dump id {map_id} -j | grep -o '\"key\": \"[^\"]*\"' | "
|
||||
f"sed 's/\"key\": \"\\([^\"]*\\)\"/\\1/g' | while read key; do "
|
||||
f"[ ! -z \"$key\" ] && bpftool map delete id {map_id} key hex $key; done")
|
||||
count += 1
|
||||
|
||||
return count
|
||||
|
||||
def load_tc_program(interface, object_file="tc_nat.o"):
|
||||
"""Carrega programas TC para interface especificada"""
|
||||
print(f"Carregando programas TC para interface {interface}...")
|
||||
|
||||
# Compilar programa BPF
|
||||
print("Compilando programa TC BPF...")
|
||||
cmd = f"clang -O2 -Wall -target bpf -g -D__TARGET_ARCH_arm64 -c tc_nat.c -o {object_file} -I/usr/include/bpf -I/usr/include/"
|
||||
if run_cmd(cmd) is None:
|
||||
return False
|
||||
|
||||
# Remover programas existentes
|
||||
run_cmd(f"tc filter del dev {interface} ingress 2>/dev/null")
|
||||
run_cmd(f"tc filter del dev {interface} egress 2>/dev/null")
|
||||
run_cmd(f"tc qdisc del dev {interface} clsact 2>/dev/null")
|
||||
|
||||
# Configurar qdisc
|
||||
run_cmd(f"tc qdisc add dev {interface} clsact")
|
||||
|
||||
# Carregar programas TC
|
||||
ingress_cmd = f"tc filter add dev {interface} ingress prio 1 handle 1 bpf da obj {object_file} sec tc_ingress"
|
||||
egress_cmd = f"tc filter add dev {interface} egress prio 1 handle 1 bpf da obj {object_file} sec tc_egress"
|
||||
|
||||
if run_cmd(ingress_cmd, show_output=True) is None or run_cmd(egress_cmd, show_output=True) is None:
|
||||
return False
|
||||
|
||||
print("Programas TC carregados com sucesso!")
|
||||
print("Aguardando criação dos mapas...")
|
||||
time.sleep(1)
|
||||
return True
|
||||
|
||||
def setup_dnat_rule_hex(map_id, external_port, internal_ip, internal_port):
|
||||
"""Configura uma regra DNAT usando strings hexadecimais diretamente"""
|
||||
# Converter porta para hex (little-endian)
|
||||
port_hex = f"{external_port & 0xff:02x} {(external_port >> 8) & 0xff:02x}"
|
||||
|
||||
# Converter IP para hex (formato de rede)
|
||||
octets = list(map(int, internal_ip.split('.')))
|
||||
ip_hex = f"{octets[3]:02x} {octets[2]:02x} {octets[1]:02x} {octets[0]:02x}"
|
||||
|
||||
# Converter porta interna para hex (little-endian)
|
||||
int_port_hex = f"{internal_port & 0xff:02x} {(internal_port >> 8) & 0xff:02x}"
|
||||
|
||||
# Valor: IP (4 bytes) + porta (2 bytes) + padding (2 bytes)
|
||||
value_hex = f"{ip_hex} {int_port_hex} 00 00"
|
||||
|
||||
# Update map usando bpftool com valores hex
|
||||
cmd = f"bpftool map update id {map_id} key hex {port_hex} value hex {value_hex}"
|
||||
success = run_cmd(cmd, show_output=True) is not None
|
||||
|
||||
if success:
|
||||
print(f"Regra DNAT configurada: {external_port} -> {internal_ip}:{internal_port}")
|
||||
else:
|
||||
print(f"Falha ao configurar regra DNAT: {external_port} -> {internal_ip}:{internal_port}")
|
||||
|
||||
return success
|
||||
|
||||
def setup_snat_network_hex(map_id, network):
|
||||
"""Configura uma rede para SNAT usando strings hexadecimais diretamente"""
|
||||
# Parse da rede (exemplo: "10.15.0.0/16")
|
||||
ip, prefix = network.split('/')
|
||||
prefix = int(prefix)
|
||||
|
||||
if prefix != 16:
|
||||
print(f"AVISO: Rede {network} não é /16. Apenas redes /16 são totalmente suportadas.")
|
||||
|
||||
# Extrair octetos do IP
|
||||
octets = list(map(int, ip.split('.')))
|
||||
|
||||
# Para /16, montamos o prefixo
|
||||
network_hex = f"00 00 {octets[1]:02x} {octets[0]:02x}"
|
||||
|
||||
# Valor é 1 byte: habilitado
|
||||
value_hex = "01" # 1 = habilitado
|
||||
|
||||
# Update map usando bpftool com valores hex
|
||||
cmd = f"bpftool map update id {map_id} key hex {network_hex} value hex {value_hex}"
|
||||
success = run_cmd(cmd, show_output=True) is not None
|
||||
|
||||
if success:
|
||||
print(f"Rede SNAT configurada: {network}")
|
||||
else:
|
||||
print(f"Falha ao configurar rede SNAT: {network}")
|
||||
|
||||
return success
|
||||
|
||||
def clear_map(map_id):
|
||||
"""Limpa todas as entradas de um mapa BPF usando comandos diretos"""
|
||||
print(f"Limpando mapa ID {map_id}...")
|
||||
|
||||
# Verificar se o mapa existe
|
||||
if run_cmd(f"bpftool map show id {map_id}") is None:
|
||||
print(f" Mapa ID {map_id} não encontrado")
|
||||
return False
|
||||
|
||||
# Obter conteúdo do mapa
|
||||
map_content = run_cmd(f"bpftool map dump id {map_id}")
|
||||
if not map_content or "key:" not in map_content:
|
||||
print(" Mapa já está vazio")
|
||||
return True
|
||||
|
||||
# Usar abordagem direta para limpar
|
||||
run_cmd(f"echo '{map_content}' | grep -o 'key: [0-9a-fx ]*' | sed 's/key: //g' | while read -r key; do [ ! -z \"$key\" ] && bpftool map delete id {map_id} key hex $key; done")
|
||||
|
||||
# Verificar se o mapa está vazio
|
||||
map_content = run_cmd(f"bpftool map dump id {map_id}")
|
||||
if not map_content or "key:" not in map_content:
|
||||
print(" Mapa limpo com sucesso")
|
||||
return True
|
||||
else:
|
||||
print(" Não foi possível limpar completamente o mapa")
|
||||
return False
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Configuração de NAT BPF para Docker")
|
||||
parser.add_argument("interface", help="Interface de rede externa (ex: enp0s6)")
|
||||
parser.add_argument("--target", default="10.15.0.45", help="IP do container alvo (ex: 10.15.0.45)")
|
||||
parser.add_argument("--networks", default="10.15.0.0/16,172.17.0.0/16",
|
||||
help="Redes para SNAT, separadas por vírgulas (ex: 10.15.0.0/16,172.17.0.0/16)")
|
||||
parser.add_argument("--http-port", type=int, default=80, help="Porta HTTP para redirecionar")
|
||||
parser.add_argument("--https-port", type=int, default=443, help="Porta HTTPS para redirecionar")
|
||||
parser.add_argument("--reload", action="store_true", help="Recarregar o programa TC")
|
||||
parser.add_argument("--clean", action="store_true", help="Limpar mapas antigos antes de configurar")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
print("=== Configuração de NAT BPF para Docker ===")
|
||||
print(f"Interface: {args.interface}")
|
||||
print(f"Container alvo: {args.target}")
|
||||
print(f"Redes para SNAT: {args.networks}")
|
||||
print(f"Portas: HTTP={args.http_port}, HTTPS={args.https_port}")
|
||||
print("")
|
||||
|
||||
# Limpar mapas antigos se solicitado
|
||||
if args.clean:
|
||||
print("Limpando mapas antigos...")
|
||||
count = clean_old_maps()
|
||||
print(f"Total de {count} mapas antigos foram limpos.")
|
||||
|
||||
# Carregar programa TC se necessário
|
||||
if args.reload:
|
||||
if not load_tc_program(args.interface):
|
||||
print("Falha ao carregar programas TC. Abortando.")
|
||||
return 1
|
||||
|
||||
# Encontrar IDs dos mapas
|
||||
dnat_map_id = find_map_id("dnat_port_map")
|
||||
snat_map_id = find_map_id("snat_networks")
|
||||
|
||||
if not dnat_map_id or not snat_map_id:
|
||||
print("Mapas BPF não encontrados. Carregando programas TC...")
|
||||
if not load_tc_program(args.interface):
|
||||
print("Falha ao carregar programas TC. Abortando.")
|
||||
return 1
|
||||
|
||||
# Tentar novamente após carregar os programas
|
||||
dnat_map_id = find_map_id("dnat_port_map")
|
||||
snat_map_id = find_map_id("snat_networks")
|
||||
|
||||
if not dnat_map_id or not snat_map_id:
|
||||
print("Ainda não foi possível encontrar os mapas. Verifique o carregamento dos programas TC.")
|
||||
return 1
|
||||
|
||||
print(f"IDs dos mapas: DNAT={dnat_map_id}, SNAT={snat_map_id}")
|
||||
|
||||
# Limpar mapas existentes
|
||||
clear_map(dnat_map_id)
|
||||
clear_map(snat_map_id)
|
||||
|
||||
# Configurar regras DNAT usando método hexadecimal direto
|
||||
setup_dnat_rule_hex(dnat_map_id, args.http_port, args.target, args.http_port)
|
||||
setup_dnat_rule_hex(dnat_map_id, args.https_port, args.target, args.https_port)
|
||||
|
||||
# Configurar redes SNAT
|
||||
for network in args.networks.split(','):
|
||||
setup_snat_network_hex(snat_map_id, network.strip())
|
||||
|
||||
# Habilitar IP forwarding
|
||||
print("Habilitando IP forwarding...")
|
||||
with open("/proc/sys/net/ipv4/ip_forward", "w") as f:
|
||||
f.write("1")
|
||||
|
||||
# Verificar configuração final
|
||||
print("\nConfiguração final:")
|
||||
print("Regras DNAT:")
|
||||
os.system(f"bpftool map dump id {dnat_map_id}")
|
||||
print("\nRedes SNAT:")
|
||||
os.system(f"bpftool map dump id {snat_map_id}")
|
||||
|
||||
print("\nNAT BPF configurado com sucesso!")
|
||||
print("Para ver logs em tempo real: cat /sys/kernel/debug/tracing/trace_pipe")
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -1,93 +0,0 @@
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/in.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_endian.h>
|
||||
|
||||
// Definir arquitetura ARM64 explicitamente
|
||||
#ifndef __TARGET_ARCH_arm64
|
||||
#define __TARGET_ARCH_arm64
|
||||
#endif
|
||||
|
||||
// Mapa para redes internas (para SNAT)
|
||||
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 regras DNAT
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 64);
|
||||
__type(key, __u16); // Porta destino
|
||||
__type(value, __u32); // IP interno
|
||||
} dnat_rules SEC(".maps");
|
||||
|
||||
// Estatísticas
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 4);
|
||||
__type(key, __u32);
|
||||
__type(value, __u64);
|
||||
} stats_map SEC(".maps");
|
||||
|
||||
// Incrementar contador de estatísticas
|
||||
static __always_inline void increment_counter(__u32 index) {
|
||||
__u64 *counter;
|
||||
counter = bpf_map_lookup_elem(&stats_map, &index);
|
||||
if (counter)
|
||||
(*counter)++;
|
||||
}
|
||||
|
||||
// Programa XDP simplificado para inspeção de tráfego
|
||||
SEC("xdp")
|
||||
int simple_xdp_filter(struct xdp_md *ctx) {
|
||||
void *data = (void *)(long)ctx->data;
|
||||
void *data_end = (void *)(long)ctx->data_end;
|
||||
struct ethhdr *eth = data;
|
||||
|
||||
// Verificação básica de limites
|
||||
if (data + sizeof(struct ethhdr) > data_end)
|
||||
return XDP_PASS;
|
||||
|
||||
// Verificar se é um pacote IPv4
|
||||
if (eth->h_proto != bpf_htons(ETH_P_IP))
|
||||
return XDP_PASS;
|
||||
|
||||
struct iphdr *ip = (void *)(eth + 1);
|
||||
if ((void *)(ip + 1) > data_end)
|
||||
return XDP_PASS;
|
||||
|
||||
// Incrementar contador de pacotes processados
|
||||
increment_counter(0);
|
||||
|
||||
// Verificar se é um pacote TCP ou UDP
|
||||
if (ip->protocol == IPPROTO_TCP) {
|
||||
struct tcphdr *tcp = (void *)(ip + 1);
|
||||
if ((void *)(tcp + 1) > data_end)
|
||||
return XDP_PASS;
|
||||
|
||||
// Contar pacotes TCP
|
||||
increment_counter(1);
|
||||
|
||||
// Verificar se é tráfego HTTPS (porta 443)
|
||||
__u16 dport = bpf_ntohs(tcp->dest);
|
||||
if (dport == 443) {
|
||||
increment_counter(3); // Contar pacotes HTTPS
|
||||
}
|
||||
|
||||
} else if (ip->protocol == IPPROTO_UDP) {
|
||||
// Contar pacotes UDP
|
||||
increment_counter(2);
|
||||
}
|
||||
|
||||
// Permitir que todos os pacotes passem
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
||||
@@ -1,2 +0,0 @@
|
||||
10.15.0.0/16
|
||||
172.17.0.0/16
|
||||
-116
@@ -1,116 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script para configurar NAT BPF com TC
|
||||
|
||||
# Parâmetros
|
||||
INTERFACE=${1:-"enp0s6"}
|
||||
TARGET_IP=${2:-"10.15.0.45"}
|
||||
GATEWAY_IP=${3:-"10.0.0.87"}
|
||||
|
||||
echo "=== Configurando NAT BPF com TC ==="
|
||||
echo "Interface: $INTERFACE"
|
||||
echo "IP alvo (container): $TARGET_IP"
|
||||
echo "Gateway IP: $GATEWAY_IP"
|
||||
|
||||
# Compilar programa TC BPF
|
||||
echo "Compilando programa TC BPF..."
|
||||
clang -O2 -Wall -target bpf -g -D__TARGET_ARCH_arm64 -c tc_nat.c -o tc_nat.o -I/usr/include/bpf -I/usr/include/
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Erro na compilação do programa TC!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verificar seções no arquivo objeto BPF
|
||||
echo "Verificando seções no arquivo objeto..."
|
||||
llvm-objdump -h tc_nat.o
|
||||
|
||||
# Remover programas TC existentes na interface
|
||||
echo "Removendo programas TC existentes na interface $INTERFACE..."
|
||||
tc filter del dev $INTERFACE ingress 2>/dev/null
|
||||
tc filter del dev $INTERFACE egress 2>/dev/null
|
||||
tc qdisc del dev $INTERFACE clsact 2>/dev/null
|
||||
|
||||
# Configurar qdisc
|
||||
echo "Configurando qdisc no $INTERFACE..."
|
||||
tc qdisc add dev $INTERFACE clsact
|
||||
|
||||
# Carregar programas TC
|
||||
echo "Carregando programa TC ingress..."
|
||||
tc filter add dev $INTERFACE ingress prio 1 handle 1 bpf da obj tc_nat.o sec tc_ingress
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Erro ao carregar o programa ingress!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Carregando programa TC egress..."
|
||||
tc filter add dev $INTERFACE egress prio 1 handle 1 bpf da obj tc_nat.o sec tc_egress
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "Erro ao carregar o programa egress!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Encontrar IDs dos mapas
|
||||
echo "Encontrando IDs dos mapas BPF..."
|
||||
DNAT_MAP_ID=$(bpftool map list | grep -m1 "name dnat_port_map" | awk '{print $1}' | tr -d ':')
|
||||
SNAT_MAP_ID=$(bpftool map list | grep -m1 "name snat_networks" | awk '{print $1}' | tr -d ':')
|
||||
|
||||
if [ -z "$DNAT_MAP_ID" ] || [ -z "$SNAT_MAP_ID" ]; then
|
||||
echo "Não foi possível encontrar todos os mapas BPF necessários."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "IDs dos mapas: DNAT=$DNAT_MAP_ID, SNAT=$SNAT_MAP_ID"
|
||||
|
||||
# Limpar mapas existentes
|
||||
echo "Limpando mapas existentes..."
|
||||
echo "Limpando DNAT..."
|
||||
bpftool map dump id $DNAT_MAP_ID -j | grep -o '"key": [0-9]*' | awk '{print $2}' | \
|
||||
while read key; do
|
||||
[ ! -z "$key" ] && bpftool map delete id $DNAT_MAP_ID key hex $(printf "%04x" $key | sed 's/\(..\)\(..\)/\2 \1/')
|
||||
done
|
||||
|
||||
echo "Limpando SNAT..."
|
||||
bpftool map dump id $SNAT_MAP_ID -j | grep -o '"key": [0-9]*' | awk '{print $2}' | \
|
||||
while read key; do
|
||||
[ ! -z "$key" ] && bpftool map delete id $SNAT_MAP_ID key hex $(printf "%08x" $key | sed 's/\(..\)\(..\)\(..\)\(..\)/\4 \3 \2 \1/')
|
||||
done
|
||||
|
||||
# Configurar regras DNAT
|
||||
echo "Configurando regras DNAT..."
|
||||
|
||||
# Função auxiliar para converter IP para valores em little-endian
|
||||
ip_to_hex_le() {
|
||||
local ip=$1
|
||||
IFS='.' read -r -a octets <<< "$ip"
|
||||
printf "%02x %02x %02x %02x" "${octets[3]}" "${octets[2]}" "${octets[1]}" "${octets[0]}"
|
||||
}
|
||||
|
||||
# Função auxiliar para converter porta para little-endian
|
||||
port_to_hex_le() {
|
||||
local port=$1
|
||||
printf "%02x %02x" $((port & 0xFF)) $(((port >> 8) & 0xFF))
|
||||
}
|
||||
|
||||
# Obter valores em hex
|
||||
TARGET_IP_HEX=$(ip_to_hex_le $TARGET_IP)
|
||||
|
||||
# Configurar redirecionamento HTTP
|
||||
echo "Configurando redirecionamento HTTP (porta 80)..."
|
||||
bpftool map update id $DNAT_MAP_ID key hex "$(port_to_hex_le 80)" value hex "$TARGET_IP_HEX $(port_to_hex_le 80) 00 00"
|
||||
|
||||
# Configurar redirecionamento HTTPS
|
||||
echo "Configurando redirecionamento HTTPS (porta 443)..."
|
||||
bpftool map update id $DNAT_MAP_ID key hex "$(port_to_hex_le 443)" value hex "$TARGET_IP_HEX $(port_to_hex_le 443) 00 00"
|
||||
|
||||
# Configurar redes para SNAT
|
||||
echo "Configurando redes para SNAT..."
|
||||
bpftool map update id $SNAT_MAP_ID key hex "00 00 0f 0a" value hex "01" # 10.15.0.0/16
|
||||
bpftool map update id $SNAT_MAP_ID key hex "00 00 11 ac" value hex "01" # 172.17.0.0/16
|
||||
|
||||
# Habilitar IP forwarding
|
||||
echo "Habilitando ip_forward..."
|
||||
echo 1 > /proc/sys/net/ipv4/ip_forward
|
||||
|
||||
echo "NAT BPF configurado com sucesso. Utilize 'tc filter show dev $INTERFACE ingress' para verificar."
|
||||
echo "Para ver logs: cat /sys/kernel/debug/tracing/trace_pipe"
|
||||
@@ -1,80 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Script para verificar se o NAT está funcionando corretamente
|
||||
|
||||
INTERFACE=${1:-"enp0s6"}
|
||||
TARGET_IP=${2:-"10.15.0.45"}
|
||||
|
||||
echo "=== Verificando Configuração NAT ==="
|
||||
echo "Interface: $INTERFACE"
|
||||
echo "Container alvo: $TARGET_IP"
|
||||
|
||||
# Verificar se os programas TC estão carregados
|
||||
echo -e "\n[Programas TC]"
|
||||
tc filter show dev $INTERFACE ingress | grep -i bpf
|
||||
tc filter show dev $INTERFACE egress | grep -i bpf
|
||||
|
||||
# Verificar mapas BPF
|
||||
echo -e "\n[Mapas BPF]"
|
||||
DNAT_MAP_ID=$(bpftool map list | grep -m1 "name dnat_port_map" | awk '{print $1}' | tr -d ':')
|
||||
SNAT_MAP_ID=$(bpftool map list | grep -m1 "name snat_networks" | awk '{print $1}' | tr -d ':')
|
||||
|
||||
if [ -n "$DNAT_MAP_ID" ]; then
|
||||
echo "Mapa DNAT (ID: $DNAT_MAP_ID):"
|
||||
bpftool map dump id $DNAT_MAP_ID
|
||||
else
|
||||
echo "Mapa DNAT não encontrado"
|
||||
fi
|
||||
|
||||
if [ -n "$SNAT_MAP_ID" ]; then
|
||||
echo -e "\nMapa SNAT (ID: $SNAT_MAP_ID):"
|
||||
bpftool map dump id $SNAT_MAP_ID
|
||||
else
|
||||
echo -e "\nMapa SNAT não encontrado"
|
||||
fi
|
||||
|
||||
# Verificar IP forwarding
|
||||
echo -e "\n[IP Forwarding]"
|
||||
IP_FWD=$(cat /proc/sys/net/ipv4/ip_forward)
|
||||
echo "IP forwarding: $IP_FWD"
|
||||
if [ "$IP_FWD" != "1" ]; then
|
||||
echo "AVISO: IP forwarding está desativado. Ative com:"
|
||||
echo " echo 1 > /proc/sys/net/ipv4/ip_forward"
|
||||
fi
|
||||
|
||||
# Verificar conectividade com o alvo
|
||||
echo -e "\n[Conectividade]"
|
||||
ping -c 1 -W 1 $TARGET_IP > /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Ping para $TARGET_IP: OK"
|
||||
else
|
||||
echo "Ping para $TARGET_IP: FALHOU"
|
||||
fi
|
||||
|
||||
# Testar HTTP/HTTPS
|
||||
echo -e "\n[Teste HTTP]"
|
||||
curl -s -m 2 --head http://$TARGET_IP > /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Acesso HTTP direto para $TARGET_IP: OK"
|
||||
else
|
||||
echo "Acesso HTTP direto para $TARGET_IP: FALHOU"
|
||||
fi
|
||||
|
||||
# Obter IP externo
|
||||
EXTERNAL_IP=$(ip -br addr show $INTERFACE | awk '{print $3}' | cut -d'/' -f1)
|
||||
echo -e "\n[Teste NAT]"
|
||||
echo "IP externo: $EXTERNAL_IP"
|
||||
curl -s -m 2 --head http://$EXTERNAL_IP > /dev/null
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Acesso HTTP via NAT ($EXTERNAL_IP): OK"
|
||||
else
|
||||
echo "Acesso HTTP via NAT ($EXTERNAL_IP): FALHOU"
|
||||
fi
|
||||
|
||||
# Verificar logs recentes
|
||||
echo -e "\n[Logs Recentes]"
|
||||
echo "Últimas 5 linhas do trace_pipe (pode estar vazio se não houver atividade recente):"
|
||||
cat /sys/kernel/debug/tracing/trace_pipe | head -n 5
|
||||
|
||||
echo -e "\nPara monitorar logs em tempo real: cat /sys/kernel/debug/tracing/trace_pipe"
|
||||
echo "Para visualizar conexões atuais: ss -tan"
|
||||
@@ -1,216 +0,0 @@
|
||||
#include <linux/bpf.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/ip.h>
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
#include <linux/in.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
#include <bpf/bpf_endian.h>
|
||||
|
||||
// Definir arquitetura ARM64 explicitamente
|
||||
#ifndef __TARGET_ARCH_arm64
|
||||
#define __TARGET_ARCH_arm64
|
||||
#endif
|
||||
|
||||
// Definições para contornar erros de compilação
|
||||
#ifndef __section
|
||||
#define __section(NAME) \
|
||||
__attribute__((section(NAME), used))
|
||||
#endif
|
||||
|
||||
// Substituir o SEC original pela versão compatível com ARM64
|
||||
#undef SEC
|
||||
#define SEC(NAME) __section(NAME)
|
||||
|
||||
/* Estrutura para conexões NAT */
|
||||
struct nat_conn {
|
||||
__u32 orig_src_ip; // IP de origem original
|
||||
__u16 orig_src_port; // Porta de origem original
|
||||
__u32 orig_dst_ip; // IP de destino original
|
||||
__u16 orig_dst_port; // Porta de destino original
|
||||
__u32 new_src_ip; // Novo IP de origem (para SNAT)
|
||||
__u16 new_src_port; // Nova porta de origem (para SNAT)
|
||||
__u32 new_dst_ip; // Novo IP de destino (para DNAT)
|
||||
__u16 new_dst_port; // Nova porta de destino (para DNAT)
|
||||
__u8 proto; // Protocolo (TCP/UDP)
|
||||
__u8 state; // Estado da conexão (1=ativo)
|
||||
__u64 last_update; // Timestamp da última atualização
|
||||
};
|
||||
|
||||
/* Chave para consulta rápida de DNAT em pacotes de entrada */
|
||||
struct dnat_key {
|
||||
__u32 dst_ip;
|
||||
__u16 dst_port;
|
||||
__u8 proto;
|
||||
__u8 padding; // Adicionado para alinhamento em ARM64
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Chave para busca de conexões de saída */
|
||||
struct conn_key {
|
||||
__u32 src_ip;
|
||||
__u16 src_port;
|
||||
__u32 dst_ip;
|
||||
__u16 dst_port;
|
||||
__u8 proto;
|
||||
__u8 padding; // Adicionado para alinhamento em ARM64
|
||||
} __attribute__((packed));
|
||||
|
||||
/* Mapas BPF para NAT */
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH); // Alterado de LRU_HASH para HASH para maior compatibilidade
|
||||
__uint(max_entries, 65536);
|
||||
__type(key, struct conn_key);
|
||||
__type(value, struct nat_conn);
|
||||
} conn_track_map SEC(".maps");
|
||||
|
||||
/* Mapa para regras DNAT estáticas */
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 1024);
|
||||
__type(key, struct dnat_key);
|
||||
__type(value, struct nat_conn);
|
||||
} dnat_rules SEC(".maps");
|
||||
|
||||
/* Mapa para redes que devem ter SNAT aplicado */
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_HASH);
|
||||
__uint(max_entries, 256);
|
||||
__type(key, __u32); // Prefixo de rede (/16)
|
||||
__type(value, __u8); // Flag (1=ativo)
|
||||
} snat_networks SEC(".maps");
|
||||
|
||||
/* Mapa para estatísticas */
|
||||
struct nat_stats {
|
||||
__u64 processed; // Pacotes processados
|
||||
__u64 snat_hits; // Acertos de SNAT
|
||||
__u64 dnat_hits; // Acertos de DNAT
|
||||
__u64 new_conns; // Novas conexões
|
||||
__u64 errors; // Erros
|
||||
};
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, __u32);
|
||||
__type(value, struct nat_stats);
|
||||
} stats_map SEC(".maps");
|
||||
|
||||
/* Configuração para IP do gateway (usado para SNAT) */
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_ARRAY);
|
||||
__uint(max_entries, 1);
|
||||
__type(key, __u32);
|
||||
__type(value, __u32);
|
||||
} gateway_ip_map SEC(".maps");
|
||||
|
||||
/* Função para calcular IPv4 checksum - simplificada para evitar loops */
|
||||
static __always_inline __u16 ip_checksum(struct iphdr *ip) {
|
||||
__u32 sum = 0;
|
||||
|
||||
// Para ARM64, calcular o checksum sem depender de loops
|
||||
__u16 *iph = (__u16 *)ip;
|
||||
|
||||
// Zeramos o campo checksum do IP header
|
||||
ip->check = 0;
|
||||
|
||||
// Calculamos a soma de palavras de 16 bits do header IP
|
||||
// O tamanho padrão do header IP é 20 bytes (5 palavras de 32 bits ou 10 de 16 bits)
|
||||
sum += iph[0];
|
||||
sum += iph[1];
|
||||
sum += iph[2];
|
||||
sum += iph[3];
|
||||
sum += iph[4];
|
||||
sum += iph[5];
|
||||
sum += iph[6];
|
||||
sum += iph[7];
|
||||
sum += iph[8];
|
||||
sum += iph[9];
|
||||
|
||||
// Dobrar 32-bit para 16-bit para obter o checksum final
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
|
||||
return ~sum; // Complemento de 1
|
||||
}
|
||||
|
||||
/* Função simplificada para atualizar checksum */
|
||||
static __always_inline __u16 update_checksum(__u16 old_checksum, __u32 old_value, __u32 new_value) {
|
||||
__u32 sum = ~((__u32)old_checksum) & 0xFFFF;
|
||||
sum += ~(old_value >> 16) & 0xFFFF;
|
||||
sum += ~old_value & 0xFFFF;
|
||||
sum += (new_value >> 16) & 0xFFFF;
|
||||
sum += new_value & 0xFFFF;
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
sum = (sum & 0xFFFF) + (sum >> 16);
|
||||
return ~sum & 0xFFFF;
|
||||
}
|
||||
|
||||
/* Função para atualizar estatísticas */
|
||||
static __always_inline void update_stats(__u32 stat_type) {
|
||||
__u32 key = 0;
|
||||
struct nat_stats *stats;
|
||||
|
||||
stats = bpf_map_lookup_elem(&stats_map, &key);
|
||||
if (stats) {
|
||||
if (stat_type == 0) stats->processed++;
|
||||
else if (stat_type == 1) stats->snat_hits++;
|
||||
else if (stat_type == 2) stats->dnat_hits++;
|
||||
else if (stat_type == 3) stats->new_conns++;
|
||||
else if (stat_type == 4) stats->errors++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Função para verificar e aplicar SNAT para redes internas */
|
||||
static __always_inline int should_apply_snat(__u32 src_ip) {
|
||||
// Extrair o prefixo /16
|
||||
__u32 prefix = src_ip & 0xFFFF0000;
|
||||
__u8 *flag;
|
||||
|
||||
flag = bpf_map_lookup_elem(&snat_networks, &prefix);
|
||||
return (flag && *flag == 1) ? 1 : 0;
|
||||
}
|
||||
|
||||
/* Programa principal XDP para aceleração de NAT */
|
||||
SEC("xdp")
|
||||
int xdp_accelerate_nat(struct xdp_md *ctx) {
|
||||
void *data = (void *)(long)ctx->data;
|
||||
void *data_end = (void *)(long)ctx->data_end;
|
||||
|
||||
// Verificação básica de limites
|
||||
if (data + sizeof(struct ethhdr) > data_end)
|
||||
return XDP_PASS;
|
||||
|
||||
struct ethhdr *eth = data;
|
||||
|
||||
// Só processa IPv4
|
||||
if (eth->h_proto != bpf_htons(ETH_P_IP))
|
||||
return XDP_PASS;
|
||||
|
||||
struct iphdr *ip = (void *)(eth + 1);
|
||||
if ((void *)(ip + 1) > data_end)
|
||||
return XDP_PASS;
|
||||
|
||||
// Ignorar pacotes não-TCP/UDP por enquanto
|
||||
if (ip->protocol != IPPROTO_TCP && ip->protocol != IPPROTO_UDP)
|
||||
return XDP_PASS;
|
||||
|
||||
// Incrementar contador de pacotes processados
|
||||
update_stats(0);
|
||||
|
||||
// Restante do código simplificado para compatibilidade ARM64
|
||||
// No caso de XDP modo genérico, vamos deixar a maioria do processamento
|
||||
// NAT para o TC/iptables padrão para garantir compatibilidade
|
||||
|
||||
// Aplicar SNAT básico para rede interna
|
||||
if (should_apply_snat(ip->saddr)) {
|
||||
update_stats(1); // SNAT hit
|
||||
// Permitir que o TC/iptables faça o trabalho real de SNAT
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
// Apenas passar pacotes normalmente
|
||||
return XDP_PASS;
|
||||
}
|
||||
|
||||
/* Simplificação extrema para compatibilidade */
|
||||
char _license[] SEC("license") = "GPL";
|
||||
@@ -1,306 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import socket
|
||||
import struct
|
||||
import argparse
|
||||
import subprocess
|
||||
import ipaddress
|
||||
from bcc import BPF
|
||||
|
||||
# Constantes
|
||||
DEFAULT_INTERFACE = "enp0s6"
|
||||
DEFAULT_GATEWAY_IP = "10.0.0.87"
|
||||
DNAT_RULES_FILE = "dnat_rules.txt"
|
||||
SNAT_NETWORKS_FILE = "snat_networks.txt"
|
||||
|
||||
def run_cmd(cmd, show_output=False):
|
||||
"""Executa um comando shell e retorna sua saída"""
|
||||
if show_output:
|
||||
print(f"Executando: {cmd}")
|
||||
|
||||
result = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
|
||||
if result.returncode != 0:
|
||||
print(f"Erro ao executar: {cmd}")
|
||||
print(f"Saída de erro: {result.stderr}")
|
||||
return None
|
||||
return result.stdout.strip()
|
||||
|
||||
def ip_to_int(ip_str):
|
||||
"""Converte um endereço IP em inteiro."""
|
||||
return struct.unpack("!I", socket.inet_aton(ip_str))[0]
|
||||
|
||||
def int_to_ip(ip_int):
|
||||
"""Converte um inteiro em endereço IP."""
|
||||
return socket.inet_ntoa(struct.pack("!I", ip_int))
|
||||
|
||||
def compile_xdp_program():
|
||||
"""Compila o programa XDP."""
|
||||
print("Compilando o programa XDP...")
|
||||
# Corrigido para incluir diretórios de inclusão e target para ARM64
|
||||
cmd = "clang -O2 -Wall -target bpf -g -D__TARGET_ARCH_arm64 -c xdp_accelerated_nat.c -o xdp_accelerated_nat.o -I/usr/include/bpf -I/usr/include/"
|
||||
return run_cmd(cmd, True) is not None
|
||||
|
||||
def attach_xdp_program(interface, program_path):
|
||||
"""Anexa o programa XDP à interface."""
|
||||
print(f"Anexando programa XDP à interface {interface}...")
|
||||
# Adicionando a flag --force para substituir qualquer programa existente
|
||||
# Usando 'generic' como modo XDP para maior compatibilidade
|
||||
cmd = f"ip link set dev {interface} xdp obj {program_path} sec xdp"
|
||||
return run_cmd(cmd, True) is not None
|
||||
|
||||
def detach_xdp_program(interface):
|
||||
"""Remove o programa XDP da interface."""
|
||||
print(f"Removendo programa XDP da interface {interface}...")
|
||||
cmd = f"ip link set dev {interface} xdp off"
|
||||
return run_cmd(cmd, True) is not None
|
||||
|
||||
def load_dnat_rules(file_path):
|
||||
"""Carrega regras DNAT de um arquivo."""
|
||||
rules = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
|
||||
# Formato: proto dst_ip:dst_port new_ip:new_port
|
||||
# Exemplo: tcp 10.0.0.87:80 10.15.0.45:80
|
||||
parts = line.split()
|
||||
if len(parts) != 3:
|
||||
print(f"Formato inválido na linha: {line}")
|
||||
continue
|
||||
|
||||
proto_name, dst, new = parts
|
||||
|
||||
# Parse proto
|
||||
if proto_name.lower() == "tcp":
|
||||
proto = socket.IPPROTO_TCP
|
||||
elif proto_name.lower() == "udp":
|
||||
proto = socket.IPPROTO_UDP
|
||||
else:
|
||||
print(f"Protocolo inválido: {proto_name}")
|
||||
continue
|
||||
|
||||
# Parse IP e portas
|
||||
try:
|
||||
dst_ip, dst_port = dst.split(':')
|
||||
new_ip, new_port = new.split(':')
|
||||
|
||||
rule = {
|
||||
'proto': proto,
|
||||
'dst_ip': dst_ip,
|
||||
'dst_port': int(dst_port),
|
||||
'new_ip': new_ip,
|
||||
'new_port': int(new_port)
|
||||
}
|
||||
rules.append(rule)
|
||||
except ValueError:
|
||||
print(f"Erro ao analisar IP/porta na linha: {line}")
|
||||
continue
|
||||
|
||||
print(f"Carregadas {len(rules)} regras DNAT")
|
||||
return rules
|
||||
except FileNotFoundError:
|
||||
print(f"Arquivo de regras DNAT não encontrado: {file_path}")
|
||||
return []
|
||||
|
||||
def load_snat_networks(file_path):
|
||||
"""Carrega redes SNAT de um arquivo."""
|
||||
networks = []
|
||||
|
||||
try:
|
||||
with open(file_path, 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'):
|
||||
continue
|
||||
|
||||
# Formato: rede/prefixo
|
||||
# Exemplo: 10.15.0.0/16
|
||||
try:
|
||||
network = ipaddress.ip_network(line)
|
||||
networks.append(str(network))
|
||||
except ValueError:
|
||||
print(f"Rede inválida na linha: {line}")
|
||||
continue
|
||||
|
||||
print(f"Carregadas {len(networks)} redes SNAT")
|
||||
return networks
|
||||
except FileNotFoundError:
|
||||
print(f"Arquivo de redes SNAT não encontrado: {file_path}")
|
||||
return []
|
||||
|
||||
def update_gateway_ip(bpf_obj, gateway_ip):
|
||||
"""Atualiza o IP do gateway no mapa BPF."""
|
||||
try:
|
||||
ip_int = ip_to_int(gateway_ip)
|
||||
key = ctypes.c_uint32(0)
|
||||
value = ctypes.c_uint32(ip_int)
|
||||
bpf_obj["gateway_ip_map"][key] = value
|
||||
print(f"IP do gateway configurado: {gateway_ip}")
|
||||
except Exception as e:
|
||||
print(f"Erro ao configurar IP do gateway: {e}")
|
||||
|
||||
def update_dnat_rules(bpf_obj, rules):
|
||||
"""Atualiza regras DNAT no mapa BPF."""
|
||||
try:
|
||||
dnat_map = bpf_obj["dnat_rules"]
|
||||
|
||||
# Limpar mapa existente
|
||||
for k in list(dnat_map.keys()):
|
||||
del dnat_map[k]
|
||||
|
||||
# Inserir novas regras
|
||||
for rule in rules:
|
||||
key = dnat_map.Key()
|
||||
key.dst_ip = ip_to_int(rule['dst_ip'])
|
||||
key.dst_port = rule['dst_port']
|
||||
key.proto = rule['proto']
|
||||
|
||||
value = dnat_map.Value()
|
||||
value.new_dst_ip = ip_to_int(rule['new_ip'])
|
||||
value.new_dst_port = rule['new_port']
|
||||
|
||||
dnat_map[key] = value
|
||||
|
||||
print(f"{len(rules)} regras DNAT atualizadas")
|
||||
except Exception as e:
|
||||
print(f"Erro ao atualizar regras DNAT: {e}")
|
||||
|
||||
def update_snat_networks(bpf_obj, networks):
|
||||
"""Atualiza redes SNAT no mapa BPF."""
|
||||
try:
|
||||
snat_map = bpf_obj["snat_networks"]
|
||||
|
||||
# Limpar mapa existente
|
||||
for k in list(snat_map.keys()):
|
||||
del snat_map[k]
|
||||
|
||||
# Inserir novas redes
|
||||
for net_str in networks:
|
||||
network = ipaddress.ip_network(net_str)
|
||||
if network.prefixlen != 16:
|
||||
print(f"Aviso: Rede {net_str} não é /16. Pode não funcionar corretamente.")
|
||||
|
||||
# Extrair prefixo /16
|
||||
prefix = int(network.network_address) & 0xFFFF0000
|
||||
key = ctypes.c_uint32(prefix)
|
||||
value = ctypes.c_uint8(1)
|
||||
|
||||
snat_map[key] = value
|
||||
|
||||
print(f"{len(networks)} redes SNAT atualizadas")
|
||||
except Exception as e:
|
||||
print(f"Erro ao atualizar redes SNAT: {e}")
|
||||
|
||||
def print_stats(bpf_obj):
|
||||
"""Imprime estatísticas de NAT."""
|
||||
stats = bpf_obj["stats_map"][0]
|
||||
print("\nEstatísticas de NAT:")
|
||||
print(f" Pacotes processados: {stats.processed}")
|
||||
print(f" Acertos de SNAT: {stats.snat_hits}")
|
||||
print(f" Acertos de DNAT: {stats.dnat_hits}")
|
||||
print(f" Novas conexões: {stats.new_conns}")
|
||||
print(f" Erros: {stats.errors}")
|
||||
|
||||
def print_connections(bpf_obj):
|
||||
"""Imprime conexões ativas."""
|
||||
conn_map = bpf_obj["conn_track_map"]
|
||||
print("\nConexões ativas:")
|
||||
|
||||
count = 0
|
||||
for k, v in conn_map.items():
|
||||
proto_name = "TCP" if k.proto == socket.IPPROTO_TCP else "UDP"
|
||||
src_ip = int_to_ip(k.src_ip)
|
||||
dst_ip = int_to_ip(k.dst_ip)
|
||||
|
||||
# Mostrar apenas as 20 primeiras conexões
|
||||
if count < 20:
|
||||
print(f" {proto_name}: {src_ip}:{k.src_port} -> {dst_ip}:{k.dst_port}")
|
||||
count += 1
|
||||
|
||||
if count > 20:
|
||||
print(f" ... e mais {count - 20} conexões")
|
||||
print(f" Total: {count} conexões ativas")
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Ferramenta para configuração de aceleração NAT com XDP')
|
||||
parser.add_argument('-i', '--interface', default=DEFAULT_INTERFACE, help=f'Interface de rede (padrão: {DEFAULT_INTERFACE})')
|
||||
parser.add_argument('-g', '--gateway', default=DEFAULT_GATEWAY_IP, help=f'IP do gateway para SNAT (padrão: {DEFAULT_GATEWAY_IP})')
|
||||
parser.add_argument('--compile', action='store_true', help='Compilar e carregar o programa XDP')
|
||||
parser.add_argument('--unload', action='store_true', help='Descarregar o programa XDP')
|
||||
parser.add_argument('--stats', action='store_true', help='Mostrar estatísticas')
|
||||
parser.add_argument('--monitor', action='store_true', help='Monitorar estatísticas continuamente')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Descarregar programa
|
||||
if args.unload:
|
||||
detach_xdp_program(args.interface)
|
||||
sys.exit(0)
|
||||
|
||||
# Compilar e carregar programa
|
||||
if args.compile:
|
||||
if not compile_xdp_program():
|
||||
print("Falha ao compilar o programa XDP. Verifique os erros acima.")
|
||||
sys.exit(1)
|
||||
|
||||
# Desanexar qualquer programa existente
|
||||
detach_xdp_program(args.interface)
|
||||
|
||||
# Anexar o novo programa
|
||||
print("Tentando anexar o programa XDP à interface...")
|
||||
if not attach_xdp_program(args.interface, "xdp_accelerated_nat.o"):
|
||||
print("Falha ao anexar o programa XDP à interface")
|
||||
# Tentar modo alternativo
|
||||
print("Tentando modo alternativo (generic)...")
|
||||
if not run_cmd(f"ip link set dev {args.interface} xdp obj xdp_accelerated_nat.o section xdp mode generic", True):
|
||||
print("Todas as tentativas de carregamento falharam. Verifique se o kernel suporta XDP.")
|
||||
sys.exit(1)
|
||||
|
||||
# Carregar o objeto BPF para interagir com o programa carregado
|
||||
try:
|
||||
b = BPF(obj="xdp_accelerated_nat.o")
|
||||
except Exception as e:
|
||||
print(f"Erro ao carregar o objeto BPF: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
# Carregar regras DNAT e redes SNAT
|
||||
dnat_rules = load_dnat_rules(DNAT_RULES_FILE)
|
||||
snat_networks = load_snat_networks(SNAT_NETWORKS_FILE)
|
||||
|
||||
# Atualizar configurações
|
||||
update_gateway_ip(b, args.gateway)
|
||||
if dnat_rules:
|
||||
update_dnat_rules(b, dnat_rules)
|
||||
if snat_networks:
|
||||
update_snat_networks(b, snat_networks)
|
||||
|
||||
# Mostrar estatísticas
|
||||
if args.stats:
|
||||
print_stats(b)
|
||||
print_connections(b)
|
||||
|
||||
# Monitorar estatísticas
|
||||
if args.monitor:
|
||||
try:
|
||||
print("Monitorando estatísticas (Ctrl+C para sair)...")
|
||||
while True:
|
||||
os.system('clear')
|
||||
print_stats(b)
|
||||
print_connections(b)
|
||||
time.sleep(1)
|
||||
except KeyboardInterrupt:
|
||||
print("\nMonitoramento interrompido.")
|
||||
|
||||
print("\nPrograma XDP NAT acelerado em execução.")
|
||||
print("Use '--stats' para visualizar estatísticas.")
|
||||
print("Use '--unload' para descarregar o programa.")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user