Change source IP address based on the system user

I would like to make a certain user have a specific source IP address. For this purpose, I added a secondary IP address to the network interface and tried to enforce the source IP using ip6tables and policy routing. Summary:

  • All IPv6-traffic gets routed via a IPv4 OpenVPN interface (tap0), the gateway is 2001:db8::1.
  • If the user is someuser, the source address must be 2001:db8::3
  • Otherwise, the source address is 2001:db8::2.

The default routes and addresses are set up as follows:

ip -6 addr add 2001:db8::2/112 dev tap0
ip -6 route add default via 2001:db8::1 src 2001:db8::2 dev tap0

For the someuser router, I mark all outgoing packets and attempt to route those packets with a different source address by using a separate routing table. These are set up with:

ip6tables -t mangle -A OUTPUT -m owner --uid-owner someuser -j MARK --set-mark 123
ip -6 rule add fwmark 123 table 1002
ip -6 addr add 2001:db8::3/112 dev tap0
ip -6 route add default via 2001:db8::1 src 2001:db8::3 dev tap0 table 1002

For some reason, all traffic still have the 2001:db8::2 source address. I can see that the ip6tables rule is hit, but the source IP is still wrong. Verified with NFLOG target + Wireshark and with curl ip.appspot.com.

Any ideas what I did wrong?


Solution 1:

Edit: misunderstood your post at first, rewrote the answer.

When you do routing you don't change packet content, you just choose the right interface to foward it to. So this won't change the source IP address you got. It will go to the right routing table and the right interface but that's all. To do this you need NAT.

So you need to masquerade in POSTROUTING, for instance with :

/sbin/ip6tables -A POSTROUTING -t nat -m mark --mark 123 -j SNAT --to-source 2001:db8::3