1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
{ cfg, lib, pkgs, ... }:
let
inherit (pkgs) writeScript writeText;
inherit (lib) concatMapStringsSep concatStringsSep attrNames unique fold any attrValues catAttrs filter flatten length hasAttr;
#===== new api v4
#buildTable :: iptablesAttrSet` -> str
#todo: differentiate by iptables-version
buildTables = iptv: ts:
let
declareChain = t: cn:
#TODO: find out what to do whit these count numbers
":${cn} ${t."${cn}".policy} [0:0]";
buildChain = tn: cn:
#"${concatStringsSep " " ((attrNames t."${cn}") ++ [cn])}";
#TODO: sort by precedence
#TODO: double check should be unneccessary, refactor!
if (hasAttr "rules" ts."${tn}"."${cn}") then
if (ts."${tn}"."${cn}".rules == null) then
""
else
concatMapStringsSep "\n" (rule: "\n-A ${cn} ${rule}") ([]
++ map buildRule ts."${tn}"."${cn}".rules
)
else
""
;
buildRule = rule:
#TODO implement rule validation-test here
#
#target:
#target needs to be an existing chain (in the same table) or ACCEPT, REJECT, DROP, LOG, QUEUE, RETURN
#predicate:
#maybe use iptables-test
#TODO: howto exit with evaluation error by shellscript?
#apperantly not possible from nix because evalatution wouldn't be deterministic.
"${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)
);
#=====
rules4 = iptables-version:
let
#TODO: find out good defaults.
tables-defaults = {
nat.PREROUTING.policy = "ACCEPT";
nat.INPUT.policy = "ACCEPT";
nat.OUTPUT.policy = "ACCEPT";
nat.POSTROUTING.policy = "ACCEPT";
filter.INPUT.policy = "ACCEPT";
filter.FORWARD.policy = "ACCEPT";
filter.OUTPUT.policy = "ACCEPT";
#if someone specifies any other rules on this chain, the default rules get lost.
#is this wanted beahiviour or a bug?
#TODO: implement abstraction of rules
filter.INPUT.rules = [
{ predicate = "-m conntrack --ctstate RELATED,ESTABLISHED"; target = "ACCEPT"; }
];
};
tables = tables-defaults // cfg.tables;
in
writeText "lass-iptables-rules${toString iptables-version}" ''
${buildTables iptables-version tables}
'';
startScript = writeScript "lass-iptables_start" ''
#! /bin/sh
set -euf
iptables-restore < ${rules4 4}
ip6tables-restore < ${rules4 6}
'';
in
{
networking.firewall.enable = false;
systemd.services.lass-iptables = {
description = "lass-iptables";
wantedBy = [ "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} lass-iptables_start";
};
};
}
|