tangled
alpha
login
or
join now
pyrox.dev
/
nixpkgs
0
fork
atom
lol
0
fork
atom
overview
issues
pulls
pipelines
nixos/jool: allow to manage multiple instances
rnhmjoj
2 years ago
355a9fa0
3c15feef
+182
-123
1 changed file
expand all
collapse all
unified
split
nixos
modules
services
networking
jool.nix
+182
-123
nixos/modules/services/networking/jool.nix
···
16
16
TemporaryFileSystem = [ "/" ];
17
17
BindReadOnlyPaths = [
18
18
builtins.storeDir
19
19
-
"/run/current-system/kernel-modules"
19
19
+
"/run/booted-system/kernel-modules"
20
20
];
21
21
22
22
# Give capabilities to load the module and configure it
···
31
31
32
32
configFormat = pkgs.formats.json {};
33
33
34
34
-
mkDefaultAttrs = lib.mapAttrs (n: v: lib.mkDefault v);
34
34
+
# Generate the config file of instance `name`
35
35
+
nat64Conf = name:
36
36
+
configFormat.generate "jool-nat64-${name}.conf"
37
37
+
(cfg.nat64.${name} // { instance = name; });
38
38
+
siitConf = name:
39
39
+
configFormat.generate "jool-siit-${name}.conf"
40
40
+
(cfg.siit.${name} // { instance = name; });
41
41
+
42
42
+
# NAT64 config type
43
43
+
nat64Options = lib.types.submodule {
44
44
+
# The format is plain JSON
45
45
+
freeformType = configFormat.type;
46
46
+
# Some options with a default value
47
47
+
options.framework = lib.mkOption {
48
48
+
type = lib.types.enum [ "netfilter" "iptables" ];
49
49
+
default = "netfilter";
50
50
+
description = lib.mdDoc ''
51
51
+
The framework to use for attaching Jool's translation to the exist
52
52
+
kernel packet processing rules. See the
53
53
+
[documentation](https://nicmx.github.io/Jool/en/intro-jool.html#design)
54
54
+
for the differences between the two options.
55
55
+
'';
56
56
+
};
57
57
+
options.global.pool6 = lib.mkOption {
58
58
+
type = lib.types.strMatching "[[:xdigit:]:]+/[[:digit:]]+"
59
59
+
// { description = "Network prefix in CIDR notation"; };
60
60
+
default = "64:ff9b::/96";
61
61
+
description = lib.mdDoc ''
62
62
+
The prefix used for embedding IPv4 into IPv6 addresses.
63
63
+
Defaults to the well-known NAT64 prefix, defined by
64
64
+
[RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052).
65
65
+
'';
66
66
+
};
67
67
+
};
68
68
+
69
69
+
# SIIT config type
70
70
+
siitOptions = lib.types.submodule {
71
71
+
# The format is, again, plain JSON
72
72
+
freeformType = configFormat.type;
73
73
+
# Some options with a default value
74
74
+
options = { inherit (nat64Options.getSubOptions []) framework; };
75
75
+
};
35
76
36
36
-
defaultNat64 = {
37
37
-
instance = "default";
38
38
-
framework = "netfilter";
39
39
-
global.pool6 = "64:ff9b::/96";
77
77
+
makeNat64Unit = name: opts: {
78
78
+
"jool-nat64-${name}" = {
79
79
+
description = "Jool, NAT64 setup of instance ${name}";
80
80
+
documentation = [ "https://nicmx.github.io/Jool/en/documentation.html" ];
81
81
+
after = [ "network.target" ];
82
82
+
wantedBy = [ "multi-user.target" ];
83
83
+
serviceConfig = {
84
84
+
Type = "oneshot";
85
85
+
RemainAfterExit = true;
86
86
+
ExecStartPre = "${pkgs.kmod}/bin/modprobe jool";
87
87
+
ExecStart = "${jool-cli}/bin/jool file handle ${nat64Conf name}";
88
88
+
ExecStop = "${jool-cli}/bin/jool -f ${nat64Conf name} instance remove";
89
89
+
} // hardening;
90
90
+
};
40
91
};
41
41
-
defaultSiit = {
42
42
-
instance = "default";
43
43
-
framework = "netfilter";
92
92
+
93
93
+
makeSiitUnit = name: opts: {
94
94
+
"jool-siit-${name}" = {
95
95
+
description = "Jool, SIIT setup of instance ${name}";
96
96
+
documentation = [ "https://nicmx.github.io/Jool/en/documentation.html" ];
97
97
+
after = [ "network.target" ];
98
98
+
wantedBy = [ "multi-user.target" ];
99
99
+
serviceConfig = {
100
100
+
Type = "oneshot";
101
101
+
RemainAfterExit = true;
102
102
+
ExecStartPre = "${pkgs.kmod}/bin/modprobe jool_siit";
103
103
+
ExecStart = "${jool-cli}/bin/jool_siit file handle ${siitConf name}";
104
104
+
ExecStop = "${jool-cli}/bin/jool_siit -f ${siitConf name} instance remove";
105
105
+
} // hardening;
106
106
+
};
44
107
};
45
108
46
46
-
nat64Conf = configFormat.generate "jool-nat64.conf" cfg.nat64.config;
47
47
-
siitConf = configFormat.generate "jool-siit.conf" cfg.siit.config;
109
109
+
checkNat64 = name: _: ''
110
110
+
printf 'Validating Jool configuration for NAT64 instance "${name}"... '
111
111
+
jool file check ${nat64Conf name}
112
112
+
printf 'Ok.\n'; touch "$out"
113
113
+
'';
114
114
+
115
115
+
checkSiit = name: _: ''
116
116
+
printf 'Validating Jool configuration for SIIT instance "${name}"... '
117
117
+
jool_siit file check ${siitConf name}
118
118
+
printf 'Ok.\n'; touch "$out"
119
119
+
'';
48
120
49
121
in
50
122
51
123
{
52
52
-
###### interface
53
53
-
54
124
options = {
55
125
networking.jool.enable = lib.mkOption {
56
126
type = lib.types.bool;
···
64
134
NAT64, analogous to the IPv4 NAPT. Refer to the upstream
65
135
[documentation](https://nicmx.github.io/Jool/en/intro-xlat.html) for
66
136
the supported modes of translation and how to configure them.
137
137
+
138
138
+
Enabling this option will install the Jool kernel module and the
139
139
+
command line tools for controlling it.
67
140
'';
68
141
};
69
142
70
70
-
networking.jool.nat64.enable = lib.mkEnableOption (lib.mdDoc "a NAT64 instance of Jool.");
71
71
-
networking.jool.nat64.config = lib.mkOption {
72
72
-
type = configFormat.type;
73
73
-
default = defaultNat64;
143
143
+
networking.jool.nat64 = lib.mkOption {
144
144
+
type = lib.types.attrsOf nat64Options;
145
145
+
default = { };
74
146
example = lib.literalExpression ''
75
147
{
76
76
-
# custom NAT64 prefix
77
77
-
global.pool6 = "2001:db8:64::/96";
148
148
+
default = {
149
149
+
# custom NAT64 prefix
150
150
+
global.pool6 = "2001:db8:64::/96";
78
151
79
79
-
# Port forwarding
80
80
-
bib = [
81
81
-
{ # SSH 192.0.2.16 → 2001:db8:a::1
82
82
-
"protocol" = "TCP";
83
83
-
"ipv4 address" = "192.0.2.16#22";
84
84
-
"ipv6 address" = "2001:db8:a::1#22";
85
85
-
}
86
86
-
{ # DNS (TCP) 192.0.2.16 → 2001:db8:a::2
87
87
-
"protocol" = "TCP";
88
88
-
"ipv4 address" = "192.0.2.16#53";
89
89
-
"ipv6 address" = "2001:db8:a::2#53";
90
90
-
}
91
91
-
{ # DNS (UDP) 192.0.2.16 → 2001:db8:a::2
92
92
-
"protocol" = "UDP";
93
93
-
"ipv4 address" = "192.0.2.16#53";
94
94
-
"ipv6 address" = "2001:db8:a::2#53";
95
95
-
}
96
96
-
];
152
152
+
# Port forwarding
153
153
+
bib = [
154
154
+
{ # SSH 192.0.2.16 → 2001:db8:a::1
155
155
+
"protocol" = "TCP";
156
156
+
"ipv4 address" = "192.0.2.16#22";
157
157
+
"ipv6 address" = "2001:db8:a::1#22";
158
158
+
}
159
159
+
{ # DNS (TCP) 192.0.2.16 → 2001:db8:a::2
160
160
+
"protocol" = "TCP";
161
161
+
"ipv4 address" = "192.0.2.16#53";
162
162
+
"ipv6 address" = "2001:db8:a::2#53";
163
163
+
}
164
164
+
{ # DNS (UDP) 192.0.2.16 → 2001:db8:a::2
165
165
+
"protocol" = "UDP";
166
166
+
"ipv4 address" = "192.0.2.16#53";
167
167
+
"ipv6 address" = "2001:db8:a::2#53";
168
168
+
}
169
169
+
];
97
170
98
98
-
pool4 = [
99
99
-
# Ports for dynamic translation
100
100
-
{ protocol = "TCP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; }
101
101
-
{ protocol = "UDP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; }
102
102
-
{ protocol = "ICMP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; }
171
171
+
pool4 = [
172
172
+
# Port ranges for dynamic translation
173
173
+
{ protocol = "TCP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; }
174
174
+
{ protocol = "UDP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; }
175
175
+
{ protocol = "ICMP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; }
103
176
104
104
-
# Ports for static BIB entries
105
105
-
{ protocol = "TCP"; prefix = "192.0.2.16/32"; "port range" = "22"; }
106
106
-
{ protocol = "UDP"; prefix = "192.0.2.16/32"; "port range" = "53"; }
107
107
-
];
177
177
+
# Ports for static BIB entries
178
178
+
{ protocol = "TCP"; prefix = "192.0.2.16/32"; "port range" = "22"; }
179
179
+
{ protocol = "UDP"; prefix = "192.0.2.16/32"; "port range" = "53"; }
180
180
+
];
181
181
+
};
108
182
}
109
183
'';
110
184
description = lib.mdDoc ''
111
111
-
The configuration of a stateful NAT64 instance of Jool managed through
112
112
-
NixOS. See https://nicmx.github.io/Jool/en/config-atomic.html for the
113
113
-
available options.
185
185
+
Definitions of NAT64 instances of Jool.
186
186
+
See the
187
187
+
[documentation](https://nicmx.github.io/Jool/en/config-atomic.html) for
188
188
+
the available options. Also check out the
189
189
+
[tutorial](https://nicmx.github.io/Jool/en/run-nat64.html) for an
190
190
+
introduction to NAT64 and how to troubleshoot the setup.
191
191
+
192
192
+
The attribute name defines the name of the instance, with the main one
193
193
+
being `default`: this can be accessed from the command line without
194
194
+
specifying the name with `-i`.
114
195
115
196
::: {.note}
116
116
-
Existing or more instances created manually will not interfere with the
117
117
-
NixOS instance, provided the respective `pool4` addresses and port
118
118
-
ranges are not overlapping.
197
197
+
Instances created imperatively from the command line will not interfere
198
198
+
with the NixOS instances, provided the respective `pool4` addresses and
199
199
+
port ranges are not overlapping.
119
200
:::
120
201
121
202
::: {.warning}
122
122
-
Changes to the NixOS instance performed via `jool instance nixos-nat64`
123
123
-
are applied correctly but will be lost after restarting
124
124
-
`jool-nat64.service`.
203
203
+
Changes to an instance performed via `jool -i <name>` are applied
204
204
+
correctly but will be lost after restarting the respective
205
205
+
`jool-nat64-<name>.service`.
125
206
:::
126
207
'';
127
208
};
128
209
129
129
-
networking.jool.siit.enable = lib.mkEnableOption (lib.mdDoc "a SIIT instance of Jool.");
130
130
-
networking.jool.siit.config = lib.mkOption {
131
131
-
type = configFormat.type;
132
132
-
default = defaultSiit;
210
210
+
networking.jool.siit = lib.mkOption {
211
211
+
type = lib.types.attrsOf siitOptions;
212
212
+
default = { };
133
213
example = lib.literalExpression ''
134
214
{
135
135
-
# Maps any IPv4 address x.y.z.t to 2001:db8::x.y.z.t and v.v.
136
136
-
pool6 = "2001:db8::/96";
215
215
+
default = {
216
216
+
# Maps any IPv4 address x.y.z.t to 2001:db8::x.y.z.t and v.v.
217
217
+
global.pool6 = "2001:db8::/96";
137
218
138
138
-
# Explicit address mappings
139
139
-
eamt = [
140
140
-
# 2001:db8:1:: ←→ 192.0.2.0
141
141
-
{ "ipv6 prefix": "2001:db8:1::/128", "ipv4 prefix": "192.0.2.0" }
142
142
-
# 2001:db8:1::x ←→ 198.51.100.x
143
143
-
{ "ipv6 prefix": "2001:db8:2::/120", "ipv4 prefix": "198.51.100.0/24" }
144
144
-
]
219
219
+
# Explicit address mappings
220
220
+
eamt = [
221
221
+
# 2001:db8:1:: ←→ 192.0.2.0
222
222
+
{ "ipv6 prefix" = "2001:db8:1::/128"; "ipv4 prefix" = "192.0.2.0"; }
223
223
+
# 2001:db8:1::x ←→ 198.51.100.x
224
224
+
{ "ipv6 prefix" = "2001:db8:2::/120"; "ipv4 prefix" = "198.51.100.0/24"; }
225
225
+
];
226
226
+
};
145
227
}
146
228
'';
147
229
description = lib.mdDoc ''
148
148
-
The configuration of a SIIT instance of Jool managed through
149
149
-
NixOS. See https://nicmx.github.io/Jool/en/config-atomic.html for the
150
150
-
available options.
230
230
+
Definitions of SIIT instances of Jool.
231
231
+
See the
232
232
+
[documentation](https://nicmx.github.io/Jool/en/config-atomic.html) for
233
233
+
the available options. Also check out the
234
234
+
[tutorial](https://nicmx.github.io/Jool/en/run-vanilla.html) for an
235
235
+
introduction to SIIT and how to troubleshoot the setup.
236
236
+
237
237
+
The attribute name defines the name of the instance, with the main one
238
238
+
being `default`: this can be accessed from the command line without
239
239
+
specifying the name with `-i`.
151
240
152
241
::: {.note}
153
153
-
Existing or more instances created manually will not interfere with the
154
154
-
NixOS instance, provided the respective `EAMT` address mappings are not
155
155
-
overlapping.
242
242
+
Instances created imperatively from the command line will not interfere
243
243
+
with the NixOS instances, provided the respective EAMT addresses and
244
244
+
port ranges are not overlapping.
156
245
:::
157
246
158
247
::: {.warning}
159
159
-
Changes to the NixOS instance performed via `jool instance nixos-siit`
160
160
-
are applied correctly but will be lost after restarting
161
161
-
`jool-siit.service`.
248
248
+
Changes to an instance performed via `jool -i <name>` are applied
249
249
+
correctly but will be lost after restarting the respective
250
250
+
`jool-siit-<name>.service`.
162
251
:::
163
252
'';
164
253
};
165
254
166
255
};
167
256
168
168
-
###### implementation
169
169
-
170
257
config = lib.mkIf cfg.enable {
171
171
-
environment.systemPackages = [ jool-cli ];
258
258
+
# Install kernel module and cli tools
172
259
boot.extraModulePackages = [ jool ];
173
173
-
174
174
-
systemd.services.jool-nat64 = lib.mkIf cfg.nat64.enable {
175
175
-
description = "Jool, NAT64 setup";
176
176
-
documentation = [ "https://nicmx.github.io/Jool/en/documentation.html" ];
177
177
-
after = [ "network.target" ];
178
178
-
wantedBy = [ "multi-user.target" ];
179
179
-
reloadIfChanged = true;
180
180
-
serviceConfig = {
181
181
-
Type = "oneshot";
182
182
-
RemainAfterExit = true;
183
183
-
ExecStartPre = "${pkgs.kmod}/bin/modprobe jool";
184
184
-
ExecStart = "${jool-cli}/bin/jool file handle ${nat64Conf}";
185
185
-
ExecStop = "${jool-cli}/bin/jool -f ${nat64Conf} instance remove";
186
186
-
} // hardening;
187
187
-
};
188
188
-
189
189
-
systemd.services.jool-siit = lib.mkIf cfg.siit.enable {
190
190
-
description = "Jool, SIIT setup";
191
191
-
documentation = [ "https://nicmx.github.io/Jool/en/documentation.html" ];
192
192
-
after = [ "network.target" ];
193
193
-
wantedBy = [ "multi-user.target" ];
194
194
-
reloadIfChanged = true;
195
195
-
serviceConfig = {
196
196
-
Type = "oneshot";
197
197
-
RemainAfterExit = true;
198
198
-
ExecStartPre = "${pkgs.kmod}/bin/modprobe jool_siit";
199
199
-
ExecStart = "${jool-cli}/bin/jool_siit file handle ${siitConf}";
200
200
-
ExecStop = "${jool-cli}/bin/jool_siit -f ${siitConf} instance remove";
201
201
-
} // hardening;
202
202
-
};
203
203
-
204
204
-
system.checks = lib.singleton (pkgs.runCommand "jool-validated" {
205
205
-
nativeBuildInputs = [ pkgs.buildPackages.jool-cli ];
206
206
-
preferLocalBuild = true;
207
207
-
} ''
208
208
-
printf 'Validating Jool configuration... '
209
209
-
${lib.optionalString cfg.siit.enable "jool_siit file check ${siitConf}"}
210
210
-
${lib.optionalString cfg.nat64.enable "jool file check ${nat64Conf}"}
211
211
-
printf 'ok\n'
212
212
-
touch "$out"
213
213
-
'');
260
260
+
environment.systemPackages = [ jool-cli ];
214
261
215
215
-
networking.jool.nat64.config = mkDefaultAttrs defaultNat64;
216
216
-
networking.jool.siit.config = mkDefaultAttrs defaultSiit;
262
262
+
# Install services for each instance
263
263
+
systemd.services = lib.mkMerge
264
264
+
(lib.mapAttrsToList makeNat64Unit cfg.nat64 ++
265
265
+
lib.mapAttrsToList makeSiitUnit cfg.siit);
217
266
267
267
+
# Check the configuration of each instance
268
268
+
system.checks = lib.optional (cfg.nat64 != {} || cfg.siit != {})
269
269
+
(pkgs.runCommand "jool-validated"
270
270
+
{
271
271
+
nativeBuildInputs = with pkgs.buildPackages; [ jool-cli ];
272
272
+
preferLocalBuild = true;
273
273
+
}
274
274
+
(lib.concatStrings
275
275
+
(lib.mapAttrsToList checkNat64 cfg.nat64 ++
276
276
+
lib.mapAttrsToList checkSiit cfg.siit)));
218
277
};
219
278
220
279
meta.maintainers = with lib.maintainers; [ rnhmjoj ];