Linux Routing Quirks

Recently I have spent some time trying to mess up a routing table of Linux appliance to trick it into leaking out certain network traffic I was interested in. In theory it looked reasonably simple, but not quite so in practice. While trying to screw up the appliance I have learned a couple of new things about Linux networking:

1. Linux box (at least kernel <= 2.6.32) silently drops packets with source IP addresses equal to any local address of the box. It was not easy to find the reason for this. Tried to ask other people on the net, but everybody was puzzled and kept telling me to switch off my iptables... Finally, I have found this post: http://patchwork.ozlabs.org/patch/40152/ which suggests it will be possible to disable this feature via sysctl by changing value 'accept_local' parameter. It was almost a show-stopper... very annoying. I so got used to Linux not doing things it is not asked to.

2. Linux kernel implement Reverse Path filtering, something like Cisco IOS's URPF. Again, this piece of ... mmm ... useful functionality is on by default on my Ubuntu, and quite possibly other distributions. Luckily, this one is easy to disable with sysctl by setting net.ipv4.conf.*.rp_filter to 0.

3. On the positive side, I have found that it is possible to convince Linux to use another IP address when originating connections, useful if certain program does not have bind-to-address option. Assuming you want all traffic to be originated from 10.0.0.1 and your default gateway is 192.168.1.1:
1) create loopback interface with the desired source address
# ifconfig lo:0 10.0.0.1 netmask 255.255.255.255 up
2) replace your routing table entry with a custom one:
# route delete default
# ip route add default via 192.168.1.1 src 10.0.0.1
3) check if it has any effect
# ip route get to 8.8.8.8
Now locally generated traffic flowing towards the default gateway (except if emitted through raw sockets, for example by nmap -sS or hping) will be originated from 10.0.0.1. I guess it should be possible to apply this more selectively on per-process basis using iptable's fwmarks or something.

Comments

By accident I came across Linux docs describing rc_filter sysctl. The author refers to RFC 1812 - Requirements for IP Version 4 Routers, but in fact that RFC explicitly says this features MUST be switched off by default.

5.3.8 Source Address Validation (related to rp_filter sysctl)

A router SHOULD IMPLEMENT the ability to filter traffic based on a
comparison of the source address of a packet and the forwarding table
for a logical interface on which the packet was received. If this
filtering is enabled, the router MUST silently discard a packet if
the interface on which the packet was received is not the interface
on which a packet would be forwarded to reach the address contained
in the source address. In simpler terms, if a router wouldn't route
a packet containing this address through a particular interface, it
shouldn't believe the address if it appears as a source address in a
packet read from this interface.

If this feature is implemented, it MUST be disabled by default.

the rp-filter setting can affect machines with multiple ethernet cards on a single box. I have a box with two ethernet cards both attached to the same router. I found that packets from SOME machines (e.g. my router) were being dropped, by one of my interfaces according to their source address.
so:
10.0.0.1 mehome
10.0.0.8 iface1
10.0.0.12 iface2
10.0.0.20 otherbox
Packets from mehome to iface1 were being silently dropped
Packets from mehome to iface2 went through fine
packets from otherbox to iface1 went through fine.
packets from the outside world THROUGH mehome to iface1 went through fine
I could access iface1 from mehome if I used an ipv6 address.
the command:
sysctl net.ipv4.conf.all.rp_filter=0
solved the problem