Enable peers' to connect to the IPv6 WAN through Wireguard's IPv4 connectivity

Hello there!

I'm revisiting a topic from a few months ago, though with a bit of a broader scope to see if I'm able to get an answer.

I have a dual stack connection to the Internet from my ISP, with both a type B NAT for my v4 and a /64 prefix for my v6, both of which I use with a domain, Cloudflare and its DDNS script to update both A and AAAA records and point them to my router's address upon boot.

This in turn is then used to connect over Wireguard several devices like laptops and phones over IPv4 in a road warrior configuration, giving them access to the v4 Internet and my home's LAN through my router, but in spite of having them assigned already a v6 address within each peer's configuration, they are only able to connect to the router's Wireguard instance over v4 as expected, given that most mobile networks have not yet deployed v6 connectivity to regular phones as far as I'm aware.

However, I was wondering if there would be a way to deploy a 6in4 tunnel within my network such as that when devices connect to the router over Wireguard in IPv4-only networks they'd get assigned a public IPv6 address alongside their respective LAN prefix, allowing them to access the Internet in a dual stack configuration while away from home and allowing them to interact with IPv6-only websites and services.

I have already installed 6in4 to my router, but aside from that I'm honestly lost as to what would the next steps be, or even if the way I'm thinking about solving the problem is wrong in any shape or measure.

What should I do?

V4 and/or v6 can be sent inside any Wireguard tunnel regardless of the type of addressing that the encrypted packets use on the outside.

As your ISP only grants you a single /64 you will need to use ipv6 relay DHCP so all the clients are under the same /64 prefix issued by the ISP.

1 Like

I see.

At the moment I have configured my LAN interface in hybrid mode, and I'm successfully able to ping a peer using its local v6 address, but even after restarting the Wireguard interface with its delegation prefix filter set to wan_6, it seems I'm unable to get the Wireguard interface a public v6 address. Should I set the LAN interface as the designated master, or am I going about it in the wrong direction?

Hey there,

I'm still trying to figure this out, I've already tried the different relay options, but so far I have not been able to get v6 connectivity any longer.

Is there anything in particular I should be doing? wan_6 has an IPv6-PD address assigned, but it doesn't seem to be able to delegate to any device on the network, and not even the router can ping an IPv6 host, though DNS resolution does work.

Road warriors do not require prefix delegation, only a successful SLAAC or DHCPv6 assignment and allowed IPs ::0 routed. When your ISP is /64, use ra_mode relay to assign the road warrior an IPv6 using a different suffix from the same /64 prefix that exists on wan. This is still a globally unique address and the ISP will route back to it since they route anything in the /64 to you.

The Wireguard interface on the server must have a link-local IP6. I think that I needed to configure that manually.

Do you have a static or a dynamic IPv6 prefix? Shorter then /64 (like a /56)?

AFAIK wireguard interfaces do not support SLAAC or DHCPv6, at least on Android and with NetworkManager I had no luck. Also, "officially" wireguard has no support for Multicast. You can cheat a little bit, but like I said, I had no luck enforcing SLAAC.

I get a /56 from my ISP, and with ip6hint the wg0 gets a "proper" GUA prefix, too, and a ULA prefix.
To enable clients to have at least IPv6 I went with NPT (Network Prefix Translation). Client gets an ULA address and with NPT the ULA prefix gets translated to a GUA prefix, using iptables (the device is still 21.03!) (NPT is not to be confused with NAT66!)
AFAIK the only downside of NPT is SIP gets broken. Other P2P application should work. But as I have no such thing on my Android I just don't know. (I'm happy if I will get mails and can browse the web on the phone; and have access to German Broadcasting stations if I'm abroad.)
I use this wireguard for a "full tunnel" setup.

My wireguard interface on OpenWrt:
(I set multicast so I can use OSPFv3 on that interface)

config device
    option  name            'wg0'
    option  multicast       '1'

config interface            'wg0'
    option  proto           'wireguard'
    option  listen_port     '<port>'
    option  private_key     '<key>'
    list    addresses       '192.168.240.1/24'
    list    addresses       'fe80::e097:46ff:fef0:2d8e/64' # Cheating and setting a LLA manually for OSPFv3
    option  mtu             '1420'
    option  ip6assign       '64'
    option  ip6hint         'f0'
    list    ip6ifaceid      'eui64'
    list    ip6ifaceid      '::1'

# Example client
config wireguard_wg0
    option  public_key      '<key>'
    list    allowed_ips     '192.168.240.3/32'
    list    allowed_ips     'fde6:a09a:b373:f0::3/128'
    list    allowed_ips     'fe80::/10'

My hotplug script:

# cat /etc/hotplug.d/iface/10-wg
#!/bin/sh

test "${ACTION}" = "ifup" && {

        case "${INTERFACE}" in
                wg*)
                        sh /root/add-npt.sh ${INTERFACE}
                        ;;
        esac
}

test "${ACTION}" = "ifdown" && {

        case "${INTERFACE}" in
                wg*)
                        sh /root/del-npt-v2.sh ${INTERFACE}
                        ;;
        esac
}
# cat add-npt.sh
#!/bin/sh

test ! -z "${1}" && iface="${1}" || exit 1

. /lib/functions/network.sh

network_get_subnets6 subnets6 "${iface}"

gua=
ula=

for _s in ${subnets6}
do
        # Find GUA and ULA prefix, and removing host-part to form a proper prefix

        __t="$( echo "${_s}" | grep -Ee '^(2|3)' | sed -e 's/::1/::/' )"
        test ! -z ${__t} && gua="${__t}"
        unset __t

        __t="$( echo "${_s}" | grep -Ee '^(fc|fd)' | sed -e 's/::1/::/' )"
        test ! -z ${__t} && ula="${__t}"
        unset __t
done

# Add a default route for hosts on the ULA subnet
ip -6 route add default from "${ula}" dev pppoe-wan || true

# Add NPT rule
ip6tables \
        -t nat \
        -A POSTROUTING \
        -s "${ula}" \
        -o pppoe-wan \
        -j NETMAP \
        --to "${gua}" \
        -m comment \
        --comment "${iface} NPT"

The ip -6 route add default from "${ula}" dev pppoe-wan uses IPv6 "source specific" routing. So routing decision is not only based on destination, but also on source, in this case the ULA prefix. As I'm using PPPoE on wan the device is pppoe-wan.

In case I have to restart the wireguard interface, I need to cleanup the ip6tables rule:

# cat del-npt-v2.sh
#!/bin/sh

test ! -z "${1}" && iface="${1}" || exit 1

# I found no other way then calling `grep` two-times...
# Substitute '--append' (`-A`) directly with '--delete' (`-D`)
ip6tables_rule="$( ip6tables-save | grep -e "${iface}" | grep -e 'NPT' | sed -e 's/-A /-D /' )"

test ! -z "${ip6tables_rule}" && {
        # Delete NPT rule if it is present
        # Needs to be run with `eval`
        eval ip6tables -t nat ${ip6tables_rule}
}

This is far away from beauty, but does an okish job.
Preferred solution would be a static IPv6 prefix, so I could configure the wireguard clients with a proper GUA.

Hey, long time no see (My Raspberry Pi died and I had to get a new one).

So it seems I'm back to square one, though I'm not too sure about it. Today I was able to start from (mostly) scratch and flashed an image from the 22.03.3 branch, ending up with the following network configuration:

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

config globals 'globals'
	option ula_prefix 'dd04:52a5:a38a::/48'

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'eth1'
	list ports 'ztrta4adry'

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option ipaddr '192.168.1.1'
	option netmask '255.255.255.0'
	option ip6assign '64'
	list ip6class 'local'
	list ip6class 'wan_6'

config interface 'docker'
	option device 'docker0'
	option proto 'none'
	option auto '0'
	option peerdns '0'
	option ip6assign '64'
	list ip6class 'local'
	list ip6class 'wan_6'

config device
	option type 'bridge'
	option name 'docker0'

config interface 'wg0'
	option proto 'wireguard'
	option private_key '********'
	option listen_port '51820'
	option ip6assign '64'
	list addresses '10.0.5.1/24'
	list addresses 'fd2d:a278:3852::1/64'
	list addresses 'fe80::e097:46ff:fef0:2d8e/64'
	list ip6class 'local'
	list ip6class 'wan_6'

config device
	option name 'eth1'
	option mtu '1492'
	option mtu6 '1492'

config device
	option name 'br-iot'
	option type 'bridge'
	list ports 'br-lan.2'

config device
	option name 'br-guest'
	option type 'bridge'
	list ports 'br-lan.3'

config interface 'ZeroTier'
	option proto 'none'
	option ip6assign '64'
	list ip6class 'local'
	list ip6class 'wan_6'
	option device 'ztrta4adry'

config device
	option name 'pppoe-wan'
	option type 'tunnel'

config device
	option name 'wg0'

config interface 'wan'
	option proto 'pppoe'
	option device 'eth0'
	option username '******@********.net'
	option password '********'
	option ipv6 'auto'

/etc/config/dhcp

config dnsmasq
	option domainneeded '1'
	option noresolv '1'
	option localise_queries '1'
	option local '/lan/'
	option domain 'lan'
	option expandhosts '1'
	option logdhcp '0'
	option authoritative '1'
	option readethers '1'
	option leasefile '/tmp/dhcp.leases'
	option localservice '1'
	option ednspacket_max '1232'
	option dnsforwardmax '2300'
	option min_cache_ttl '270'
	list address '/router/192.168.1.1'
	list address '/status.client/192.168.1.1'
	option sequential_ip '1'
	option dnssec '1'
	option allservers '1'
	option confdir '/tmp/dnsmasq.d'
	list doh_backup_server '127.0.0.1#1053'
	list doh_backup_server '::1#1053'
	option rebind_protection '0'
	option port '5353'
	option cachesize '5000'
	option dhcp_match 'set:efi64-2,60,PXEClient:Arch:00009'
	list server '/mask.icloud.com/'
	list server '/mask-h2.icloud.com/'
	list server '/use-application-dns.net/'
	list server '127.0.0.1#5053'
	list server '127.0.0.1#5054'
	option doh_backup_noresolv '1'
	option enable_tftp '1'

config dhcp 'lan'
	option interface 'lan'
	option leasetime '12h'
	option dhcpv4 'server'
	list dhcp_option '6,192.168.1.1'
	list dhcp_option '3,192.168.1.1'
	list dhcp_option '44,192.168.1.1'
	list dhcp_option_force '114,http://status.client'
	option ra 'hybrid'
	list ra_flags 'managed-config'
	list ra_flags 'other-config'
	option dhcpv6 'hybrid'
	option ndp 'hybrid'
	option start '2'
	option limit '255'

config dhcp 'wan6'
	option dhcpv6 'hybrid'
	option ra 'hybrid'
	option ndp 'hybrid'
	option master '1'
	option interface 'wan6'

config odhcpd 'odhcpd'
	option maindhcp '0'
	option leasefile '/tmp/hosts/odhcpd'
	option leasetrigger '/usr/sbin/odhcpd-update'
	option loglevel '4'

/etc/config/firewall


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

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

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

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

config zone
	option name 'vpnzone'
	option input 'REJECT'
	option forward 'REJECT'
	option output 'ACCEPT'
	option masq '1'
	option masq6 '1'
	option masq6_privacy '1'
	option mtu_fix '1'
	list network 'wg_usa'
	list network 'wg_uk'
	list network 'wg_spa'

config forwarding
	option src 'lan'
	option dest 'vpnzone'

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 replies'
	option src 'wan'
	option proto 'udp'
	option src_port '547'
	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 rule
	option name 'Support-UDP-Traceroute'
	option src 'wan'
	option dest_port '33434:33689'
	option proto 'udp'
	option family 'ipv4'
	option target 'REJECT'
	option enabled '0'

config rule
	option target 'ACCEPT'
	option src 'wan'
	option proto 'udp'
	option dest_port '547'
	option name 'Allow DHCPv6 (546-to-547)'
	option family 'ipv6'
	option src_port '546'

config rule
	option target 'ACCEPT'
	option src 'wan'
	option proto 'udp'
	option dest_port '546'
	option name 'Allow DHCPv6 (547-to-546)'
	option family 'ipv6'
	option src_port '547'

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

config zone 'docker'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	option name 'docker'
	list device 'br-5adff94956ab'
	list network 'docker'

config rule
	option name 'AllowNGINXPMAdmin'
	option src_port '81'
	option dest 'lan'
	option dest_port '81'
	option target 'ACCEPT'
	option src 'lan'
	list dest_ip '172.18.0.2'

config redirect
	option target 'DNAT'
	option name 'RProxy-Admin'
	option src 'lan'
	option src_dport '81'
	option dest 'lan'
	option dest_port '81'
	option dest_ip '172.18.0.2'
	option enabled '0'

config redirect
	option target 'DNAT'
	option name 'RProxy'
	option src 'wan'
	option dest 'lan'
	option dest_ip '172.18.0.2'
	option src_dport '80'
	option dest_port '80'

config redirect
	option target 'DNAT'
	option name 'RProxy-SSL'
	option src 'wan'
	option dest 'lan'
	option dest_ip '172.18.0.2'
	option dest_port '443'
	option src_dport '443'

config redirect 'adblock_wan853'
	option src 'wan'
	option proto 'tcp udp'
	option src_dport '853'
	option dest_port '853'
	option target 'DNAT'
	option name 'AGH DNS over TLS'
	option dest 'lan'
	option dest_ip '192.168.1.1'

config redirect
	option target 'DNAT'
	option name 'AGH DNS over QUIC'
	option src 'wan'
	option src_dport '784'
	option dest 'lan'
	option dest_ip '192.168.1.1'
	option dest_port '784'

config rule
	option name 'RClone-GUI'
	option src 'lan'
	option src_port '5572'
	option dest 'lan'
	option dest_port '5572'
	option target 'ACCEPT'
	list dest_ip '192.168.1.1'
	list dest_ip 'fd04:52a5:a38a::1'

config rule
	option name 'HomeAssistant'
	option src 'lan'
	option src_port '8123'
	option dest 'lan'
	option dest_port '8123'
	option target 'ACCEPT'
	list dest_ip '192.168.1.1'
	list dest_ip 'fd04:52a5:a38a::1'

config rule
	option name 'Allow-NFS-RPC'
	option src 'lan'
	option proto 'tcp udp'
	option dest_port '111'
	option target 'ACCEPT'

config rule
	option name 'Allow-NFS'
	option src 'lan'
	option proto 'tcp udp'
	option dest_port '2049'
	option target 'ACCEPT'

config rule
	option name 'Allow-NFS-Lock'
	option src 'lan'
	option proto 'tcp udp'
	option dest_port '32777:32780'
	option target 'ACCEPT'

config rule
	option name 'Tautulli'
	option src 'lan'
	option src_port '8181'
	option dest 'lan'
	list dest_ip '172.18.0.5'
	option dest_port '8181'
	option target 'ACCEPT'

config rule
	option name 'PiHole-Admin'
	option src_port '82'
	option dest 'lan'
	option dest_port '82'
	option target 'ACCEPT'
	option src 'lan'
	list dest_ip '192.168.1.1'
	list dest_ip 'fd04:52a5:a38a::1'

config rule
	option name 'Transmission-GUI'
	option src 'lan'
	option dest 'lan'
	option target 'ACCEPT'
	list dest_ip '192.168.1.1'
	list dest_ip 'fd04:52a5:a38a::1'
	option src_port '9091'
	option dest_port '9091'

config rule
	option name 'NGINXPM-DB'
	option src 'lan'
	list src_ip '172.18.0.2'
	option src_port '3306'
	option dest 'lan'
	list dest_ip '172.18.0.3'
	option dest_port '3306'
	option target 'ACCEPT'

config rule
	option name 'Adguard-Admin'
	option src 'wan'
	option src_port '82'
	option dest 'lan'
	option dest_port '82'
	option target 'ACCEPT'
	list dest_ip '172.18.0.6'
	list dest_ip '2001:3984:3989::6'

config rule 'wg'
	option dest_port '51820'
	option target 'ACCEPT'
	option name 'Allow-WireGuard-lan'
	list proto 'tcp'
	list proto 'udp'
	option src 'wan'

config defaults
	option input 'REJECT'
	option output 'REJECT'
	option forward 'REJECT'
	option synflood_protect '1'
	option drop_invalid '1'

config rule
	option name 'Allow-ZeroTier-Inbound'
	list proto 'udp'
	option src 'wan'
	option dest_port '9993'
	option target 'ACCEPT'

config zone
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	option masq '1'
	option name 'ZeroTier'
	list network 'ZeroTier'

config forwarding
	option dest 'lan'
	option src 'ZeroTier'

config forwarding
	option dest 'wan'
	option src 'ZeroTier'

config forwarding
	option src 'lan'
	option dest 'ZeroTier'

config forwarding
	option src 'wan'
	option dest 'ZeroTier'

config redirect 'adblock_docker53'
	option name 'Adblock DNS (docker, 53)'
	option src 'docker'
	option proto 'tcp udp'
	option src_dport '53'
	option dest_port '53'
	option target 'DNAT'

config redirect 'adblock_docker853'
	option name 'Adblock DNS (docker, 853)'
	option src 'docker'
	option proto 'tcp udp'
	option src_dport '853'
	option dest_port '853'
	option target 'DNAT'

config redirect 'adblock_docker5353'
	option name 'Adblock DNS (docker, 5353)'
	option src 'docker'
	option proto 'tcp udp'
	option src_dport '5353'
	option dest_port '5353'
	option target 'DNAT'

config redirect 'adblock_lan53'
	option name 'Adblock DNS (lan, 53)'
	option src 'lan'
	option proto 'tcp udp'
	option src_dport '53'
	option dest_port '53'
	option target 'DNAT'

config redirect 'adblock_lan853'
	option name 'Adblock DNS (lan, 853)'
	option src 'lan'
	option proto 'tcp udp'
	option src_dport '853'
	option dest_port '853'
	option target 'DNAT'

config redirect 'adblock_lan5353'
	option name 'Adblock DNS (lan, 5353)'
	option src 'lan'
	option proto 'tcp udp'
	option src_dport '5353'
	option dest_port '5353'
	option target 'DNAT'

config redirect 'adblock_vpnzone53'
	option name 'Adblock DNS (vpnzone, 53)'
	option src 'vpnzone'
	option proto 'tcp udp'
	option src_dport '53'
	option dest_port '53'
	option target 'DNAT'

config redirect 'adblock_vpnzone853'
	option name 'Adblock DNS (vpnzone, 853)'
	option src 'vpnzone'
	option proto 'tcp udp'
	option src_dport '853'
	option dest_port '853'
	option target 'DNAT'

config redirect 'adblock_vpnzone5353'
	option name 'Adblock DNS (vpnzone, 5353)'
	option src 'vpnzone'
	option proto 'tcp udp'
	option src_dport '5353'
	option dest_port '5353'
	option target 'DNAT'

config redirect 'adblock_wan53'
	option name 'Adblock DNS (wan, 53)'
	option src 'wan'
	option proto 'tcp udp'
	option src_dport '53'
	option dest_port '53'
	option target 'DNAT'

config redirect 'adblock_wan5353'
	option name 'Adblock DNS (wan, 5353)'
	option src 'wan'
	option proto 'tcp udp'
	option src_dport '5353'
	option dest_port '5353'
	option target 'DNAT'

config redirect
	option dest 'lan'
	option target 'DNAT'
	option name 'Allow-P2P-USA'
	option src 'vpnzone'
	option src_dport '58861'

config include 'opennds'
	option type 'script'
	option path '/usr/lib/opennds/restart.sh'

config redirect
	option dest 'lan'
	option target 'DNAT'
	option name 'Mosquitto-Outside'
	option src 'wan'
	option src_dport '8883-8884'
	option dest_ip '192.168.1.1'
	option dest_port '8883-8884'

config redirect
	option dest 'lan'
	option target 'DNAT'
	option name 'Mosquitto-WebSockets'
	option src 'wan'
	option src_dport '8083'
	option dest_ip '192.168.1.1'
	option dest_port '8083'

config redirect
	option dest 'lan'
	option target 'DNAT'
	option name 'Allow-ZeroTier-Inbound'
	list proto 'udp'
	option src 'wan'
	option src_dport '9993'
	option dest_ip '192.168.1.1'
	option dest_port '9993'

config forwarding
	option src 'docker'
	option dest 'wan'

config include 'miniupnpd'
	option type 'script'
	option path '/usr/share/miniupnpd/firewall.include'

config rule 'samba_nsds_nt'
	option name 'NoTrack-Samba/NS/DS'
	option src 'lan'
	option dest 'lan'
	option dest_port '137-138'
	option proto 'udp'
	option target 'NOTRACK'

config rule 'samba_ss_nt'
	option name 'NoTrack-Samba/SS'
	option src 'lan'
	option dest 'lan'
	option dest_port '139'
	option proto 'tcp'
	option target 'NOTRACK'

config rule 'samba_smb_nt'
	option name 'NoTrack-Samba/SMB'
	option src 'lan'
	option dest 'lan'
	option dest_port '445'
	option proto 'tcp'
	option target 'NOTRACK'

config redirect 'dns_int'
	option src 'lan'
	option src_dport '53'
	option proto 'tcp udp'
	option target 'DNAT'
	option family 'any'
	list src_mac '!2C:16:DB:A0:E6:92'
	option name 'Redirect-DNS'
	option dest_ip '192.168.1.1'
	option src_ip '!192.168.1.1'
	option enabled '0'

config nat 'dns_masq'
	option name 'Masquerade-DNS'
	option src 'lan'
	option dest_ip '192.168.1.1'
	option dest_port '53'
	option proto 'tcp udp'
	option target 'MASQUERADE'

config include 'pbr'
	option fw4_compatible '1'
	option type 'script'
	option path '/usr/share/pbr/pbr.firewall.include'

However, for some reason I'm not able to get br-lan to get a public-facing address at all from wan_6, even though resetting the network service successfully spawns one for the router:

Alas, I'm unable to ping to any IPv6 address:

ping ipv6.google.com
ping: connect: Network unreachable

As such, I think I'm stuck between a rock and a hard place, given I'm not able to progress in turning my connection into a NAT64 to be able to perform PBR configuration.

Where do you think I could begin to troubleshoot this issue?

Thanks for the help!

P.D.: It took a lot of wait time, but I confirmed with my ISP and long story short, a /64 is all I'm going to get.

This is no ULA prefix.

And I see no wan_6 stanza.

I see

Oddly it seems it was auto-generated, but I just rewrote it with the following:

fdf8:f929:5f71::/48

As for that, I'm not too sure how would I proceed. From what I had understood, given my connection relies on PPPoE, the Virtual Dynamic Interface that spawns from within the wan interface should have been enough, and trying to manually write one from scratch seemingly did no difference. Would you happen to have handy a reference for how to manually spawn it?

config interface            'wan'
    option  device          'eth0.7'    # I need an tagged interface
    option  proto           'pppoe'
    option  username        '<username>'
    option  password        '<password>'
    option  ipv6            'auto'

config interface            'wan6'
    option  device          'eth0.7'
    option  proto           'dhcpv6'
    option  reqaddress      'try'       # [try,force,none]
    option  reqprefix       '56'        # I know my provider hands out /56 if asked

But back to the initial issue you have:
From your first post, I understand you have dynamic IPv4 and (only) an dynamic /64 IPv6 on your router. And you have dyndns domain with A and AAAA record.
Your road warrior devices connects on IPv4-Only, they should get IPv6 connectivity via your router at home?

In your last config I don't see the wg-client configs.

Second, @mk24 didn't provided more details how is it possible to not configure IPv6 on the client-config but still getting IPv6 addresses out of the GUA prefix used on wan6.
As I was unable to find information on this, I went the route of assigning my clients only a ULA address and then do NPT (network prefix translation).

Did you had a look at https://openwrt.org/docs/guide-user/network/ipv6/configuration#ipv6_relay too?

Back to wireguard: Your clients can connect, and IPv4 to LAN and WAN works? And its only that IPv6 does not work?

Okay, just adapted it to my current configuration, it ended up as follows:

config interface 'wan'
	option proto 'pppoe'
	option device 'eth0'
	option username '*******@********.net'
	option password '**********'
	option ipv6 'auto'

config interface            'wan6'
    option  device          'eth0'
    option  proto           'dhcpv6'
    option  reqaddress      'try'       # [try,force,none]
    option  reqprefix       '64'        # Max /64

That's exactly it, fortunately when running through IPv4 at least 4 different peers have successfully connected and stayed stable for the better part of a year, one of them even across different countries.

Getting them to connect through IPv6 meanwhile hasn't been as successful.

Probing for the same device with ping leads to the following results:

ping fd2d:a278:3852::2
PING fd2d:a278:3852::2(fd2d:a278:3852::2) 56 data bytes
From fd2d:a278:3852::1 icmp_seq=1 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=2 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=3 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=4 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=5 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=6 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=7 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=8 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=9 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=10 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=11 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=12 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=13 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=14 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=15 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
From fd2d:a278:3852::1 icmp_seq=16 Destination unreachable: Address unreachable
ping: sendmsg: Destination address required
^C
--- fd2d:a278:3852::2 ping statistics ---
16 packets transmitted, 0 received, +16 errors, 100% packet loss, time 15572ms


ping 10.0.5.2
PING 10.0.5.2 (10.0.5.2) 56(84) bytes of data.
64 bytes from 10.0.5.2: icmp_seq=1 ttl=64 time=22.8 ms
64 bytes from 10.0.5.2: icmp_seq=2 ttl=64 time=20.8 ms
64 bytes from 10.0.5.2: icmp_seq=3 ttl=64 time=19.0 ms
64 bytes from 10.0.5.2: icmp_seq=4 ttl=64 time=83.2 ms
64 bytes from 10.0.5.2: icmp_seq=5 ttl=64 time=16.3 ms
^C
--- 10.0.5.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4007ms
rtt min/avg/max/mdev = 16.329/32.425/83.222/25.486 ms

Truth be told I wasn't sure if it would have fitted within the character limit, but you're right, this are the client configs:

config interface 'wg0'
	option proto 'wireguard'
	option private_key 'REDACTED'
	option listen_port '51820'
	option ip6assign '64'
	list addresses '10.0.5.1/24'
	list addresses 'fd2d:a278:3852::1/64'
	list addresses 'fe80::e097:46ff:fef0:2d8e/64'
	list ip6class 'local'
	list ip6class 'wan_6'

config wireguard_wg0
	option public_key 'REDACTED'
	option description 'ToastyPen10+'
	option endpoint_port '51820'
	option persistent_keepalive '25'
	list allowed_ips '10.0.5.2/32'
	list allowed_ips 'fd2d:a278:3852::2/64'
	option preshared_key 'REDACTED'

config wireguard_wg0
	option description 'ToastyUFO'
	option preshared_key 'REDACTED'
	list allowed_ips '10.0.5.3/32'
	list allowed_ips 'fd2d:a278:3852::3/64'
	option endpoint_port '51820'
	option persistent_keepalive '25'
	option public_key 'REDACTED'

config wireguard_wg0
	option description 'Moto One Action de Liz'
	option preshared_key 'REDACTED'
	list allowed_ips '10.0.5.4/32'
	list allowed_ips 'fd2d:a278:3852::4/64'
	option endpoint_port '51820'
	option persistent_keepalive '25'
	option public_key 'REDACTED'

config wireguard_wg0
	option description 'Liz-PC'
	option public_key 'REDACTED'
	option preshared_key 'REDACTED'
	list allowed_ips '10.0.5.5/32'
	list allowed_ips 'fd2d:a278:3852::5/64'
	option endpoint_port '51820'
	option persistent_keepalive '25'

config wireguard_wg0
	option description 'Moto One Action de Celia'
	option preshared_key 'REDACTED'
	list allowed_ips '10.0.5.6/32'
	list allowed_ips 'fd2d:a278:3852::6/64'
	option endpoint_port '51820'
	option persistent_keepalive '25'
	option public_key 'REDACTED'

I see, I'd like to know how you did this after we figure out the delegation issue if possible.

Yeah, that's kind of what had me stumped, as neither using the relay or hybrid options for any of the configurations seemed to make a difference.

For what it's worth, this is how my dhcp config file looks like on the relevant section:

config dhcp 'lan'
	option interface 'lan'
	option leasetime '12h'
	option dhcpv4 'server'
	list dhcp_option '6,192.168.1.1'
	list dhcp_option '3,192.168.1.1'
	list dhcp_option '44,192.168.1.1'
	list dhcp_option '44,192.168.1.1'
	list dhcp_option_force '114,http://status.client'
	option ra 'relay'
	list ra_flags 'managed-config'
	list ra_flags 'other-config'
	option dhcpv6 'relay'
	option ndp 'relay'
	option start '2'
	option limit '255'

config dhcp 'wan6'
	option dhcpv6 'relay'
	option ra 'relay'
	option ndp 'relay'
	option master '1'
	option interface 'wan6'

config odhcpd 'odhcpd'
	option maindhcp '0'
	option leasefile '/tmp/hosts/odhcpd'
	option leasetrigger '/usr/sbin/odhcpd-update'
	option loglevel '4'

As of right now, the Interfaces section ends up looking like this on the affected ones:

That's exactly right, been this way for the better part of a year, if I'm remembering correctly.

This is a test coming from my phone on LTE and connected to my router through the Wireguard tunnel at home:

Looking at this latest configuration, there is a lot there that can't be active. Since there is only a single /64 from the ISP, prefix delegation to local networks is not possible. The LAN and VPN interfaces cannot hold a GUA since there is no unique prefix for them to use. The settings of ip6assign and ip6class are being ignored. ip6assign should not be set at all in this use case.

So relay mode is the key. In relay mode:

  • LAN-like interfaces do not have any GUA, only link-local and possibly ULA.
  • LAN endpoints are advertised the wan prefix via relay, then use SLAAC to assign themselves an IP within that prefix.
  • dhcpv6 may be run in server mode to configure DNS servers onto the endpoints. (odhcpd does not presently support a DNS option in relayed RAs).
  • LAN endpoints use the routers link-local as their default gateway.

From looking at the source code it appears that the hybrid setting does nothing more than automatically choose between relay and server at startup time. It is not a unique mode.

Your road warrior does not hold a GUA, only a ULA. Since ULAs cannot be routed on the Internet, a request to an Internet site must have a source IP that is a GUA.

The obvious workaround for this is to NAT6 in the home router, converting the ULAs of LAN and VPN endpoints to the router's GUA. This is also not a very good solution. Some OSs will not use a ULA as a default route.

The real solution is for the road warrior to hold a GUA and use it directly to originate connections to the Internet via VPN. This is a problem with Wireguard, since the road warrior's /128 needs to be installed as an allowed_ip on the server, and when the road warrior chose it by SLAAC or privacy enhancement, the server has no way to know what IP was chosen.

1 Like

Okay, first of all thanks for the detailed answer, I'm honestly still trying to make heads or tails of it, but if I'm understanding correctly there might be an (imperfect/unstable) way to achieve things still (I'm still kind of out of my depth when it comes to IPv6, so please correct me if I'm wrong anywhere).

From what I understand here, this is what both AsusWRT/Merlin and stock OpenWRT tried to do with my PPPoE link, given that before I started tinkering around with the Interface's settings all network devices would receive an individually addressable SLAAC-assigned IP Address (albeit a /64 one, but still), being as such that they were able to both traverse and directly communicate with the global Internet even if I was to manually disable their access to the v4 section of the network.

At some point along the journey, I broke this while trying to implement NAT6 and left it unfinished, thus everything capable of holding one would now only receive a link-local address, leaving no traversal connectivity and only DNS6 capabilities on a good day since the rest of the network stack was still
expected to handle such connections.

Thing is, how can I turn this back on if needed?

Given this was the original plan, it concerns me a little that you mention possible (I hope) edge cases where certain OSs would not accept such topology and use it, but if so, which ones should I watch out for and (possibly) find a workaround for, if I were to go this route?

This would certainly be an interesting approach, and given what you say probably the most reasonable answer (though it still would leave me concerned for how to perform Policy Based Routing without NAT6), but it leaves me wondering if perhaps a hotplug script would be able to add and/or delete the rotating addresses of each peer on the moment of the handshake, even if from my understanding this would have the potential of causing temporary disconnects for any other peer using the server.

In any case, taking into account the configurations I've shared, would this be sufficient as a starting point to proceed to any of the three scenarios? And if so, how could any of them be achieved?

In the meantime, thanks for the patience and the help!

Edit:

After sending this message I started trying to bring up manually the wan6 interface, prompted by this forum post, and after letting LuCI adapt it to the modern syntax, nothing happened.

Then, I checked again what you mentioned regarding the relay roles, and finally got it working with the following configuration:

/etc/config/network

config interface 'wan'
	option proto 'pppoe'
	option device 'eth0'
	option username '*********@*******.net'
	option password '***********'
	option ipv6 '1'

config interface 'wan6'
	option proto 'dhcpv6'
	option device '@wan'
	option reqaddress 'try'
	option reqprefix '64'

/etc/config/dhcp

config dhcp 'lan'
	option interface 'lan'
	option leasetime '12h'
	option dhcpv4 'server'
	list dhcp_option_force '114,http://status.client'
	list ra_flags 'managed-config'
	list ra_flags 'other-config'
	option ndp 'relay'
	option start '2'
	option limit '255'
	list dhcp_option '6,192.168.1.1'
	list dhcp_option '3,192.168.1.1'
	list dhcp_option '44,192.168.1.1'
	option ra 'server'
	option dhcpv6 'server'

config dhcp 'wan6'
	option dhcpv6 'relay'
	option ra 'relay'
	option ndp 'relay'
	option master '1'
	option interface 'wan6'

After this was set, I performed a reboot and ended up with no Internet connectivity... sorta.

Turns out that for some reason, pbr ends in a segmentation fault when under these settings, and also AdGuard Home crashes when failing to create its ipset file (FATAL: preparing ipset settings: open /var/run/pbr.adguardhome.ipsets: no such file or directory), so after commenting out its variable in the config file and restarting the service, I am back online!

I think I was able to get back to Native IPv6, but for some reason each device is receiving two addresses from WAN6 and LAN, and not even the router is able to reach anywhere through IPv6, but hey, progress!

On the lan, ra must be set to 'relay'. Do not set the managed-config flag, as a router in relay mode has no IPv6s of its own to issue by dhcp.

Avoid adguard and pbr until basic connectivity has been worked out.

Okay, done and done. Though for some reason when I checked right now to make the change the ra_flags were no longer present.

Sure, no problem. At the moment they are already disabled.

After setting br-lan to relay, I'm back to no devices having IPv6 addresses, but setting it as server I'm able to connect through IPv6 from everywhere now except the router itself, even though it has an IPv6 address. A bit weird, but still progress.

Okay, status report.

So far, I was able to get back to using the default dual-stack configuration on all devices including the router after a reboot. And after doing so, I ended up configuring NAT6 so I would be able to still use the IPv6 Internet while allowing for PBR if needed. So far both devices on the network and the router itself have been able to make successful connections within this configuration, so I believe everything is ready to begin with this solution:

How should I continue?

Final status report:

I had to open another thread to fix things around this issue, but fortunately everything is as expected at the moment.

I'll go ahead and link it here for posterity and archival purposes. Thank you everyone for your help!

The solution's thread

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.