Loading nixos/modules/services/networking/jool.nix +186 −127 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ let TemporaryFileSystem = [ "/" ]; BindReadOnlyPaths = [ builtins.storeDir "/run/current-system/kernel-modules" "/run/booted-system/kernel-modules" ]; # Give capabilities to load the module and configure it Loading @@ -31,26 +31,96 @@ let configFormat = pkgs.formats.json {}; mkDefaultAttrs = lib.mapAttrs (n: v: lib.mkDefault v); # Generate the config file of instance `name` nat64Conf = name: configFormat.generate "jool-nat64-${name}.conf" (cfg.nat64.${name} // { instance = name; }); siitConf = name: configFormat.generate "jool-siit-${name}.conf" (cfg.siit.${name} // { instance = name; }); # NAT64 config type nat64Options = lib.types.submodule { # The format is plain JSON freeformType = configFormat.type; # Some options with a default value options.framework = lib.mkOption { type = lib.types.enum [ "netfilter" "iptables" ]; default = "netfilter"; description = lib.mdDoc '' The framework to use for attaching Jool's translation to the exist kernel packet processing rules. See the [documentation](https://nicmx.github.io/Jool/en/intro-jool.html#design) for the differences between the two options. ''; }; options.global.pool6 = lib.mkOption { type = lib.types.strMatching "[[:xdigit:]:]+/[[:digit:]]+" // { description = "Network prefix in CIDR notation"; }; default = "64:ff9b::/96"; description = lib.mdDoc '' The prefix used for embedding IPv4 into IPv6 addresses. Defaults to the well-known NAT64 prefix, defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052). ''; }; }; # SIIT config type siitOptions = lib.types.submodule { # The format is, again, plain JSON freeformType = configFormat.type; # Some options with a default value options = { inherit (nat64Options.getSubOptions []) framework; }; }; makeNat64Unit = name: opts: { "jool-nat64-${name}" = { description = "Jool, NAT64 setup of instance ${name}"; documentation = [ "https://nicmx.github.io/Jool/en/documentation.html" ]; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; ExecStartPre = "${pkgs.kmod}/bin/modprobe jool"; ExecStart = "${jool-cli}/bin/jool file handle ${nat64Conf name}"; ExecStop = "${jool-cli}/bin/jool -f ${nat64Conf name} instance remove"; } // hardening; }; }; defaultNat64 = { instance = "default"; framework = "netfilter"; global.pool6 = "64:ff9b::/96"; makeSiitUnit = name: opts: { "jool-siit-${name}" = { description = "Jool, SIIT setup of instance ${name}"; documentation = [ "https://nicmx.github.io/Jool/en/documentation.html" ]; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; ExecStartPre = "${pkgs.kmod}/bin/modprobe jool_siit"; ExecStart = "${jool-cli}/bin/jool_siit file handle ${siitConf name}"; ExecStop = "${jool-cli}/bin/jool_siit -f ${siitConf name} instance remove"; } // hardening; }; defaultSiit = { instance = "default"; framework = "netfilter"; }; nat64Conf = configFormat.generate "jool-nat64.conf" cfg.nat64.config; siitConf = configFormat.generate "jool-siit.conf" cfg.siit.config; checkNat64 = name: _: '' printf 'Validating Jool configuration for NAT64 instance "${name}"... ' jool file check ${nat64Conf name} printf 'Ok.\n'; touch "$out" ''; checkSiit = name: _: '' printf 'Validating Jool configuration for SIIT instance "${name}"... ' jool_siit file check ${siitConf name} printf 'Ok.\n'; touch "$out" ''; in { ###### interface options = { networking.jool.enable = lib.mkOption { type = lib.types.bool; Loading @@ -64,15 +134,18 @@ in 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. Enabling this option will install the Jool kernel module and the command line tools for controlling it. ''; }; networking.jool.nat64.enable = lib.mkEnableOption (lib.mdDoc "a NAT64 instance of Jool."); networking.jool.nat64.config = lib.mkOption { type = configFormat.type; default = defaultNat64; networking.jool.nat64 = lib.mkOption { type = lib.types.attrsOf nat64Options; default = { }; example = lib.literalExpression '' { default = { # custom NAT64 prefix global.pool6 = "2001:db8:64::/96"; Loading @@ -96,7 +169,7 @@ in ]; pool4 = [ # Ports for dynamic translation # Port ranges 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"; } Loading @@ -105,116 +178,102 @@ in { 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. Definitions of NAT64 instances of Jool. See the [documentation](https://nicmx.github.io/Jool/en/config-atomic.html) for the available options. Also check out the [tutorial](https://nicmx.github.io/Jool/en/run-nat64.html) for an introduction to NAT64 and how to troubleshoot the setup. The attribute name defines the name of the instance, with the main one being `default`: this can be accessed from the command line without specifying the name with `-i`. ::: {.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. Instances created imperatively from the command line will not interfere with the NixOS instances, 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`. Changes to an instance performed via `jool -i <name>` are applied correctly but will be lost after restarting the respective `jool-nat64-<name>.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; networking.jool.siit = lib.mkOption { type = lib.types.attrsOf siitOptions; default = { }; example = lib.literalExpression '' { default = { # Maps any IPv4 address x.y.z.t to 2001:db8::x.y.z.t and v.v. pool6 = "2001:db8::/96"; global.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" } { "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" } ] { "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. Definitions of SIIT instances of Jool. See the [documentation](https://nicmx.github.io/Jool/en/config-atomic.html) for the available options. Also check out the [tutorial](https://nicmx.github.io/Jool/en/run-vanilla.html) for an introduction to SIIT and how to troubleshoot the setup. The attribute name defines the name of the instance, with the main one being `default`: this can be accessed from the command line without specifying the name with `-i`. ::: {.note} Existing or more instances created manually will not interfere with the NixOS instance, provided the respective `EAMT` address mappings are not overlapping. Instances created imperatively from the command line will not interfere with the NixOS instances, provided the respective EAMT addresses and port ranges 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`. Changes to an instance performed via `jool -i <name>` are applied correctly but will be lost after restarting the respective `jool-siit-<name>.service`. ::: ''; }; }; ###### implementation config = lib.mkIf cfg.enable { environment.systemPackages = [ jool-cli ]; # Install kernel module and cli tools boot.extraModulePackages = [ jool ]; environment.systemPackages = [ jool-cli ]; 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; }; # Install services for each instance systemd.services = lib.mkMerge (lib.mapAttrsToList makeNat64Unit cfg.nat64 ++ lib.mapAttrsToList makeSiitUnit cfg.siit); system.checks = lib.singleton (pkgs.runCommand "jool-validated" { nativeBuildInputs = [ pkgs.buildPackages.jool-cli ]; # Check the configuration of each instance system.checks = lib.optional (cfg.nat64 != {} || cfg.siit != {}) (pkgs.runCommand "jool-validated" { nativeBuildInputs = with 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; } (lib.concatStrings (lib.mapAttrsToList checkNat64 cfg.nat64 ++ lib.mapAttrsToList checkSiit cfg.siit))); }; meta.maintainers = with lib.maintainers; [ rnhmjoj ]; Loading Loading
nixos/modules/services/networking/jool.nix +186 −127 Original line number Diff line number Diff line Loading @@ -16,7 +16,7 @@ let TemporaryFileSystem = [ "/" ]; BindReadOnlyPaths = [ builtins.storeDir "/run/current-system/kernel-modules" "/run/booted-system/kernel-modules" ]; # Give capabilities to load the module and configure it Loading @@ -31,26 +31,96 @@ let configFormat = pkgs.formats.json {}; mkDefaultAttrs = lib.mapAttrs (n: v: lib.mkDefault v); # Generate the config file of instance `name` nat64Conf = name: configFormat.generate "jool-nat64-${name}.conf" (cfg.nat64.${name} // { instance = name; }); siitConf = name: configFormat.generate "jool-siit-${name}.conf" (cfg.siit.${name} // { instance = name; }); # NAT64 config type nat64Options = lib.types.submodule { # The format is plain JSON freeformType = configFormat.type; # Some options with a default value options.framework = lib.mkOption { type = lib.types.enum [ "netfilter" "iptables" ]; default = "netfilter"; description = lib.mdDoc '' The framework to use for attaching Jool's translation to the exist kernel packet processing rules. See the [documentation](https://nicmx.github.io/Jool/en/intro-jool.html#design) for the differences between the two options. ''; }; options.global.pool6 = lib.mkOption { type = lib.types.strMatching "[[:xdigit:]:]+/[[:digit:]]+" // { description = "Network prefix in CIDR notation"; }; default = "64:ff9b::/96"; description = lib.mdDoc '' The prefix used for embedding IPv4 into IPv6 addresses. Defaults to the well-known NAT64 prefix, defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052). ''; }; }; # SIIT config type siitOptions = lib.types.submodule { # The format is, again, plain JSON freeformType = configFormat.type; # Some options with a default value options = { inherit (nat64Options.getSubOptions []) framework; }; }; makeNat64Unit = name: opts: { "jool-nat64-${name}" = { description = "Jool, NAT64 setup of instance ${name}"; documentation = [ "https://nicmx.github.io/Jool/en/documentation.html" ]; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; ExecStartPre = "${pkgs.kmod}/bin/modprobe jool"; ExecStart = "${jool-cli}/bin/jool file handle ${nat64Conf name}"; ExecStop = "${jool-cli}/bin/jool -f ${nat64Conf name} instance remove"; } // hardening; }; }; defaultNat64 = { instance = "default"; framework = "netfilter"; global.pool6 = "64:ff9b::/96"; makeSiitUnit = name: opts: { "jool-siit-${name}" = { description = "Jool, SIIT setup of instance ${name}"; documentation = [ "https://nicmx.github.io/Jool/en/documentation.html" ]; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; serviceConfig = { Type = "oneshot"; RemainAfterExit = true; ExecStartPre = "${pkgs.kmod}/bin/modprobe jool_siit"; ExecStart = "${jool-cli}/bin/jool_siit file handle ${siitConf name}"; ExecStop = "${jool-cli}/bin/jool_siit -f ${siitConf name} instance remove"; } // hardening; }; defaultSiit = { instance = "default"; framework = "netfilter"; }; nat64Conf = configFormat.generate "jool-nat64.conf" cfg.nat64.config; siitConf = configFormat.generate "jool-siit.conf" cfg.siit.config; checkNat64 = name: _: '' printf 'Validating Jool configuration for NAT64 instance "${name}"... ' jool file check ${nat64Conf name} printf 'Ok.\n'; touch "$out" ''; checkSiit = name: _: '' printf 'Validating Jool configuration for SIIT instance "${name}"... ' jool_siit file check ${siitConf name} printf 'Ok.\n'; touch "$out" ''; in { ###### interface options = { networking.jool.enable = lib.mkOption { type = lib.types.bool; Loading @@ -64,15 +134,18 @@ in 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. Enabling this option will install the Jool kernel module and the command line tools for controlling it. ''; }; networking.jool.nat64.enable = lib.mkEnableOption (lib.mdDoc "a NAT64 instance of Jool."); networking.jool.nat64.config = lib.mkOption { type = configFormat.type; default = defaultNat64; networking.jool.nat64 = lib.mkOption { type = lib.types.attrsOf nat64Options; default = { }; example = lib.literalExpression '' { default = { # custom NAT64 prefix global.pool6 = "2001:db8:64::/96"; Loading @@ -96,7 +169,7 @@ in ]; pool4 = [ # Ports for dynamic translation # Port ranges 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"; } Loading @@ -105,116 +178,102 @@ in { 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. Definitions of NAT64 instances of Jool. See the [documentation](https://nicmx.github.io/Jool/en/config-atomic.html) for the available options. Also check out the [tutorial](https://nicmx.github.io/Jool/en/run-nat64.html) for an introduction to NAT64 and how to troubleshoot the setup. The attribute name defines the name of the instance, with the main one being `default`: this can be accessed from the command line without specifying the name with `-i`. ::: {.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. Instances created imperatively from the command line will not interfere with the NixOS instances, 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`. Changes to an instance performed via `jool -i <name>` are applied correctly but will be lost after restarting the respective `jool-nat64-<name>.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; networking.jool.siit = lib.mkOption { type = lib.types.attrsOf siitOptions; default = { }; example = lib.literalExpression '' { default = { # Maps any IPv4 address x.y.z.t to 2001:db8::x.y.z.t and v.v. pool6 = "2001:db8::/96"; global.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" } { "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" } ] { "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. Definitions of SIIT instances of Jool. See the [documentation](https://nicmx.github.io/Jool/en/config-atomic.html) for the available options. Also check out the [tutorial](https://nicmx.github.io/Jool/en/run-vanilla.html) for an introduction to SIIT and how to troubleshoot the setup. The attribute name defines the name of the instance, with the main one being `default`: this can be accessed from the command line without specifying the name with `-i`. ::: {.note} Existing or more instances created manually will not interfere with the NixOS instance, provided the respective `EAMT` address mappings are not overlapping. Instances created imperatively from the command line will not interfere with the NixOS instances, provided the respective EAMT addresses and port ranges 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`. Changes to an instance performed via `jool -i <name>` are applied correctly but will be lost after restarting the respective `jool-siit-<name>.service`. ::: ''; }; }; ###### implementation config = lib.mkIf cfg.enable { environment.systemPackages = [ jool-cli ]; # Install kernel module and cli tools boot.extraModulePackages = [ jool ]; environment.systemPackages = [ jool-cli ]; 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; }; # Install services for each instance systemd.services = lib.mkMerge (lib.mapAttrsToList makeNat64Unit cfg.nat64 ++ lib.mapAttrsToList makeSiitUnit cfg.siit); system.checks = lib.singleton (pkgs.runCommand "jool-validated" { nativeBuildInputs = [ pkgs.buildPackages.jool-cli ]; # Check the configuration of each instance system.checks = lib.optional (cfg.nat64 != {} || cfg.siit != {}) (pkgs.runCommand "jool-validated" { nativeBuildInputs = with 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; } (lib.concatStrings (lib.mapAttrsToList checkNat64 cfg.nat64 ++ lib.mapAttrsToList checkSiit cfg.siit))); }; meta.maintainers = with lib.maintainers; [ rnhmjoj ]; Loading