c7f94ff3ce
GitOrigin-RevId: b85ed9dcbf187b909ef7964774f8847d554fab3b
222 lines
7.3 KiB
Nix
222 lines
7.3 KiB
Nix
{ config, pkgs, lib, ... }:
|
|
|
|
let
|
|
cfg = config.networking.jool;
|
|
|
|
jool = config.boot.kernelPackages.jool;
|
|
jool-cli = pkgs.jool-cli;
|
|
|
|
hardening = {
|
|
# Run as unprivileged user
|
|
User = "jool";
|
|
Group = "jool";
|
|
DynamicUser = true;
|
|
|
|
# Restrict filesystem to only read the jool module
|
|
TemporaryFileSystem = [ "/" ];
|
|
BindReadOnlyPaths = [
|
|
builtins.storeDir
|
|
"/run/current-system/kernel-modules"
|
|
];
|
|
|
|
# Give capabilities to load the module and configure it
|
|
AmbientCapabilities = [ "CAP_SYS_MODULE" "CAP_NET_ADMIN" ];
|
|
RestrictAddressFamilies = [ "AF_NETLINK" ];
|
|
|
|
# Other restrictions
|
|
RestrictNamespaces = [ "net" ];
|
|
SystemCallFilter = [ "@system-service" "@module" ];
|
|
CapabilityBoundingSet = [ "CAP_SYS_MODULE" "CAP_NET_ADMIN" ];
|
|
};
|
|
|
|
configFormat = pkgs.formats.json {};
|
|
|
|
mkDefaultAttrs = lib.mapAttrs (n: v: lib.mkDefault v);
|
|
|
|
defaultNat64 = {
|
|
instance = "default";
|
|
framework = "netfilter";
|
|
global.pool6 = "64:ff9b::/96";
|
|
};
|
|
defaultSiit = {
|
|
instance = "default";
|
|
framework = "netfilter";
|
|
};
|
|
|
|
nat64Conf = configFormat.generate "jool-nat64.conf" cfg.nat64.config;
|
|
siitConf = configFormat.generate "jool-siit.conf" cfg.siit.config;
|
|
|
|
in
|
|
|
|
{
|
|
###### interface
|
|
|
|
options = {
|
|
networking.jool.enable = lib.mkOption {
|
|
type = lib.types.bool;
|
|
default = false;
|
|
relatedPackages = [ "linuxPackages.jool" "jool-cli" ];
|
|
description = lib.mdDoc ''
|
|
Whether to enable Jool, an Open Source implementation of IPv4/IPv6
|
|
translation on Linux.
|
|
|
|
Jool can perform stateless IP/ICMP translation (SIIT) or stateful
|
|
NAT64, analogous to the IPv4 NAPT. Refer to the upstream
|
|
[documentation](https://nicmx.github.io/Jool/en/intro-xlat.html) for
|
|
the supported modes of translation and how to configure them.
|
|
'';
|
|
};
|
|
|
|
networking.jool.nat64.enable = lib.mkEnableOption (lib.mdDoc "a NAT64 instance of Jool.");
|
|
networking.jool.nat64.config = lib.mkOption {
|
|
type = configFormat.type;
|
|
default = defaultNat64;
|
|
example = lib.literalExpression ''
|
|
{
|
|
# custom NAT64 prefix
|
|
global.pool6 = "2001:db8:64::/96";
|
|
|
|
# Port forwarding
|
|
bib = [
|
|
{ # SSH 192.0.2.16 → 2001:db8:a::1
|
|
"protocol" = "TCP";
|
|
"ipv4 address" = "192.0.2.16#22";
|
|
"ipv6 address" = "2001:db8:a::1#22";
|
|
}
|
|
{ # DNS (TCP) 192.0.2.16 → 2001:db8:a::2
|
|
"protocol" = "TCP";
|
|
"ipv4 address" = "192.0.2.16#53";
|
|
"ipv6 address" = "2001:db8:a::2#53";
|
|
}
|
|
{ # DNS (UDP) 192.0.2.16 → 2001:db8:a::2
|
|
"protocol" = "UDP";
|
|
"ipv4 address" = "192.0.2.16#53";
|
|
"ipv6 address" = "2001:db8:a::2#53";
|
|
}
|
|
];
|
|
|
|
pool4 = [
|
|
# Ports for dynamic translation
|
|
{ protocol = "TCP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; }
|
|
{ protocol = "UDP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; }
|
|
{ protocol = "ICMP"; prefix = "192.0.2.16/32"; "port range" = "40001-65535"; }
|
|
|
|
# Ports for static BIB entries
|
|
{ protocol = "TCP"; prefix = "192.0.2.16/32"; "port range" = "22"; }
|
|
{ protocol = "UDP"; prefix = "192.0.2.16/32"; "port range" = "53"; }
|
|
];
|
|
}
|
|
'';
|
|
description = lib.mdDoc ''
|
|
The configuration of a stateful NAT64 instance of Jool managed through
|
|
NixOS. See https://nicmx.github.io/Jool/en/config-atomic.html for the
|
|
available options.
|
|
|
|
::: {.note}
|
|
Existing or more instances created manually will not interfere with the
|
|
NixOS instance, provided the respective `pool4` addresses and port
|
|
ranges are not overlapping.
|
|
:::
|
|
|
|
::: {.warning}
|
|
Changes to the NixOS instance performed via `jool instance nixos-nat64`
|
|
are applied correctly but will be lost after restarting
|
|
`jool-nat64.service`.
|
|
:::
|
|
'';
|
|
};
|
|
|
|
networking.jool.siit.enable = lib.mkEnableOption (lib.mdDoc "a SIIT instance of Jool.");
|
|
networking.jool.siit.config = lib.mkOption {
|
|
type = configFormat.type;
|
|
default = defaultSiit;
|
|
example = lib.literalExpression ''
|
|
{
|
|
# Maps any IPv4 address x.y.z.t to 2001:db8::x.y.z.t and v.v.
|
|
pool6 = "2001:db8::/96";
|
|
|
|
# Explicit address mappings
|
|
eamt = [
|
|
# 2001:db8:1:: ←→ 192.0.2.0
|
|
{ "ipv6 prefix": "2001:db8:1::/128", "ipv4 prefix": "192.0.2.0" }
|
|
# 2001:db8:1::x ←→ 198.51.100.x
|
|
{ "ipv6 prefix": "2001:db8:2::/120", "ipv4 prefix": "198.51.100.0/24" }
|
|
]
|
|
}
|
|
'';
|
|
description = lib.mdDoc ''
|
|
The configuration of a SIIT instance of Jool managed through
|
|
NixOS. See https://nicmx.github.io/Jool/en/config-atomic.html for the
|
|
available options.
|
|
|
|
::: {.note}
|
|
Existing or more instances created manually will not interfere with the
|
|
NixOS instance, provided the respective `EAMT` address mappings are not
|
|
overlapping.
|
|
:::
|
|
|
|
::: {.warning}
|
|
Changes to the NixOS instance performed via `jool instance nixos-siit`
|
|
are applied correctly but will be lost after restarting
|
|
`jool-siit.service`.
|
|
:::
|
|
'';
|
|
};
|
|
|
|
};
|
|
|
|
###### implementation
|
|
|
|
config = lib.mkIf cfg.enable {
|
|
environment.systemPackages = [ jool-cli ];
|
|
boot.extraModulePackages = [ jool ];
|
|
|
|
systemd.services.jool-nat64 = lib.mkIf cfg.nat64.enable {
|
|
description = "Jool, NAT64 setup";
|
|
documentation = [ "https://nicmx.github.io/Jool/en/documentation.html" ];
|
|
after = [ "network.target" ];
|
|
wantedBy = [ "multi-user.target" ];
|
|
reloadIfChanged = true;
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStartPre = "${pkgs.kmod}/bin/modprobe jool";
|
|
ExecStart = "${jool-cli}/bin/jool file handle ${nat64Conf}";
|
|
ExecStop = "${jool-cli}/bin/jool -f ${nat64Conf} instance remove";
|
|
} // hardening;
|
|
};
|
|
|
|
systemd.services.jool-siit = lib.mkIf cfg.siit.enable {
|
|
description = "Jool, SIIT setup";
|
|
documentation = [ "https://nicmx.github.io/Jool/en/documentation.html" ];
|
|
after = [ "network.target" ];
|
|
wantedBy = [ "multi-user.target" ];
|
|
reloadIfChanged = true;
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
RemainAfterExit = true;
|
|
ExecStartPre = "${pkgs.kmod}/bin/modprobe jool_siit";
|
|
ExecStart = "${jool-cli}/bin/jool_siit file handle ${siitConf}";
|
|
ExecStop = "${jool-cli}/bin/jool_siit -f ${siitConf} instance remove";
|
|
} // hardening;
|
|
};
|
|
|
|
system.checks = lib.singleton (pkgs.runCommand "jool-validated" {
|
|
nativeBuildInputs = [ pkgs.buildPackages.jool-cli ];
|
|
preferLocalBuild = true;
|
|
} ''
|
|
printf 'Validating Jool configuration... '
|
|
${lib.optionalString cfg.siit.enable "jool_siit file check ${siitConf}"}
|
|
${lib.optionalString cfg.nat64.enable "jool file check ${nat64Conf}"}
|
|
printf 'ok\n'
|
|
touch "$out"
|
|
'');
|
|
|
|
networking.jool.nat64.config = mkDefaultAttrs defaultNat64;
|
|
networking.jool.siit.config = mkDefaultAttrs defaultSiit;
|
|
|
|
};
|
|
|
|
meta.maintainers = with lib.maintainers; [ rnhmjoj ];
|
|
|
|
}
|