wg-access-server icon indicating copy to clipboard operation
wg-access-server copied to clipboard

Add IPv6 support to wg-access-server

Open DasSkelett opened this issue 4 years ago • 0 comments

This repository is no longer maintained by the original author, for full IPv6 support, further features, bug fixes and general updates please use https://github.com/freifunkMUC/wg-access-server

Motivation

IPv6 is the successor of IPv4 as internet protocol. It has several advantages over IPv4, such as a much larger address space (64 bits for the network identifier and another 64 bits just for the host identifier), thus also no requirement for NAT (at least not due to address shortage, there are still situations that require NAT). No NAT in turn means proper end-to-end connectivity and less issues with P2P applications like WebRTC.

It is getting more and more relevant as more and more networks and companies enable IPv6 on their systems; and as IPv4 addresses are getting more sparse and very expensive.

IMHO it is very important for a VPN solution like wg-access-server to have IPv6 support.

@freifunkMUC is running most of these changes (in Docker with --network=host) successfully for a few months now, and it appears to be stable as I haven't received any complaints yet :)

Changes

The changes can roughly be divided in these areas:

  • config & flags
  • forwarding / iptables
  • IPAM / device creation
  • DNS proxy
  • wg-embed

Overview:

  • With this PR, the VPN will run dual-stack by default, with a ULA prefix inside the VPN.
  • To turn off IPv6, pass --vpn-cidrv6=0 / WG_IPv6_NAT_ENABLED=0 / vpn.cidrv6: "" (same works for IPv4 if you want to run IPv6-only).
  • Client configs need to be regenerated to receive IPv6 addresses, existing clients stay IPv4-only

Config

Next to vpn.CIDR there is now also vpn.cidrv6 to specify the IPv6 CIDR to use within the VPN. It defaults to fd48:4c4:7aa9::/64, a more or less randomly generated ULA prefix. Then there is vpn.nat66, to toggle the creation of MASQUERADE rules for IPv6. It defaults to true, to make the default ULA prefix work. Users who configure a GUA prefix can turn it off. vpn.allowedIPs now defaults to ["0.0.0.0/0", "::/0"]

IPtables

We first sort the prefixes in AllowedIPs by address family, then configure iptables / ip6tables accordinlgy. The code for ip6tables is pretty much the same as the existing one for iptables, except that the MASQUERADE rule is optional and depends on the aforementioned config value.

IPAM

To make upgrading easy and avoid any database migrations, the two device addresses are comma-concatenated, so they fit in the existing string column. The nextClientAddress() logic for IPv6 is the same as for IPv4 (loop through all devices and remember which ones are already in use, then take the first one that's free), but it is separate. That means that for existing deployments, the last part of the addresses (e.g. .1 / ::1, .2 / ::2 etc.) won't match.

DNS proxy

The DNS proxy now always listens on IPv6 and IPv4 (even with no CIDRv6 specified). It now supports multiple upstreams, if IPv6 is enabled the default includes 2606:4700:4700::1111 as well. When asking upstream, it loops through all servers in configuration order until it receives a successful answer. There is a small TODO left, preferably the logic would be bit smarter and disable an upstream server if it fails repeatedly.

wg-embed

wg-embed and the places it's called in wg-access-server needed some adjustments as well. AddPeer() and the interface config now take a slice of strings for multiple addresses. IfaceConfig The PR is here: https://github.com/Place1/wg-embed/pull/1

Closes #109

DasSkelett avatar Oct 04 '21 15:10 DasSkelett