Title: Full WireGuard setup with OpenBSD
       Author: Solène
       Date: 09 October 2021
       Tags: openbsd wireguard vpn
       Description: 
       
       # Introduction
       
       We want all our network traffic to go through a WireGuard VPN tunnel
       automatically, both WireGuard client and server are running OpenBSD,
       how to do that?  While I thought it was simple at first, it soon became
       clear that the "default" part of the problem was not easy to solve,
       fortunately there are solutions.
       
       This guide should work from OpenBSD 6.9.
       
 (HTM) pf.conf man page about NAT
 (HTM) WireGuard interface man page
 (HTM) ifconfig man page, WireGuard section
       
       # Setup
       
       For this setup I assume we have a server running OpenBSD with a public
       IP address (1.2.3.4 for the example) and an OpenBSD computer with
       Internet connectivity.
       
       Because you want to use the WireGuard tunnel as the default route, you
       can't define a default route through WireGuard as this, that would
       prevent our interface to reach the WireGuard endpoint to make the
       tunnel working.  We could play with the routing table by deleting the
       default route found on the interface, create a new route to reach the
       WireGuard server and then create a default route through WireGuard, but
       the whole process is fragile and there is no right place to trigger a
       script doing this.
       
       Instead, you can assign the network interface used to access the
       Internet to the rdomain 1, configure WireGuard to reach its remote peer
       through rdomain 1 and create a default route through WireGuard on the
       rdomain 0.  Quick explanation about rdomain: they are different routing
       tables, default is rdomain 0 but you can create new routing tables and
       run commands using a specific routing table with "route -T 1 exec ping
       perso.pw" to make a ping through rdomain 1.
       
       
       ```network diagram in text
       
           +-------------+
           |   server    | wg0: 192.168.10.1
           |             |---------------+
           +-------------+               |
                  | public IP            |
                  | 1.2.3.4              |
                  |                      |
                  |                      |
           /\/\/\/\/\/\/\                |WireGuard
           |  internet  |                |VPN
           \/\/\/\/\/\/\/                |
                  |                      |
                  |                      |
                  |rdomain 1             |
           +-------------+               |
           |   computer  |---------------+
           +-------------+ wg0: 192.168.10.2
                           rdomain 0 (default)
       
       ```
       
       # Configuration
       
       The configuration process will be done in this order:
       
       1. create the WireGuard interface on your computer to get its public
       key
       2. create the WireGuard interface on the server to get its public key
       3. configure PF to enable NAT and enable IP forwarding
       4. reconfigure computer's WireGuard tunnel using server's public key
       5. time to test the tunnel
       6. make it default route
       
       Our WireGuard server will accept connections on address 1.2.3.4 at the
       UDP port 4433, we will use the network 192.168.10.0/24 for the VPN, the
       server IP on WireGuard will be 192.168.10.1 and this will be our future
       default route.
       
       ## On your computer
       
       We will make a simple script to generate the configuration file, you
       can easily understand what is being done.  Replace "1.2.3.4 4433" by
       your IP and UDP port to match your setup.
       
       ```shell script
       PRIVKEY=$(openssl rand -base64 32)
       cat <<EOF > /etc/hostname.wg0
       wgkey $PRIVKEY
       wgpeer wgendpoint 1.2.3.4 4433 wgaip 0.0.0.0/0
       inet 192.168.10.2/24
       up
       EOF
       
       # start interface so you can get the public key
       # we should have an error here, this is normal
       sh /etc/netstart wg0
       
       PUBKEY=$(ifconfig wg0 | grep 'wgpubkey' | cut -d ' ' -f 2)
       echo "You need $PUBKEY to setup the remote peer"
       ```
       
       ## On the server
       
       ### WireGuard
       
       Like we did on the computer, we will use a script to configure the
       server.  It's important to get the PUBKEY displayed in the previous
       step.
       
       ```shell script
       PUBKEY=PASTE_PUBKEY_HERE
       PRIVKEY=$(openssl rand -base64 32)
       
       cat <<EOF > /etc/hostname.wg0
       wgkey $PRIVKEY
       wgpeer $PUBKEY wgaip 192.168.10.0/24
       inet 192.168.10.1/24
       wgport 4433
       up
       EOF
       
       # start interface so you can get the public key
       # we should have an error here, this is normal
       sh /etc/netstart wg0
       
       PUBKEY=$(ifconfig wg0 | grep 'wgpubkey' | cut -d ' ' -f 2)
       echo "You need $PUBKEY to setup the local peer"
       ```
       
       Keep the public key for next step.
       
       ## Firewall
       
       You want to enable NAT so you can reach the Internet through the server
       using WireGuard, edit /etc/pf.conf to add the following line (after the
       skip lines):
       
       ```pf.conf configuration line
       pass out quick on egress from wg0:network to any nat-to (egress)
       ```
       
       Reload with "pfctl -f /etc/pf.conf".
       
       NOTE: if you block all incoming traffic by default, you need to open
       UDP port 4433.  You will also need to either skip firewall on wg0 or
       configure PF to open what you need.  This is beyond the scope of this
       guide.
       
       ## IP forwarding
       
       We need to enable IP forwarding because we will pass packets from an
       interface to another, this is done with "sysctl
       net.inet.ip.forwarding=1" as root.  To make it persistent across
       reboot, add "net.inet.ip.forwarding=1" to /etc/sysctl.conf (you may
       have to create the file).
       
       From now, the server should be ready.
       
       ## On your computer
       
       Edit /etc/hostname.wg0 and paste the public key between "wgpeer" and
       "wgaip", the public key is wgpeer's parameter.  Then run "sh
       /etc/netstart wg0" to reconfigure your wg0 tunnel.
       
       After this step, you should be able to ping 192.168.10.1 from your
       computer (and 192.168.10.2 from the server).  If not, please double
       check the WireGuard and PF configurations on both side.
       
       ## Default route
       
       This simple setup for the default route will truly make WireGuard your
       default route.  You have to understand services listening on all
       interfaces will only attach to WireGuard interface because it's the
       only address in rdomain 0, if needed you can use a specific routing
       table for a service as explained in rc.d man page.
       
       Replace the line "up" with the following:
       
       ```hostname.if configuration
       wgrtable 1
       up
       !route add -net default 192.168.10.1
       ```
       
       Your configuration file should look like this:
       
       ```hostname.if configuration example
       wgkey YOUR_KEY
       wgpeer YOUR_PUBKEY wgendpoint REMOTE_IP 4433 wgaip 0.0.0.0/0
       inet 192.168.10.2/24
       wgrtable 1
       up
       !route add -net default 192.168.10.1
       ```
       
       Now, add "rdomain 1" to your network interface used to reach the
       Internet, in my setup it's /etc/hostname.iwn0 and it looks like this.
       
       ```hostname.if example
       join network wpakey superprivatekey
       join home wpakey notsuperprivatekey
       rdomain 1
       up
       autoconf
       ```
       
       Now, you can restart network with "sh /etc/netstart" and all the
       network should pass through the WireGuard tunnel.
       
       # Handling DNS
       
       Because you may use a nameserver in /etc/resolv.conf that was provided
       by your local network, it's not reachable anymore.  I highly recommend
       to use unwind (in every case anyway) to have a local resolver, or
       modify /etc/resolv.conf to use a public resolver.
       
       unwind can be enabled with "rcctl enable unwind" and "rcctl start
       unwind", from OpenBSD 7.0 you should have resolvd running by default
       that will rewrite /etc/resolv.conf if unwind is started, otherwise you
       need to write "nameserver 127.0.0.1" in /etc/resolv.conf
       
       # Bypass VPN
       
       If you need for some reason to run a program and not route its traffic
       through the VPN, it is possible.  The following command will run
       firefox using the routing table 1, however depending on the content of
       your /etc/resolv.conf you may have issues resolving names (because
       127.0.0.1 is only reachable on rdomain 0!).  So a simple fix would be
       to use a public resolver if you really need to do so often.
       
       ```command
       route -T 1 exec firefox
       ```
       
 (HTM) route man page about exec command
       
       # WireGuard behind a NAT
       
       If you are behind a NAT you may need to use the KeepAlive option on
       your WireGuard tunnel to keep it working.  Just add "wgpka 20" to
       enable a KeepAlive packet every 20 seconds in /etc/hostname.wg0 like
       this:
       
       ```hostname.if example
       wgpeer YOUR_PUBKEY wgendpoint REMOTE_IP 4433 wgaip 0.0.0.0/0 wgpka 20
       [....]
       ```
       
 (HTM) ifconfig man page explaining wgpka parameter
       
       
       # Conclusion
       
       WireGuard is easy to deploy but making it a default network interface
       adds some complexity.  This is usually simpler for protocols like
       OpenVPN because the OpenVPN daemon can automatically do the magic to
       rewrite the routes (and it doesn't do it very well) and won't prevent
       non-VPN access until the VPN is connected.