This config allows the usage of a dedicated interface from wireguard (or openvpn or whatever) to be used by programs without tunneling all internet traffic to it (default gateway). The program must be able to bind to a specific network interface (the one from wireguard or openvpn). Since only one default route can exist, we use the fact that with iproute2 it is possible to have muliple routing tables where one default route for each table is allowed. The findigns are based on the article here: https://www.thomas-krenn.com/de/wiki/Zwei_Default_Gateways_in_einem_System
Pre-defined (rather "named") tables can be found in /etc/iproute2/rt_tables. This file holds a mapping between the id and the name (separated by whitespace). In commands these names can be used instead of the id but this is not required but might be easier to remember what table is used for what connection. Pretty much any free id can be used. If you look closely when using the wireguard default routing, you can see table 51821
in the output which means that the table with id 51821
is used automatically.
The most important part of the wireguard config is the AllowedIPs
bit, it MUST be 0.0.0.0/0
(plus ipv6 decl if needed) because this also acts as a packet filter inside wireguard!
However, by using this, wireguard assumes that you want to route everything ands sets up a default gateway for all you traffic. Therefore, Table = off
is used to prevent automatic creation of routs and rules.
The most crucial part is the PostUp
where we now can insert our own routs and rules. We pretty much want the following, assuming that the Address
is 10.69.159.188
and using routing table with id 1007:
ip route add default dev %i table 1007
ip route add 10.69.159.188/32 dev %i src 10.69.159.188 table 1007
ip rule add from 10.69.159.188/32 table 1007
ip rule add to 10.69.159.188/32 table 1007
I don't really know how or why this works but it does for me. What I could not find out is, if there is a placeholder that holds the ip address which would make it a lot more convenient than replacing the ipaddress everywhere. %i
holds the name of the interface, e.g. wg0
.
To add this to the wireguard config, it has to be put in PostUp
but these are multiple commands, so we just put them in one long line separated by ;
.
The program that should use the interface must den bind itself to the interface. Ping for example has the -I
flag accepting the ip address of the interface. In our example this would be ping -I 10.69.159.188 8.8.8.8
resulting in pinging 8.8.8.8 over the wireguard interface instead of the default one. For curl this can be achieved by curl --interface 10.69.159.188 http://myexternalip.com/raw
.