Not able to get wireguard split tunnel to work

Hello,


I tried for a quite some time to get it working, but unsuccessful so far. I hope to get some pointers here that will help me to learn more about FreeBSD, wireguard and networking, also the content might be helpful for others browsing the web for solutions. Note that I am very new to FreeBSD and networking, please forgive me for any erroneous use of terminology.


Problem statement

I have been trying to set-up a FreeBSD wireguard client to only work for part the the network traffic, however so far I am only able to route all traffic through the wireguard tunnel.

From my understanding this is called a split tunnel and can be achieved by having services bind to an internal IP address/interface and all traffic to and from that interface is routed through the wireguard tunnel (the AllowedIP attribute in the wireguard config file). The traffic not bound to the wireguard tunnel interface will follow the default route that is not wrapped in wireguard.


Example of what I want to achieve:

When a service / program such as curl would be called without binding it to a specfic address it would choose the default route and not use the wireguard tunnel:

Code:
curl icanhazip.com

<redacted my public IP>

When I want to route the traffic of the service through wireguard, I can do this by binding to the interface. Let's say we configure 10.77.222.111 to the wireguard tunnel as interface address, then

Code:
curl --interface 10.77.222.111 icanhazip.com

<redacted wireguard server public IP>


Set-up

Devices

- At home: FreeBSD 12.4 as client behind a modem-router(DHCP, but I fixed the IP for my ethernets MAC) combo device from my internet provider

- On the world wide web: the wireguard server is a payed service from a standard VPN provider, from their website I exported the pubic keys, private keys, public IP address and port, and interface address


My firewall config is as follows, to get it initially working I tried to make it as simple as possible

Code:
# pfctl -n -v -f /etc/pf.conf

ext_if = "igb0"

home_lan = "192.168.1.0/24"

wg_clients = "10.77.222.111/32"

nat on igb0 inet from 10.77.222.111 to any -> (igb0) round-robin


My forwarding settings are

Code:
# cat /etc/sysctl.conf | grep net

net.inet.ip.forwarding=1

# cat /etc/rc.conf | grep gate

gateway_enable="YES"


My wireguard config is

Code:
# cat /etc/rc.conf | grep wireguard

wireguard_interfaces="wgtunnel"

wireguard_enable="YES"

with wireguard configuration settings to have only 1 IP

Code:
# cat /usr/local/etc/wireguard/wgtunnel.conf

[Interface]

PrivateKey = <redacted priv key>

Address = 10.77.222.111/32

DNS = 1.1.1.1


[Peer]

PublicKey = <redacted pub key>

AllowedIPs = 10.77.222.111/32

Endpoint = <redacted public IP>:55555

Without wireguard service enabled, my routes are

Code:
# netstat -rnfinet

Routing tables


Internet:

Destination        Gateway            Flags     Netif Expire

default            192.168.1.1        UGS        igb0

127.0.0.1          link#3             UH          lo0

192.168.1.0/24     link#1             U          igb0

192.168.1.188      link#1             UHS         lo0


Start wireguard split tunnel

When I start wireguard with above settings and configurations

Code:
# service wireguard start

[#] ifconfig wg create name wgtunnel

[#] wg setconf wgtunnel /dev/stdin

[#] ifconfig wgtunnel inet 10.77.222.111/32 alias

[#] ifconfig wgtunnel mtu 1420

[#] ifconfig wgtunnel up

[#] resolvconf -a wgtunnel -x

[+] Backgrounding route monitor

which changes the routing to

Code:
# netstat -rnfinet

Routing tables


Internet:

Destination        Gateway            Flags     Netif Expire

default            192.168.1.1        UGS        igb0

10.77.222.111      link#5             UHS         lo0

10.77.222.111/32   link#5             U      wgtunnel

127.0.0.1          link#3             UH          lo0

192.168.1.0/24     link#1             U          igb0

192.168.1.188      link#1             UHS         lo0

However, when I run curl --interface 10.77.222.111 icanhazip.com it returns my home IP instead of the wireguard server IP.


I tried many things such as

- route add <redacted public IP> 10.77.222.111

- nat on $ext_if from { $wg_clients $home_lan } to any -> ($ext_if)

- Use a subnet for the AllowedIPs

- Play around with the pf and route configurations

but without luck. I am not able to route only part of the traffic through the wgtunnel interface. Hence, I am asking more experienced people for help here. Do you see what I am doing wrong? Is it at all possible what I am trying to achieve or should I fully change the method to achieve that? Do you have any suggestions what I can try to find what I am missing in my approach? I would like to apply and get back on any comments I get here!


Configuration tunneling all traffic through the wireguard tunnel

When I start wireguard with AllowedIPs = 0.0.0.0/0 under the [peer] attribute,

Code:
# service wireguard start

[#] ifconfig wg create name wgtunnel

[#] wg setconf wgtunnel /dev/stdin

[#] ifconfig wgtunnel inet 10.77.222.111/32 alias

[#] ifconfig wgtunnel mtu 1420

[#] ifconfig wgtunnel up

[#] resolvconf -a wgtunnel -x

[#] route -q -n add -inet 0.0.0.0/1 -interface wgtunnel

[#] route -q -n add -inet 128.0.0.0/1 -interface wgtunnel

[#] route -q -n delete -inet <redacted public IP>

[#] route -q -n add -inet <redacted public IP> -gateway 192.168.1.1

[+] Backgrounding route monitor

Changing the routing to

Code:
# netstat -rnfinet

Routing tables


Internet:

Destination        Gateway            Flags     Netif Expire

0.0.0.0/1          wgtunnel           US     wgtunnel

default            192.168.1.1        UGS        igb0

10.77.222.111      link#5             UHS         lo0

10.77.222.111/32   link#5             U      wgtunnel

127.0.0.1          link#3             UH          lo0

128.0.0.0/1        wgtunnel           US     wgtunnel

<redacted wg server public IP>     192.168.1.1        UGHS       igb0

192.168.1.0/24     link#1             U          igb0

192.168.1.188      link#1             UHS         lo0

All the network traffic goes with wireguard as expected

Code:
curl --interface 10.77.222.111 icanhazip.com

<redacted wireguard server public IP>

curl icanhazip.com

<redacted wireguard server public IP>

This shows, that authentication is going well and once I properly set-up the firewall and routing the actual connection should be OK.

What I think is going wrong is the route. FreeBSD route only looks at the destination IP, resulting in the default route, whereas in my method of implementation, I hope I can set rules for the route based on the origin IP.

I am looking forward to see if this example will result in any response and hope to be able to get the split tunneling to work with some help.
 
Back
Top