diff --git a/nixos/modules/services/networking/iodine.nix b/nixos/modules/services/networking/iodine.nix index f9ca26c27960..46051d7044b5 100644 --- a/nixos/modules/services/networking/iodine.nix +++ b/nixos/modules/services/networking/iodine.nix @@ -9,6 +9,8 @@ let iodinedUser = "iodined"; + /* is this path made unreadable by ProtectHome = true ? */ + isProtected = x: hasPrefix "/root" x || hasPrefix "/home" x; in { imports = [ @@ -35,45 +37,48 @@ in corresponding attribute name. ''; example = literalExample '' - { - foo = { - server = "tunnel.mdomain.com"; - relay = "8.8.8.8"; - extraConfig = "-v"; + { + foo = { + server = "tunnel.mdomain.com"; + relay = "8.8.8.8"; + extraConfig = "-v"; + } } - } ''; - type = types.attrsOf (types.submodule ( - { - options = { - server = mkOption { - type = types.str; - default = ""; - description = "Domain or Subdomain of server running iodined"; - example = "tunnel.mydomain.com"; - }; + type = types.attrsOf ( + types.submodule ( + { + options = { + server = mkOption { + type = types.str; + default = ""; + description = "Hostname of server running iodined"; + example = "tunnel.mydomain.com"; + }; - relay = mkOption { - type = types.str; - default = ""; - description = "DNS server to use as a intermediate relay to the iodined server"; - example = "8.8.8.8"; - }; + relay = mkOption { + type = types.str; + default = ""; + description = "DNS server to use as an intermediate relay to the iodined server"; + example = "8.8.8.8"; + }; - extraConfig = mkOption { - type = types.str; - default = ""; - description = "Additional command line parameters"; - example = "-l 192.168.1.10 -p 23"; - }; + extraConfig = mkOption { + type = types.str; + default = ""; + description = "Additional command line parameters"; + example = "-l 192.168.1.10 -p 23"; + }; - passwordFile = mkOption { - type = types.str; - default = ""; - description = "File that contains password"; - }; - }; - })); + passwordFile = mkOption { + type = types.str; + default = ""; + description = "Path to a file containing the password."; + }; + }; + } + ) + ); }; server = { @@ -121,31 +126,67 @@ in boot.kernelModules = [ "tun" ]; systemd.services = - let - createIodineClientService = name: cfg: - { - description = "iodine client - ${name}"; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - script = "exec ${pkgs.iodine}/bin/iodine -f -u ${iodinedUser} ${cfg.extraConfig} ${optionalString (cfg.passwordFile != "") "< \"${cfg.passwordFile}\""} ${cfg.relay} ${cfg.server}"; - serviceConfig = { - RestartSec = "30s"; - Restart = "always"; + let + createIodineClientService = name: cfg: + { + description = "iodine client - ${name}"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + script = "exec ${pkgs.iodine}/bin/iodine -f -u ${iodinedUser} ${cfg.extraConfig} ${optionalString (cfg.passwordFile != "") "< \"${builtins.toString cfg.passwordFile}\""} ${cfg.relay} ${cfg.server}"; + serviceConfig = { + RestartSec = "30s"; + Restart = "always"; + + # hardening : + # Filesystem access + ProtectSystem = "strict"; + ProtectHome = if isProtected cfg.passwordFile then "read-only" else "true" ; + PrivateTmp = true; + ReadWritePaths = "/dev/net/tun"; + PrivateDevices = false; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + # Caps + NoNewPrivileges = true; + # Misc. + LockPersonality = true; + RestrictRealtime = true; + PrivateMounts = true; + MemoryDenyWriteExecute = true; + }; + }; + in + listToAttrs ( + mapAttrsToList + (name: value: nameValuePair "iodine-${name}" (createIodineClientService name value)) + cfg.clients + ) // { + iodined = mkIf (cfg.server.enable) { + description = "iodine, ip over dns server daemon"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + script = "exec ${pkgs.iodine}/bin/iodined -f -u ${iodinedUser} ${cfg.server.extraConfig} ${optionalString (cfg.server.passwordFile != "") "< \"${builtins.toString cfg.server.passwordFile}\""} ${cfg.server.ip} ${cfg.server.domain}"; + serviceConfig = { + # Filesystem access + ProtectSystem = "strict"; + ProtectHome = if isProtected cfg.server.passwordFile then "read-only" else "true" ; + PrivateTmp = true; + ReadWritePaths = "/dev/net/tun"; + PrivateDevices = false; + ProtectKernelTunables = true; + ProtectKernelModules = true; + ProtectControlGroups = true; + # Caps + NoNewPrivileges = true; + # Misc. + LockPersonality = true; + RestrictRealtime = true; + PrivateMounts = true; + MemoryDenyWriteExecute = true; + }; + }; }; - }; - in - listToAttrs ( - mapAttrsToList - (name: value: nameValuePair "iodine-${name}" (createIodineClientService name value)) - cfg.clients - ) // { - iodined = mkIf (cfg.server.enable) { - description = "iodine, ip over dns server daemon"; - after = [ "network.target" ]; - wantedBy = [ "multi-user.target" ]; - script = "exec ${pkgs.iodine}/bin/iodined -f -u ${iodinedUser} ${cfg.server.extraConfig} ${optionalString (cfg.server.passwordFile != "") "< \"${cfg.server.passwordFile}\""} ${cfg.server.ip} ${cfg.server.domain}"; - }; - }; users.users.${iodinedUser} = { uid = config.ids.uids.iodined; diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 7dd0f23df658..51b463747b0e 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -135,6 +135,7 @@ in initrd-network-ssh = handleTest ./initrd-network-ssh {}; initrdNetwork = handleTest ./initrd-network.nix {}; installer = handleTest ./installer.nix {}; + iodine = handleTest ./iodine.nix {}; ipv6 = handleTest ./ipv6.nix {}; jackett = handleTest ./jackett.nix {}; jellyfin = handleTest ./jellyfin.nix {}; diff --git a/nixos/tests/iodine.nix b/nixos/tests/iodine.nix new file mode 100644 index 000000000000..8bd9603a6d6c --- /dev/null +++ b/nixos/tests/iodine.nix @@ -0,0 +1,63 @@ +import ./make-test-python.nix ( + { pkgs, ... }: let + domain = "whatever.example.com"; + in + { + name = "iodine"; + nodes = { + server = + { ... }: + + { + networking.firewall = { + allowedUDPPorts = [ 53 ]; + trustedInterfaces = [ "dns0" ]; + }; + boot.kernel.sysctl = { + "net.ipv4.ip_forward" = 1; + "net.ipv6.ip_forward" = 1; + }; + + services.iodine.server = { + enable = true; + ip = "10.53.53.1/24"; + passwordFile = "${builtins.toFile "password" "foo"}"; + inherit domain; + }; + + # test resource: accessible only via tunnel + services.openssh = { + enable = true; + openFirewall = false; + }; + }; + + client = + { ... }: { + services.iodine.clients.testClient = { + # test that ProtectHome is "read-only" + passwordFile = "/root/pw"; + relay = "server"; + server = domain; + }; + systemd.tmpfiles.rules = [ + "f /root/pw 0666 root root - foo" + ]; + environment.systemPackages = [ + pkgs.nagiosPluginsOfficial + ]; + }; + + }; + + testScript = '' + start_all() + + server.wait_for_unit("sshd") + server.wait_for_unit("iodined") + client.wait_for_unit("iodine-testClient") + + client.succeed("check_ssh -H 10.53.53.1") + ''; + } +) diff --git a/pkgs/tools/networking/iodine/default.nix b/pkgs/tools/networking/iodine/default.nix index 44bf52c9933f..c978a330ceeb 100644 --- a/pkgs/tools/networking/iodine/default.nix +++ b/pkgs/tools/networking/iodine/default.nix @@ -1,11 +1,14 @@ -{ stdenv, fetchurl, zlib, nettools }: +{ stdenv, fetchFromGitHub, zlib, nettools, nixosTests }: stdenv.mkDerivation rec { - name = "iodine-0.7.0"; + pname = "iodine"; + version = "unstable-2019-09-27"; - src = fetchurl { - url = "https://code.kryo.se/iodine/${name}.tar.gz"; - sha256 = "0gh17kcxxi37k65zm4gqsvbk3aw7yphcs3c02pn1c4s2y6n40axd"; + src = fetchFromGitHub { + owner = "yarrick"; + repo = "iodine"; + rev = "8e14f18"; + sha256 = "0k8m99qfjd5n6n56jnq85y7q8h2i2b8yw6ba0kxsz4jyx97lavg3"; }; buildInputs = [ zlib ]; @@ -16,6 +19,10 @@ stdenv.mkDerivation rec { installFlags = [ "prefix=\${out}" ]; + passthru.tests = { + inherit (nixosTests) iodine; + }; + meta = { homepage = http://code.kryo.se/iodine/; description = "Tool to tunnel IPv4 data through a DNS server"; diff --git a/pkgs/tools/networking/network-manager/iodine/default.nix b/pkgs/tools/networking/network-manager/iodine/default.nix index 29c0d550fe2f..9042605caf17 100644 --- a/pkgs/tools/networking/network-manager/iodine/default.nix +++ b/pkgs/tools/networking/network-manager/iodine/default.nix @@ -1,15 +1,18 @@ -{ stdenv, fetchurl, substituteAll, iodine, intltool, pkgconfig, networkmanager, libsecret, gtk3 +{ stdenv, fetchFromGitLab, substituteAll, autoreconfHook, iodine, intltool, pkgconfig, networkmanager, libsecret, gtk3 , withGnome ? true, gnome3, fetchpatch, networkmanagerapplet }: let pname = "NetworkManager-iodine"; - version = "1.2.0"; + version = "unstable-2019-11-05"; in stdenv.mkDerivation { name = "${pname}${if withGnome then "-gnome" else ""}-${version}"; - src = fetchurl { - url = "mirror://gnome/sources/${pname}/${stdenv.lib.versions.majorMinor version}/${pname}-${version}.tar.xz"; - sha256 = "0njdigakidji6mfmbsp8lfi8wl88z1dk8cljbva2w0xazyddbwyh"; + src = fetchFromGitLab { + domain = "gitlab.gnome.org"; + owner = "GNOME"; + repo = "network-manager-iodine"; + rev = "2ef0abf089b00a0546f214dde0d45e63f2990b79"; + sha256 = "1ps26fr9b1yyafj7lrzf2kmaxb0ipl0mhagch5kzrjdsc5xkajz7"; }; patches = [ @@ -27,11 +30,12 @@ in stdenv.mkDerivation { buildInputs = [ iodine networkmanager ] ++ stdenv.lib.optionals withGnome [ gtk3 libsecret networkmanagerapplet ]; - nativeBuildInputs = [ intltool pkgconfig ]; + nativeBuildInputs = [ intltool autoreconfHook pkgconfig ]; # glib-2.62 deprecations NIX_CFLAGS_COMPILE = "-DGLIB_DISABLE_DEPRECATION_WARNINGS"; + preConfigure = "intltoolize"; configureFlags = [ "--without-libnm-glib" "--with-gnome=${if withGnome then "yes" else "no"}"