An address from the IPv6 range shows up in a test page, the tunnel is clearly not carrying it, and the internet's most popular advice is to disable IPv6 everywhere. That command does make the panel go quiet. It also removes a protocol the access network may depend on, and it leaves you with no idea whether the address was a real leak, a link-local interface address, or a resolver doing its job. Three conditions decide the right control, and only one of them leads to blocking.

Identify what the tool actually measured

The most common false alarm is a link-local address, which begins with fe80: and exists on every IPv6-capable interface whether or not the machine can reach the internet over IPv6. It appears in interface listings and in some application diagnostics, and it says nothing about your traffic path.

The second false alarm is a unique local address in fc00::/7, which is a private range used inside a network. A tool that prints every address the host holds will list it happily next to the public one. Anyone reading quickly calls that a leak, and then spends an hour on a problem that does not exist.

The third is not a false alarm at all. A global address that reaches the internet outside the tunnel is the real leak, and it is worth measuring before deciding anything:

ip -6 addr show scope global
ip -6 route show default
curl -6 -sS --max-time 6 https://ifconfig.co

If the first command prints a global address and the third returns a public IPv6 address that is not the tunnel's, you have a genuine path outside the tunnel. If the first prints nothing but link-local entries, there was never a leak to fix.

Three conditions decide the control

The decision is not "IPv6 good" or "IPv6 bad". It is which of three situations you are in, and each has a different correct answer with a different cost when you get it wrong.

SituationCorrect controlCost if you disable IPv6 instead
Exit has no IPv6, host doesBlock IPv6 deliberately in the tunnel policySame visible result, no documentation of intent
Exit carries IPv6, host leaksRoute IPv6 into the tunnel and verifyYou lose IPv6 reachability entirely
Access network is IPv6-onlyChange nothing; use the tunnel's IPv6Machine loses connectivity completely

The first row is what people usually mean, and it is legitimate. A client whose exit has no IPv6 support should not silently let the host's native IPv6 traffic out, because that is the documented dual-stack leak. The point is to block it as a stated policy, not to disable a protocol at the kernel. The visible outcome is identical and only one of them can be reviewed later.

The third row is where the blanket advice becomes actively harmful. Mobile carriers and some home connections run IPv6-only networks with translation for IPv4 destinations. Remove IPv6 there and you remove the only transport the network offers, which produces a much worse outage than the one you were debugging.

If the exit has no IPv6, block it on purpose

Prefer the client's own mechanism, because it applies exactly while the tunnel is up and reverts when it goes down. OpenVPN has an option for this, and iptables has an equivalent rule for other clients:

block-ipv6
ip6tables -A OUTPUT -o eth0 -j REJECT --reject-with ipv6-port-unreachable

The directive belongs in the profile; the rule belongs in a firewall that you can review and remove. Both fail closed, which is what you want, and both are visible in a configuration diff, which a kernel sysctl buried in a startup script is not.

Record why it is there. A blocking rule with no comment gets removed by the next person who needs IPv6 for something unrelated, and then the leak quietly returns.

If the exit carries IPv6, route it and test both families

Carrying IPv6 is the better answer when the server supports it, and it is not much harder. The requirement is that the tunnel interface has an address in that family and that the default route for it points into the tunnel rather than out of the physical interface:

ip -6 route get 2606:4700:4700::1111
ip -6 route show default
curl -6 -sS --max-time 6 https://ifconfig.co
curl -4 -sS --max-time 6 https://ifconfig.co

The route lookup is the decisive test: if it names the tunnel interface, IPv6 traffic is being carried. The two curl calls then confirm what each family sees, and comparing them is how you prove that both paths now leave by the same exit.

Do not stop at a successful connection. Reconnect the tunnel and check again, because a pushed IPv6 route can be lost on re-establishment if the server sends it only in the initial configuration. Then check one excluded destination, since split-tunnel rules are where the two families most often disagree.

If the access network is IPv6-only, leave it alone

Some networks provide only IPv6 and expect the device to reach IPv4 services through a translation mechanism on the carrier side. Disabling IPv6 on such a machine is not a security improvement; it removes the only route to anything. That is a self-inflicted outage in service of a test result nobody needed.

The symptom of getting this wrong is distinctive and unpleasant: the tunnel appears to establish, name resolution works, and nothing loads. If you see that after an IPv6 change, restore the setting immediately and continue the diagnosis elsewhere.

Whatever you choose, keep the decision explicit in the profile or the firewall, tie it to what the exit actually supports, and note the dual-stack behaviour the RFC 7359 dual-stack discussion describes. A stated block is a policy. A disabled protocol is a workaround that nobody can audit, and they look identical from the test page.

Winndannde jowitiiɗe heen