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:
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
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
My forwarding settings are
My wireguard config is
with wireguard configuration settings to have only 1 IP
Without wireguard service enabled, my routes are
Start wireguard split tunnel
When I start wireguard with above settings and configurations
which changes the routing to
However, when I run
I tried many things such as
-
-
- 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
Changing the routing to
All the network traffic goes with wireguard as expected
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.
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.