💾 Archived View for vignette.kalasarn.se › gemlog_20201117.gmi captured on 2024-03-21 at 15:06:22. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2022-04-28)

-=-=-=-=-=-=-

OpenBSD rdomains and wireguard

2020-11-17

This post is a bit wider than usual. This is to preserve the examples

intact and paste-able. Hopefully it looks allright in your client. Let me

know otherwise.

The last few weeks I've been experimenting with Wireguard on OpenBSD in

various ways. Since I saw that support showed up in the kernel a while

ago, I was curious what it could be used for. Turns out that it is nicely

integrated, so that utilities like ifconfig and pf can be used to control

wireguard-interfaces, and hence they can also be defined in "hostname.if"

to be started at system boot and so on.

The obvious first thing was to try to set up a server, which I did quite

easily on a VPS:

server# cat /etc/hostname.wg0

wgkey $SERVER_PRIVKEY_HERE

wgport 4343 # Peer 1

wgpeer $PEER_PUBKEY_HERE wgaip 192.168.100.100/32

wgaip fda8:9887:eecb:9051::11/128

# Peer 2 wgpeer $PEER_PUBKEY_HERE

wgaip 192.168.100.101/32

wgaip fda8:9887:eecb:9051::12/128

# Peer 3 wgpeer $PEER_PUBKEY_HERE

wgaip 192.168.100.102/32

wgaip fda8:9887:eecb:9051::13/128

# Peer 4

wgpeer $PEER_PUBKEY_HERE

wgaip 192.168.100.103/32

wgaip fda8:9887:eecb:9051::14/128

inet 192.168.100.1/24

inet6 fda8:9887:eecb:9051::1/64

up

This is all it really takes to set up a server on OpenBSD. You can start

it by doing:

sh /etc/netstart wg0

Now for the peers. There are multiple ways to set these up. A common

use-case is to set the default route via the wg-interface:

peer1# cat /etc/hostname.wg0

wgkey $PEER_PRIVKEY_HERE wgpeer $SERVER_PUBKEY_HERE

wgendpoint server.example.net 4343

wgaip 0.0.0.0/0 wgaip ::/0

inet 192.168.100.100/24

inet6 fda8:9887:eecb:9051::11/64

#!route add -inet -priority 7 default 192.168.100.1

#!route add -inet6 -priority 7 default fda8:9887:eecb:9051::1/64

This can be a bit clunky though. What I opted for instead is to use

rdomains and rtables to set up a separate routing table for the

wg-interface on the peer. That way, I can utilize pf on the peer to

control which traffic goes through the tunnel, or use "route -Tn exec" to

run specific applications in that specific rdomain, making it only go out

via the wg-interface. This is what I ended up with:

peer1# cat /etc/hostname.wg0

wgkey $PEER_PRIVKEY_HERE wgpeer $SERVER_PUBKEY_HERE

wgendpoint server.example.net 4343 wgaip 0.0.0.0/0 wgaip ::/0

rdomain 1

inet 192.168.100.100/24

inet6 fda8:9887:eecb:9051::11/64

!route -T 1 add -inet -priority 7 default 192.168.100.1

!route -T 1 add -inet6 -priority 7 default fda8:9887:eecb:9051::1/64

!ifconfig lo1 rdomain 1 127.0.0.1

Here, I set the interface to belong to the rdomain 1, and I also add the

default routes, but to the rtable 1 in rdomain 1. I also set up a

loopback-interface so stuff that expects to be able to bind to it can do

that. This may or may not be desired. In my specific use-case, I used it

because the tor-browser-bundle expects to be able to bind to 127.0.0.1,

which it cannot if it's not available in the rdomain. Next, I used some

rules in pf to re-direct DNS to specific servers reachable through

wireguard. In this case, it's an unbound-instance running on the

wireguard-server, and I wanted all DNS-requests to go to that server. So I

did something along these lines on the peer:

pass out on rdomain 1 proto { udp tcp } from any to any port 53 \

rdr-to 192.168.100.1 port 53

This will make any traffic towards anything on port 53 (either tcp or udp)

be redirected to 192.168.100.1. This will force DNS-requests happening in

the rdomain go to a server on the other side of the tunnel. Once this is

done and the pf-config and brought up the interfaces, you should be able

to do stuff like this on the peer:

route exec curl ifconfig.io/all

route -T 1 exec curl ifconfig.io/all

The first example should go through the default routing table, showing

your public IP. The second should go through the tunnel, and show the

corresponding public IP for that system. Success! (Hopefully). With this,

you can do all sorts of interesting things. You could for example run:

route -T 1 exec ksh

This will give you a shell belonging to rdomain 1, and hence, any process

spawned in that shell will inherit that. This is a simple way to not have

to prepend the route/exec-combination to run stuff through the tunnel.

So I hope that you enjoyed this little post. It may be a bit unclear, but

it's also a bit of a mental note to myself, even though the idea of

sharing it here is to give others a way to utilize similar solutions as

well. I've had a lot of fun with this during the last few days, and

hopefully it can be meaningful for others as well. Please send me some

feedback if you enjoyed it!

The content for this site is CC-BY-SA-4.0.