Open primeos opened 7 years ago
If I understand correctly you can't just block ICMPv6 because that would break neighbour discovery and as the result you won't be able to connect to a host on the same subnet (it's something like ARP), discover a router and so on. I'm not sure but blocking non-fe00::/9
addresses may work though. But yes, if we can block IPv6 pings with this option it would be more consistent (I'm not a fan of ICMP blackholing myself but we are not talking about defaults here).
:+1: to other suggestions (I like autoloading conntrack helpers by default though).
See also #4155.
For the ICMP stuff see: http://shouldiblockicmp.com/
Regarding the ICMP discussion:
The idea wasn't to block all ICMPv6 messages (which would obviously be a very bad idea and break IPv6 as described by @abbradar :+1:) - only "ICMPv6 Echo Requests" (Type 128, Code 0).
Of course even just blocking ICMPv6 echo requests can cause (unexpected) problems, so that it should never be the default (which is why the default of networking.firewall.allowPing
is true
.
BTW: It's probably a good idea to include a statement, that this option shouldn't be disabled if the user isn't aware of the implications (especially on a server - on a laptop, etc. it could make sense (imho)).
AFAIK blocking ICMPv6 echo requests would cause the following problems:
But note that blocking ICMP(v4) echo request can "break" stuff too (IIRC DHCP (at least some implementations) use ICMP echo requests in order to avoid duplicate addresses if misconfigured)
From [https://tools.ietf.org/html/rfc4890#appendix-A.5](RFC 4890 - Recommendations for Filtering ICMPv6 Messages in Firewalls):
Echo Request (Type 128) uses unicast addresses as source addresses, but may be sent to any legal IPv6 address, including multicast and anycast addresses [RFC4443]. Echo Requests travel end-to-end. Similarly, Echo Responses (Type 129) travel end-to-end and would have a unicast address as destination and either a unicast or anycast address as source. They are mainly used in combination for monitoring and debugging connectivity. Their only role in establishing communication is that they are required when verifying connectivity through Teredo tunnels [RFC4380]: Teredo tunneling to IPv6 nodes on the site will not be possible if these messages are blocked. It is not thought that there is a significant risk from scanning attacks on a well-designed IPv6 network (see Section 3.2), and so connectivity checks should be allowed by default.
The RFC states "it is not thought that there is a significant risk from scanning attacks on a well-designed IPv6 network" but please note that that RFC is from 2007.
This is why I would still suggest we do one of the following:
See also #4155.
@edolstra Good point, I forgot to mention that issue (but included a statement that there are other issues - Unfortunately I didn't manage to read the complete issue yet...).
My idea was to break that transition into multiple steps (not mentioned above) by beginning with "Properly reset the firewall". However unfortunately this doesn't work as simple as I described above (at least not without breaking stuff).
(I'll probably update/change that suggestion later.)
For disabling conntrack helper autloading, see PR #22034.
(Moved the conntrack part to the bottom in the description to make reading the summary easier.)
@primeos did you give up on this? I have seen some odd race conditions at times when rules are changed and would very much like to explore how we can make the firewall handling better.
@peterhoeg Unfortunately yes, at least for now... (I've had some more ideas and it got a bit too complicated)
I might have some time for this in ~1 month and could give it another try. The main problem is that we would probably need to restructure the firewall module(s) a bit (for other ideas, not mentioned in this issue). I'd like to have a generic firewall module (backwards compatible to the current one but can be used to switch between iptables, nftables, etc. - i.e. these modules would all have to implement the options from the generic firewall module but could also implement additional options that won't go into the generic module), two iptables modules (the current one and an atomic one - IMO it would most likely be too complex to use one module for both cases) and one nftable module (already exists but probably needs to be extended). Especially the atomic iptables module should solve all race conditions and be better suited for a declarative configuration but wouldn't work for all use-cases (e.g. dynamic rules from Virtualbox, etc. would get lost/overwritten).
And since this change wouldn't be minor I should formalize this idea (e.g. an extra issue - I guess (/hope :D) an RFC would be overkill) and ask for some feedback before implementing something like this. Any help with this as well as feedback/suggestions would be very welcome :smile:. But as mentioned above it would have to wait ~1 month, except someone else would take it over.
Edit: @peterhoeg And thanks for your comment, I'm glad to hear that there's some interest :smile:.
(triage) @primeos Did you find time to give it another try / do you still think you will be able to give it another try anytime “soon”? :)
Thank you for your contributions.
This has been automatically marked as stale because it has had no activity for 180 days.
If this is still important to you, we ask that you leave a comment below. Your comment can be as simple as "still important to me". This lets people see that at least one person still cares about this. Someone will have to do this at most twice a year if there is no other activity.
Here are suggestions that might help resolve this more quickly:
@primeos is there something left from the initial improvements/suggestions/discussions?
Could this be split into individual issues, so it's easier to track? Also, how does some of this still apply with the recent switch from iptables to nftables?
Sorry, this got bigger than I had time for so I basically just dropped it. I haven't kept up with recent changes but I assume that many of the ideas are still relevant. I could try to split it up into individual issues but it might make more sense to just close this for now - unless someone else has time and motivation to work on a implementation.
Suggestion: Use allowPing for both IPv4 and IPv6
That's a low-hanging fruit. I'd like that setting to also apply to IPv6 for consistency but I don't know how others feel about it. It's not a big deal in any case (and IMO there are very few (if any) reasons for setting it to false
in the first place).
Suggestion: Use -w (wait for the xtables lock) everywhere
The switch to iptables-nftables-compat
may or may not fix that automatically (I haven't checked).
Suggestion: Properly reset the firewall
This was my main motivation and would require a complete rewrite of the firewall module. Or rather an additional module as it doesn't work for every use-case. The idea was that the firewall rules would be configured completely declarative via the NixOS configurations and all changes would be applied with an atomic operation (i.e., it either works completely or the operation fails and everything will remain as it is - currently this isn't the case). This is easy to implement when configuring everything through NixOS but it doesn't work when using tools like Docker and LXD as they modify firewall rules by default (can be disabled but I doubt that many users do it manually). The "problem" is that any firewall changes made outside the NixOS configuration will be discarded when reloading the firewall rules. (The nftables module might already use an atomic approach.) Edit: Yes, from a quick look it seems to be an atomic operation:
https://wiki.nftables.org/wiki-nftables/index.php/Atomic_rule_replacement
Suggestion: Use -w (wait for the xtables lock) everywhere
Doesn't seem to be a problem anymore, according to https://www.redhat.com/en/blog/using-iptables-nft-hybrid-linux-firewall:
In comparison to legacy iptables, iptables-nft has a few clear benefits: With back end transactions being atomic, there is no need for the global xtables lock which has proven problematic in environments with large and/or rapidly changing rulesets.
Suggestion: Use allowPing for both IPv4 and IPv6
I'd rather prefer renaming this to allowPing4
to make the distinction clear. Blocking ICMP is bad in general, and even worse for IPv6. If people really want to block ping6 without breaking the rest of icmp, they should probably configure things explicitly, and what ICMP messages to drop.
Suggestion: Properly reset the firewall / atomic replacement
I don't think it's feasible without a refactor of the firewall module (and probably switching to more nftables features). I'm also not sure declaratively managing all firewall rules exclusively will work - maybe we can do atomic replacements of individual "NixOS firewall" nf_tables. I propose we tackle https://github.com/NixOS/nixpkgs/issues/161428 first (which would further clarify networking.nftables.rulesetFile
and then follow up on that. There's also already an issue on that, https://github.com/NixOS/nixpkgs/issues/4155#issuecomment-1048295371.
Hey, I'd like to get some feedback on the following suggestions - thanks :)
Suggestion: Use allowPing for both IPv4 and IPv6
Even without considering the scanning I would suggest we use this option for IPv6 as well or rename it to something like
networking.firewall.allowIPv4Ping
.Regarding the scanning of the larger address space of IPv6: This isn't necessarily true since one can do way better than just brute-forcing a /64 subnet (e.g. via DNS, patterns in the interface identifiers). Some references:
Suggestion: Use -w (wait for the xtables lock) everywhere
This covers most of the commands but there are
iptables
andip6tables
commands in the module where that-w
option is missing. And users probably won't use that option as well (additionalCommands
).Not using that option could cause some problems (race conditions):
Suggestion: Properly reset the firewall
This method keeps quite some state (e.g. policies, additional chains/tables) which shouldn't be the case imho (this is a functional OS at least :).
Imho we should completely reset the firewall (also in the
firewall-stop
script and deprecateextraStopCommands
). This could be done atomically withiptables-restore
which could help us improvingfirewall-reload
as well.Currently
firewall-reload
uses an additional chain to drop all traffic while reloading, but if thefirewall-start
script failsfirewall-stop
will be called which by default results in accepting all traffic.We could probably improve that situation by executing
iptables-save
before calling thefirewall-start
script and restoring the firewall to the previous state if thefirewall-start
script fails.After that we could try to make the whole operation atomic (there are other issues on this).
Issue/Inconsistency: Connection tracking helpers(edit by @globin: FIXED in #22034 )The description states that these helpers can pose a security risk and should therefore not be used.
However the default value of
networking.firewall.connectionTrackingModules
is[ "ftp" ]
andnetworking.firewall.autoLoadConntrackHelpers
is enabled by default.Do we need the
ftp
connection tracking helper for anything? If not I suggest we use the following defaults:Setting
networking.firewall.autoLoadConntrackHelpers = false
would be even better imho but it seems like that could lead to some problems: