diff options
author | tv <tv@krebsco.de> | 2023-09-11 18:24:28 +0200 |
---|---|---|
committer | tv <tv@krebsco.de> | 2023-09-13 18:07:11 +0200 |
commit | 0c4f3acb281be6290c55a6e96bc29fab5b5c7a11 (patch) | |
tree | dadaec00477a095273475ac345b2066b4748c399 /modules/iptables.nix | |
parent | ab1d0479e90f11806d4703ec6fffed3d5f782914 (diff) |
stockholm -> hrm
Diffstat (limited to 'modules/iptables.nix')
-rw-r--r-- | modules/iptables.nix | 207 |
1 files changed, 207 insertions, 0 deletions
diff --git a/modules/iptables.nix b/modules/iptables.nix new file mode 100644 index 0000000..e2fdcbc --- /dev/null +++ b/modules/iptables.nix @@ -0,0 +1,207 @@ +{ config, lib, pkgs, ... }: let { + cfg = config.tv.iptables; + + body = { + options.tv.iptables = api; + config = lib.mkIf cfg.enable imp; + }; + + extraTypes = { + rules = lib.types.submodule { + options = { + nat.OUTPUT = lib.mkOption { + type = with lib.types; listOf str; + default = []; + }; + nat.PREROUTING = lib.mkOption { + type = with lib.types; listOf str; + default = []; + }; + nat.POSTROUTING = lib.mkOption { + type = with lib.types; listOf str; + default = []; + }; + filter.FORWARD = lib.mkOption { + type = with lib.types; listOf str; + default = []; + }; + filter.INPUT = lib.mkOption { + type = with lib.types; listOf str; + default = []; + }; + filter.Retiolum = lib.mkOption { + type = with lib.types; listOf str; + default = []; + }; + filter.Wiregrill = lib.mkOption { + type = with lib.types; listOf str; + default = []; + }; + }; + }; + }; + + api = { + enable = lib.mkEnableOption "tv.iptables"; + + accept-echo-request = lib.mkOption { + type = with lib.types; nullOr (enum ["internet" "retiolum"]); + default = "retiolum"; + }; + + input-internet-accept-tcp = lib.mkOption { + type = with lib.types; listOf (either int str); + default = []; + }; + + input-internet-accept-udp = lib.mkOption { + type = with lib.types; listOf (either int str); + default = []; + }; + + input-retiolum-accept-tcp = lib.mkOption { + type = with lib.types; listOf (either int str); + default = []; + }; + + input-retiolum-accept-udp = lib.mkOption { + type = with lib.types; listOf (either int str); + default = []; + }; + + input-wiregrill-accept-tcp = lib.mkOption { + type = with lib.types; listOf (either int str); + default = []; + }; + + input-wiregrill-accept-udp = lib.mkOption { + type = with lib.types; listOf (either int str); + default = []; + }; + + extra = lib.mkOption { + default = {}; + type = extraTypes.rules; + }; + + extra4 = lib.mkOption { + default = {}; + type = extraTypes.rules; + }; + + extra6 = lib.mkOption { + default = {}; + type = extraTypes.rules; + }; + }; + + imp = { + networking.firewall.enable = false; + + systemd.services.tv-iptables = { + wantedBy = [ "sysinit.target" ]; + wants = [ "network-pre.target" ]; + before = [ "network-pre.target" ]; + after = [ "systemd-modules-load.service" ]; + + path = with pkgs; [ + iptables + ]; + + restartIfChanged = true; + + serviceConfig = { + Type = "simple"; + RemainAfterExit = true; + Restart = "always"; + SyslogIdentifier = "tv-iptables_start"; + ExecStart = pkgs.writeDash "tv-iptables_start" '' + set -euf + iptables-restore < ${rules 4} + ip6tables-restore < ${rules 6} + ''; + }; + + unitConfig.DefaultDependencies = false; + }; + }; + + formatTable = table: + (lib.concatStringsSep "\n" + (lib.mapAttrsToList + (chain: lib.concatMapStringsSep "\n" (rule: "-A ${chain} ${rule}")) + table)); + + rules = iptables-version: let + accept-echo-request = { + ip4tables = "-p icmp -m icmp --icmp-type echo-request -j ACCEPT"; + ip6tables = "-p ipv6-icmp -m icmp6 --icmpv6-type echo-request -j ACCEPT"; + }."ip${toString iptables-version}tables"; + accept-tcp = port: "-p tcp -m tcp --dport ${port} -j ACCEPT"; + accept-udp = port: "-p udp -m udp --dport ${port} -j ACCEPT"; + in + pkgs.writeText "tv-iptables-rules${toString iptables-version}" '' + *nat + :PREROUTING ACCEPT [0:0] + :INPUT ACCEPT [0:0] + :OUTPUT ACCEPT [0:0] + :POSTROUTING ACCEPT [0:0] + ${formatTable cfg."extra${toString iptables-version}".nat} + ${formatTable cfg.extra.nat} + COMMIT + *filter + :INPUT DROP [0:0] + :FORWARD DROP [0:0] + :OUTPUT ACCEPT [0:0] + :Retiolum - [0:0] + :Wiregrill - [0:0] + ${lib.concatMapStringsSep "\n" (rule: "-A INPUT ${rule}") ([] + ++ [ + "-m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT" + "-i lo -j ACCEPT" + ] + ++ lib.optional (cfg.accept-echo-request == "internet") accept-echo-request + ++ map accept-tcp (lib.unique (map toString cfg.input-internet-accept-tcp)) + ++ map accept-udp (lib.unique (map toString cfg.input-internet-accept-udp)) + ++ ["-i retiolum -j Retiolum"] + ++ ["-i wiregrill -j Wiregrill"] + )} + ${formatTable cfg.extra.filter} + ${formatTable cfg."extra${toString iptables-version}".filter} + ${lib.concatMapStringsSep "\n" (rule: "-A Retiolum ${rule}") ([] + ++ lib.optional (cfg.accept-echo-request == "retiolum") accept-echo-request + ++ map accept-tcp (lib.unique (map toString cfg.input-retiolum-accept-tcp)) + ++ map accept-udp (lib.unique (map toString cfg.input-retiolum-accept-udp)) + ++ { + ip4tables = [ + "-p tcp -j REJECT --reject-with tcp-reset" + "-p udp -j REJECT --reject-with icmp-port-unreachable" + "-j REJECT --reject-with icmp-proto-unreachable" + ]; + ip6tables = [ + "-p tcp -j REJECT --reject-with tcp-reset" + "-p udp -j REJECT --reject-with icmp6-port-unreachable" + "-j REJECT" + ]; + }."ip${toString iptables-version}tables" + )} + ${lib.concatMapStringsSep "\n" (rule: "-A Wiregrill ${rule}") ([] + ++ lib.optional (cfg.accept-echo-request == "wiregrill") accept-echo-request + ++ map accept-tcp (lib.unique (map toString cfg.input-wiregrill-accept-tcp)) + ++ map accept-udp (lib.unique (map toString cfg.input-wiregrill-accept-udp)) + ++ { + ip4tables = [ + "-p tcp -j REJECT --reject-with tcp-reset" + "-p udp -j REJECT --reject-with icmp-port-unreachable" + "-j REJECT --reject-with icmp-proto-unreachable" + ]; + ip6tables = [ + "-p tcp -j REJECT --reject-with tcp-reset" + "-p udp -j REJECT --reject-with icmp6-port-unreachable" + "-j REJECT" + ]; + }."ip${toString iptables-version}tables" + )} + COMMIT + ''; +} |