nixpkgs/nixos/modules/services/networking/jool.nix

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

223 lines
7.3 KiB
Nix
Raw Normal View History

{ 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 ];
}