4

I'm trying to configure a Wireguard client currently set to route all traffic through Wireguard to only route one network interface through Wireguard.

Ex: The Client has both wlan0 and eth0 interfaces and I would like to route traffic from eth0 to wireguard, having wlan0 (and all of its traffic) accessible to the internet and not routed.

I do not want to use the IP address as a way to adjust the traffic as the client (which is a SFF PC) changes locations and networks and would require re-configuration given the newly assigned IP address.

I use docker containers on the client that are configured to use the different network interfaces for different tasks and would like the traffic for the interfaces split between the eth0 and wlan0 interfaces.

Ex: I have a web server with a container control panel which is accessible by the IP address/ port combination exposed by the eth0 interface (192.168.0.**:3100).

I use this in combination with Wireguard while I'm remote to control and update the web server for maintenance (through the ip address assigned by the client through Wireguard (10.68.9.*:3100).

The same server uses the wlan0 interface to serve the actual site to the internet -- given the latency of the eth0 interface through Wireguard would be bad for traffic to and from the site.

Both server and control panel communicate through the local network of the computer.

Everytime Wireguard is enabled for the client, wlan0 is knocked out.

I've tried writing PostUp/Down rules that explicitly route traffic from eth0 to Wireguard and leave wlan0 alone, so that I can access the control panel of the application while still having it accessible over wlan0, but they didn't seem to work.

Here were my rules for postUp -- same as postDown aside from the -I / -D

iptables -t nat -I POSTROUTING 1 -s <ip4-address> -o eth0 -j MASQUERADE;
ip6tables -t nat -I POSTROUTING 1 -s <ip6-address> -o eth0 -j MASQUERADE;
iptables -I INPUT 1 -i wg0 -j ACCEPT;
iptables -I FORWARD 1 -i eth0 -o wg0 -j ACCEPT;
iptables -I FORWARD 1 -i wg0 -o eth0 -j ACCEPT;
iptables -I INPUT 1 -i eth0 -p udp --dport 51820 -j ACCEPT

Here's the output of ip route on my current network

default via 192.168.0.1 dev eth0 proto dhcp metric 100 
default via 192.168.0.1 dev wlan0 proto dhcp metric 600 
169.254.0.0/16 dev eth0 scope link metric 1000 
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 
192.168.0.0/24 dev eth0 proto kernel scope link src 192.168.0.192 metric 100 
192.168.0.0/24 dev wlan0 proto kernel scope link src 192.168.0.105 metric 600

Basically: All eth0 traffic through Wireguard, all wlan0 traffic not.

1 Answers1

6

I see 3 parts to this question:

  1. Allow remote access to host services through WireGuard
  2. Default route preference for one network interface
  3. Route certain traffic through the other network interface

To get to 3, you have to fix up 1 and 2.

1. Allow remote access to host services through WireGuard

You didn't include your WireGuard configuration in your question, but it sounds like the WireGuard config for the machine in question (I'm going to call it Host L for local) looks something like this:

# wg0 on Host L
[Interface]
PrivateKey = ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBFA=
Address = 10.68.9.2/32
ListenPort = 51820

[Peer] PublicKey = /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU= AllowedIPs = 0.0.0.0/0

If you set the config for a peer to AllowedIPs = 0.0.0.0/0, when wg-quick starts up the wg0 interface, it's going to set up some routing rules on the host to route all traffic through wg0 (except for any non-default routes you have explicitly specified in your main routing table). This will appear to "knock out" remote inbound access except through WireGuard.

In your scenario, it sounds like the only traffic you want going through wg0 on Host L is the traffic from a specific remote host (or several similar remote hosts), connected directly to the other end of the WireGuard tunnel; I'll call this Host R (for remote). Change the AllowedIPs setting on Host L for Host R to use just the WireGuard IP address of that remote host.

For example, if the Host R's WireGuard config is this:

# wg0 on Host R
[Interface]
PrivateKey = AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEE=
Address = 10.68.9.1/32

connection to Host L

[Peer] PublicKey = fE/wdxzl0klVp/IR8UcaoGUMjqaWi3jAd7KzHKFS6Ds= AllowedIPs = 10.68.9.2/32 Endpoint = 203.0.113.2:51820

Change the AllowedIPs setting on Host L to use 10.68.9.1/32 for the peer representing Host R:

# wg0 on Host L
[Interface]
PrivateKey = ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBFA=
Address = 10.68.9.2/32
ListenPort = 51820

connection to Host R

[Peer] PublicKey = /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU= AllowedIPs = 10.68.9.1/32

Then get rid of all the iptables rules you mentioned in your question on Host L execpt for these two:

iptables -I INPUT 1 -i wg0 -j ACCEPT
iptables -I INPUT 1 -i eth0 -p udp --dport 51820 -j ACCEPT

Restart WireGuard after making the change to its config, and now you should be able to access any of the services running on Host L from Host R using Host L's WireGuard IP address. For example, if you have a web server running at port 3100 on Host L, you should be able to access it from Host R as http://10.68.9.2:3100.

2. Default route preference for one network interface

Assuming that the Endpoint IP address in Host R's WireGuard configuration (203.0.113.2 above) is the IP address of a router that forwards UDP port 51820 to 192.168.0.192, the IP address of Host L's eth0 interface, you don't need to do anything more to ensure that inbound connections using WireGuard go through Host L's eth0 interface (or that inbound connections to Host L using the IP address of wlan0 on Host L, 192.168.0.105, use the wlan0 interface).

However, because the metric on interface eth0 is 100, and the metric on wlan0 is 600, for any connections Host L initiates outbound, Host L will try to use eth0 over wlan0. If you want to reverse that, and make wlan0 preferred for outbound connections, you need to reconfigure one or both interfaces to make wlan0's metric lower than eth0's. These answers cover a few different options for doing this:

3. Route certain traffic through the other network interface

If you change the metric values of eth0 and/or wlan0 on Host L to use wlan0 by default for outbound connections, then you need to make some routing changes if you want to ensure Host L will route outbound WireGuard connections through eth0.

If Host R has a static IP address, you can just add a simple route for it to Host L's main routing table. Say Host R has a static IP address of 198.51.100.1. You could then just add this route on Host L:

ip route add 198.51.100.1/32 via 192.168.0.1 dev eth0

However, if Host R doesn't have a fixed IP address (or fixed pool or range of addresses), you'll have to set up some policy routing for it. First add a custom routing table on Host L (number 123, or some other table number not in use) with the default route set for eth0:

ip route add default via 192.168.0.1 dev eth0 table 123

Then add a policy rule to use this new table for any packets marked 0x7b (or some other mark value you want to use instead):

ip rule add fwmark 0x7b table 123

Finally, configure WireGuard on Host L to mark packets emitted by WireGuard with 0x7b (or whatever mark value you used for the above policy rule):

# wg0 on Host L
[Interface]
PrivateKey = ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBFA=
Address = 10.68.9.2/32
ListenPort = 51820
FwMark = 0x7b

[Peer] PublicKey = /TOE4TKtAqVsePRVR+5AA43HkAK5DSntkOCO7nYq5xU= AllowedIPs = 10.68.9.1/32

Restart WireGuard. Host L will now always send WireGuard traffic through its eth0 interface.