Make WireGuard traffic go through iptables NAT just like LAN traffic?

With the objective of letting my phone access my home network on cellular, I have the following home network setup:

  1. OpenWRT router at 192.168.2.1,
  2. WireGuard on the router at 10.168.2.1/24 .
  3. For firewall zones, I have "wg" zone for WireGuard, and it has Input: accept, Output: accept, Forward: accept, Masquerading, MSS clamping, allowing forwarding to the "lan zone" and the "wan zone".

WireGuard setup is successful. I can connect to my home network on a cellular data network and visit my NAS and even channel Internet through this WireGuard instance.

The problem is that on the router, I have a set of iptables rules to circumvent a local Internet access restriction by using "shadowsocks" (http://shadowsocks.org/en/index.html) to proxy traffic to certain IPs through a server on the Internet. Basically, it has a "ss-redir" (https://manpages.debian.org/testing/shadowsocks-libev/ss-redir.1.en.html) command that allows you to use iptables NAT to transparently forward traffic via ss-redir.

The example iptables setup is on the manpage, but here's a simplified excerpt:

iptables -t nat -N SHADOWSOCKS
iptables -t nat -A SHADOWSOCKS -p tcp -d [RESTRICTED-CIDR] -j REDIRECT --to-ports [SS-REDIR-PORT]
iptables -t nat -A SHADOWSOCKS -p tcp -j RETURN
iptables -t nat -A PREROUTING -p tcp -j SHADOWSOCKS

The iptables rules worked for all LAN clients, but not WireGuard connected peers. I can verify that the WireGuard peers can access the Internet through the router. Just the iptables rules didn't apply to them.

How do I make the iptables setup work for WireGuard peers the same way as my LAN clients?

https://www.frozentux.net/iptables-tutorial/iptables-tutorial.html

Try the OUTPUT chain of NAT

REDIRECT
This target is only valid in the nat table, in the PREROUTING and OUTPUT chains, and user-defined chains which are only
called from those chains. It redirects the packet to the machine itself by changing the destination IP to the primary ad-
dress of the incoming interface (locally-generated packets are mapped to the localhost address, 127.0.0.1 for IPv4 and ::1
for IPv6, and packets arriving on interfaces that don't have an IP address configured are dropped).

   --to-ports port[-port]
          This specifies a destination port or range of ports to use: without this, the destination  port  is  never  altered.
          This is only valid if the rule also specifies one of the following protocols: tcp, udp, dccp or sctp.

   --random
          If option --random is used then port mapping will be randomized (kernel >= 2.6.22).

   IPv6 support available starting Linux kernels >= 3.7.

Hi Xinhui, thanks for the answer. But if you meant iptables -t nat -A OUTPUT -p tcp -j SHADOWSOCKS, I actually already have that for my router itself to go through shadowsocks. It works for the router but not WireGuard traffic.

Temporary disable all WireGuard firewall rules that you have created. Assign the wg interface to the LAN zone and restart the firewall.
Thus, all traffic coming from the WireGuard interface should be processed in the same way as the one coming from LAN.

1 Like

Thank you Pavel. However, reassigning the wg interface to LAN zone didn't change the behavior.

Although after some further investigation, I discovered that the culprit is not the iptables rules, but the DNS requests which should go into the WireGuard tunnel but didn't (which is another local restriction I have to circumvent).

Eventually I discovered this post: https://www.reddit.com/r/WireGuard/comments/ejjppr/wireguard_not_sending_dns_requests_through_tunnel/ , which says setting the Peer AllowedIPs to 0.0.0.0/0 will make DNS requests go through the tunnel.

Just for reference, my previous configuration for WireGuard was:

[Peer]
...
AllowedIPs=10.168.2.1/24, 192.168.2.1/24

And my new configuration is:

[Peer]
...
AllowedIPs=0.0.0.0/0

And now DNS requests are tunneled correctly, plus iptables rules are working.

Thank you both for your help.

2 Likes

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.