Problema: A regra IP criada para rotear o tráfego L4 para fora de uma interface específica não é respeitada quando os pacotes são gerados com endereços de origem diferentes.
Visão geral Quero gerar pacotes com um endereço de origem diferente do endereço do host. Para fazer isso, estou usando o pacote Scapy do python. Nota: meu objetivo é enviar para enviar tráfego DNS, porém não consegui encontrar uma solução simples que me permitisse falsificar o endereço de origem nas solicitações DNS, então estou apenas gerando um pacote UDP com endereço src e dst na porta 53, acredito que isso ainda funciona, pois estou testando apenas L3 e L4, não o protocolo DNS real no momento. Aqui está meu roteiro
#!/usr/bin/python3
# The following is designed to generate a packet with a different source address
import sys
from scapy.all import *
def main():
S = "10.0.26.122" # spoofed source IP address
D = "10.0.26.123" # destination IP address
SP = 53 # source port
DP = 53 # destination port
payload = "This is a fake message" # packet payload
spoofed_packet = IP(src=S, dst=D) / UDP(sport=53, dport=53) / payload
send(spoofed_packet)
#Entry point
main()
Antes de executar o script, esta é a aparência da minha tabela de rotas:
# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.104.8.1 0.0.0.0 UG 101 0 0 ens192
10.0.21.0 0.0.0.0 255.255.255.0 U 104 0 0 ens256
10.0.26.0 0.0.0.0 255.255.255.0 U 0 0 0 ens224
10.0.27.0 0.0.0.0 255.255.255.0 U 102 0 0 ens193
10.0.28.0 10.0.29.1 255.255.255.0 UG 100 0 0 ens161
10.0.29.0 0.0.0.0 255.255.255.0 U 100 0 0 ens161
10.104.8.0 0.0.0.0 255.255.255.0 U 101 0 0 ens192
10.212.134.0 10.104.8.1 255.255.255.0 UG 101 0 0 ens192
192.168.122.0 0.0.0.0 255.255.255.0 U 0 0 0 virbr0
Aqui estão as interfaces IP
# ip -br a
lo UNKNOWN 127.0.0.1/8
ens161 UP 10.0.29.122/24
ens192 UP 10.104.8.122/24
ens193 UP 10.0.27.122/24
ens224 UP 10.0.26.122/24
ens256 UP 10.0.21.122/24
virbr0 DOWN 192.168.122.1/24
virbr0-nic DOWN
ip_vti0@NONE DOWN
Quando executo o script, ./packet-gen.py "10.0.26.122" "10.0.26.123"
ele funciona. Isso ocorre porque ainda não construí minha regra de IP/tabela de roteamento separada. Eu executo um tcpdump no host (10.0.26.122) e no host extremo (10.0.26.123) e vejo o pacote UDP sendo enviado. Também testei dig www.google.com @10.0.26.123
e vi uma solicitação de DNS real sendo executada e obtive uma resposta.
Agora o problema. Quero remover a entrada da rota na tabela principal e, em seguida, rotear apenas com base no número da porta. Para fazer isso, executo o seguinte para primeiro remover a entrada da rota para 10.0.26.0/24.
# ip route del 10.0.26.0/24 dev ens224
# route -n
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
0.0.0.0 10.104.8.1 0.0.0.0 UG 101 0 0 ens192
10.0.21.0 0.0.0.0 255.255.255.0 U 104 0 0 ens256
10.0.27.0 0.0.0.0 255.255.255.0 U 102 0 0 ens193
10.0.28.0 10.0.29.1 255.255.255.0 UG 100 0 0 ens161
10.0.29.0 0.0.0.0 255.255.255.0 U 100 0 0 ens161
10.104.8.0 0.0.0.0 255.255.255.0 U 101 0 0 ens192
10.212.134.0 10.104.8.1 255.255.255.0 UG 101 0 0 ens192
192.168.122.0 0.0.0.0 255.255.255.0 U 0 0 0 virbr0
A entrada é removida. Se eu executar meu script novamente, ele não funcionará. A solicitação dig também falha. Isto é esperado porque não há rota L3 na tabela de roteamento principal do kernel.
Para rotear em L4, primeiro criei uma nova tabela de rotas IP para enviar todo o tráfego via ens224:
# ip route add table 53 0.0.0.0/0 dev ens224
Em seguida, crio uma regra de IP para capturar qualquer tráfego usando a porta 53 e envio minha tabela personalizada 53.
# ip rule add ipproto udp dport 53 lookup 53
Eu também criei uma regra sysctl especial para rp_filter para afrouxar regras estritas de encaminhamento de caminho reverso
# sysctl -w "net.ipv4.conf.ens224.rp_filter=2"
Para verificar meu trabalho, vejo o seguinte:
# ip route list table 53
default dev ens224 scope link
# ip rule list
0: from all lookup local
32765: from all ipproto udp dport 53 lookup 53
32766: from all lookup main
32767: from all lookup default
# ip route get 10.0.26.123 ipproto udp dport 53
10.0.26.123 dev ens224 table 53 src 10.0.26.122 uid 0
cache
# ip route get 10.0.26.123
10.0.26.123 via 10.104.8.1 dev ens192 src 10.104.8.122 uid 0
cache
O último comando mostra que por padrão se a comunicação não for DNS, use a rota padrão.
Para testar isso, primeiro tento executar ping em 10.0.26.123. Ele falha, o que é esperado. Agora tento realizar uma solicitação dig dig www.google.com @10.0.26.123
e funciona. A solicitação dig atinge a regra ip antes de ir para a tabela principal e é roteada adequadamente. Vejo o tráfego chegar ao serviço com tcpdump (10.0.26.123) e vindo do meu host (10.0.26.122).
Agora tento executar meu script scapy novamente e nada. Mesmo com o mesmo endereço de origem do host, nada no tcpdump no meu host ou no servidor. Tentei alterar o endereço de origem, sem alteração, nada. Se eu adicionar novamente a rota L3 principal para 10.0.26.0/24 na tabela principal, o script scapy funcionará novamente. O que estou perdendo aqui? Por que meu tráfego gerado não respeita os conjuntos de regras de IP que criei?
Responder1
O Scapy não usa o mecanismo de roteamento do SO, mas usa sua própria tabela de roteamento ( conf.route
objeto), sincronizada a partir da tabela de roteamento do SO quando o Scapy é iniciado (ou sempre que conf.route.resync()
o método é chamado).
O mecanismo de roteamento do Scapy não oferece suporte ao roteamento de origem, o que explica o comportamento que você descreve.