OPNsense: Prefer source address

Note: This post is about IPv6 addresses. I assume it works with legacy IP, too (untested).

Problem

Before switching to a modem I had configured a static WAN address. I chose that address to be also used as WireGuard endpoint address. WireGuard has one major problem: You can’t configure the address it’s listening on. It relies on the underlying operating system to fill in the source address. And this can cause problems on a machine with multiple interfaces and addresses like an OPNsense firewall as you will see now.
After I switched to a modem I’m doing DHCPv6 on WAN. I now receive my ISP assigned /56 prefix directly and an additional ULA outside said prefix. Since I wanted to continue using my former static WAN address for my WireGuard stuff I created it as a virtual IP. However OPNsense (actually the underlying BSD) prefers to use the ULA in replies instead of the virtual IP breaking the WireGuard connection. It’s a little bit hard to explain what I mean so here are the interface configs before and after switching to a modem:

Before: Statically assigned address out of a /64 on WAN (vtnet0):

vtnet0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
options=d00b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,LINKSTATE>
ether xx:xx:xx:xx:xx:xx
hwaddr xx:xx:xx:xx:xx:xx
inet6 2001:db8:150::a534:c14e prefixlen 64

After: Doing DHCPv6:

vtnet0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
options=d00b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,LINKSTATE>
ether xx:xx:xx:xx:xx:xx
hwaddr xx:xx:xx:xx:xx:xx
inet6 2001:db8:0:c0::38 prefixlen 128 <- ULA from my ISP
inet6 2001:db8:150::a534:c14e prefixlen 64 <- Virtual IP

Before the BSD had no other choice than using the only address on the interface to create reply packets:

root@firewall:~ # tcpdump -i vtnet0 -nn ‘port 51820’
IP6 2003:d4:4720:f500:ba27:ebff:fe57:e6bb.57061 > 2001:db8:150::a534:c14e.51820: UDP, length 96
IP6 2001:db8:150::a534:c14e.51820 > 2003:d4:4720:f500:ba27:ebff:fe57:e6bb.57061: UDP, length 128

But now the reply is created with the ULA:

root@firewall:~ # tcpdump -i vtnet0 -nn ‘port 51820’
IP6 2003:d4:4720:f500:ba27:ebff:fe57:e6bb.57061 > 2001:db8:150::a534:c14e.51820: UDP, length 96
IP6 2001:db8:0:c0::38.51820 > 2003:d4:4720:f500:ba27:ebff:fe57:e6bb.57061: UDP, length 128

This breaks the “connection”, because the reply packet is dropped by my client (or a firewall on the way). It turns out I was just really lucky to initially choose my WAN address for my endpoints.

Possible workarounds

  1. Use the ULA as WireGuard endpoint address.
    Pros: No change to the underlying system is needed
    Cons: My ULA is not static
  2. NAT everything on WAN where source is WAN address (the system alias points to the ULA), protocol is UDP and source port is 51820. Translation target would be the virtual IP (2001:db8:150::a534:c14e).
    Pros: Using the problem with board tools and won’t break with future updates
    Cons: NAT is something I want to avoid whenever possible with IPv6
  3. Check the box Request only an IPv6 prefix on the WAN interface config page. Afterwards no ULA is configured on the WAN interface and the BSDs only choice is to use the virtual IP.
    Pros: Again a solution using board tools
    Cons: After creating a new virtual IP on WAN the BSD may prefers the new address and you are back at the beginning. Additionally an address outside your prefix may come in handy in the future.

It’s your decision what suits you best. Of course the perfect solution would be to extend WireGuard and tell it which addresses to use. It works with any other software I know so why not with WireGuard? Maybe we will see this in the foreseeable future.

My solution

I told the underlying BSD that it should prefer my virtual IP for outgoing packets:

ifconfig vtnet0 inet6 prefer_source 2001:db8:150::a534:c14e

If you loot at at the ifconfig output afterwards you’ll notice that the address now has another attribute called prefer_source:

vtnet0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
options=d00b8<VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,VLAN_HWFILTER,VLAN_HWTSO,LINKSTATE>
ether xx:xx:xx:xx:xx:xx
hwaddr xx:xx:xx:xx:xx:xx
inet6 2001:db8:0:c0::38 prefixlen 128
inet6 2001:db8:150::a534:c14e prefixlen 64 prefer_source

Every WireGuard reply packet now uses 2001:db8:150::a534:c14e. But connections initiated by OPNsense itself (NTP, DNS, etc) now also use that address. But that’s something I could live with. I also created a cron job to issue that command periodically:

  1. Log in via ssh as root onto your firewall
  2. Optional: Install vim if you prefer it over vi: pkg install vim-console
  3. Create a bash script /usr/bin/set_preferred_source.sh with the following content:

#!/bin/sh
/sbin/ifconfig vtnet0 inet6 prefer_source 2001:db8:150::a534:c14e

  1. Create the configd action file under /usr/local/opnsense/service/conf/actions.d/actions_set_preferred_source.conf with the following content:

[set_preferred_source]
command:/usr/bin/set_preferred_source.sh
type:script
description:set preferred source on wan
message:set preferred source on wan

  1. Reload configd: service configd restart
  2. Create a cronjob in the Webgui: Systems -> Settings -> Cron. You should be able to select set preferred source on wan as Command.

Done!


Du hast einen Kommentar, einen Wunsch oder eine Verbesserung? Schreib mir doch eine E-Mail! Die Infos dazu stehen hier.

🖇️ = Link zu anderer Webseite
🔐 = Webseite nutzt HTTPS (verschlüsselter Transportweg)
Zurück