opnsense / core

OPNsense GUI, API and systems backend
https://opnsense.org/
BSD 2-Clause "Simplified" License
3.26k stars 726 forks source link

IPv6 NAT: Weird behaviour #4743

Closed vlcty closed 3 years ago

vlcty commented 3 years ago

Environment

OPNsense 21.1.2-amd64
FreeBSD 12.1-RELEASE-p13-HBSD
OpenSSL 1.1.1j 16 Feb 2021

Important notices

Before you add a new report, we ask you kindly to acknowledge the following:

Describe the bug

I'm currently working around a WireGuard issue. It's impossible to setup the source addres of WireGuard and therefore the WAN Address is used.

My previous setup: I had 2001:db8:300:b000::/64 statically configured on my WAN. My static WAN address was 2001:db8:300:b000:5054:ff:fe22:c14e.

I kicked out the route in front of OPNsense and exchanged it with a modem. The current setup:
DHCPv6 on WAN with the following addresses:

I want to continue using 2001:db8:300:b000:5054:ff:fe22:c14e for WireGuard (UDP port 51820), because the single ULA is not static. The prefix is. So I added a Virtual IP (IP alias, no gateway) with said address on WAN. I created a matching firewall rule allowing incoming traffic. A trace shows the following traffic:

IP6 2a01:598:b9a3:af6b:d618:8ad:228f:f7aa.47499 > 2001:db8:300:b000:5054:ff:fe22:c14e.51820: UDP, length 148
IP6 2001:db8:0:c0::16.51820 > 2a01:598:b9a3:af6b:d618:8ad:228f:f7aa.47499: UDP, length 92

As you can see the WAN address is used. Sadly I cant configure Wirecard to use a specific address. Therefore the system fills in it's default address. So my thought was: A NAT rule will correct that. I created the following:

Interface: WAN
Source: 2001:db8:0:c0::16
Source port: Wireguard
Destination: any
Destination port: any
NAT address: 2001:db8:300:b000:5054:ff:fe22:c14e

rules.tmp:

Wireguard = "{ 51820 }"
nat on vtnet0 inet6 from 2001:db8:0:c0::16/128 port $Wireguard to any -> 2001:db8:300:b000:5054:ff:fe22:c14e port 1024:65535

Trace:

23:34:08.146286 IP6 2a01:598:b9a3:af6b:d618:8ad:228f:f7aa.39070 > 2001:db8:300:b000:5054:ff:fe22:c14e.51820: UDP, length 148
23:34:08.148902 IP6 2001:db8:300:b000:5054:ff:fe22:c14e.1576 > 2a01:598:b9a3:af6b:d618:8ad:228f:f7aa.39070: UDP, length 92

The translation works, but the source port is changed (51820 -> 1576). Of course the receiver drops that packet.

I changed my NAT rule and checked "static Port", applied and looked at the dump again:

Wireguard = "{ 51820 }"
nat on vtnet0 inet6 from 2001:db8:0:c0::16/128 port $Wireguard to any -> 2001:db8:300:b000:5054:ff:fe22:c14e static-port

Traffic changes to something I did not expect:

23:37:02.684799 IP6 2a01:598:b9a3:af6b:d618:8ad:228f:f7aa.49628 > 2001:db8:300:b000:5054:ff:fe22:c14e.51820: UDP, length 148
23:37:02.687420 IP6 2001:db8:0:c0::16.51820 > 2a01:598:b9a3:af6b:d618:8ad:228f:f7aa.49628: UDP, length 92

The source port is okay now. But the translation does not happen.

Next modification to the rules was:

Dump:

Wireguard = "{ 51820 }"
nat on vtnet0 inet6 from 2001:db8:0:c0::16/128 port $Wireguard to any -> 2001:db8:300:b000:5054:ff:fe22:c14e port 51820

Traffic:

23:40:20.747056 IP6 2a01:598:b9a3:af6b:d618:8ad:228f:f7aa.43931 > 2001:db8:300:b000:5054:ff:fe22:c14e.51820: UDP, length 148
23:40:20.749660 IP6 2001:db8:0:c0::16.51820 > 2a01:598:b9a3:af6b:d618:8ad:228f:f7aa.43931: UDP, length 92

Nothing changed. Last adaption: Setting source to any and only match source port = wireguard.

Rules:

Wireguard = "{ 51820 }"
nat on vtnet0 inet6 from any port $Wireguard to any -> 2001:db8:300:b000:5054:ff:fe22:c14e port 51820

Traffic:

23:41:26.273001 IP6 2a01:598:b9a3:af6b:d618:8ad:228f:f7aa.40067 > 2001:db8:300:b000:5054:ff:fe22:c14e.51820: UDP, length 148
23:41:26.275501 IP6 2001:db8:0:c0::16.51820 > 2a01:598:b9a3:af6b:d618:8ad:228f:f7aa.40067: UDP, length 92

At this stage I don't know what else I could try. I've no other NAT rules for IPv6. It seems my previous setup only worked because I used the WAN address out of pure luck. I'm glad for any advice.

vlcty commented 3 years ago

Without any change on my side the wg connection suddently was up and running again. I did no change since yesterday :-)

It seems that the address 2001:db8:0:c0::16 was suddently not good enough as source address and the "next" address aka the virtual ip 2001:db8:300:b000:5054:ff:fe22:c14e was used instead. Strange but no solution to my problem. This got me into thinking: I need to "trick" the underlying BSD to use the virtual IP as default source address and indeed, you can do that over the CLI:

ifconfig vtnet0 inet6 prefer_source 2001:db0:300:b000:5054:ff:fe22:c14e

Funny! Such an easy solution for my needed workaround :-)

I'm closing this issue because I don't think that there is actually a bug here. Maybe due to my wild clicking something got a hiccup.

mimugmail commented 3 years ago

Interesting, might be a hack for the CARP problem too