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 220.127.116.11
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.