Bug: Mullvad and IPv6 only host / improve IPv6 detection
Is this urgent?
No
Host OS
Amazon Linux 2023
CPU arch
aarch64
VPN service provider
Mullvad
What are you using to run the container
docker run
What is the version of Gluetun
Running version latest built on 2024-09-29T18:12:41.313Z (commit 7ebbaf4)
What's the problem 🤔
I'm getting no Wireguard connection when running a Docker container on an IPv6-only host. I've narrowed it down to the following two issues:
-
Gluetun is selecting IPv4 addresses from its server list and fails to connect until it randomly selects an IPv6 address. It would be nice to have a flag for Gluetun so that Wireguard (and maybe OpenVPN too?) will only try servers via their IPv6 address.
-
There's a bug in allowing NDP multicast packets:
https://github.com/qdm12/gluetun/blob/7ebbaf4351404b0ae4ed3ff67985637385338094/internal/firewall/iptables.go#L191
The destination subnet should be
ff02::1:ff00:0/104. I have confirmed this change restores Wireguard connectivity (when Gluetun selects an IPv6 address as mentioned above). Even with this fix, it seems like theip6tablesrules are still blocking some NDP packets from the link-local address:Oct 3 23:31:05 IN= OUT=eth0 MAC= SRC=fe80::42:acff:fe11:2 DST=fc00::1 LEN=72 TC=0 HOPLIMIT=255 FLOWLBL=0 PROTO=ICMPv6 TYPE=135 CODE=0 MARK=0x0 Oct 3 23:31:06 IN= OUT=eth0 MAC= SRC=fe80::42:acff:fe11:2 DST=fc00::1 LEN=72 TC=0 HOPLIMIT=255 FLOWLBL=0 PROTO=ICMPv6 TYPE=135 CODE=0 MARK=0x0 Oct 3 23:31:07 IN= OUT=eth0 MAC= SRC=fe80::42:acff:fe11:2 DST=fc00::1 LEN=72 TC=0 HOPLIMIT=255 FLOWLBL=0 PROTO=ICMPv6 TYPE=135 CODE=0 MARK=0x0 Oct 3 23:31:11 IN= OUT=eth0 MAC= SRC=fe80::42:acff:fe11:2 DST=fe80::1 LEN=72 TC=0 HOPLIMIT=255 FLOWLBL=0 PROTO=ICMPv6 TYPE=135 CODE=0 MARK=0x0 Oct 3 23:31:12 IN= OUT=eth0 MAC= SRC=fe80::42:acff:fe11:2 DST=fe80::1 LEN=72 TC=0 HOPLIMIT=255 FLOWLBL=0 PROTO=ICMPv6 TYPE=135 CODE=0 MARK=0x0However, Wireguard still works and I'm not sure if this is impacting anything else.
I've also noticed that several
OUTPUTchain rules are being duplicated:Chain OUTPUT (policy DROP 9 packets, 648 bytes) pkts bytes target prot opt in out source destination 3 732 ACCEPT 0 -- * lo ::/0 ::/0 0 0 ACCEPT 0 -- * * ::/0 ::/0 ctstate RELATED,ESTABLISHED 5 320 ACCEPT 0 -- * eth0 ::/0 ff02::/104 0 0 ACCEPT 0 -- * eth0 fc00::242:ac11:2 fc00::/7 0 0 ACCEPT 0 -- * eth0 ::/0 ff02::/104 # DUPLICATE 0 0 ACCEPT 0 -- * eth0 fc00::242:ac11:2 fe80::/64 0 0 ACCEPT 0 -- * eth0 ::/0 ff02::/104 # TRIPLICATE 3 588 ACCEPT 17 -- * eth0 ::/0 2a03:1b20:4:f011::a04f udp dpt:51820 0 0 ACCEPT 17 -- * eth0 ::/0 2a03:1b20:4:f011::a04f udp dpt:51820 # DUPLICATE 0 0 ACCEPT 0 -- * tun0 ::/0 ::/0This of course does not affect connectivity but does pollute the netfilter chain.
Share your logs (at least 10 lines)
2024-10-03T22:31:24Z INFO [routing] default route found: interface eth0, gateway 172.17.0.1, assigned IP 172.17.0.3 and family v4
2024-10-03T22:31:24Z INFO [routing] default route found: interface eth0, gateway fc00::1, assigned IP fc00::242:ac11:3 and family v6
2024-10-03T22:31:24Z INFO [routing] local ethernet link found: eth0
2024-10-03T22:31:24Z INFO [routing] local ipnet found: 172.17.0.0/16
2024-10-03T22:31:24Z INFO [routing] local ipnet found: fc00::/7
2024-10-03T22:31:24Z INFO [routing] local ipnet found: fe80::/64
2024-10-03T22:31:24Z INFO [firewall] enabling...
2024-10-03T22:31:24Z DEBUG [firewall] /sbin/iptables --policy INPUT DROP
2024-10-03T22:31:24Z DEBUG [firewall] /sbin/iptables --policy OUTPUT DROP
2024-10-03T22:31:24Z DEBUG [firewall] /sbin/iptables --policy FORWARD DROP
2024-10-03T22:31:24Z DEBUG [firewall] /sbin/ip6tables --policy INPUT DROP
2024-10-03T22:31:24Z DEBUG [firewall] /sbin/ip6tables --policy OUTPUT DROP
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --policy FORWARD DROP
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/iptables --append INPUT -i lo -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --append INPUT -i lo -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/iptables --append OUTPUT -o lo -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -o lo -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/iptables --append OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/iptables --append INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --append INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/iptables --append OUTPUT -o eth0 -s 172.17.0.3 -d 172.17.0.0/16 -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -o eth0 -d ff02::1:ff/104 -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -o eth0 -s fc00::242:ac11:3 -d fc00::/7 -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -o eth0 -d ff02::1:ff/104 -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -o eth0 -s fc00::242:ac11:3 -d fe80::/64 -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -o eth0 -d ff02::1:ff/104 -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/iptables --append INPUT -i eth0 -d 172.17.0.0/16 -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --append INPUT -i eth0 -d fc00::/7 -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --append INPUT -i eth0 -d fe80::/64 -j ACCEPT
2024-10-03T22:31:25Z INFO [firewall] enabled successfully
2024-10-03T22:31:25Z INFO [storage] creating /gluetun/servers.json with 20553 hardcoded servers
2024-10-03T22:31:25Z INFO Alpine version: 3.20.3
2024-10-03T22:31:25Z INFO OpenVPN 2.5 version: 2.5.10
2024-10-03T22:31:25Z INFO OpenVPN 2.6 version: 2.6.11
2024-10-03T22:31:25Z INFO IPtables version: v1.8.10
2024-10-03T22:31:25Z INFO Settings summary:
├── VPN settings:
| ├── VPN provider settings:
| | ├── Name: mullvad
| | └── Server selection settings:
| | ├── VPN type: wireguard
| | ├── Countries: sweden
| | ├── Owned only servers: yes
| | └── Wireguard selection settings:
| └── Wireguard settings:
| ├── Private key: ****
| ├── Interface addresses:
| | ├── 10.70.233.184/32
| | └── fc00:bbbb:bbbb:bb01::7:e9b7/128
| ├── Allowed IPs:
| | ├── 0.0.0.0/0
| | └── ::/0
| └── Network interface: tun0
| └── MTU: 1400
├── DNS settings:
| ├── Keep existing nameserver(s): no
| ├── DNS server address to use: 127.0.0.1
| └── DNS over TLS settings:
| ├── Enabled: yes
| ├── Update period: every 24h0m0s
| ├── Upstream resolvers:
| | └── cloudflare
| ├── Caching: yes
| ├── IPv6: no
| └── DNS filtering settings:
| ├── Block malicious: yes
| ├── Block ads: no
| ├── Block surveillance: no
| └── Blocked IP networks:
| ├── 127.0.0.1/8
| ├── 10.0.0.0/8
| ├── 172.16.0.0/12
| ├── 192.168.0.0/16
| ├── 169.254.0.0/16
| ├── ::1/128
| ├── fc00::/7
| ├── fe80::/10
| ├── ::ffff:127.0.0.1/104
| ├── ::ffff:10.0.0.0/104
| ├── ::ffff:169.254.0.0/112
| ├── ::ffff:172.16.0.0/108
| └── ::ffff:192.168.0.0/112
├── Firewall settings:
| ├── Enabled: yes
| └── Debug mode: on
├── Log settings:
| └── Log level: info
├── Health settings:
| ├── Server listening address: 127.0.0.1:9999
| ├── Target address: cloudflare.com:443
| ├── Duration to wait after success: 5s
| ├── Read header timeout: 100ms
| ├── Read timeout: 500ms
| └── VPN wait durations:
| ├── Initial duration: 5m0s
| └── Additional duration: 5s
├── Shadowsocks server settings:
| └── Enabled: no
├── HTTP proxy settings:
| └── Enabled: no
├── Control server settings:
| ├── Listening address: :8000
| ├── Logging: yes
| └── Authentication file path: /gluetun/auth/config.toml
├── Storage settings:
| └── Filepath: /gluetun/servers.json
├── OS Alpine settings:
| ├── Process UID: 1000
| └── Process GID: 1000
├── Public IP settings:
| ├── Fetching: every 12h0m0s
| ├── IP file path: /tmp/gluetun/ip
| └── Public IP data API: ipinfo
└── Version settings:
└── Enabled: yes
2024-10-03T22:31:25Z INFO [routing] default route found: interface eth0, gateway 172.17.0.1, assigned IP 172.17.0.3 and family v4
2024-10-03T22:31:25Z INFO [routing] default route found: interface eth0, gateway fc00::1, assigned IP fc00::242:ac11:3 and family v6
2024-10-03T22:31:25Z DEBUG [routing] ip rule add from 172.17.0.3/32 lookup 200 pref 100
2024-10-03T22:31:25Z DEBUG [routing] ip rule add from fc00::242:ac11:3/128 lookup 200 pref 100
2024-10-03T22:31:25Z INFO [routing] adding route for 0.0.0.0/0
2024-10-03T22:31:25Z DEBUG [routing] ip route replace 0.0.0.0/0 via 172.17.0.1 dev eth0 table 200
2024-10-03T22:31:25Z INFO [routing] adding route for ::/0
2024-10-03T22:31:25Z DEBUG [routing] ip route replace ::/0 via fc00::1 dev eth0 table 200
2024-10-03T22:31:25Z INFO [firewall] setting allowed subnets...
2024-10-03T22:31:25Z INFO [routing] default route found: interface eth0, gateway 172.17.0.1, assigned IP 172.17.0.3 and family v4
2024-10-03T22:31:25Z INFO [routing] default route found: interface eth0, gateway fc00::1, assigned IP fc00::242:ac11:3 and family v6
2024-10-03T22:31:25Z DEBUG [routing] ip rule add to 172.17.0.0/16 lookup 254 pref 98
2024-10-03T22:31:25Z DEBUG [routing] ip rule add to fc00::/7 lookup 254 pref 98
2024-10-03T22:31:25Z DEBUG [routing] ip rule add to fe80::/64 lookup 254 pref 98
2024-10-03T22:31:25Z INFO TUN device is not available: open /dev/net/tun: no such file or directory; creating it...
2024-10-03T22:31:25Z INFO [dns] using plaintext DNS at address 1.1.1.1
2024-10-03T22:31:25Z INFO [http server] http server listening on [::]:8000
2024-10-03T22:31:25Z INFO [healthcheck] listening on 127.0.0.1:9999
2024-10-03T22:31:25Z INFO [firewall] allowing VPN connection...
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -d 2a03:1b20:4:f011::a11f -o eth0 -p udp -m udp --dport 51820 -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -d 2a03:1b20:4:f011::a11f -o eth0 -p udp -m udp --dport 51820 -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/iptables --append OUTPUT -o tun0 -j ACCEPT
2024-10-03T22:31:25Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -o tun0 -j ACCEPT
2024-10-03T22:31:25Z INFO [wireguard] Using available kernelspace implementation
2024-10-03T22:31:25Z INFO [wireguard] Connecting to [2a03:1b20:4:f011::a11f]:51820
2024-10-03T22:31:25Z INFO [wireguard] Wireguard setup is complete. Note Wireguard is a silent protocol and it may or may not work, without giving any error message. Typically i/o timeout errors indicate the Wireguard connection is not working.
2024-10-03T22:31:26Z INFO [dns] downloading hostnames and IP block lists
2024-10-03T22:31:41Z WARN [dns] cannot update filter block lists: Get "https://raw.githubusercontent.com/qdm12/files/master/malicious-hostnames.updated": context deadline exceeded (Client.Timeout exceeded while awaiting headers), Get "https://raw.githubusercontent.com/qdm12/files/master/malicious-ips.updated": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
2024-10-03T22:31:41Z INFO [dns] attempting restart in 10s
2024-10-03T22:31:51Z INFO [dns] downloading hostnames and IP block lists
2024-10-03T22:31:56Z ERROR [vpn] getting public IP address information: fetching information: Get "https://ipinfo.io/": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
Share your configuration
No response
@qdm12 is more or less the only maintainer of this project and works on it in his free time. Please:
- do not ask for updates, be patient
- :+1: the issue to show your support instead of commenting @qdm12 usually checks issues at least once a week, if this is a new urgent bug, revert to an older tagged container image
Hello and thanks for the detailed issue with the thorough investigation!
Gluetun is selecting IPv4 addresses from its server list and fails to connect until it randomly selects an IPv6 address. It would be nice to have a flag for Gluetun so that Wireguard (and maybe OpenVPN too?) will only try servers via their IPv6 address.
Ideally I would like this to be fully automated. For now, if IPv6 is "supported", IPv6 servers are added to the pool of servers to randomly pick from:
https://github.com/qdm12/gluetun/blob/3d6d03b32738ac80e71d9e4b9bb1b8c4318fa7ea/internal/provider/utils/connection.go#L51-L53
I think we could just use only IPv6 servers if IPv6 is supported right?
Now the problem with this is that IPv6 detection is sadly not that reliable yet. For now, it looks all IPv6 ip routes (excluding loopback destination) and if it finds one, it assumes it's supported. This is great because no external network request is needed, but it's still unreliable. Maybe to improve it, what do you get from ip -6 route show table all in a container on your ipv6 host? For example, in my case, my container has
/ # ip -6 route show table all
fe80::/64 dev eth0 metric 256
local ::1 dev lo table local metric 0
local fe80::42:acff:fe11:2 dev eth0 table local metric 0
multicast ff00::/8 dev eth0 table local metric 256
but IPv6 is not supported on my host, so I have the opposite case as yours, it cycles through IPv4+v6 addresses until it uses an IPv4 address, which has been annoying me as well for some time 😄
The alternative, which fixes this, is to actually send a request to an IPv6 address at container start, without the VPN enabled, to check if IPv6 is indeed supported or not. We could allow only that single IPv6 address (i.e. cloudflare dns ipv6 address) to be reached in the firewall, so that nothing much can be leaked from other connected containers, but I would rather avoid this if possible.
The destination subnet should be
ff02::1:ff00:0/104
Perfect, fixed in 7842ff4cdca24048e15178d03c01062c9a3cfc85
Even with this fix, it seems like the
ip6tablesrules are still blocking some NDP packets from the link-local address
Hmmm if you find the reason, let me know and I'll dig into it!
I've also noticed that several
OUTPUTchain rules are being duplicated:
This should be fixed with 9ef14ee070be25aeb584d3283746c9d931b27be9 and 99e9bc87cfed7716fe2751f59d34bb0d62492b3a
Although, where is ff02::/104 coming from?? Shouldn't it be either ff02::1:ff/104 (before) or now ff02::1:ff00:0/104? 🤔
Thanks for the quick turnaround with the fixes!
Maybe to improve it, what do you get from
ip -6 route show table allin a container on your ipv6 host?
# ip -6 route show table all
fc00::/7 dev eth0 proto kernel metric 256 pref medium
fe80::/64 dev eth0 proto kernel metric 256 pref medium
default via fc00::1 dev eth0 metric 1024 pref medium
local ::1 dev lo table local proto kernel metric 0 pref medium
local fc00::242:ac11:2 dev eth0 table local proto kernel metric 0 pref medium
local fe80::42:acff:fe11:2 dev eth0 table local proto kernel metric 0 pref medium
multicast ff00::/8 dev eth0 table local proto kernel metric 256 pref medium
# 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
4: eth0@if5: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.2/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fc00::242:ac11:2/7 scope global nodad
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:2/64 scope link
valid_lft forever preferred_lft forever
I'm not a networking expert but I think the key difference in my setup vs. yours is either having a default route or an IPv6 address with scope global. Does Docker assign a global-scoped IPv6 address if IPv6 is disabled for your network?
Docker currently doesn't support disabling the IPv4 stack (tracked here). Even if it did, I suppose you could have some sort of weird setup where you have a local network-only IPv4 address and an internet-reachable IPv6 address. Perhaps a more robust solution would be to have an environment variable that allows the end user to specify an address (and by extension, interface) to bind to, and Gluetun could then set up the appropriate routes and netfilter rules. Otherwise, Gluetun would look for global-scoped addresses (both IPv4 and IPv6) and choose either or both server types.
Although, where is
ff02::/104coming from?? Shouldn't it be eitherff02::1:ff/104(before) or nowff02::1:ff00:0/104? 🤔
I got this output with the previous version of Gluetun. The ff02::/104 and ff02::1:ff/104 networks are equal (a 104-bit mask cuts off the 17-bit 1:ff at the end) and so iptables is simplifying its output.
On my side (Docker with ipv6 disabled, but host supports ipv6, and network is not configured with ipv6...) I get:
/ # ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 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
1130: eth0@if1131: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UP
link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.3/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::42:acff:fe11:3/64 scope link
valid_lft forever preferred_lft forever
So it seems you're right, the two factors indicating ipv6 support are inet6 fc00::242:ac11:2/7 scope global nodad (ipv6 address with scope global on default interface eth0) or/and default via fc00::1 dev eth0 metric 1024 pref medium (ipv6 route with default destination on default interface eth0). I can check for both in the code, but for now I limited it to find a default route for simplicity's sake.
I put up code in #2523 (feel free to review, it's not too much Go-kungfu), where instead of finding ipv6 as supported or not, it now finds a level which can be 'unsupported', 'supported' (my case - non-loopback non-default ipv6 route) or 'internet' (your case - default ipv6 route. The need for this is because:
- some code needs to know if we can reach out to ipv6, i.e. pick a vpn server ipv6 address, aka 'internet' support
- some code needs to know if we should handle ipv6 (i.e. ip rules, ignore ipv6 tunneling etc.), aka 'supported' support
Could you run it (image tag :pr-2523) with LOG_LEVEL=debug and see if you get the debug log message IPv6 internet access is enabled on link eth0?
If this works, I'll move ahead and add an option to ONLY pick IPv6 address VPN server endpoints (since some users might want to complete pool of ipv4+ipv6). I'm thinking about OPENVPN_ENDPOINT_FAMILY=v4,v6 which you could change to v6 only. Obviously the program would error out if you don't have 'ipv6 internet' support and try to use v6 only. That could be useful in the future for debugging as well, to use ipv4 only servers if your host has ipv6 internet as well.
Sorry the CI failed for some reason, the image is now up.
@arseneyr when you have the time, can you try pulling qmcgaw/gluetun:pr-2523 and see how it does?
Now if a default non-loopback IPv6 route is found, gluetun allows through the firewall tcp output traffic only to the ipv6:port defined in IPV6_CHECK_ADDRESS (defaults to cloudflare.com [2606:4700::6810:84e5]:443, something that can be changed, happy to hear suggestions), and does a TCP dial to that ip:port. If it succeeds, then it's "ipv6 internet supported", otherwise it's just "ipv6 supported".
Wow, real sorry for not getting to your initial messages. Thanks for the update. I am seeing that log line:
Logs
$ docker run --env-file gluetun.env --cap-add=NET_ADMIN --name gluetun --sysctl net.ipv6.conf.all.disable_ipv6=0 -v $(pwd):/data --rm -it qmcgaw/gluetun:pr-2523
========================================
========================================
=============== gluetun ================
========================================
=========== Made with ❤️ by ============
======= https://github.com/qdm12 =======
========================================
========================================
Running version pr-2523 built on 2024-11-15T15:43:42.025Z (commit 5cec3c0)
🔧 Need help? ☕ Discussion? https://github.com/qdm12/gluetun/discussions/new/choose
🐛 Bug? ✨ New feature? https://github.com/qdm12/gluetun/issues/new/choose
💻 Email? [email protected]
💰 Help me? https://www.paypal.me/qmcgaw https://github.com/sponsors/qdm12
2024-12-14T04:07:35Z INFO [routing] default route found: interface eth0, gateway 172.17.0.1, assigned IP 172.17.0.2 and family v4
2024-12-14T04:07:35Z INFO [routing] default route found: interface eth0, gateway fc00::1, assigned IP fc00::242:ac11:2 and family v6
2024-12-14T04:07:35Z INFO [routing] local ethernet link found: eth0
2024-12-14T04:07:35Z INFO [routing] local ipnet found: 172.17.0.0/16
2024-12-14T04:07:35Z INFO [routing] local ipnet found: fc00::/7
2024-12-14T04:07:35Z INFO [routing] local ipnet found: fe80::/64
2024-12-14T04:07:36Z INFO [firewall] enabling...
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/iptables --policy INPUT DROP
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/iptables --policy OUTPUT DROP
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/iptables --policy FORWARD DROP
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/ip6tables --policy INPUT DROP
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/ip6tables --policy OUTPUT DROP
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/ip6tables --policy FORWARD DROP
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/iptables --append INPUT -i lo -j ACCEPT
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/ip6tables --append INPUT -i lo -j ACCEPT
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/iptables --append OUTPUT -o lo -j ACCEPT
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -o lo -j ACCEPT
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/iptables --append OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/iptables --append INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/ip6tables --append INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/iptables --append OUTPUT -o eth0 -s 172.17.0.2 -d 172.17.0.0/16 -j ACCEPT
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -o eth0 -d ff02::1:ff00:0/104 -j ACCEPT
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -o eth0 -s fc00::242:ac11:2 -d fc00::/7 -j ACCEPT
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/ip6tables --append OUTPUT -o eth0 -s fc00::242:ac11:2 -d fe80::/64 -j ACCEPT
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/iptables --append INPUT -i eth0 -d 172.17.0.0/16 -j ACCEPT
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/ip6tables --append INPUT -i eth0 -d fc00::/7 -j ACCEPT
2024-12-14T04:07:36Z DEBUG [firewall] /sbin/ip6tables --append INPUT -i eth0 -d fe80::/64 -j ACCEPT
2024-12-14T04:07:36Z INFO [firewall] enabled successfully
2024-12-14T04:07:36Z INFO [storage] creating /gluetun/servers.json with 20776 hardcoded servers
2024-12-14T04:07:36Z DEBUG [netlink] Checking route (link eth0): netlink.Route{LinkIndex:38, Dst:netip.Prefix{ip:netip.Addr{addr:netip.uint128{hi:0xfc00000000000000, lo:0x0}, z:unique.Handle[net/netip.addrDetail]{value:(*netip.addrDetail)(0x40000c2228)}}, bitsPlusOne:0x8}, Src:netip.Addr{addr:netip.uint128{hi:0x0, lo:0x0}, z:unique.Handle[net/netip.addrDetail]{value:(*netip.addrDetail)(nil)}}, Gw:netip.Addr{addr:netip.uint128{hi:0x0, lo:0x0}, z:unique.Handle[net/netip.addrDetail]{value:(*netip.addrDetail)(nil)}}, Priority:256, Family:10, Table:254, Type:1}
2024-12-14T04:07:36Z DEBUG [netlink] IPv6 is supported by link eth0
2024-12-14T04:07:36Z DEBUG [netlink] Checking route (link eth0): netlink.Route{LinkIndex:38, Dst:netip.Prefix{ip:netip.Addr{addr:netip.uint128{hi:0xfe80000000000000, lo:0x0}, z:unique.Handle[net/netip.addrDetail]{value:(*netip.addrDetail)(0x40000c2228)}}, bitsPlusOne:0x41}, Src:netip.Addr{addr:netip.uint128{hi:0x0, lo:0x0}, z:unique.Handle[net/netip.addrDetail]{value:(*netip.addrDetail)(nil)}}, Gw:netip.Addr{addr:netip.uint128{hi:0x0, lo:0x0}, z:unique.Handle[net/netip.addrDetail]{value:(*netip.addrDetail)(nil)}}, Priority:256, Family:10, Table:254, Type:1}
2024-12-14T04:07:36Z DEBUG [netlink] IPv6 is supported by link eth0
2024-12-14T04:07:36Z DEBUG [netlink] Checking route (link eth0): netlink.Route{LinkIndex:38, Dst:netip.Prefix{ip:netip.Addr{addr:netip.uint128{hi:0x0, lo:0x0}, z:unique.Handle[net/netip.addrDetail]{value:(*netip.addrDetail)(0x40000c2228)}}, bitsPlusOne:0x1}, Src:netip.Addr{addr:netip.uint128{hi:0x0, lo:0x0}, z:unique.Handle[net/netip.addrDetail]{value:(*netip.addrDetail)(nil)}}, Gw:netip.Addr{addr:netip.uint128{hi:0xfc00000000000000, lo:0x1}, z:unique.Handle[net/netip.addrDetail]{value:(*netip.addrDetail)(0x40000c2228)}}, Priority:1024, Family:10, Table:254, Type:1}
2024-12-14T04:07:36Z DEBUG [netlink] IPv6 internet access is enabled on link eth0
2024-12-14T04:07:36Z INFO Alpine version: 3.20.3
2024-12-14T04:07:37Z INFO OpenVPN 2.5 version: 2.5.10
2024-12-14T04:07:37Z INFO OpenVPN 2.6 version: 2.6.11
2024-12-14T04:07:37Z INFO IPtables version: v1.8.10
I think improving IPv4/6 autodetect is a worthwhile pursuit to support minimal config setups. Specifically, if there is no IPv4 connectivity detected, Gluetun should not try any IPv4 servers (and similarly for IPv6). However, to preemptively solve this for those with weird setups, I think the most useful level of configuration would be an env variable that allows you to specify the address of the interface to use. This would cover multi-interface setups and would unambiguously choose either v4 or v6. So instead of doing OPENVPN_ENDPOINT_FAMILY=v6, you would just do something like VPN_INTERFACE_ADDR=fc00::242:ac11:2 and that would restrict you to only using the IPv6 stack and IPv6 servers. However, your proposed solution with OPENVPN_ENDPOINT_FAMILY would cover my specific use case so I have no strong feelings here.
Thanks for the update. I am seeing that log line:
My apologies the build did not succeed (coded this in a rush a few days ago), due to some tests failing, it's fixed now, can you try pulling and run the container again? 🙏 Thanks!
Specifically, if there is no IPv4 connectivity detected, Gluetun should not try any IPv4 servers (and similarly for IPv6)
The bigger problem here is we have
- IPv6 supported but no default IPv6 route
- IPv6 supported, with a default IPv6 route, but IPv6 internet does not work
- IPv6 supported, with a default IPv6 route and IPv6 internet does not work
Now :latest for now assumes 2. and 3. if 1. is true, which turns out is pretty wrong. The previous image (from mid November, sorry for my slowness!) considers 1. and 2. as two separate categories "IPv6 supported" and "IPv6 internet", but assumes 3. if 2. is true. Now we need to discern 2. and 3. with the IPv6 check mentioned previously.
What you say makes sense though, I could explore IPv4 support too, but that's for a later time if/when someone complains about it 😉
I think the most useful level of configuration would be an env variable that allows you to specify the address of the interface to use.
That's a great idea! However, by default this interface should be picked automagically, so we need a decent automated way to find which IP families we can use (hence this first PR). Second PR will then be VPN_INTERFACE_ADDR which would indeed cover niche use cases users might have (i.e. multiple internet interfaces).
IPv6 supported but no default IPv6 route
You don't necessarily need a default route there might be a route to a specific destination, perhaps it would make sense to walk the list of target servers and ensure there is a matching route entry (either specific, or a default). Any server address for which there is no route should then be skipped, and the algorithm moves to the next. Makes sense to do the same for legacy routing too. Theoretically the kernel should generate a "no route to host" error on its own in these cases...
IPv6 supported, with a default IPv6 route, but IPv6 internet does not work
The same would happen with broken legacy routing (happens a lot here because the ISP's CGNAT gateway is unreliable). There are also cases where the connection is down entirely, or where the server(s) are down, or there is broken routing somewhere in between etc... all you can really do is keep trying until you hit a successful connection.
Hey, I tried to run an ipv6 only network with gluetun. I think there is an issue because I can't get it to keep running, I'm pretty close but I think it's related to the fact that the healthcheck only works in ipv4: https://github.com/qdm12/gluetun/blob/9933dd3ec5c88d6a6b0f08a23031674c0591248c/internal/healthcheck/health.go#L78
gluetun-1 | 2025-04-06T17:05:27Z INFO [ip getter] Public IP address is 2a00:7c80:0:3ad::14 (The Netherlands, South Holland, Naaldwijk - source: ifconfig.co)
gluetun-1 | 2025-04-06T17:06:37Z INFO [healthcheck] program has been unhealthy for 1m1s: restarting VPN (healthcheck error: dialing: dial tcp4 104.16.132.229:443: i/o timeout)
gluetun-1 | 2025-04-06T17:06:37Z INFO [healthcheck] 👉 See https://github.com/qdm12/gluetun-wiki/blob/main/faq/healthcheck.md
gluetun-1 | 2025-04-06T17:06:37Z INFO [healthcheck] DO NOT OPEN AN ISSUE UNLESS YOU READ AND TRIED EACH POSSIBLE SOLUTION
gluetun-1 | 2025-04-06T17:06:37Z INFO [vpn] stopping
gluetun-1 | 2025-04-06T17:06:37Z INFO [vpn] starting
gluetun-1 | 2025-04-06T17:06:37Z INFO [firewall] allowing VPN connection...
gluetun-1 | 2025-04-06T17:06:37Z INFO [wireguard] Using available kernelspace implementation
gluetun-1 | 2025-04-06T17:06:37Z INFO [wireguard] Connecting to 185.177.124.84:51820
gluetun-1 | 2025-04-06T17:06:37Z INFO [wireguard] Wireguard setup is complete. Note Wireguard is a silent protocol and it may or may not work, without giving any error message. Typically i/o timeout errors indicate the Wireguard connection is not working.
gluetun-1 | 2025-04-06T17:06:37Z INFO [ip getter] Public IP address is 2a00:7c80:0:3a4::13 (The Netherlands, South Holland, Naaldwijk - source: ifconfig.co)
gluetun-1 | 2025-04-06T17:07:47Z INFO [healthcheck] program has been unhealthy for 1m6s: restarting VPN (healthcheck error: dialing: dial tcp4 104.16.133.229:443: i/o timeout)
gluetun-1 | 2025-04-06T17:07:47Z INFO [healthcheck] 👉 See https://github.com/qdm12/gluetun-wiki/blob/main/faq/healthcheck.md
gluetun-1 | 2025-04-06T17:07:47Z INFO [healthcheck] DO NOT OPEN AN ISSUE UNLESS YOU READ AND TRIED EACH POSSIBLE SOLUTION
gluetun-1 | 2025-04-06T17:07:47Z INFO [vpn] stopping
gluetun-1 | 2025-04-06T17:07:47Z INFO [vpn] starting
gluetun-1 | 2025-04-06T17:07:47Z INFO [firewall] allowing VPN connection...
gluetun-1 | 2025-04-06T17:07:47Z INFO [wireguard] Using available kernelspace implementation
gluetun-1 | 2025-04-06T17:07:47Z INFO [wireguard] Connecting to 89.39.107.113:51820
gluetun-1 | 2025-04-06T17:07:47Z INFO [wireguard] Wireguard setup is complete. Note Wireguard is a silent protocol and it may or may not work, without giving any error message. Typically i/o timeout errors indicate the Wireguard connection is not working.
gluetun-1 | 2025-04-06T17:07:48Z INFO [ip getter] Public IP address is 2a00:7c80:0:3ad::14 (The Netherlands, South Holland, Naaldwijk - source: ifconfig.co)
Maybe the healthcheck should check if ipv6 connectivity is available and use that instead?
EDIT: I was able to bypass the healthcheck using HEALTH_TARGET_ADDRESS=127.0.0.1:9999
Here is my docker compose for protonvpn:
version: "3"
services:
gluetun:
image: qmcgaw/gluetun
cap_add:
- NET_ADMIN
devices:
- /dev/net/tun:/dev/net/tun
environment:
- VPN_SERVICE_PROVIDER=protonvpn
- WIREGUARD_ADDRESSES=2a07:b944::2:2/128
- VPN_TYPE=wireguard
- VERSION_INFORMATION=off
- PUBLICIP_ENABLED=off
- PUBLICIP_API=ifconfigco
- FREE_ONLY=on
- DOT=off
- DNS_UPDATE_PERIOD=0
- DNS_ADDRESS=2620:fe::fe
- WIREGUARD_PRIVATE_KEY=XXX
- HEALTH_TARGET_ADDRESS=127.0.0.1:9999
- SERVER_COUNTRIES=Netherlands
sysctls:
- net.ipv6.conf.all.disable_ipv6=0
networks:
- vpnnet
ubuntu:
image: ubuntu
command: sleep infinity # Keeps the container running
network_mode: "service:gluetun"
networks:
vpnnet:
driver: bridge
enable_ipv6: true
ipam:
driver: default
config:
- subnet: 2001:db8:1::/64