Estou escrevendo um proxy UDP transparente em Rust, estou usando várias caixas
- soquete2=> Acesso à criação de um soquete RAW
- nix::sys::soquete=> Acesso a todas as chamadas de API de soquete de baixo nível
- std::net::soquete=> Acesso ao soquete padrão
a máquina que deveria atuar como proxy foi definida como gateway para as máquinas de destino.
A máquina proxy tem os recursos de redirecionamento do kernel Linux habilitados, veja o trecho abaixo
#!/bin/sh
# Redirect packets coming to the computer
sysctl -w net.ipv4.ip_forward=1
sysctl -w net.ipv6.conf.all.forwarding=1
# Disable ICMP redirection
sysctl -w net.ipv4.conf.all.send_redirects=0
A máquina também possui uma NFTABLES
regra configurada para redirecionar todo o tráfego de entrada para o programa proxy, veja o trecho abaixo
#!/bin/sh
# Setting up NFTABLES
nft add table filter
nft add chain filter divert "{ type filter hook prerouting priority -150; }"
nft add rule filter divert meta l4proto udp socket transparent 1 meta mark set 1 accept
#nft add table ip nat
#nft -- add chain ip nat prerouting { type nat hook prerouting priority -100 \; }
# Creating a new rule that redirects UDP traffic from P1-P2 to port 35
nft add rule filter divert udp dport 80-65525 tproxy to :35 meta mark set 1 accept
#nft add rule ip nat prerouting udp dport 80-65525 redirect to :35
Como você pode ver nas partes comentadas, experimentei ambos NAT PREROUTING
e TPROXY
. Após extensa pesquisa e testes, descobri que quando uso NAT PREROUTING
meu proxy (que está escutando na porta 35) recebe TODO o tráfego de entrada dos clientes, mas quando leio os pacotes do soquete, o endereço de destino original é substituído pelo endereço da máquina proxy ip (o que eu não quero). Mas se eu usar, TPROXY
não recebo todo o tráfego de entrada, só recebo o que minha máquina "deveria" ver, por exemplo, tráfego de transmissão e tráfego que tem o endereço MAC da máquina proxy como destino, isso significa que posso não vejo todo o tráfego dos clientes conectados.
Eu segui as instruções dadas nomanual tproxy do kernel linux.
Deve-se notar que eu defino IP_TRANSPARENT
.
Estas são as coisas que eu defini no meu programa
use socket2::{Socket, Domain, Type, Protocol};
use std::os::fd::{OwnedFd, RawFd, AsRawFd};
use nix::sys::socket::{
...
sockopt::{IpTransparent, Ipv4OrigDstAddr, Ipv4PacketInfo},
setsockopt,
...
};
...
let client_to_proxy_socket = match Socket::new(Domain::IPV4, Type::RAW, Some(Protocol::UDP)) { ... };
let socket_ref: OwnedFd = client_to_proxy_socket.into();
let active: bool = true;
match setsockopt(&socket_ref, IpTransparent, &active) { ... }; // IP_TRANSPARENT
match setsockopt(&socket_ref, Ipv4OrigDstAddr, &active) { ... }; // SO_ORIGINAL_DST
match setsockopt(&socket_ref, Ipv4PacketInfo, &active) { ... }; // IP_PKTINFO
...
Quando se trata do que tentei, devo dizer que tentei muitas combinações possíveis de regras e códigos com variações e estruturas diferentes.
Vou postar uma pequena lista de links que já visitei e li diversas vezes
- Implementar recvmsg de soquete assíncrono para carimbo de data / hora RX e TX em Rust
- Obtenha o endereço de destino de um pacote UDP recebido
- Redireciona o tráfego de todo o sistema para o servidor proxy local usando iptables
- Usando iptables TPROXY em vez de REDIRECT
- Configuração IPTables para Proxy Transparente
Quanto ao que espero, espero receber todo o tráfego de entrada e redirecioná-lo TPROXY
para a porta 35.
Também postei uma pergunta semelhante no stackoverflow, mas me ocorreu que esta não é apenas uma questão de programação, mas também pode ser uma questão de rede/Linux.
Gostaria de ressaltar mais uma coisa, durante meus testes de ontem descobri que mesmo tendo desabilitado ICMP redirection
(veja o primeiro trecho) vi que a máquina estava enviando mensagens de redirecionamento ICMP de qualquer maneira lendo-as através do wireshark, e isso é algo que me deixou bastante confuso .