Project

General

Profile

Bug #3285

Virtual IPs on FreeBSD cannot set IPv6 addresses

Added by Chris Ryder over 2 years ago. Updated 8 months ago.

Status:
Feedback
Priority:
Normal
Assignee:
-
Category:
freebsd
Start date:
03.12.2019
Due date:
Estimated time:
Affected version:
5.8.1
Resolution:

Description

Running StrongSwan 5.8.1 on a FreeBSD 12.1 machine, acting as a roaming VPN client it appears that StrongSwan is only able to assign IPv4 addresses to the tun interface. IPv4 traffic works fine, and I have other VPN clients (iOS and Mac OS X built-in clients) connect to the VPN server and get both IPv6 and IPv4 addresses assigned correctly. However, on the FreeBSD client, StrongSwan reports the following when it brings up the VPN:

.....
scheduling reauthentication in 86170s
maximum IKE_SA lifetime 86350s
installing new virtual IP 81.XX.XX.XX
created TUN device: tun0
installing new virtual IP 2001:XXX:XXXX:XXXX::XXXX
created TUN device: tun1
failed to add address on tun1: Invalid argument
installing virtual IP 2001:XXXX:XXXX:XXXX::XXXX failed
selected proposal: ESP:AES_CBC_256/HMAC_SHA1_96/NO_EXT_SEQ
CHILD_SA vpn{2} established with SPIs c740b4b1_i 65f904ab_o and TS 81.XX.XX.XX/32 === 81.XX.XX.YY/29 ZZ.ZZ.ZZ.ZZ/28
connection 'vpn' established successfully

Digging into the `failed to add address on tun1: Invalid argument` message, I think the problem is that in https://wiki.strongswan.org/projects/strongswan/repository/revisions/master/entry/src/libstrongswan/networking/tun_device.c#L168 the SIOCAIFADDR ioctl (and other friends) is being used, which I think only supports IPv4 address on FreeBSD/Darwin - for IPv6 I think SIOCAIFADDR_IN6 and friends are needed. I don't have any experience of that level of networking code though, but the source for the FreeBSD ifconfig tool https://github.com/freebsd/freebsd/tree/master/sbin/ifconfig shows a difference between inet and inet6 code paths: https://github.com/freebsd/freebsd/blob/master/sbin/ifconfig/af_inet.c https://github.com/freebsd/freebsd/blob/master/sbin/ifconfig/af_inet6.c

There is also a sample of how to set IPv6 addresses on Darwin which looks similar: https://gist.github.com/icpz/65476f8c1ae4c0451b2f67c3fccc2244

noroutes.ifconfig (1.95 KB) noroutes.ifconfig Dries Michiels, 23.09.2021 21:03
noroutes.netstat (2.01 KB) noroutes.netstat Dries Michiels, 23.09.2021 21:03
preconn.ifconfig (1.43 KB) preconn.ifconfig Dries Michiels, 23.09.2021 21:03
preconn.netstat (1.72 KB) preconn.netstat Dries Michiels, 23.09.2021 21:03
routes.ifconfig (1.97 KB) routes.ifconfig Dries Michiels, 23.09.2021 21:03
routes.netstat (2.25 KB) routes.netstat Dries Michiels, 23.09.2021 21:03
charon.log (256 KB) charon.log Dries Michiels, 27.09.2021 21:08
charon.log (322 KB) charon.log Dries Michiels, 30.10.2021 16:06

Related issues

Related to Issue #974: Charon crash on Mac OS with IPv6 Virtual IPNew

History

#1 Updated by Tobias Brunner over 2 years ago

  • Status changed from New to Feedback

That's a known issue. See the (very old) commit in the tun-device-ipv6 branch. Since I had no IPv6 connectivity at the time (and nobody really seemed interested), I never tested it (don't know if it even is complete).

#2 Updated by Chris Ryder over 2 years ago

Ah, I hadn't managed to find that branch - I'll see if I can get that code updated to work in my FreeBSD scenario, thanks!

#3 Updated by Tobias Brunner over 2 years ago

  • Related to Issue #974: Charon crash on Mac OS with IPv6 Virtual IP added

#4 Updated by Dries Michiels 10 months ago

Could we give this some priority? Would be cool for my FreeBSD client to support IPv6.
I am happy to test a branch if you have something ready to test.

#5 Updated by Dries Michiels 10 months ago

Tobias, is this the commit in question I could test? Could you maybe rebase it so I can apply it cleanly?

https://wiki.strongswan.org/projects/strongswan/repository/revisions/0b236674069f004a9c4102e6ee8af2de9e9f4eb8/diff/src/libstrongswan/networking/tun_device.c?

#6 Updated by Tobias Brunner 10 months ago

I've quickly rebased the branch. Only compile tested.

#7 Updated by Dries Michiels 9 months ago

Tobias Brunner wrote:

I've quickly rebased the branch. Only compile tested.

Hi Tobias,

Is it possible for you to rebase to the 5.9.3 tag source code. That's what's used in the FreeBSD port, that makes it easy for me to create a patch on top of the current port.
Hopefully this is not asking to much but this will make it much easier for me to get your changes regarding the ipv6 virtual ip in and compiled, and tested :)

#8 Updated by Tobias Brunner 9 months ago

The patch should apply cleanly to 5.9.3 as there have not been any changes to tun_device.c.

#9 Updated by Dries Michiels 9 months ago

Tobias Brunner wrote:

The patch should apply cleanly to 5.9.3 as there have not been any changes to tun_device.c.

You are right :), so I briefly tested and the virtual IPv6 address is installed correctly.
I still have to search why I lost IPv6 connectivity (couldnt ping6 after initiating the conn)

I did a test with install_routes = no (noroutes), and install_routes = yes (routes), and my default config without any tunnel (preconn).

The only error I got was with the install_routes = yes config as you see bellow.

"[KNL] installing route failed: 0.0.0.0/0 via fe80::a236:9fff:fecd:7de7 src 10.0.1.1 dev tun0"

[IKE] maximum IKE_SA lifetime 14978s
[IKE] installing DNS server 10.0.0.1 via resolvconf
[IKE] installing new virtual IP 10.0.1.1
[LIB] created TUN device: tun0
[IKE] installing new virtual IP 2a02:1811:251a:d210::1
[LIB] created TUN device: tun1
[IKE] received ESP_TFC_PADDING_NOT_SUPPORTED, not using ESPv3 TFC padding
[CFG] selected proposal: ESP:AES_GCM_16_128
[KNL] adding PF_ROUTE route failed: Invalid argument
[KNL] installing route failed: 0.0.0.0/0 via fe80::a236:9fff:fecd:7de7 src 10.0.1.1 dev tun0
[IKE] CHILD_SA home{1} established with SPIs c6c78156_i cec4c700_o and TS 10.0.1.1/32 2a02:1811:251a:d210::1/128 === 0.0.0.0/0 ::/0

#10 Updated by Dries Michiels 9 months ago

TLDR: Code works fine for installing the IPv6 virtual IP. SHIP IT! :D

#11 Updated by Tobias Brunner 9 months ago

I still have to search why I lost IPv6 connectivity (couldnt ping6 after initiating the conn)

Through the tunnel? Or in the LAN?

"[KNL] installing route failed: 0.0.0.0/0 via fe80::a236:9fff:fecd:7de7 src 10.0.1.1 dev tun0"

Hm, that's a very weird combination (IPv4 subnet and source address but IPv6 link-local address as next hop).

Could you try this again with the log level for knl increased to 2?

But even if the next hop is IPv6, da565d9832 should prevent that address from getting set on the route, so not sure why the installation still fails (unless it's related to this recent FreeBSD kernel issue).

#12 Updated by Dries Michiels 9 months ago

Could you try this again with the log level for knl increased to 2?

Is this equivalent to "swanctl --initiate --debug=2 --child=home"

#13 Updated by Tobias Brunner 9 months ago

Could you try this again with the log level for knl increased to 2?

Is this equivalent to "swanctl --initiate --debug=2 --child=home"

Not exactly. First, --debug only sets the log level for messages generated by swanctl itself. To change the log level for messages generated by the daemon while initiating, the option would be --loglevel. However, that logs messages from all subsystems on level 2 (including some that produce a lot of unnecessary output like enc and asn). And it only logs messages related to the initiation, i.e. it stops after the CHILD_SA has been installed (that should be OK in this case, though).

#14 Updated by Dries Michiels 9 months ago

Ok, I put the default log level at 2 in charon-logging.conf. Hopefully it is not to much clutter.

#15 Updated by Tobias Brunner 9 months ago

  • Category set to freebsd

Ok, I put the default log level at 2 in charon-logging.conf. Hopefully it is not to much clutter.

Would have been better to only increase the level for knl, but it's OK. So since the IKE traffic is sent over IPv6 the next hop selection kinda makes sense, I guess:

Sep 27 21:06:03 DRIES-NB charon[72932]: 04[KNL] using fe80::a236:9fff:fecd:7de7 as nexthop to reach 2a02:1811:251a:d200:4ecc:6aff:fe28:3ea3

As mentioned earlier, the value is then ignored when installing the route as the address family doesn't match, so the question is why this installation fails:

Sep 27 21:06:03 DRIES-NB charon[72932]: 04[KNL] installing route: 0.0.0.0/0 via fe80::a236:9fff:fecd:7de7 src 10.0.1.1 dev tun0
Sep 27 21:06:03 DRIES-NB charon[72932]: 04[KNL] adding PF_ROUTE route failed: Invalid argument

One possibility might actually be the missing RTAX_GATEWAY attribute. But I'm pretty sure this worked when I added the commit linked above four years ago. So maybe it's something that changed in the FreeBSD kernel. We could maybe configure an AF_LINK address as RTAX_GATEWAY, set to the interface we have for the route. Could you try the patch I pushed to the tun-device-ipv6 branch?

#16 Updated by Tobias Brunner 9 months ago

Any feedback on the "route via interface" patch?

#17 Updated by Dries Michiels 8 months ago

Tobias Brunner wrote:

Any feedback on the "route via interface" patch?

Sorry for the late feedback.

I'm getting the same error regarding the PF_ROUTE, attach my log file (check 30 Oct).
Giving it a closer look it doesn't seem that IPv6 is the problem but rather the route all traffic route (0.0.0.0/0) for IPv4 (given src is set as 10.0.1.1?).

Maybe its not allowed to add such a destination for a route on FreeBSD?
What I'm wondering about is why it wants to use a link local address for the IPv4 catchall route? Shouldn't that be tun0 as interface as gateway?

PS: I'm just taking guesses here :)

#18 Updated by Tobias Brunner 8 months ago

Any feedback on the "route via interface" patch?

Sorry for the late feedback.

I'm getting the same error regarding the PF_ROUTE, attach my log file (check 30 Oct).

No problem, thanks for testing.

Giving it a closer look it doesn't seem that IPv6 is the problem but rather the route all traffic route (0.0.0.0/0) for IPv4 (given src is set as 10.0.1.1?).

What do you mean? Why should that source IP (i.e. the virtual IP on tun0) not work for a default route via VPN? But note that we don't actually set the source IP on the route (i.e. we don't set RTA_IFA, which could possibly be used for this, not sure, though, as the route(4) man page just describes it as "interface addr", not as preferred source address).

Maybe its not allowed to add such a destination for a route on FreeBSD?

You mean default routes i.e. 0.0.0.0/0 in general? Note that /0 routes are split into two /1 routes to not conflict with any existing default routes, and that this seems to work fine in non-mixed setups (even the IPv6 route here is apparently installed successfully). Also, while FreeBSD apparently has the concept of multiple routing tables (FIBs), I've no idea how that works exactly or is configured via PF_ROUTE, so routes have always been installed in the main routing table (hence this split).

What I'm wondering about is why it wants to use a link local address for the IPv4 catchall route? Shouldn't that be tun0 as interface as gateway?

The "via" address in that log message is the next hop to reach the VPN peer (which is 2a02:1811:251a:d200:4ecc:6aff:fe28:3ea3, that's why it's an IPv6 address even for the IPv4 route) determined via routing table. And given that fe80::faac:65ff:fee1:267a, i.e. a link-local address, is apparently used as source IP to reach the peer, a link-local next hop kinda makes sense. Why the source IP is a link-local address, I don't know, though. While that address is initially (i.e. for the first message sent) determined via routing table using RTM_GET, it will later be the address as reported via IPV6_PKTINFO from the kernel for the received responses. So how that exactly works with link-local addresses I don't know.

But as I said before, that address will be ignored anyway when the route is installed due to the address family mismatch. With the additional patch, the TUN interface is instead set as next hop/gateway, but that doesn't seem to work either. Maybe RTA_GATEWAY doesn't actually accept AF_LINK sockaddrs (however, there are routes with link#... as gateway in the output of netstat -r you posted before, but maybe the format is different), or maybe the problem is that we also set RTA_IFP, which is the interface of the route, to the same interface (but again the existing routes show such an interface too). Unfortunately, FreeBSD networking/routing is pretty much a blackbox to me, so no idea what the correct way to do this would be (or if there even is one).

Also available in: Atom PDF