mirror of
https://github.com/ilyakooo0/nixpkgs.git
synced 2024-11-10 08:39:08 +03:00
Merge pull request #240982 from rnhmjoj/pr-jool
nixos/jool: add service for setting up SIIT/NAT64
This commit is contained in:
commit
7c75694db9
@ -30,6 +30,8 @@
|
||||
|
||||
- [sitespeed-io](https://sitespeed.io), a tool that can generate metrics (timings, diagnostics) for websites. Available as [services.sitespeed-io](#opt-services.sitespeed-io.enable).
|
||||
|
||||
- [Jool](https://nicmx.github.io/Jool/en/index.html), an Open Source implementation of IPv4/IPv6 translation on Linux. Available as [networking.jool.enable](#opt-networking.jool.enable).
|
||||
|
||||
- [Apache Guacamole](https://guacamole.apache.org/), a cross-platform, clientless remote desktop gateway. Available as [services.guacamole-server](#opt-services.guacamole-server.enable) and [services.guacamole-client](#opt-services.guacamole-client.enable) services.
|
||||
|
||||
- [pgBouncer](https://www.pgbouncer.org), a PostgreSQL connection pooler. Available as [services.pgbouncer](#opt-services.pgbouncer.enable).
|
||||
|
@ -929,6 +929,7 @@
|
||||
./services/networking/jibri/default.nix
|
||||
./services/networking/jicofo.nix
|
||||
./services/networking/jitsi-videobridge.nix
|
||||
./services/networking/jool.nix
|
||||
./services/networking/kea.nix
|
||||
./services/networking/keepalived/default.nix
|
||||
./services/networking/keybase.nix
|
||||
|
222
nixos/modules/services/networking/jool.nix
Normal file
222
nixos/modules/services/networking/jool.nix
Normal file
@ -0,0 +1,222 @@
|
||||
{ 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 ];
|
||||
|
||||
}
|
@ -391,6 +391,7 @@ in {
|
||||
jibri = handleTest ./jibri.nix {};
|
||||
jirafeau = handleTest ./jirafeau.nix {};
|
||||
jitsi-meet = handleTest ./jitsi-meet.nix {};
|
||||
jool = handleTest ./jool.nix {};
|
||||
k3s = handleTest ./k3s {};
|
||||
kafka = handleTest ./kafka.nix {};
|
||||
kanidm = handleTest ./kanidm.nix {};
|
||||
|
250
nixos/tests/jool.nix
Normal file
250
nixos/tests/jool.nix
Normal file
@ -0,0 +1,250 @@
|
||||
{ system ? builtins.currentSystem,
|
||||
config ? {},
|
||||
pkgs ? import ../.. { inherit system config; }
|
||||
}:
|
||||
|
||||
with import ../lib/testing-python.nix { inherit system pkgs; };
|
||||
|
||||
let
|
||||
inherit (pkgs) lib;
|
||||
|
||||
ipv6Only = {
|
||||
networking.useDHCP = false;
|
||||
networking.interfaces.eth1.ipv4.addresses = lib.mkVMOverride [ ];
|
||||
};
|
||||
|
||||
ipv4Only = {
|
||||
networking.useDHCP = false;
|
||||
networking.interfaces.eth1.ipv6.addresses = lib.mkVMOverride [ ];
|
||||
};
|
||||
|
||||
webserver = ip: msg: {
|
||||
systemd.services.webserver = {
|
||||
description = "Mock webserver";
|
||||
wants = [ "network-online.target" ];
|
||||
wantedBy = [ "multi-user.target" ];
|
||||
serviceConfig.Restart = "always";
|
||||
script = ''
|
||||
while true; do
|
||||
{
|
||||
printf 'HTTP/1.0 200 OK\n'
|
||||
printf 'Content-Length: ${toString (1 + builtins.stringLength msg)}\n'
|
||||
printf '\n${msg}\n\n'
|
||||
} | ${pkgs.libressl.nc}/bin/nc -${toString ip}nvl 80
|
||||
done
|
||||
'';
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [ 80 ];
|
||||
};
|
||||
|
||||
in
|
||||
|
||||
{
|
||||
siit = makeTest {
|
||||
# This test simulates the setup described in [1] with two IPv6 and
|
||||
# IPv4-only devices on different subnets communicating through a border
|
||||
# relay running Jool in SIIT mode.
|
||||
# [1]: https://nicmx.github.io/Jool/en/run-vanilla.html
|
||||
name = "jool-siit";
|
||||
meta.maintainers = with lib.maintainers; [ rnhmjoj ];
|
||||
|
||||
# Border relay
|
||||
nodes.relay = { ... }: {
|
||||
imports = [ ../modules/profiles/minimal.nix ];
|
||||
virtualisation.vlans = [ 1 2 ];
|
||||
|
||||
# Enable packet routing
|
||||
boot.kernel.sysctl = {
|
||||
"net.ipv6.conf.all.forwarding" = 1;
|
||||
"net.ipv4.conf.all.forwarding" = 1;
|
||||
};
|
||||
|
||||
networking.useDHCP = false;
|
||||
networking.interfaces = lib.mkVMOverride {
|
||||
eth1.ipv6.addresses = [ { address = "fd::198.51.100.1"; prefixLength = 120; } ];
|
||||
eth2.ipv4.addresses = [ { address = "192.0.2.1"; prefixLength = 24; } ];
|
||||
};
|
||||
|
||||
networking.jool = {
|
||||
enable = true;
|
||||
siit.enable = true;
|
||||
siit.config.global.pool6 = "fd::/96";
|
||||
};
|
||||
};
|
||||
|
||||
# IPv6 only node
|
||||
nodes.alice = { ... }: {
|
||||
imports = [
|
||||
../modules/profiles/minimal.nix
|
||||
ipv6Only
|
||||
(webserver 6 "Hello, Bob!")
|
||||
];
|
||||
|
||||
virtualisation.vlans = [ 1 ];
|
||||
networking.interfaces.eth1.ipv6 = {
|
||||
addresses = [ { address = "fd::198.51.100.8"; prefixLength = 120; } ];
|
||||
routes = [ { address = "fd::192.0.2.0"; prefixLength = 120;
|
||||
via = "fd::198.51.100.1"; } ];
|
||||
};
|
||||
};
|
||||
|
||||
# IPv4 only node
|
||||
nodes.bob = { ... }: {
|
||||
imports = [
|
||||
../modules/profiles/minimal.nix
|
||||
ipv4Only
|
||||
(webserver 4 "Hello, Alice!")
|
||||
];
|
||||
|
||||
virtualisation.vlans = [ 2 ];
|
||||
networking.interfaces.eth1.ipv4 = {
|
||||
addresses = [ { address = "192.0.2.16"; prefixLength = 24; } ];
|
||||
routes = [ { address = "198.51.100.0"; prefixLength = 24;
|
||||
via = "192.0.2.1"; } ];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
relay.wait_for_unit("jool-siit.service")
|
||||
alice.wait_for_unit("network-addresses-eth1.service")
|
||||
bob.wait_for_unit("network-addresses-eth1.service")
|
||||
|
||||
with subtest("Alice and Bob can't ping each other"):
|
||||
relay.systemctl("stop jool-siit.service")
|
||||
alice.fail("ping -c1 fd::192.0.2.16")
|
||||
bob.fail("ping -c1 198.51.100.8")
|
||||
|
||||
with subtest("Alice and Bob can ping using the relay"):
|
||||
relay.systemctl("start jool-siit.service")
|
||||
alice.wait_until_succeeds("ping -c1 fd::192.0.2.16")
|
||||
bob.wait_until_succeeds("ping -c1 198.51.100.8")
|
||||
|
||||
with subtest("Alice can connect to Bob's webserver"):
|
||||
bob.wait_for_open_port(80)
|
||||
alice.succeed("curl -vvv http://[fd::192.0.2.16] >&2")
|
||||
alice.succeed("curl --fail -s http://[fd::192.0.2.16] | grep -q Alice")
|
||||
|
||||
with subtest("Bob can connect to Alices's webserver"):
|
||||
alice.wait_for_open_port(80)
|
||||
bob.succeed("curl --fail -s http://198.51.100.8 | grep -q Bob")
|
||||
'';
|
||||
};
|
||||
|
||||
nat64 = makeTest {
|
||||
# This test simulates the setup described in [1] with two IPv6-only nodes
|
||||
# (a client and a homeserver) on the LAN subnet and an IPv4 node on the WAN.
|
||||
# The router runs Jool in stateful NAT64 mode, masquarading the LAN and
|
||||
# forwarding ports using static BIB entries.
|
||||
# [1]: https://nicmx.github.io/Jool/en/run-nat64.html
|
||||
name = "jool-nat64";
|
||||
meta.maintainers = with lib.maintainers; [ rnhmjoj ];
|
||||
|
||||
# Router
|
||||
nodes.router = { ... }: {
|
||||
imports = [ ../modules/profiles/minimal.nix ];
|
||||
virtualisation.vlans = [ 1 2 ];
|
||||
|
||||
# Enable packet routing
|
||||
boot.kernel.sysctl = {
|
||||
"net.ipv6.conf.all.forwarding" = 1;
|
||||
"net.ipv4.conf.all.forwarding" = 1;
|
||||
};
|
||||
|
||||
networking.useDHCP = false;
|
||||
networking.interfaces = lib.mkVMOverride {
|
||||
eth1.ipv6.addresses = [ { address = "2001:db8::1"; prefixLength = 96; } ];
|
||||
eth2.ipv4.addresses = [ { address = "203.0.113.1"; prefixLength = 24; } ];
|
||||
};
|
||||
|
||||
networking.jool = {
|
||||
enable = true;
|
||||
nat64.enable = true;
|
||||
nat64.config = {
|
||||
bib = [
|
||||
{ # forward HTTP 203.0.113.1 (router) → 2001:db8::9 (homeserver)
|
||||
"protocol" = "TCP";
|
||||
"ipv4 address" = "203.0.113.1#80";
|
||||
"ipv6 address" = "2001:db8::9#80";
|
||||
}
|
||||
];
|
||||
pool4 = [
|
||||
# Ports for dynamic translation
|
||||
{ protocol = "TCP"; prefix = "203.0.113.1/32"; "port range" = "40001-65535"; }
|
||||
{ protocol = "UDP"; prefix = "203.0.113.1/32"; "port range" = "40001-65535"; }
|
||||
{ protocol = "ICMP"; prefix = "203.0.113.1/32"; "port range" = "40001-65535"; }
|
||||
# Ports for static BIB entries
|
||||
{ protocol = "TCP"; prefix = "203.0.113.1/32"; "port range" = "80"; }
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
# LAN client (IPv6 only)
|
||||
nodes.client = { ... }: {
|
||||
imports = [ ../modules/profiles/minimal.nix ipv6Only ];
|
||||
virtualisation.vlans = [ 1 ];
|
||||
|
||||
networking.interfaces.eth1.ipv6 = {
|
||||
addresses = [ { address = "2001:db8::8"; prefixLength = 96; } ];
|
||||
routes = [ { address = "64:ff9b::"; prefixLength = 96;
|
||||
via = "2001:db8::1"; } ];
|
||||
};
|
||||
};
|
||||
|
||||
# LAN server (IPv6 only)
|
||||
nodes.homeserver = { ... }: {
|
||||
imports = [
|
||||
../modules/profiles/minimal.nix
|
||||
ipv6Only
|
||||
(webserver 6 "Hello from IPv6!")
|
||||
];
|
||||
|
||||
virtualisation.vlans = [ 1 ];
|
||||
networking.interfaces.eth1.ipv6 = {
|
||||
addresses = [ { address = "2001:db8::9"; prefixLength = 96; } ];
|
||||
routes = [ { address = "64:ff9b::"; prefixLength = 96;
|
||||
via = "2001:db8::1"; } ];
|
||||
};
|
||||
};
|
||||
|
||||
# WAN server (IPv4 only)
|
||||
nodes.server = { ... }: {
|
||||
imports = [
|
||||
../modules/profiles/minimal.nix
|
||||
ipv4Only
|
||||
(webserver 4 "Hello from IPv4!")
|
||||
];
|
||||
|
||||
virtualisation.vlans = [ 2 ];
|
||||
networking.interfaces.eth1.ipv4.addresses =
|
||||
[ { address = "203.0.113.16"; prefixLength = 24; } ];
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
start_all()
|
||||
|
||||
for node in [client, homeserver, server]:
|
||||
node.wait_for_unit("network-addresses-eth1.service")
|
||||
|
||||
with subtest("Client can ping the WAN server"):
|
||||
router.wait_for_unit("jool-nat64.service")
|
||||
client.succeed("ping -c1 64:ff9b::203.0.113.16")
|
||||
|
||||
with subtest("Client can connect to the WAN webserver"):
|
||||
server.wait_for_open_port(80)
|
||||
client.succeed("curl --fail -s http://[64:ff9b::203.0.113.16] | grep -q IPv4!")
|
||||
|
||||
with subtest("Router BIB entries are correctly populated"):
|
||||
router.succeed("jool bib display | grep -q 'Dynamic TCP.*2001:db8::8'")
|
||||
router.succeed("jool bib display | grep -q 'Static TCP.*2001:db8::9'")
|
||||
|
||||
with subtest("WAN server can reach the LAN server"):
|
||||
homeserver.wait_for_open_port(80)
|
||||
server.succeed("curl --fail -s http://203.0.113.1 | grep -q IPv6!")
|
||||
'';
|
||||
|
||||
};
|
||||
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
{ lib, stdenv, fetchFromGitHub, fetchpatch, autoreconfHook, pkg-config, libnl, iptables }:
|
||||
{ lib, stdenv, fetchFromGitHub, nixosTests
|
||||
, autoreconfHook, pkg-config, libnl, iptables
|
||||
}:
|
||||
|
||||
let
|
||||
sourceAttrs = (import ./source.nix) { inherit fetchFromGitHub; };
|
||||
@ -10,6 +12,10 @@ stdenv.mkDerivation {
|
||||
|
||||
src = sourceAttrs.src;
|
||||
|
||||
patches = [
|
||||
./validate-config.patch
|
||||
];
|
||||
|
||||
outputs = [
|
||||
"out"
|
||||
"man"
|
||||
@ -24,6 +30,8 @@ stdenv.mkDerivation {
|
||||
sed -e 's%^XTABLES_SO_DIR = .*%XTABLES_SO_DIR = '"$out"'/lib/xtables%g' -i src/usr/iptables/Makefile
|
||||
'';
|
||||
|
||||
passthru.tests = { inherit (nixosTests) jool; };
|
||||
|
||||
meta = with lib; {
|
||||
homepage = "https://www.jool.mx/";
|
||||
description = "Fairly compliant SIIT and Stateful NAT64 for Linux - CLI tools";
|
||||
|
@ -1,4 +1,4 @@
|
||||
{ lib, stdenv, fetchFromGitHub, fetchpatch, kernel }:
|
||||
{ lib, stdenv, fetchFromGitHub, kernel, nixosTests }:
|
||||
|
||||
let
|
||||
sourceAttrs = (import ./source.nix) { inherit fetchFromGitHub; };
|
||||
@ -23,6 +23,8 @@ stdenv.mkDerivation {
|
||||
|
||||
installTargets = "modules_install";
|
||||
|
||||
passthru.tests = { inherit (nixosTests) jool; };
|
||||
|
||||
meta = with lib; {
|
||||
homepage = "https://www.jool.mx/";
|
||||
description = "Fairly compliant SIIT and Stateful NAT64 for Linux - kernel modules";
|
||||
|
193
pkgs/os-specific/linux/jool/validate-config.patch
Normal file
193
pkgs/os-specific/linux/jool/validate-config.patch
Normal file
@ -0,0 +1,193 @@
|
||||
From df0a1cf61188b5b7bb98675d746cb63d9300f148 Mon Sep 17 00:00:00 2001
|
||||
From: rnhmjoj <rnhmjoj@inventati.org>
|
||||
Date: Sat, 1 Jul 2023 18:47:05 +0200
|
||||
Subject: [PATCH] Add mode to validate the atomic configuration
|
||||
|
||||
---
|
||||
src/usr/argp/main.c | 6 ++++++
|
||||
src/usr/argp/wargp/file.c | 26 +++++++++++++++++++++++++-
|
||||
src/usr/argp/wargp/file.h | 1 +
|
||||
src/usr/nl/file.c | 32 ++++++++++++++++++++++----------
|
||||
src/usr/nl/file.h | 3 ++-
|
||||
5 files changed, 56 insertions(+), 12 deletions(-)
|
||||
|
||||
diff --git a/src/usr/argp/main.c b/src/usr/argp/main.c
|
||||
index 744a6df0..d04917da 100644
|
||||
--- a/src/usr/argp/main.c
|
||||
+++ b/src/usr/argp/main.c
|
||||
@@ -238,6 +238,12 @@ static struct cmd_option file_ops[] = {
|
||||
.handler = handle_file_update,
|
||||
.handle_autocomplete = autocomplete_file_update,
|
||||
},
|
||||
+ {
|
||||
+ .label = "check",
|
||||
+ .xt = XT_ANY,
|
||||
+ .handler = handle_file_check,
|
||||
+ .handle_autocomplete = autocomplete_file_update,
|
||||
+ },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
diff --git a/src/usr/argp/wargp/file.c b/src/usr/argp/wargp/file.c
|
||||
index 0951b544..27ee3e64 100644
|
||||
--- a/src/usr/argp/wargp/file.c
|
||||
+++ b/src/usr/argp/wargp/file.c
|
||||
@@ -26,6 +26,30 @@ static struct wargp_option update_opts[] = {
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
+int handle_file_check(char *iname, int argc, char **argv, void const *arg)
|
||||
+{
|
||||
+ struct update_args uargs = { 0 };
|
||||
+ struct joolnl_socket sk = { 0 };
|
||||
+ struct jool_result result;
|
||||
+
|
||||
+ result.error = wargp_parse(update_opts, argc, argv, &uargs);
|
||||
+ if (result.error)
|
||||
+ return result.error;
|
||||
+
|
||||
+ if (!uargs.file_name.value) {
|
||||
+ struct requirement reqs[] = {
|
||||
+ { false, "a file name" },
|
||||
+ { 0 }
|
||||
+ };
|
||||
+ return requirement_print(reqs);
|
||||
+ }
|
||||
+
|
||||
+ result = joolnl_file_parse(&sk, xt_get(), iname, uargs.file_name.value,
|
||||
+ uargs.force.value, true);
|
||||
+
|
||||
+ return pr_result(&result);
|
||||
+}
|
||||
+
|
||||
int handle_file_update(char *iname, int argc, char **argv, void const *arg)
|
||||
{
|
||||
struct update_args uargs = { 0 };
|
||||
@@ -49,7 +73,7 @@ int handle_file_update(char *iname, int argc, char **argv, void const *arg)
|
||||
return pr_result(&result);
|
||||
|
||||
result = joolnl_file_parse(&sk, xt_get(), iname, uargs.file_name.value,
|
||||
- uargs.force.value);
|
||||
+ uargs.force.value, false);
|
||||
|
||||
joolnl_teardown(&sk);
|
||||
return pr_result(&result);
|
||||
diff --git a/src/usr/argp/wargp/file.h b/src/usr/argp/wargp/file.h
|
||||
index ce5de508..8ea4a4d2 100644
|
||||
--- a/src/usr/argp/wargp/file.h
|
||||
+++ b/src/usr/argp/wargp/file.h
|
||||
@@ -2,6 +2,7 @@
|
||||
#define SRC_USR_ARGP_WARGP_FILE_H_
|
||||
|
||||
int handle_file_update(char *iname, int argc, char **argv, void const *arg);
|
||||
+int handle_file_check(char *iname, int argc, char **argv, void const *arg);
|
||||
void autocomplete_file_update(void const *args);
|
||||
|
||||
#endif /* SRC_USR_ARGP_WARGP_FILE_H_ */
|
||||
diff --git a/src/usr/nl/file.c b/src/usr/nl/file.c
|
||||
index f9413236..51a668bd 100644
|
||||
--- a/src/usr/nl/file.c
|
||||
+++ b/src/usr/nl/file.c
|
||||
@@ -29,6 +29,7 @@ static struct joolnl_socket sk;
|
||||
static char const *iname;
|
||||
static xlator_flags flags;
|
||||
static __u8 force;
|
||||
+static bool check;
|
||||
|
||||
struct json_meta {
|
||||
char const *name; /* This being NULL signals the end of the array. */
|
||||
@@ -163,9 +164,11 @@ static struct jool_result handle_array(cJSON *json, int attrtype, char *name,
|
||||
goto too_small;
|
||||
|
||||
nla_nest_end(msg, root);
|
||||
- result = joolnl_request(&sk, msg, NULL, NULL);
|
||||
- if (result.error)
|
||||
- return result;
|
||||
+ if (!check) {
|
||||
+ result = joolnl_request(&sk, msg, NULL, NULL);
|
||||
+ if (result.error)
|
||||
+ return result;
|
||||
+ }
|
||||
|
||||
msg = NULL;
|
||||
json = json->prev;
|
||||
@@ -179,6 +182,8 @@ static struct jool_result handle_array(cJSON *json, int attrtype, char *name,
|
||||
return result_success();
|
||||
|
||||
nla_nest_end(msg, root);
|
||||
+ if (check)
|
||||
+ return result_success();
|
||||
return joolnl_request(&sk, msg, NULL, NULL);
|
||||
|
||||
too_small:
|
||||
@@ -244,6 +249,8 @@ static struct jool_result handle_global(cJSON *json)
|
||||
|
||||
nla_nest_end(msg, root);
|
||||
free(meta);
|
||||
+ if (check)
|
||||
+ return result_success();
|
||||
return joolnl_request(&sk, msg, NULL, NULL);
|
||||
|
||||
revert_meta:
|
||||
@@ -654,9 +661,11 @@ static struct jool_result send_ctrl_msg(bool init)
|
||||
else
|
||||
NLA_PUT(msg, JNLAR_ATOMIC_END, 0, NULL);
|
||||
|
||||
- result = joolnl_request(&sk, msg, NULL, NULL);
|
||||
- if (result.error)
|
||||
- return result;
|
||||
+ if (!check) {
|
||||
+ result = joolnl_request(&sk, msg, NULL, NULL);
|
||||
+ if (result.error)
|
||||
+ return result;
|
||||
+ }
|
||||
|
||||
return result_success();
|
||||
|
||||
@@ -683,9 +692,11 @@ static struct jool_result do_parsing(char const *iname, char *buffer)
|
||||
if (result.error)
|
||||
goto fail;
|
||||
|
||||
- result = send_ctrl_msg(true);
|
||||
- if (result.error)
|
||||
- goto fail;
|
||||
+ if (!check) {
|
||||
+ result = send_ctrl_msg(true);
|
||||
+ if (result.error)
|
||||
+ goto fail;
|
||||
+ }
|
||||
|
||||
switch (xlator_flags2xt(flags)) {
|
||||
case XT_SIIT:
|
||||
@@ -718,12 +729,13 @@ fail:
|
||||
}
|
||||
|
||||
struct jool_result joolnl_file_parse(struct joolnl_socket *_sk, xlator_type xt,
|
||||
- char const *iname, char const *file_name, bool _force)
|
||||
+ char const *iname, char const *file_name, bool _force, bool _check)
|
||||
{
|
||||
char *buffer;
|
||||
struct jool_result result;
|
||||
|
||||
sk = *_sk;
|
||||
+ check = _check;
|
||||
flags = xt;
|
||||
force = _force ? JOOLNLHDR_FLAGS_FORCE : 0;
|
||||
|
||||
diff --git a/src/usr/nl/file.h b/src/usr/nl/file.h
|
||||
index 51802aaf..8b4a66dd 100644
|
||||
--- a/src/usr/nl/file.h
|
||||
+++ b/src/usr/nl/file.h
|
||||
@@ -9,7 +9,8 @@ struct jool_result joolnl_file_parse(
|
||||
xlator_type xt,
|
||||
char const *iname,
|
||||
char const *file_name,
|
||||
- bool force
|
||||
+ bool force,
|
||||
+ bool check
|
||||
);
|
||||
|
||||
struct jool_result joolnl_file_get_iname(
|
||||
--
|
||||
2.40.1
|
||||
|
Loading…
Reference in New Issue
Block a user