189 lines
5.4 KiB
Nix
189 lines
5.4 KiB
Nix
{ config, lib, pkgs, ... }:
|
|
|
|
with lib;
|
|
|
|
let
|
|
inherit (pkgs) writeText;
|
|
|
|
inherit (builtins)
|
|
elem
|
|
;
|
|
|
|
cfg = config.krebs.iptables;
|
|
|
|
out = {
|
|
options.krebs.iptables = api;
|
|
config = mkIf cfg.enable imp;
|
|
};
|
|
|
|
api = {
|
|
enable = mkEnableOption "iptables";
|
|
|
|
#tables.filter.INPUT = {
|
|
# policy = "DROP";
|
|
# rules = [
|
|
# { predicate = "-i retiolum"; target = "ACCEPT"; priority = -10; }
|
|
# ];
|
|
#};
|
|
#new api
|
|
tables = mkOption {
|
|
type = with types; attrsOf (attrsOf (submodule ({
|
|
options = {
|
|
#TODO: find out good defaults.
|
|
policy = mkOption {
|
|
type = str;
|
|
default = "ACCEPT";
|
|
};
|
|
rules = mkOption {
|
|
type = nullOr (listOf (submodule ({
|
|
options = {
|
|
predicate = mkOption {
|
|
type = str;
|
|
};
|
|
target = mkOption {
|
|
type = str;
|
|
};
|
|
v4 = mkOption {
|
|
type = bool;
|
|
default = true;
|
|
};
|
|
v6 = mkOption {
|
|
type = bool;
|
|
default = true;
|
|
};
|
|
};
|
|
})));
|
|
default = null;
|
|
};
|
|
};
|
|
})));
|
|
default = {
|
|
filter.INPUT.policy = "ACCEPT";
|
|
filter.FORWARD.policy = "ACCEPT";
|
|
filter.OUTPUT.policy = "ACCEPT";
|
|
nat.PREROUTING.policy = "ACCEPT";
|
|
nat.INPUT.policy = "ACCEPT";
|
|
nat.OUTPUT.policy = "ACCEPT";
|
|
nat.POSTROUTING.policy = "ACCEPT";
|
|
};
|
|
};
|
|
};
|
|
|
|
imp = mkMerge ([{
|
|
networking.firewall.enable = false;
|
|
|
|
systemd.services.krebs-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";
|
|
ExecStart = startScript;
|
|
};
|
|
|
|
unitConfig.DefaultDependencies = false;
|
|
};
|
|
}] ++ compat);
|
|
|
|
compat = [
|
|
({
|
|
krebs.iptables.tables.filter.INPUT.rules = map
|
|
(port: { predicate = "-p tcp --dport ${toString port}"; target = "ACCEPT"; })
|
|
config.networking.firewall.allowedTCPPorts;
|
|
})
|
|
({
|
|
krebs.iptables.tables.filter.INPUT.rules = map
|
|
(port: { predicate = "-p udp --dport ${toString port}"; target = "ACCEPT"; })
|
|
config.networking.firewall.allowedUDPPorts;
|
|
})
|
|
({
|
|
krebs.iptables.tables.filter.INPUT.rules = map
|
|
(portRange: { predicate = "-p tcp --dport ${toString portRange.from}:${toString portRange.to}"; target = "ACCEPT"; })
|
|
config.networking.firewall.allowedTCPPortRanges;
|
|
})
|
|
({
|
|
krebs.iptables.tables.filter.INPUT.rules = map
|
|
(portRange: { predicate = "-p udp --dport ${toString portRange.from}:${toString portRange.to}"; target = "ACCEPT"; })
|
|
config.networking.firewall.allowedUDPPortRanges;
|
|
})
|
|
({
|
|
krebs.iptables.tables.filter.INPUT.rules = flatten (mapAttrsToList
|
|
(interface: interfaceConfig: [
|
|
(map (port: { predicate = "-i ${interface} -p tcp --dport ${toString port}"; target = "ACCEPT"; }) interfaceConfig.allowedTCPPorts)
|
|
(map (port: { predicate = "-i ${interface} -p udp --dport ${toString port}"; target = "ACCEPT"; }) interfaceConfig.allowedUDPPorts)
|
|
(map (portRange: { predicate = "-i ${interface} -p tcp --dport ${toString portRange.from}:${toString portRange.to}"; target = "ACCEPT"; }) interfaceConfig.allowedTCPPortRanges)
|
|
(map (portRange: { predicate = "-i ${interface} -p udp --dport ${toString portRange.from}:${toString portRange.to}"; target = "ACCEPT"; }) interfaceConfig.allowedUDPPortRanges)
|
|
])
|
|
config.networking.firewall.interfaces
|
|
);
|
|
})
|
|
];
|
|
|
|
#buildTable :: iptablesVersion -> iptablesAttrSet` -> str
|
|
#todo: differentiate by iptables-version
|
|
buildTables = v: ts:
|
|
let
|
|
|
|
declareChain = t: cn:
|
|
#TODO: find out what to do whit these count numbers
|
|
":${cn} ${t."${cn}".policy} [0:0]";
|
|
|
|
buildChain = tn: cn:
|
|
let
|
|
filteredRules = filter (r: r."${v}") ts."${tn}"."${cn}".rules;
|
|
in
|
|
#TODO: double check should be unneccessary, refactor!
|
|
if ts.${tn}.${cn}.rules or null != null then
|
|
concatMapStringsSep "\n" (rule: "\n-A ${cn} ${rule}") ([]
|
|
++ map (buildRule tn cn) filteredRules
|
|
)
|
|
else
|
|
""
|
|
;
|
|
|
|
|
|
buildRule = tn: cn: rule:
|
|
"${rule.predicate} -j ${rule.target}";
|
|
|
|
buildTable = tn:
|
|
"*${tn}\n" +
|
|
concatStringsSep "\n" ([]
|
|
++ map (declareChain ts."${tn}") (attrNames ts."${tn}")
|
|
) +
|
|
#this looks dirty, find a better way to do this (maybe optionalString)
|
|
concatStringsSep "" ([]
|
|
++ map (buildChain tn) (attrNames ts."${tn}")
|
|
) +
|
|
"\nCOMMIT";
|
|
in
|
|
concatStringsSep "\n" ([]
|
|
++ map buildTable (attrNames ts)
|
|
);
|
|
|
|
#=====
|
|
|
|
rules = iptables-version:
|
|
pkgs.writeText "krebs-iptables-rules${iptables-version}" ''
|
|
${buildTables iptables-version cfg.tables}
|
|
'';
|
|
|
|
startScript = pkgs.writers.writeDash "krebs-iptables_start" ''
|
|
set -euf
|
|
iptables-restore < ${rules "v4"}
|
|
ip6tables-restore < ${rules "v6"}
|
|
'';
|
|
|
|
in
|
|
out
|
|
|