ip rule not respecting packet generation how to fix?
1
vote
1
answer
950
views
**Problem:**
ip rule built to route L4 traffic out a specific interface are not respected when packets are generated with different source address.
**Overview**
I want to generate packets with a different source address than the host's address's. To accomplish this I am using python's package Scapy. Note: my goal is to send to send DNS traffic, however I was not able to find a simple solution that let me spoof the source address in DNS requests, so I am just generating a UDP packet with src and dst address at port 53, believe this still works as I am only testing L3 and L4, not the actual DNS protocol at the moment.
Here is my script
#!/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()
Before running the script, here is what my route table looks like:
# 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
Here are the ip interfaces
# 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
When I run the script with ./packet-gen.py "10.0.26.122" "10.0.26.123"
it works.
This is because I have not yet built my ip rule / separate routing table. I perform a tcpdump at the host (10.0.26.122) and on the far end host (10.0.26.123), and I see the UDP packet being sent. I also tested with dig www.google.com @10.0.26.123
and see an actual DNS request being performed and get a response.
Now the problem.
I want to remove the route entry in the main table, then only route based on the port number. To do this I run the following to first remove the route entry to 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
The entry is removed. If I run my script again it does not work. The dig request also fails. This is expected as there is no L3 route in the main kernel routing table.
To route on L4 I first created a new ip route table to send all traffic via ens224:
# ip route add table 53 0.0.0.0/0 dev ens224
Then I create an ip rule to capture any traffic using port 53, and send out my custom table 53.
# ip rule add ipproto udp dport 53 lookup 53
I also created a special sysctl rule for rp_filter too loosen strict reverse path forwarding rules
# sysctl -w "net.ipv4.conf.ens224.rp_filter=2"
To check my work I see the following:
# 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
The last command shows that by default if communication is not dns, use the default route.
To test this I first try to ping 10.0.26.123. It fails which is expected.
Now I try to perform a dig request dig www.google.com @10.0.26.123
, and it works. The dig request hits the ip rule before going to the main table and is routed appropriately. I see the traffic reach the service with tcpdump (10.0.26.123), and coming from my host (10.0.26.122).
Now I try running my scapy script again, and nothing.
Even with the same source address as the host, nothing in tcpdump on my host or the server. I tried changing the source address, no change, nothing.
If I add back the main L3 route for 10.0.26.0/24 in the main table, the scapy script works again.
What am I missing here? Why wont my generate traffic respect the ip rule sets I created?
Asked by Dave
(700 rep)
Oct 28, 2021, 04:04 PM
Last activity: Oct 28, 2021, 07:54 PM
Last activity: Oct 28, 2021, 07:54 PM