Wireguard with IPv6 not working as expected

Hey everyone,

for the sake of completeness: I already started a Discussion of this topic on Reddit: https://www.reddit.com/r/WireGuard/comments/kytwf0/just_another_why_is_my_config_not_working_post/ and hijacked another discussion in the DietPi Forum: https://dietpi.com/forum/t/pivpn-with-wireguard-and-pihole-not-working-correctly/4862/1
However, I start from the beginning:

I run Dietpi on a Raspi with PiHole set up and working fine.

Next step was to set up Wireguard to have PiHole functionality and access to LAN on the go. My ISP provides only DS Lite, so just having IPv6 was the first problem for me (IPv4 is so much easier to understand). However, i managed to get a connection from WAN via Wireguard to the Dietpi with these configs:

[Interface]
Address = 192.168.0.3/24, fe80::dea6:32ff:fe33:85cb/64
PrivateKey = *Key*
ListenPort = 51902

PreUp = /boot/dietpi/func/obtain_network_details
PostUp = sysctl net.ipv4.conf.%i.forwarding=1 net.ipv4.conf.$(mawk 'NR==3' /run/dietpi/.network).forwarding=1
PostUp = sysctl net.ipv6.conf.$(mawk 'NR==3' /run/dietpi/.network).accept_ra=2
PostUp = sysctl net.ipv6.conf.%i.forwarding=1 net.ipv6.conf.$(mawk 'NR==3' /run/dietpi/.network).forwarding=1
PostUp = ip neigh add proxy fe80::dea6:32ff:fe33:85c2 dev eth0
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o $(mawk 'NR==3' /run/dietpi/.network) -j MASQUERADE
PostUp = ip6tables -A FORWARD -i %i -j ACCEPT; ip6tables -t nat -A POSTROUTING -o $(mawk 'NR==3' /run/dietpi/.network) -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o $(mawk 'NR==3' /run/dietpi/.network) -j MASQUERADE
PostDown = ip6tables -D FORWARD -i %i -j ACCEPT; ip6tables -t nat -D POSTROUTING -o $(mawk 'NR==3' /run/dietpi/.network) -j MASQUERADE

# Client 1
[Peer]
PublicKey = *Key*
AllowedIPs = 192.168.0.5/32, fe80::dea6:32ff:fe33:85c2/128

Client.conf:

[Interface]
Address = 192.168.0.5/32, fe80::dea6:32ff:fe33:85c2/128
PrivateKey = *Key*
DNS = fe80::dea6:32ff:fe33:85cb, 192.168.0.3

[Peer]
PublicKey = *Key*
Endpoint = *correct-ipv6-address*:51902
AllowedIPs = 0.0.0.0/0, ::/0

My sysctl.conf looks like this:

net.ipv6.conf.all.accept_ra = 2
net.ipv6.conf.eth0.accept_ra = 2
net.ipv6.conf.wg0.accept_ra = 2
net.ipv6.conf.all.forwarding = 1
net.ipv4.ip_forward = 1

net.ipv6.conf.all.proxy_ndp = 1
net.ipv6.conf.eth0.proxy_ndp=1
ip neigh add proxy fe80::dea6:32ff:fe33:85c2 dev fe80::dea6:32ff:fe33:85cb

So by checking with the wg command a connection is established, as well as PiHole queries indicate that DNS requests are being made, so routing doesn’t seem to be the problem. However, no packets seem to get through (or just not back?) because whenever i test the connection by trying to load a website, I always get a “server stopped responding” message.

sudo wg gives this:

  endpoint: *public IPv6*:51393
  allowed ips: 192.168.0.5/32, fe80::dea6:32ff:fe33:85c2/128
  latest handshake: 42 seconds ago
  transfer: 50.75 KiB received, 1.02 KiB sent

wg setconf wg0 wg0.conf gives:

Line unrecognized: `Address=192.168.0.3/24,fe80::dea6:32ff:fe33:85cb/64'
Configuration parsing error

I also thought that maybe my choice of private IPv6 was wrong, but then PiHole wouldn’t show queries from that IP…I guess.

trendy and Joulinar noted in the other DietPi Forum Thread that if I have or had Docker installed, it might be a problem, however I never had Docker installed.

So, that’s my problem with I hope nearly all information required given. Let the trouble shooting begin :smiley:

First of all the address you are using is link local, it cannot be routed. Use a ULA address for example fddd:aaaa:bbbb::/48 for the whole site and assign a /64 for the tunnel.
Or if you have a prefix delegated from the provider you can use from that.
In case you use the ULA, then NAT6 is necessary to access the internet.
If you use GUA from the delegated prefix, then no NAT is necessary, just to make sure that the ISP router has a route for it via your dietpi.

Ok, so now my absolute absence of IPv6 knowledge comes to light.
Honestly, the choice of the internal IPv6 adress for the client came from the DietPi. I took the IPv6 adress of it and just changed the last digit. Seemed like a good idea, especially because I was able to even establish the connection after that.

I will be able to test your supposed IPv6 use later but for now, do I understand correctly that I can use the prefix delegated from my ISP used for the Wireguard Server as the “Allowed IP” in the client setting?
It MAY be that then the router won’t be too happy with it, as it is the one given from my ISP with very limited settings but I will see when I’m able to test it later.

Yes, you can use a subnet of the delegated prefix for the wg tunnel.
Ideally dietpi should request a delegated prefix from the ISP router, which then will be used in the tunnel. This however has a few drawbacks, especially in case the prefix you have from the ISP is not static. Then you’d have to change it somehow, or use the ULA and NAT6.

is there a strong need to use IPv6?

Ok now I can try it out a bit.

Joulinar Yes, my ISP only provides DS Lite, so no IPv4 unfortunately.

So i tried to use the dietpi subnet with the ISP prefix I got by using

ip addr

and then taking from eth0 the /64 inet6 address whereafter it said “scope global dynamic mngtmpaddr”.

I used this address as IPv6 address in the “Interface” section of my wg0.conf and in the “Peer” section for “Allowed IPs” I used the same address, but with the last digit changed and with /128. (Here I think may be an logic error on my side as I not quite understand IPv6 yet)

In the wg0-client.conf I then used the same /128 IP in the “Interface” section, but still using the local IPv6 for DNS (which I think makes sense so I don’t route the DNS lookup over WAN back to my DietPi)


This whole setup “worked” in the way that I still could connect, PiHole still showed queries but the problem remains the same, no packets coming back to my client, wg shows:

transfer: 29.15 KiB received, 468 B sent

if you have a windows box, you could use wireshark to check what and if packages are arriving

This is not how I meant to delegate a prefix. You cannot assign IPs from the lan into the wg.It has to be a separate network.
E.g if lan is 2001:aaaa:bbbb:ccc0::/64 you could ask from the ISP router a prefix for delegation by dhcp6 client and let’s say it assigns you 2001:aaaa:bbbb:ccc1::/64 , that can be assigned to the wg.

I need to say, I don’t use IPv6 at all. Therefore the question might be useless. But would it be possible to work inside the local network using IPv4. The IPv6 connection is between mobile device and the router, and inside the VPN tunnel, IPv4 is used?

Hey guys,

sorry I wasn’t able to play with the problem as I was preoccupied with other things…

Joulinar, Interesting approach. Tried that, just commenting out the IPv6 addresses (except the Endpoint one in the client.conf, this obviously needs to stay IPv6). And…it worked. Well, at least it worked the same as before. So, connection is established, I can ssh into the pi from the wg client and PiHole on the server sees queries, but no packets get through.
I also tried to ping the wg client (192.168.0.5) with a machine on LAN and with the DietPi wg server Raspi

On the machine on LAN, I got

Request timeout for icmp_seq 0
Request timeout for icmp_seq 1
Request timeout for icmp_seq 2
Request timeout for icmp_seq 3
ping: sendto: No route to host
Request timeout for icmp_seq 4
ping: sendto: Host is down
Request timeout for icmp_seq 5
ping: sendto: Host is down
Request timeout for icmp_seq 6
ping: sendto: Host is down
Request timeout for icmp_seq 7
ping: sendto: Host is down
Request timeout for icmp_seq 8
^Xping: sendto: Host is down
Request timeout for icmp_seq 9
ping: sendto: Host is down
Request timeout for icmp_seq 10

and on the DietPi

PING 192.168.0.5 (192.168.0.5) 56(84) bytes of data.
From 192.168.0.3 icmp_seq=1 Destination Host Unreachable
From 192.168.0.3 icmp_seq=2 Destination Host Unreachable
From 192.168.0.3 icmp_seq=3 Destination Host Unreachable
From 192.168.0.3 icmp_seq=4 Destination Host Unreachable
From 192.168.0.3 icmp_seq=5 Destination Host Unreachable
From 192.168.0.3 icmp_seq=6 Destination Host Unreachable
From 192.168.0.3 icmp_seq=7 Destination Host Unreachable
From 192.168.0.3 icmp_seq=8 Destination Host Unreachable
From 192.168.0.3 icmp_seq=9 Destination Host Unreachable
From 192.168.0.3 icmp_seq=10 Destination Host Unreachable
From 192.168.0.3 icmp_seq=11 Destination Host Unreachable

which I don’t understand because PiHole sees the queries. I’m pretty confused now.

Edit:

Sorry, I still don’t quite understand. If I take the subnet I get from using

ip addr

on the dietpi, am I not in a different subnet than the LAN? (My ISP delegates a /59 network, of which LAN uses the /64 of the prefix (again, not sure if I understand this IPv6 stuff correctly) which again is narrowed down as - following my understanding -

ip addr

shows.

I get the feeling that I should relearn subnetting, after rereading what I just wrote something feels off. Please tell me, so I can try to read up subnetting again.

are you using same IP range for VPN as for the local network?

As I now am getting more and more confused: yes? :smiley:

My LAN is 192.168.0.0/24. DietPi wg server is static 192.168.0.3 and I assign in wireguard 192.168.0.5/32 for the client.

can you share ip a

Result of ip a

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether dc:a6:32:33:85:cb brd ff:ff:ff:ff:ff:ff
    inet 192.168.0.3/24 brd 192.168.0.255 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 **ipv6**:85cb/64 scope global dynamic mngtmpaddr
       valid_lft 172799sec preferred_lft 86399sec
    inet6 fe80::dea6:32ff:fe33:85cb/64 scope link
       valid_lft forever preferred_lft forever
12: wg0: <POINTOPOINT,NOARP,UP,LOWER_UP> mtu 1420 qdisc noqueue state UNKNOWN group default qlen 1000
    link/none
    inet 192.168.0.3/24 scope global wg0
       valid_lft forever preferred_lft forever

you have assigned same ip 192.168.0.3/24 to eth0 as well as wg0. That’s very bad idea. :wink:

Usually VPN should have an own IP range. Use 10.9.0.1/24 as server address and 10.9.0.2/24 for first client

First of all the wireguard doesn’t bridge, you must use a different subnet for the tunnel than the one you use in your lan.
The second thing is that this subnet must be advertised in the lan, as only the dietpi knows about it. Either a static route on the ISP router or SNAT on the dietpi (but this means only wg->lan communication). With some DNATs on dietpi you can achieve a few ports forwarded from lan to wg clients, if needed.

The lan and the wg must be different subnets, not the same. Just like with IPv4. And since the smallest prefix in IPv6 is /64, you need to use a different /64 than the one you have in lan.

Sorry guys, was very busy today. Just had the time to test your suggestions.

Okay, that seems logical. Don’t know what I thought, setting it up like that. Unfortunately changing it to the IPs suggested by you doesn’t solve the problem. A connection is still established, I still see queries in PiHole and can still ssh into the Pi from my client.

However, things changed when I try to ping the client.

Trying to ping from the DietPi:

PING 10.9.0.2 (10.9.0.2) 56(84) bytes of data.
64 bytes from 10.9.0.2: icmp_seq=1 ttl=64 time=318 ms
64 bytes from 10.9.0.2: icmp_seq=2 ttl=64 time=21.1 ms
64 bytes from 10.9.0.2: icmp_seq=3 ttl=64 time=4.00 ms
64 bytes from 10.9.0.2: icmp_seq=4 ttl=64 time=4.23 ms
64 bytes from 10.9.0.2: icmp_seq=5 ttl=64 time=4.06 ms

→ Great success! :smiley:

Trying to ping from machine in lan:

PING 10.9.0.2 (10.9.0.2): 56 data bytes
92 bytes from 84.116.198.94: Destination Net Unreachable
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
 4  5  00 5400 c2f9   0 0000  3f  01 edb3 192.168.0.73  10.9.0.2

Request timeout for icmp_seq 0
92 bytes from 84.116.198.94: Destination Net Unreachable
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
 4  5  00 5400 05a6   0 0000  3f  01 ab07 192.168.0.73  10.9.0.2

Request timeout for icmp_seq 1
92 bytes from 84.116.198.94: Destination Net Unreachable
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
 4  5  00 5400 1a88   0 0000  3f  01 9625 192.168.0.73  10.9.0.2

Request timeout for icmp_seq 2
92 bytes from 84.116.198.94: Destination Net Unreachable
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
 4  5  00 5400 53a6   0 0000  3f  01 5d07 192.168.0.73  10.9.0.2

Request timeout for icmp_seq 3
92 bytes from 84.116.198.94: Destination Net Unreachable
Vr HL TOS  Len   ID Flg  off TTL Pro  cks      Src      Dst
 4  5  00 5400 f9b4   0 0000  3f  01 b6f8 192.168.0.73  10.9.0.2

I guess that’s because I’m on another subnet?(I REALLY have to read up subnetting again)

…aaaaand as I wrote I simultaneously tried to load a website again and it worked. Don’t know why it first did nothing but it seems, ditching the assignment of internal IPv6 and choosing the right IPv4 subnet was the solution. Classic case of thinking too complicated.

Big thanks to trendy and Joulinar, you guys rock!

One additional question regarding choosing the right subnet: When I first played with a Raspi/Wireguard setup, I had an ISP with IPv4. The LAN was 192.168.2.0/24. The Raspi had static 192.168.2.111 and I assigned 192.168.2.180/24 for wg0, with clients going from 192.168.2.181/32 counting up. This worked flawless…why? If overlapping eth0 and wg0 subnets is such a big deal (as we saw in my problem here), why did it work then?

basically it’s 2 different networks with 2 different interfaces. where does the system should know to which interface to sent packages as the ip range is the same? In fact the VPN server is doing a routing between networks and not a bridging :slight_smile:

And if you use dietpi-software to setup WireGuard, you would get correct implementation already :wink:

And doing a ping from your local network towards the VPN will work only if you tell your local network where to sent packages for the VPN to. Usually all packages are sent to your router and the router will most probably sent it to the internet. But you would need to setup a route inside the router to push packages to your VPN server for the VPN IP range.

This is how it looks on my privat network if I try to ping my WireGuard server locally.

>ping 10.9.0.1

Pinging 10.9.0.1 with 32 bytes of data:
Request timed out.
Request timed out.
Request timed out.
Request timed out.

Ping statistics for 10.9.0.1:
    Packets: Sent = 4, Received = 0, Lost = 4 (100% loss)

It’s failing same way as on you network, because my router simply doesn’t know what to do.

But it change if I setup a static route like this.


Now, success :wink:

>ping 10.9.0.1

Pinging 10.9.0.1 with 32 bytes of data:
Reply from 10.9.0.1: bytes=32 time=21ms TTL=64
Reply from 10.9.0.1: bytes=32 time=7ms TTL=64
Reply from 10.9.0.1: bytes=32 time=10ms TTL=64
Reply from 10.9.0.1: bytes=32 time=13ms TTL=64

Ping statistics for 10.9.0.1:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 7ms, Maximum = 21ms, Average = 12ms