OpenVPN with client IPv6 GUA (dynamic prefix) + external IPv6 interface issue

Good evening,

first: Thanks for your thoughts and tips!

I am currently trying to make my OpenVPN setup IPv6 ready. It is working so fare but I have two issues.

  1. The outgoing IPv6 address of the OVPN server is not the one of the WAN6 interface - so I get an error at the client side if not adding "float" to the config there. The server is accepting client requests via the WAN6 but replies from the LAN IPv6 address.

TCP/UDP: Incoming packet rejected from [AF_INET6]XXXX:XXX:b816:c5fc::1:1194[10], expected peer address: [AF_INET6]XXXX:XXXX:b816:c500:XXXX:XXXX:XXXX:ce25:1194 (allow this incoming source address/port by removing --remote or adding --float)

  1. I manually added a /112 subnet to the server config - however as my IPv6 prefix changes from time to time, I wonder whether their is way to have a /112 subnet delegated to the OpenVPN setting automatically? I have a /64 prefix delegated to the OpenWRT router.

I am running OpenWrt 19.07.2, r10947-65030d81f3 on a TP-Link TL-WDR4300 v1.

Thanks a lot!

Markus

Open VPN server

config openvpn 'lan'
    option enabled '1'
    option verb '3'
    option log '/tmp/openvpn.log'
    option tls_server '1'
    option tls_version_min '1.2'
    option user 'nobody'
    option fast_io '1'
    option group 'nogroup'
    option dev 'tun0'
    option port '1194'
    option proto 'udp6'
    option server '10.1.8.0 255.255.255.0'
## Here is the /112 global IPv6 prefix
    option server_ipv6 'XXXX:XXXX:b816:c5fc::8:0/112'
    option client_to_client '0'
    option topology 'subnet'
    option mute_replay_warnings '1'
    option compress 'lzo'
    option keepalive '10 120'
    option persist_tun '1'
    option persist_key '1'
    option tls_crypt '/etc/openvpn/lan/ssl/tc.pem'
    option dh '/etc/openvpn/lan/ssl/dh.pem'
    option cert '/etc/openvpn/lan/ssl/lan_vpnserver.crt'
    option key '/etc/openvpn/lan/ssl/lan_vpnserver.key'
    option ca '/etc/openvpn/lan/ssl/ca.crt'
    option cipher AES-256-GCM
    option auth SHA512
    option tls_cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256:TLS-DHE-RSA-WITH-AES-256-CBC-SHA
    list push 'dhcp-option DOMAIN lan'
    list push 'redirect-gateway def1'
    list push 'topology subnet'
    list push 'dhcp-option DNS 10.1.8.1'
    list push 'block-outside-dns'

Open VPN client

verb 3
nobind
dev tun0
tls-client
proto udp
resolv-retry infinite
remote XXX.XXXX.XX 1194 udp
float
fast-io
comp-lzo
remote-cert-tls server
user nobody
group nobody
persist-key
persist-tun
mute-replay-warnings
cipher AES-256-GCM
mute 20
topology subnet
pull
auth SHA512
# ca, cert etc.

Firewall

config defaults
	option syn_flood '1'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'REJECT'

config zone 'lan'
	option name 'lan'
	list network 'lan'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'

config zone
	option name 'wan'
	list network 'wan'
	list network 'wan6'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option masq '1'
	option mtu_fix '1'

config forwarding
	option src 'lan'
	option dest 'wan'

config rule
	option name 'Allow-DHCP-Renew'
	option src 'wan'
	option proto 'udp'
	option dest_port '68'
	option target 'ACCEPT'
	option family 'ipv4'

config rule
	option name 'Allow-Ping'
	option src 'wan'
	option proto 'icmp'
	option icmp_type 'echo-request'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-IGMP'
	option src 'wan'
	option proto 'igmp'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-DHCPv6'
	option src 'wan'
	option proto 'udp'
	option src_ip 'fc00::/6'
	option dest_ip 'fc00::/6'
	option dest_port '546'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-MLD'
	option src 'wan'
	option proto 'icmp'
	option src_ip 'fe80::/10'
	list icmp_type '130/0'
	list icmp_type '131/0'
	list icmp_type '132/0'
	list icmp_type '143/0'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Input'
	option src 'wan'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	list icmp_type 'router-solicitation'
	list icmp_type 'neighbour-solicitation'
	list icmp_type 'router-advertisement'
	list icmp_type 'neighbour-advertisement'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Forward'
	option src 'wan'
	option dest '*'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-IPSec-ESP'
	option src 'wan'
	option dest 'lan'
	option proto 'esp'
	option target 'ACCEPT'

config rule
	option name 'Allow-ISAKMP'
	option src 'wan'
	option dest 'lan'
	option dest_port '500'
	option proto 'udp'
	option target 'ACCEPT'

config include
	option path '/etc/firewall.user'

config rule 'ovpn'
	option name 'Allow-OpenVPN-lan'
	option src 'wan'
	option dest_port '1194'
	option proto 'udp'
	option target 'ACCEPT'

config zone
	option network 'lanvpn'
	option input 'ACCEPT'
	option forward 'REJECT'
	option name 'lanvpn'
	option output 'ACCEPT'

config forwarding
	option dest 'wan'
	option src 'lanvpn'

Network

config interface 'loopback'
	option ifname 'lo'
	option proto 'static'
	option ipaddr '127.0.0.1'
	option netmask '255.0.0.0'

config globals 'globals'
	option ula_prefix 'fde0:cab8:dd28::/48'

config interface 'lan'
	option type 'bridge'
	option ifname 'eth0.1'
	option proto 'static'
	option ipaddr '192.168.1.1'
	option netmask '255.255.255.0'
	option ip6assign '60'

config interface 'lanvpn'
	option ifname 'tun0'
	option proto 'none'

config interface 'wan'
	option ifname 'eth0.2'
	option proto 'dhcp'

config device 'wan_eth0_2_dev'
	option name 'eth0.2'
	option macaddr '90:f6:52:ff:ce:25'

config interface 'wan6'
	option ifname 'eth0.2'
	option proto 'dhcpv6'

config switch
	option name 'switch0'
	option reset '1'
	option enable_vlan '1'

config switch_vlan
	option device 'switch0'
	option vlan '1'
	option ports '2 3 4 5 0t'

config switch_vlan
	option device 'switch0'
	option vlan '2'
	option ports '1 0t'

Hey,

I found some kind of "solutions" to my two issues:

1. Only use wan6 GUA for answers to ovpn client requests

The outgoing IPv6 address of the OVPN server is not the one of the WAN6 interface - so I get an error at the client side if not adding "float" to the config there. The server is accepting client requests via the WAN6 but replies from the LAN IPv6 address.

To "solve" this issue, there is an option called "multihome" for the ovpn UDP server setting. This option demands the ovpn server to always reply from the IP address where the request was received on. Also refer to the documentation:

–multihome
Configure a multi-homed UDP server. This option needs to be used when a server has more than one IP address (e.g. multiple interfaces, or secondary IP addresses), and is not using –local to force binding to one specific address only. This option will add some extra lookups to the packet path to ensure that the UDP reply packets are always sent from the address that the client is talking to. This is not supported on all platforms, and it adds more processing, so it’s not enabled by default. Note: this option is only relevant for UDP servers.

2. Automatically assign GUA subnet to ovpn server for ovpn clients if IPv6 prefix changes

I manually added an IPv6 /112 subnet to the server config - however as my IPv6 prefix changes from time to time, I wonder whether their is way to have a /112 subnet delegated to the OpenVPN setting automatically? I have a /64 prefix delegated to the OpenWRT router

I overcome this issue with a rather dirty solution. I wrote a hotplug script triggered if the wan6 address changes, refer to script below (must be located at /etc/hotplug.d/iface). The script creates a temporary helper interface and VLAN, restarts the network and grabs the GUA subnet assigned by odhcpd to this temporary helper interface. After that, it deletes the helper interface and VLAN and assigns the cached GUA subnet to the ovpn server. To make this dirty solution work keep in mind, that in my setting a /58 prefix is assign to the router by the upstream FritzBox and all my interfaces on OpenWRT demand a /64 IPv6 subnet. In addition, to ensure that the grabbed GUA subnet assigned to the helper interface does not get assigned to another interface after deletion of the helper interface, the helper interface must have the lowest priority in the IPv6 assignment by odhcpd, refer to https://openwrt.org/docs/guide-user/network/ipv6/start see extract below. Thus, the name of the helper interface in my scripts starts with the letter Z.

For multiple interfaces, the prefixes are assigned based on firstly the assignment length (smallest first) then on weight and finally alphabetical order of interface names. e.g. if wlan0 and eth1 have ip6assign 61 and eth2 has ip6assign 62, the prefixes are assigned to eth1 then wlan0 (alphabetic) and then eth2 (longest prefix). Note that if there are not enough prefixes, the last interfaces get no prefix - which would happen to eth2 if the overall prefix length was 60 in this example.

I was thinking of better solutions i.e. determining a free /64 GUA subnet in my script by itself based on the assignment status of the other interfaces, however I did not find suitable packages for ash to handle that kind of exercise. Another option, I was thinking of, was to get the next free /64 GUA subnet from odhcpd but was not finding such function.

Hotplug iface script (/etc/hotplug.d/iface/)

#!/bin/sh

# if ipv6 address has changed on WAN6 go for it
if [ "$INTERFACE" = "wan6" -a "$IFUPDATE_ADDRESSES" = "1" ]
then
    # create helper switch to get free IPv6 net for OVPN
    uci set network.TMP1="switch_vlan"
    uci set network.TMP1.device="switch0"
    uci set network.TMP1.vlan="7"
    uci set network.TMP1.vid="99"
    uci set network.TMP1.ports="6t"

    # create helper interface to get free IPv6 net for OVPN
    uci set network.ZTMP="interface"
    uci set network.ZTMP.proto="static"
    uci set network.ZTMP.ifname="eth0.99"
    uci set network.ZTMP.ip6assign="64"
    uci commit network

    # restart network
    /etc/init.d/network restart

    # wait some time to get network up
    sleep 5

    # reload interface to update PD to downstream interfaces, refer to bug described here https://forum.openwrt.org/t/delegated-ipv6-prefix-not-updated/56135
    /sbin/ifup wan6

    # wait some time to get IPv6 up
    sleep 15

    # get IPv6 of helper interface
    source /lib/functions/network.sh
    network_get_ipaddr6 IPV6_OVPN "ZTMP"

    # delete helper switch and interface
    uci del network.TMP1
    uci del network.ZTMP
    uci commit network

    # restart network
    /etc/init.d/network restart

    # wait some time to get network up
    sleep 5

    # set openvpn server-ipv6 option
    uci set openvpn.LAN.server_ipv6="$IPV6_OVPN/64"
    uci commit openvpn

    # restart openvpn
    /etc/init.d/openvpn restart
fi