With a wireguard configuration provided from a VPN company:
How do you modify iptables
and wg0.conf
to route only traffic from the user vpn
trough wireguard's interface wg0, leaving all other traffic untouched?
reactions to comments and answers
When running suggested commands (by Hauke Laging) as PostUp
script in wg0.conf
results in the user sending traffic trough the wg0 interface but still unable to reach internet, why?
#!/bin/sh
# up.sh
iptables -t mangle -nvL OUTPUT | grep -q 0x2a ||
iptables -t mangle -A OUTPUT -m owner --uid-owner test -j MARK --set-mark 42
grep -q '^42 vpn$' /etc/iproute2/rt_tables ||
echo '42 vpn' >>/etc/iproute2/rt_tables
ip route show table vpn | grep -q default ||
ip route add default via 10.66.95.98 dev wg0 table vpn
ip rule | grep -q 0x2a ||
ip rule add fwmark 42 lookup vpn prio 42
The configuration wg0.conf
currently looks the following:
[Interface]
PrivateKey = <Hidden>
Address = 10.66.95.98/32,fc00:bbbb:bbbb:bb01::3:5f61/128
DNS = <DNS>
Table = off
PostUp = up.sh
#Following 2 lines added in attempt to allow local traffic
PreUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
PreDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o wg0 -j MASQUERADE
[Peer]
PublicKey = <Hidden>
AllowedIPs = 0.0.0.0/0,::0/0
Endpoint = 185.65.135.224:51820
ip route
returns following output:
default via 192.168.1.1 dev enp2s0 proto dhcp metric 100
169.254.0.0/16 dev enp2s0 scope link metric 1000
192.168.1.0/24 dev enp2s0 proto kernel scope link src 192.168.1.2 metric 100
ip route show table vpn
returns output
default via 10.66.95.98 dev wg0
ip rule
returns
0: from all lookup local
42: from all fwmark 0x2a lookup vpn
32766: from all lookup main
32767: from all lookup default
iptables -t nvL
returns
Chain PREROUTING (policy ACCEPT 5465 packets, 1114K bytes)
pkts bytes target prot opt in out source destination
2829 671K CONNMARK udp -- * * 0.0.0.0/0 0.0.0.0/0 /* wg-quick(8) rule for wg0 */ CONNMARK restore
Chain INPUT (policy ACCEPT 5450 packets, 1113K bytes)
pkts bytes target prot opt in out source destination
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
Chain OUTPUT (policy ACCEPT 5786 packets, 1203K bytes)
pkts bytes target prot opt in out source destination
961 1123K RETURN all -- * * 0.0.0.0/0 192.168.1.0/24 owner UID match 1002
261M 414G MARK all -- * * 0.0.0.0/0 0.0.0.0/0 owner UID match 1002 MARK set 0x2a
156 56019 RETURN all -- * * 0.0.0.0/0 192.168.1.0/24 owner UID match 1002
261M 414G MARK all -- * * 0.0.0.0/0 0.0.0.0/0 owner UID match 1002 MARK set 0x2a
77 48572 MARK all -- * * 0.0.0.0/0 0.0.0.0/0 owner UID match 1002 MARK set 0x2a
Chain POSTROUTING (policy ACCEPT 6507 packets, 1310K bytes)
pkts bytes target prot opt in out source destination
1281 209K CONNMARK udp -- * * 0.0.0.0/0 0.0.0.0/0 mark match 0xca6c /* wg-quick(8) rule for wg0 */ CONNMARK save
When running tcpdump -i wg0 -n
& ping google.se
following returns:
17:48:43.496475 IP 192.168.1.2.33044 > 185.65.135.224.51820: UDP, length 1184
indicating that packets indeed reach the wg0 interface. However, the ping doesn't yield any results.
110 packets transmitted, 0 received, 100% packet loss, time 111603ms
vpn
also into that namespace (for example, if he logs on). That has the advantage that this also works for multiple users, on the fly, or even for one user wanting to choose between those per application.