about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
authorMichele Guerini Rocco <rnhmjoj@users.noreply.github.com>2023-10-29 23:19:38 +0100
committerGitHub <noreply@github.com>2023-10-29 23:19:38 +0100
commit800965ce8c3d8d7abb91267886f6b43e37f2bf18 (patch)
tree19db3f93e138c549cd63641fab41c72e4f067a5c /nixos
parentcfb3988290cc0e5ea39abd55ecb39c824609b380 (diff)
parentfc4691cd06adeb4bebb00fa7137e135055a5e491 (diff)
Merge pull request #245855 from rnhmjoj/pr-sslh
nixos/sslh: update and refactor for RFC42
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/release-notes/rl-2311.section.md3
-rw-r--r--nixos/modules/services/networking/sslh.nix189
-rw-r--r--nixos/tests/sslh.nix18
3 files changed, 132 insertions, 78 deletions
diff --git a/nixos/doc/manual/release-notes/rl-2311.section.md b/nixos/doc/manual/release-notes/rl-2311.section.md
index e7eeca2af3e91..74d29ab1cf9ca 100644
--- a/nixos/doc/manual/release-notes/rl-2311.section.md
+++ b/nixos/doc/manual/release-notes/rl-2311.section.md
@@ -396,6 +396,9 @@
 
 - The `fonts.fonts` and `fonts.enableDefaultFonts` options have been renamed to `fonts.packages` and `fonts.enableDefaultPackages` respectively.
 
+- The `services.sslh` module has been updated to follow [RFC 0042](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md). As such, several options have been moved to the freeform attribute set [services.sslh.settings](#opt-services.sslh.settings), which allows to change any of the settings in {manpage}`sslh(8)`.
+  In addition, the newly added option [services.sslh.method](#opt-services.sslh.method) allows to switch between the {manpage}`fork(2)`, {manpage}`select(2)` and `libev`-based connection handling method; see the [sslh docs](https://github.com/yrutschle/sslh/blob/master/doc/INSTALL.md#binaries) for a comparison.
+
 - `pkgs.openvpn3` now optionally supports systemd-resolved. `programs.openvpn3` will automatically enable systemd-resolved support if `config.services.resolved.enable` is enabled.
 
 - `services.fail2ban.jails` can now be configured with attribute sets defining settings and filters instead of lines. The stringed options `daemonConfig` and `extraSettings` have respectively been replaced by `daemonSettings` and `jails.DEFAULT.settings` which use attribute sets.
diff --git a/nixos/modules/services/networking/sslh.nix b/nixos/modules/services/networking/sslh.nix
index daf2f2f3668ee..dd29db510020a 100644
--- a/nixos/modules/services/networking/sslh.nix
+++ b/nixos/modules/services/networking/sslh.nix
@@ -5,81 +5,131 @@ with lib;
 let
   cfg = config.services.sslh;
   user = "sslh";
-  configFile = pkgs.writeText "sslh.conf" ''
-    verbose: ${boolToString cfg.verbose};
-    foreground: true;
-    inetd: false;
-    numeric: false;
-    transparent: ${boolToString cfg.transparent};
-    timeout: "${toString cfg.timeout}";
-
-    listen:
-    (
-      ${
-        concatMapStringsSep ",\n"
-        (addr: ''{ host: "${addr}"; port: "${toString cfg.port}"; }'')
-        cfg.listenAddresses
-      }
-    );
-
-    ${cfg.appendConfig}
-  '';
-  defaultAppendConfig = ''
-    protocols:
-    (
-      { name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; probe: "builtin"; },
-      { name: "openvpn"; host: "localhost"; port: "1194"; probe: "builtin"; },
-      { name: "xmpp"; host: "localhost"; port: "5222"; probe: "builtin"; },
-      { name: "http"; host: "localhost"; port: "80"; probe: "builtin"; },
-      { name: "tls"; host: "localhost"; port: "443"; probe: "builtin"; },
-      { name: "anyprot"; host: "localhost"; port: "443"; probe: "builtin"; }
-    );
-  '';
+
+  configFormat = pkgs.formats.libconfig {};
+  configFile = configFormat.generate "sslh.conf" cfg.settings;
 in
+
 {
   imports = [
     (mkRenamedOptionModule [ "services" "sslh" "listenAddress" ] [ "services" "sslh" "listenAddresses" ])
+    (mkRenamedOptionModule [ "services" "sslh" "timeout" ] [ "services" "sslh" "settings" "timeout" ])
+    (mkRenamedOptionModule [ "services" "sslh" "transparent" ] [ "services" "sslh" "settings" "transparent" ])
+    (mkRemovedOptionModule [ "services" "sslh" "appendConfig" ] "Use services.sslh.settings instead")
+    (mkChangedOptionModule [ "services" "sslh" "verbose" ] [ "services" "sslh" "settings" "verbose-connections" ]
+      (config: if config.services.sslh.verbose then 1 else 0))
   ];
 
-  options = {
-    services.sslh = {
-      enable = mkEnableOption (lib.mdDoc "sslh");
+  meta.buildDocsInSandbox = false;
 
-      verbose = mkOption {
-        type = types.bool;
-        default = false;
-        description = lib.mdDoc "Verbose logs.";
-      };
+  options.services.sslh = {
+    enable = mkEnableOption (lib.mdDoc "sslh, protocol demultiplexer");
 
-      timeout = mkOption {
-        type = types.int;
-        default = 2;
-        description = lib.mdDoc "Timeout in seconds.";
-      };
+    method = mkOption {
+      type = types.enum [ "fork" "select" "ev" ];
+      default = "fork";
+      description = lib.mdDoc ''
+        The method to use for handling connections:
 
-      transparent = mkOption {
-        type = types.bool;
-        default = false;
-        description = lib.mdDoc "Will the services behind sslh (Apache, sshd and so on) see the external IP and ports as if the external world connected directly to them";
-      };
+          - `fork` forks a new process for each incoming connection. It is
+          well-tested and very reliable, but incurs the overhead of many
+          processes.
 
-      listenAddresses = mkOption {
-        type = types.coercedTo types.str singleton (types.listOf types.str);
-        default = [ "0.0.0.0" "[::]" ];
-        description = lib.mdDoc "Listening addresses or hostnames.";
-      };
+          - `select` uses only one thread, which monitors all connections at once.
+          It has lower overhead per connection, but if it stops, you'll lose all
+          connections.
 
-      port = mkOption {
-        type = types.port;
-        default = 443;
-        description = lib.mdDoc "Listening port.";
-      };
+          - `ev` is implemented using libev, it's similar to `select` but
+            scales better to a large number of connections.
+      '';
+    };
+
+    listenAddresses = mkOption {
+      type = with types; coercedTo str singleton (listOf str);
+      default = [ "0.0.0.0" "[::]" ];
+      description = lib.mdDoc "Listening addresses or hostnames.";
+    };
+
+    port = mkOption {
+      type = types.port;
+      default = 443;
+      description = lib.mdDoc "Listening port.";
+    };
+
+    settings = mkOption {
+      type = types.submodule {
+        freeformType = configFormat.type;
+
+        options.timeout = mkOption {
+          type = types.ints.unsigned;
+          default = 2;
+          description = lib.mdDoc "Timeout in seconds.";
+        };
+
+        options.transparent = mkOption {
+          type = types.bool;
+          default = false;
+          description = lib.mdDoc ''
+            Whether the services behind sslh (Apache, sshd and so on) will see the
+            external IP and ports as if the external world connected directly to
+            them.
+          '';
+        };
+
+        options.verbose-connections = mkOption {
+          type = types.ints.between 0 4;
+          default = 0;
+          description = lib.mdDoc ''
+            Where to log connections information. Possible values are:
+
+             0. don't log anything
+             1. write log to stdout
+             2. write log to syslog
+             3. write log to both stdout and syslog
+             4. write to a log file ({option}`sslh.settings.logfile`)
+          '';
+        };
+
+        options.numeric = mkOption {
+          type = types.bool;
+          default = true;
+          description = lib.mdDoc ''
+            Whether to disable reverse DNS lookups, thus keeping IP
+            address literals in the log.
+          '';
+        };
+
+        options.protocols = mkOption {
+          type = types.listOf configFormat.type;
+          default = [
+            { name = "ssh";     host = "localhost"; port =  "22"; service= "ssh"; }
+            { name = "openvpn"; host = "localhost"; port = "1194"; }
+            { name = "xmpp";    host = "localhost"; port = "5222"; }
+            { name = "http";    host = "localhost"; port =   "80"; }
+            { name = "tls";     host = "localhost"; port =  "443"; }
+            { name = "anyprot"; host = "localhost"; port =  "443"; }
+          ];
+          description = lib.mdDoc ''
+            List of protocols sslh will probe for and redirect.
+            Each protocol entry consists of:
+
+              - `name`: name of the probe.
+
+              - `service`: libwrap service name (see {manpage}`hosts_access(5)`),
 
-      appendConfig = mkOption {
-        type = types.str;
-        default = defaultAppendConfig;
-        description = lib.mdDoc "Verbatim configuration file.";
+              - `host`, `port`: where to connect when this probe succeeds,
+
+              - `log_level`: to log incoming connections,
+
+              - `transparent`: proxy this protocol transparently,
+
+              - etc.
+
+            See the documentation for all options, including probe-specific ones.
+          '';
+        };
       };
+      description = lib.mdDoc "sslh configuration. See {manpage}`sslh(8)` for available settings.";
     };
   };
 
@@ -96,20 +146,29 @@ in
           PermissionsStartOnly = true;
           Restart              = "always";
           RestartSec           = "1s";
-          ExecStart            = "${pkgs.sslh}/bin/sslh -F${configFile}";
+          ExecStart            = "${pkgs.sslh}/bin/sslh-${cfg.method} -F${configFile}";
           KillMode             = "process";
-          AmbientCapabilities  = "CAP_NET_BIND_SERVICE CAP_NET_ADMIN CAP_SETGID CAP_SETUID";
+          AmbientCapabilities  = ["CAP_NET_BIND_SERVICE" "CAP_NET_ADMIN" "CAP_SETGID" "CAP_SETUID"];
           PrivateTmp           = true;
           PrivateDevices       = true;
           ProtectSystem        = "full";
           ProtectHome          = true;
         };
       };
+
+      services.sslh.settings = {
+        # Settings defined here are not supposed to be changed: doing so will
+        # break the module, as such you need `lib.mkForce` to override them.
+        foreground = true;
+        inetd = false;
+        listen = map (addr: { host = addr; port = toString cfg.port; }) cfg.listenAddresses;
+      };
+
     })
 
     # code from https://github.com/yrutschle/sslh#transparent-proxy-support
     # the only difference is using iptables mark 0x2 instead of 0x1 to avoid conflicts with nixos/nat module
-    (mkIf (cfg.enable && cfg.transparent) {
+    (mkIf (cfg.enable && cfg.settings.transparent) {
       # Set route_localnet = 1 on all interfaces so that ssl can use "localhost" as destination
       boot.kernel.sysctl."net.ipv4.conf.default.route_localnet" = 1;
       boot.kernel.sysctl."net.ipv4.conf.all.route_localnet"     = 1;
diff --git a/nixos/tests/sslh.nix b/nixos/tests/sslh.nix
index 17094606e8e6b..30ffd389d4422 100644
--- a/nixos/tests/sslh.nix
+++ b/nixos/tests/sslh.nix
@@ -10,21 +10,13 @@ import ./make-test-python.nix {
           prefixLength = 64;
         }
       ];
-      # sslh is really slow when reverse dns does not work
-      networking.hosts = {
-        "fe00:aa:bb:cc::2" = [ "server" ];
-        "fe00:aa:bb:cc::1" = [ "client" ];
-      };
       services.sslh = {
         enable = true;
-        transparent = true;
-        appendConfig = ''
-          protocols:
-          (
-            { name: "ssh"; service: "ssh"; host: "localhost"; port: "22"; probe: "builtin"; },
-            { name: "http"; host: "localhost"; port: "80"; probe: "builtin"; },
-          );
-        '';
+        settings.transparent = true;
+        settings.protocols = [
+          { name = "ssh"; service = "ssh"; host = "localhost"; port = "22"; probe = "builtin"; }
+          { name = "http"; host = "localhost"; port = "80"; probe = "builtin"; }
+        ];
       };
       services.openssh.enable = true;
       users.users.root.openssh.authorizedKeys.keyFiles = [ ./initrd-network-ssh/id_ed25519.pub ];