I am trying to forward network traffic through a wireguard VPN into a VM running on another host. All that - while preserving original source IP address in order to achieve transparent proxying. Both servers are hosted in different datacenters. This is my network setup:

Network Diagram

Network is "Proxy" machine forwards network using DNAT:

iptables -t nat -A PREROUTING  -i eth0 -p tcp -m multiport --dport $ports -j DNAT --to 192.168.122.100
ip route add 192.168.122.100 dev wg1

I can access VM IP address from ssh session on a proxy machine by querying 192.168.122.100 directly. If i try to access these forwarded ports from external network by querying y.y.y.y IP address - traffic stops on Host machine, nat table / PREROUTING step.

TRACE of packet that fails to be delivered (z.z.z.z would be my home IP address). Trace is from the "Host" machine:

raw:PREROUTING:policy:2 IN=wg1 OUT= MAC= SRC=z.z.z.z DST=192.168.122.100 LEN=60 TOS=0x00 PREC=0x00 TTL=55 ID=60652 DF PROTO=TCP SPT=34744 DPT=8080 SEQ=2330378731 ACK=0 WINDOW=29200 RES=0x00 CWR ECE SYN URGP=0 OPT 
mangle:PREROUTING:rule:1 IN=wg1 OUT= MAC= SRC=z.z.z.z DST=192.168.122.100 LEN=60 TOS=0x00 PREC=0x00 TTL=55 ID=60652 DF PROTO=TCP SPT=34744 DPT=8080 SEQ=2330378731 ACK=0 WINDOW=29200 RES=0x00 CWR ECE SYN URGP=0 OPT 
mangle:PREROUTING-CUSTOM-BACK:rule:1 IN=wg1 OUT= MAC= SRC=z.z.z.z DST=192.168.122.100 LEN=60 TOS=0x00 PREC=0x00 TTL=55 ID=60652 DF PROTO=TCP SPT=34744 DPT=8080 SEQ=2330378731 ACK=0 WINDOW=29200 RES=0x00 CWR ECE SYN URGP=0 OPT 
mangle:PREROUTING-CUSTOM-BACK:return:3 IN=wg1 OUT= MAC= SRC=z.z.z.z DST=192.168.122.100 LEN=60 TOS=0x00 PREC=0x00 TTL=55 ID=60652 DF PROTO=TCP SPT=34744 DPT=8080 SEQ=2330378731 ACK=0 WINDOW=29200 RES=0x00 CWR ECE SYN URGP=0 OPT 
mangle:PREROUTING:policy:2 IN=wg1 OUT= MAC= SRC=z.z.z.z DST=192.168.122.100 LEN=60 TOS=0x00 PREC=0x00 TTL=55 ID=60652 DF PROTO=TCP SPT=34744 DPT=8080 SEQ=2330378731 ACK=0 WINDOW=29200 RES=0x00 CWR ECE SYN URGP=0 OPT 
nat:PREROUTING:rule:1 IN=wg1 OUT= MAC= SRC=z.z.z.z DST=192.168.122.100 LEN=60 TOS=0x00 PREC=0x00 TTL=55 ID=60652 DF PROTO=TCP SPT=34744 DPT=8080 SEQ=2330378731 ACK=0 WINDOW=29200 RES=0x00 CWR ECE SYN URGP=0 OPT 
nat:PREROUTING-CUSTOM-FRONT:return:3 IN=wg1 OUT= MAC= SRC=z.z.z.z DST=192.168.122.100 LEN=60 TOS=0x00 PREC=0x00 TTL=55 ID=60652 DF PROTO=TCP SPT=34744 DPT=8080 SEQ=2330378731 ACK=0 WINDOW=29200 RES=0x00 CWR ECE SYN URGP=0 OPT 
nat:PREROUTING:policy:2 IN=wg1 OUT= MAC= SRC=z.z.z.z DST=192.168.122.100 LEN=60 TOS=0x00 PREC=0x00 TTL=55 ID=60652 DF PROTO=TCP SPT=34744 DPT=8080 SEQ=2330378731 ACK=0 WINDOW=29200 RES=0x00 CWR ECE SYN URGP=0 OPT 

nat:PREROUTING:policy:2 executes default ACCEPT policy here.

A working packet trace (on the Host machine) when i try to access 192.168.122.100 directly:

raw:PREROUTING:policy:2 IN=wg1 OUT= MAC= SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=41 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT
mangle:PREROUTING:rule:1 IN=wg1 OUT= MAC= SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=41 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT 
mangle:PREROUTING-CUSTOM-BACK:rule:1 IN=wg1 OUT= MAC= SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=41 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT
mangle:PREROUTING-CUSTOM-BACK:return:3 IN=wg1 OUT= MAC= SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=41 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT
mangle:PREROUTING:policy:2 IN=wg1 OUT= MAC= SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=41 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT
nat:PREROUTING:rule:1 IN=wg1 OUT= MAC= SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=41 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT
nat:PREROUTING-CUSTOM-FRONT:return:3 IN=wg1 OUT= MAC= SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=41 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT
nat:PREROUTING:policy:2 IN=wg1 OUT= MAC= SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=41 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT
mangle:FORWARD:policy:1 IN=wg1 OUT=virbr0 MAC= SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=40 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT
filter:FORWARD:rule:1 IN=wg1 OUT=virbr0 MAC= SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=40 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT
filter:FORWARD-CUSTOM-FRONT:rule:1 IN=wg1 OUT=virbr0 MAC= SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=40 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT
mangle:POSTROUTING:policy:2 IN= OUT=virbr0 SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=40 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT
nat:POSTROUTING:rule:1 IN= OUT=virbr0 SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=40 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT
nat:POSTROUTING-CUSTOM-FRONT:return:1 IN= OUT=virbr0 SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=40 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT
nat:POSTROUTING:policy:7 IN= OUT=virbr0 SRC=10.1.0.101 DST=192.168.122.100 LEN=44 TOS=0x00 PREC=0x00 TTL=40 ID=36489 PROTO=TCP SPT=52189 DPT=8080 SEQ=1361865945 ACK=0 WINDOW=1024 RES=0x00 SYN URGP=0 OPT

As you can see nat:PREROUTING:policy:2 is still executed and after that packet is routed to a VM. The only difference really is the source IP address.


My question is this: does linux networking stack drop packets that come from LAN network device but have non-lan source address? Is there any way to work this around and have packet routed further?

Turns out linux networking stack indeed dropped these packets and for very good purpose. Networking stack does something called "Reverse Path Filtering". Packets coming in from network device have a source ip that would not be routed through the same device would be dropped. Under normal circumstances such packets are not valid or could mean malicious intent. However if you know what you are doing it is possible to disable this behaviour:

echo 0 >/proc/sys/net/ipv4/conf/all/rp_filter   # blanket-disable for all interfaces
echo 1 >/proc/sys/net/ipv4/conf/eth0/rp_filter  # enable for external network device just to be safe

Now packets are forwarded further and transparent proxying can be achieved.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.