If you need to SNAT local processes over a specific interface(for example a tunnel) there are a few things you have to do and this artical describes the required steps.

= Sysctls =
net.ipv4.ip_forward=1
net.ipv4.conf.default.rp_filter=0
net.ipv4.conf.all.rp_filter=0
More specific, you need to disable the rp_filter over the interface you are receiving the traffic. For tunnels this usually is tun[0-9]
net.ipv4.conf.tun0.rp_filter=0

Note: ”’Without the above changes, traffic goes out the interface and comes back to the machine, but it is NEVER delivered to the process. ”’

= Routing =
You need a separate routing table. I will be using the sg table with id 100:
root@enot:~# cat /etc/iproute2/rt_tables
#
# reserved values
#
255 local
254 main
253 default
100 sg
0 unspec
In this table you have to have default gw via the tunnel device and routing to the ip that is sending the traffic:
root@enot:~# ip r l t sg
default via 10.21.0.10 dev tun0
10.21.0.0/24 dev tun0 scope link src 10.21.0.5

Finally you have to route traffic via this table. Since we have to select specific processes and not the whole server, we will use FWMARKs to achieve that.
root@enot:~# ip ru a fwmark 10 t sg
The result should be something like this:
root@enot:~# ip ru l
0: from all lookup local
32765: from all fwmark 0xa lookup sg
32766: from all lookup main
32767: from all lookup default

= iptables =
Now in order to select certain processes we can either use a specific pid(this is supported with the “-m owner –pid-owner PID” option but its available only with newer iptables.)
iptables -t mangle -A OUTPUT -j MARK --set-mark 10 -m owner --pid-owner 1012
Where 1012 is the pid of the process who’s traffic we want to mark and put inside the sg routing tables.

On older linuxes we can use “-m owner –uid-owner username”.
iptables -t mangle -A OUTPUT -j MARK --set-mark 10 -m owner --uid-owner site
Where “site” is the actual linux username. Now all outgoing traffic of processes started by user site will be marked with mark 10 and thus go trough the sg routing table.

You could also use the “-m owner –gid-owner groupname” option for a whole group.
iptables -t mangle -A OUTPUT -j MARK --set-mark 10 -m owner --gid-owner users

Note: ”’The above rules are in the mangle table, so the traffic can be marked before a routing decision is taken. The rules are valid in the nat table, but does not work there!”’

Now the final step is to SNAT the traffic to the IP form the tun interface:
root@enot:~# ip a l tun0
3: tun0: mtu 1500 qdisc pfifo_fast state UNKNOWN qlen 500
link/[65534]
inet 10.21.0.5/24 scope global tun0
valid_lft forever preferred_lft forever

Add the NAT rule:
iptables -t nat -A POSTROUTING -j SNAT -o tun0 --to 10.21.0.5

We need the SNAT, because otherwise the traffic may leave our machine via the tun0 interface but with wrong source IP and obviously, never come back to us.


Comments are closed.

Posted by HackMan
Dated: 13th December 2019
Filled Under: Uncategorized