| 
									
										
										
										
											2016-09-22 15:45:42 +10:00
										 |  |  | { config, pkgs, lib, ... }: | 
					
						
							|  |  |  | with lib; | 
					
						
							|  |  |  | let | 
					
						
							|  |  |  |   cfg = config.networking.nftables; | 
					
						
							|  |  |  | in | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   ###### interface | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   options = { | 
					
						
							|  |  |  |     networking.nftables.enable = mkOption { | 
					
						
							|  |  |  |       type = types.bool; | 
					
						
							|  |  |  |       default = false; | 
					
						
							|  |  |  |       description = | 
					
						
							|  |  |  |         ''
 | 
					
						
							|  |  |  |           Whether to enable nftables.  nftables is a Linux-based packet | 
					
						
							|  |  |  |           filtering framework intended to replace frameworks like iptables. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           This conflicts with the standard networking firewall, so make sure to | 
					
						
							|  |  |  |           disable it before using nftables. | 
					
						
							| 
									
										
										
										
											2017-03-25 16:34:02 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  |           Note that if you have Docker enabled you will not be able to use | 
					
						
							|  |  |  |           nftables without intervention. Docker uses iptables internally to | 
					
						
							|  |  |  |           setup NAT for containers. This module disables the ip_tables kernel | 
					
						
							|  |  |  |           module, however Docker automatically loads the module. Please see [1] | 
					
						
							|  |  |  |           for more information. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           There are other programs that use iptables internally too, such as | 
					
						
							|  |  |  |           libvirt. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           [1]: https://github.com/NixOS/nixpkgs/issues/24318#issuecomment-289216273 | 
					
						
							| 
									
										
										
										
											2016-09-22 15:45:42 +10:00
										 |  |  |         '';
 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     networking.nftables.ruleset = mkOption { | 
					
						
							|  |  |  |       type = types.lines; | 
					
						
							| 
									
										
										
										
											2017-02-26 15:23:01 +01:00
										 |  |  |       example = ''
 | 
					
						
							|  |  |  |         # Check out https://wiki.nftables.org/ for better documentation. | 
					
						
							|  |  |  |         # Table for both IPv4 and IPv6. | 
					
						
							|  |  |  |         table inet filter { | 
					
						
							|  |  |  |           # Block all incomming connections traffic except SSH and "ping". | 
					
						
							|  |  |  |           chain input { | 
					
						
							|  |  |  |             type filter hook input priority 0; | 
					
						
							| 
									
										
										
										
											2016-09-22 15:45:42 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-26 15:23:01 +01:00
										 |  |  |             # accept any localhost traffic | 
					
						
							|  |  |  |             iifname lo accept | 
					
						
							| 
									
										
										
										
											2016-09-22 15:45:42 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-26 15:23:01 +01:00
										 |  |  |             # accept traffic originated from us | 
					
						
							|  |  |  |             ct state {established, related} accept | 
					
						
							| 
									
										
										
										
											2016-09-22 15:45:42 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-26 15:23:01 +01:00
										 |  |  |             # ICMP | 
					
						
							|  |  |  |             # routers may also want: mld-listener-query, nd-router-solicit | 
					
						
							|  |  |  |             ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept | 
					
						
							|  |  |  |             ip protocol icmp icmp type { destination-unreachable, router-advertisement, time-exceeded, parameter-problem } accept | 
					
						
							| 
									
										
										
										
											2016-09-22 15:45:42 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-26 15:23:01 +01:00
										 |  |  |             # allow "ping" | 
					
						
							|  |  |  |             ip6 nexthdr icmp icmpv6 type echo-request accept | 
					
						
							|  |  |  |             ip protocol icmp icmp type echo-request accept | 
					
						
							| 
									
										
										
										
											2016-09-22 15:45:42 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-26 15:23:01 +01:00
										 |  |  |             # accept SSH connections (required for a server) | 
					
						
							|  |  |  |             tcp dport 22 accept | 
					
						
							| 
									
										
										
										
											2016-09-22 15:45:42 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-26 15:23:01 +01:00
										 |  |  |             # count and drop any other traffic | 
					
						
							|  |  |  |             counter drop | 
					
						
							| 
									
										
										
										
											2016-09-22 15:45:42 +10:00
										 |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-26 15:23:01 +01:00
										 |  |  |           # Allow all outgoing connections. | 
					
						
							|  |  |  |           chain output { | 
					
						
							|  |  |  |             type filter hook output priority 0; | 
					
						
							|  |  |  |             accept | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2016-09-22 15:45:42 +10:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-26 15:23:01 +01:00
										 |  |  |           chain forward { | 
					
						
							|  |  |  |             type filter hook forward priority 0; | 
					
						
							|  |  |  |             accept | 
					
						
							| 
									
										
										
										
											2016-09-22 15:45:42 +10:00
										 |  |  |           } | 
					
						
							| 
									
										
										
										
											2017-02-26 15:23:01 +01:00
										 |  |  |         } | 
					
						
							|  |  |  |       '';
 | 
					
						
							| 
									
										
										
										
											2016-09-22 15:45:42 +10:00
										 |  |  |       description = | 
					
						
							|  |  |  |         ''
 | 
					
						
							|  |  |  |           The ruleset to be used with nftables.  Should be in a format that | 
					
						
							|  |  |  |           can be loaded using "/bin/nft -f".  The ruleset is updated atomically. | 
					
						
							|  |  |  |         '';
 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |     networking.nftables.rulesetFile = mkOption { | 
					
						
							|  |  |  |       type = types.path; | 
					
						
							|  |  |  |       default = pkgs.writeTextFile { | 
					
						
							|  |  |  |         name = "nftables-rules"; | 
					
						
							|  |  |  |         text = cfg.ruleset; | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |       description = | 
					
						
							|  |  |  |         ''
 | 
					
						
							|  |  |  |           The ruleset file to be used with nftables.  Should be in a format that | 
					
						
							|  |  |  |           can be loaded using "nft -f".  The ruleset is updated atomically. | 
					
						
							|  |  |  |         '';
 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ###### implementation | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   config = mkIf cfg.enable { | 
					
						
							|  |  |  |     assertions = [{ | 
					
						
							|  |  |  |       assertion = config.networking.firewall.enable == false; | 
					
						
							|  |  |  |       message = "You can not use nftables with services.networking.firewall."; | 
					
						
							|  |  |  |     }]; | 
					
						
							|  |  |  |     boot.blacklistedKernelModules = [ "ip_tables" ]; | 
					
						
							|  |  |  |     environment.systemPackages = [ pkgs.nftables ]; | 
					
						
							|  |  |  |     systemd.services.nftables = { | 
					
						
							|  |  |  |       description = "nftables firewall"; | 
					
						
							|  |  |  |       before = [ "network-pre.target" ]; | 
					
						
							|  |  |  |       wants = [ "network-pre.target" ]; | 
					
						
							|  |  |  |       wantedBy = [ "multi-user.target" ]; | 
					
						
							|  |  |  |       reloadIfChanged = true; | 
					
						
							|  |  |  |       serviceConfig = let | 
					
						
							|  |  |  |         rulesScript = pkgs.writeScript "nftables-rules" ''
 | 
					
						
							|  |  |  |           #! ${pkgs.nftables}/bin/nft -f | 
					
						
							|  |  |  |           flush ruleset | 
					
						
							|  |  |  |           include "${cfg.rulesetFile}" | 
					
						
							|  |  |  |         '';
 | 
					
						
							|  |  |  |         checkScript = pkgs.writeScript "nftables-check" ''
 | 
					
						
							| 
									
										
										
										
											2018-03-01 14:38:53 -05:00
										 |  |  |           #! ${pkgs.runtimeShell} -e | 
					
						
							| 
									
										
										
										
											2016-09-22 15:45:42 +10:00
										 |  |  |           if $(${pkgs.kmod}/bin/lsmod | grep -q ip_tables); then | 
					
						
							|  |  |  |             echo "Unload ip_tables before using nftables!" 1>&2 | 
					
						
							|  |  |  |             exit 1 | 
					
						
							|  |  |  |           else | 
					
						
							|  |  |  |             ${rulesScript} | 
					
						
							|  |  |  |           fi | 
					
						
							|  |  |  |         '';
 | 
					
						
							|  |  |  |       in { | 
					
						
							|  |  |  |         Type = "oneshot"; | 
					
						
							|  |  |  |         RemainAfterExit = true; | 
					
						
							|  |  |  |         ExecStart = checkScript; | 
					
						
							|  |  |  |         ExecReload = checkScript; | 
					
						
							|  |  |  |         ExecStop = "${pkgs.nftables}/bin/nft flush ruleset"; | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | } |