Opened 4 years ago

Closed 3 years ago

#306 closed Bug / Defect (fixed)

--proto udp6 --multihome fails for IPv4-mapped clients

Reported by: tore Owned by: cron2
Priority: major Milestone: release 2.3.3
Component: Networking Version: 2.3.1
Severity: Not set (if unsure, select this one) Keywords: IPv6 multihome udp6 linux dualstack
Cc: plaisthos

Description

When using --proto udp6 on a Linux server (which opens a dual-stacked socket), --multihome does not work correctly for IPv4 clients.

Some (anonymised) debugging information:

Client = 192.0.2.1
Server (eth1 - primary network interface) = 198.51.100.1
Server (eth3 - OpenVPN service interface) = 203.0.113.1 & 2001:db8::1

eth1 has the default route in the routing table "main", so 198.51.100.1 is the default source address used for outgoing packets unless the application explicitly requests another one being used.

eth3 has the default route in a special routing table "3", which is used only for traffic sourced from 203.0.113.1 & 2001:db8::1 (using "rule add from {203.0.113.1,2001:db8::1} table 3")

A tcpdump on client during connection attempt shows that the server is using its primary address for responding rather than the service address it was initially contacted on:

12:29:27.126077 IP 192.0.2.1.55685 > 203.0.113.1.6666: UDP, length 14
12:29:27.126993 IP 198.51.100.1.6666 > 192.0.2.1.55685: UDP, length 22

The server logs the following when receiving the connection attempt:

ovpn-udp6666[8906]: ::ffff:192.0.2.1 TLS: Initial packet from [AF_INET6]::ffff:192.0.2.1:55685 (via 2001:db8::1%eth3), sid=a62a6958 8bb08f04

If I use "proto udp" instead, the multihoming functionality work correctly - the server responds using the address it was initially contacted on. However, then I end up with an IPv4-only server, so that's not a good workaround for me.

If I connect using native IPv6 from the client, it also works as expected. However, not all of my users have IPv6 connectivity where they go, so that's not a good workaround either.

Tore

Change History (7)

comment:1 Changed 4 years ago by tore

Correction, meant "ip rule add ..." rather than just "rule add ...".

comment:2 Changed 4 years ago by cron2

  • Owner set to cron2
  • Status changed from new to assigned

Uh. Sorry to let this lie around for so long, I was kind of occupied elsewhere.

No idea what is happening in these parts of the code, and the udp6/tcp6 socket.c code is a bit hard to grok, but I'll go and investigate. This is quite obviously a bug.

comment:3 Changed 4 years ago by cron2

  • Cc plai added

comment:4 Changed 4 years ago by cron2

  • Cc plaisthos added; plai removed
  • Milestone set to release 2.3.3

could be related to #327 (in which case it might be somewhat easier to fix)

Tore, could you test whether it works if the server has multiple IPv6 addresses, properly responding from the address you connected to? I think it is not actually related to "v4 mapped", but to "multihome is broken for IPv6".

I *thought* I had committed a fix for the struct length issue but can't find it in the commit log... need to look more closely.

comment:5 Changed 4 years ago by tore

"multihome" with "proto udp6" works for native IPv6, it only fails if the client is coming in over IPv4 (appearing as ::ffff:<ipv4> to the openvpn process). When tcpdumping I see that the server responds using the primary IPv4 address no matter what, and if the client initially contacted a secondary IPv4 address, it doesn't work.

If the client contacted a secondary IPv6 address, openvpn vill respond from that address and it all works (but only if "multihome" is in use though, otherwise it breaks in the same way as described above).

BTW: I didn't get any e-mail notification about your update, it was a coincidence that I wanted to look into this now and saw it. So in case there's some permanent issue here, please feel free to notify me on IRC of any updates.

Tore

comment:6 Changed 3 years ago by cron2

So, let's wrap this up:

  • the code in 2.3 actually gets this right, if the operating system can handle this particular case (IPv4 packets arriving as IPv4-mapped on an IPv6 socket). Linux could not until 3.15 (see below for details)
  • the code in git master had some issues as consequence of the dual-stack rewrite, but that got fixed, so it works now as well

On the Linux details, quoting Tore:


There are two patches that are required for this to work:

«ipv6: make IPV6_RECVPKTINFO work for ipv4 datagrams»
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=4b261c75a99f29c93a0b6babfc180cdf566bd654

«ipv6: honor IPV6_PKTINFO with v4 mapped addresses on sendmsg»
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c8e6ad0829a723a74cd2fea9996a3392d2579a18

Only the first one is in Linux 3.14, the second one is not (it first appeared in 3.15-rc1).

Another thing worth noting though, is that Ubuntu backported both patches to the 3.13-based kernel they are shipping as part of Ubuntu 14.04 «Trusty». So it works out of the box there, which is great news because it's a "Long Term Support" release that will probably be popular on servers in the years to come. The patches will eventually make it into the previous LTS release 12.04 «Precise» too, as part of the upcoming 12.04.5 point release (expected in August).

https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1284535

The 12.04.5 «Precise» fixes will come about by importing a collection of packages from 14.04. They call this a Hardware Enablement Stack (the purpose is to bring support for modern hardware and its drivers to the older but still-supported releases):

https://wiki.ubuntu.com/Kernel/LTSEnablementStack

Anyway, what I wanted to clarify is that if a user is installing 12.04.5 from scratch, then it should default to using the kernel package from 14.04, and the IPv6 multihoming fixes should be there out of the box. However if the user is on <=12.04.4, doing a distribution upgrade is not sufficient, he would also need to manually install the kernel from the 14.04 Hardware Enablement Stack to get the required fixes. This is done by installing the package "linux-generic-lts-trusty".

comment:7 Changed 3 years ago by cron2

  • Resolution set to fixed
  • Status changed from assigned to closed

Closing this now, since I think all this ticket is about has been addressed and documented.

All the other warts need to get their own tickets.

Note: See TracTickets for help on using tickets.