Sem usar soquetes brutos, existe uma maneira no Linux de forçar um pacote de rede a ser enviado fisicamente para um gateway primeiro, mesmo que o endereço de destino esteja vinculado a uma interface local?
Meu sistema tem uma única interface ativa, eno1
, à qual é atribuído um IPv4 192.168.1.1
com uma /20
máscara. O gateway tem endereço 192.168.0.1
. Eu tentei adicionar uma rota usando ip route add 192.168.1.0/24 via 192.168.0.1
, que tem a maior especificidade de roteamento para 192.168.1.1
. Mas a chamada traceroute 192.168.1.1
ainda mostra apenas um único salto, indicando que não foi a lugar nenhum. Eu esperaria que mostrasse um primeiro salto de 192.168.0.1
, seguido por 192.168.1.1
. Evidência adicional para a rota que não está sendo seguida é que o envio de pacotes com SO_TIMESTAMPING
resultados em carimbos de data/hora de hardware ausentes, indicando que o pacote não foi realmente colocado na rede.
Caso este seja um problema XY, estou tentando construir uma ferramenta de medição semelhante a ping que mede a latência de ida e volta e a perda de pacotes para o CMTS do meu ISP, mas o roteador usa limitação de taxa nas respostas ICMP, então não posso t medir a latência com a frequência que eu gostaria. Além disso, pings de dispositivos locais na minha rede contam com o limite de taxa, levando a pacotes descartados espúrios (embora eu suponha que poderia bloquear o encaminhamento de pacotes com o CMTS como destino ou aqueles com TTL = 1). Observe que, enquanto estou testando isso localmente em um sistema em minha rede privada usando meu próprio roteador como primeiro salto, na realidade estarei executando isso no próprio roteador, substituindo o .1.1
endereço pelo meu endereço IPv4 público e o .0.1
endereço com o endereço do roteador upstream do CMTS.
Meu pensamento era enviar um pacote para o roteador upstream com um destino de meu próprio IP público, o que, com sorte, resultaria no envio de volta ao meu próprio roteador, tendo percorrido cada perna uma vez, mas aparecendo para o ISP como encaminhado genérico tráfego em vez de algo ao qual o CMTS responde diretamente.
Idealmente, a solução pode ser configurada uma vez como superusuário e, em seguida, usada por tarefas de espaço de usuário, ou seja, não requer a execução da ferramenta como superusuário (daí o desejo de evitar raw-sockets).
Crie um namespace de rede separado:
Crie uma interface Ethernet virtual em cima da física e mova-a para o netns:
Configure seu endereço IP:
Execute o programa:
(Um namespace 'persistente' não é realmente necessário - você pode usar
unshare --net <program>
e mover a interface virtual para ele por PID - mas isso é um pouco menos conveniente.)Antes do roteamento, todos os pacotes são verificados em relação às regras definidas em
ip -4 rule
. Por padrão, a primeira regra os envia primeiro por meio da tabela de roteamento 'local' especial (que contém rotas de loopback para todos os endereços IP "locais").As rotas na tabela de roteamento 'principal' são usadas apenas se não houver correspondência na tabela 'local'.
Dê à ferramenta apenas o privilégio CAP_NET_RAW usando
setcap cap_net_raw=ep
se for uma ferramenta CLI ou usando systemd'sAmbientCapabilities=
se for um serviço. Então você pode usar soquetes brutos sem obter nenhum outro privilégio de root.O primeiro (setcap no executável) é freqüentemente usado por ferramentas
ping
emtr
, então isso não é nada novo.(Sistemas de arquivos incorporados podem não suportar "recursos" no nível do arquivo, mas nesse caso você ainda pode definir o bit setuid. Ele precisa de mais cuidado com a segurança, pois sua ferramenta obtém privilégios de root completos mesmo quando executada por um usuário normal.)
setcap/suid só funciona com executáveis binários compilados, não com executáveis de script interpretados.