linux-cli-community icon indicating copy to clipboard operation
linux-cli-community copied to clipboard

[BUG] IPv6 leak protection doesn't work as intended with pre-existing iptables rules

Open tycho opened this issue 5 years ago • 13 comments

I have a bunch of iptables rules already set up so that I can route networking for virtual machines running on my local machine. The commands that protonvpn-cli-ng uses to drop IPv6 traffic end up doing nothing, as they're appended to the end of the relevant chains, after my existing rules selectively allowing traffic.

For example, my OUTPUT chain contains something like this (simplified for readability):

-A OUTPUT -o br0 -j ACCEPT

protonvpn-cli-ng adds this rule after it, which is never hit:

-A OUTPUT -o br0 -j DROP

As a result, IPv6 traffic ends up leaking.

One option to solve this would be to disable IPv6 entirely while connected: e.g. save off the value of net.ipv6.conf.all.disable_ipv6 before connecting, set it to 1 while connected and restore it to the previous value when disconnected. This would disable IPv6 on all interfaces, which would probably be better than a DROP rule anyway because applications wouldn't even attempt to make any IPv6 connections when that's set.

tycho avatar Feb 15 '20 18:02 tycho

One downside to the net.ipv6.conf.all.disable_ipv6 approach is that setting it back to 0 will not necessarily cause IPv6 address assignments to come back in a timely fashion.

SLAAC addresses obtained via router advertisements would come back quickly, depending on the router advertisement interval (typically only a few seconds in most configurations).

DHCPv6 addresses are another story, because whatever is managing the interface (NetworkManager or systemd-networkd, for example) would have to explicitly request a new address assignment. This will eventually happen automatically, but it does take longer (in my local testing it took about 2-3 minutes before it noticed the missing DHCPv6 lease and refreshed it).

That said, I still think the net.ipv6.conf.all.disable_ipv6 approach is probably the better one.

tycho avatar Feb 15 '20 18:02 tycho

It was like that in the past actually, but the problem was that it didn't do anything after a while, as you've mentioned. So it's a very problematic approach.

Rafficer avatar Feb 15 '20 18:02 Rafficer

Well, even if the iptables rules were working as intended, the input/output drop rules would eventually cause the IPv6 leases to expire anyway, because the system would be prohibited from communicating to maintain the leases.

tycho avatar Feb 15 '20 18:02 tycho

Yeah, but they won't come back this way. I've already thought it's not working as intended and think about making the ipv6 protection just like the kill switch... Blocking everything.

Rafficer avatar Feb 15 '20 18:02 Rafficer

They do come back. Once disable_ipv6 is restored to 0, SLAAC addresses come back almost instantly, and DHCPv6 addresses come back after a few minutes. Using the sysctl also has the advantage of clearly communicating to other things that the interfaces have had a state change. Silently dropping IPv6 via iptables until the leases die off just makes things think the system has poor/broken IPv6 connectivity instead of no IPv6 connectivity.

tycho avatar Feb 15 '20 19:02 tycho

I don't get your point. If connectivity comes back at some point but the users expects it not to come back, it's really bad and shouldn't be done this way. So sysctl is out.

Rafficer avatar Feb 15 '20 19:02 Rafficer

We must be talking past each other. I'm saying it comes back once the VPN is disconnected. It should not come back on its own while disable_ipv6=1.

tycho avatar Feb 15 '20 19:02 tycho

Oh, yeah, I meant it comes back while the VPN is on, making it possible to connect via IPv6 to services and not go over the VPN.

Rafficer avatar Feb 15 '20 19:02 Rafficer

Okay. Under what conditions has it been observed to come back while the VPN is on and disable_ipv6=1? The only case I can think of is that something else independently explicitly enables IPv6 again.

I mean, even if the iptables approach was working (e.g. if it was using -I instead of -A), there's nothing to prevent the table from being automatically stomped on by whatever's managing the rules there and negating the IPv6 leak prevention there, either.

tycho avatar Feb 15 '20 19:02 tycho

Check out #59 and also this reddit thread.

I'm all for going back and not playing with the IPv6 firewall rules, but it leaked...

Rafficer avatar Feb 15 '20 19:02 Rafficer

Could do both. Insert (instead of append) the rules first, and then do the disable_ipv6=1 sysctl. So even if the sysctl gets reverted somehow, the firewall rules would be in place. It's still not perfect, but less likely to result in leakage.

tycho avatar Feb 15 '20 20:02 tycho

I was more thinking about doing

ip6tables -F
ip6tables -P INPUT DROP
ip6tables -P OUTPUT DROP
ip6tables -P FORWARD DROP

And upon disconnecting restoring again. Basically how the Kill Switch works.

Rafficer avatar Feb 15 '20 20:02 Rafficer

That should work. It's a bit heavy-handed, but I think it'd functionally do the right thing. I think the sysctl is still necessary on top of it, though (i.e. for link state change notifications via netlink).

tycho avatar Feb 15 '20 20:02 tycho