Merge pull request #245855 from rnhmjoj/pr-sslh

nixos/sslh: update and refactor for RFC42

Changed files
+143 -81
nixos
doc
manual
release-notes
modules
services
networking
tests
pkgs
servers
+3
nixos/doc/manual/release-notes/rl-2311.section.md
···
- 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.
+123 -64
nixos/modules/services/networking/sslh.nix
···
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
-
}
-
);
+
configFormat = pkgs.formats.libconfig {};
+
configFile = configFormat.generate "sslh.conf" cfg.settings;
+
in
-
${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"; }
-
);
-
'';
-
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;
+
+
options.services.sslh = {
+
enable = mkEnableOption (lib.mdDoc "sslh, protocol demultiplexer");
+
+
method = mkOption {
+
type = types.enum [ "fork" "select" "ev" ];
+
default = "fork";
+
description = lib.mdDoc ''
+
The method to use for handling connections:
+
+
- `fork` forks a new process for each incoming connection. It is
+
well-tested and very reliable, but incurs the overhead of many
+
processes.
+
+
- `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.
+
+
- `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.
-
verbose = mkOption {
-
type = types.bool;
-
default = false;
-
description = lib.mdDoc "Verbose logs.";
-
};
+
- `service`: libwrap service name (see {manpage}`hosts_access(5)`),
-
timeout = mkOption {
-
type = types.int;
-
default = 2;
-
description = lib.mdDoc "Timeout in seconds.";
-
};
+
- `host`, `port`: where to connect when this probe succeeds,
-
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";
-
};
+
- `log_level`: to log incoming connections,
-
listenAddresses = mkOption {
-
type = types.coercedTo types.str singleton (types.listOf types.str);
-
default = [ "0.0.0.0" "[::]" ];
-
description = lib.mdDoc "Listening addresses or hostnames.";
-
};
+
- `transparent`: proxy this protocol transparently,
-
port = mkOption {
-
type = types.port;
-
default = 443;
-
description = lib.mdDoc "Listening port.";
-
};
+
- etc.
-
appendConfig = mkOption {
-
type = types.str;
-
default = defaultAppendConfig;
-
description = lib.mdDoc "Verbatim configuration file.";
+
See the documentation for all options, including probe-specific ones.
+
'';
+
};
};
+
description = lib.mdDoc "sslh configuration. See {manpage}`sslh(8)` for available settings.";
};
};
···
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;
+5 -13
nixos/tests/sslh.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 ];
+12 -4
pkgs/servers/sslh/default.nix
···
-
{ lib, stdenv, fetchFromGitHub, libcap, libconfig, perl, tcp_wrappers, pcre2, nixosTests }:
+
{ lib, stdenv, fetchFromGitHub, fetchpatch, libcap, libev, libconfig, perl, tcp_wrappers, pcre2, nixosTests }:
stdenv.mkDerivation rec {
pname = "sslh";
-
version = "1.22c";
+
version = "2.0.0";
src = fetchFromGitHub {
owner = "yrutschle";
repo = pname;
rev = "v${version}";
-
sha256 = "sha256-A+nUWiOPoz/T5afZUzt5In01e049TgHisTF8P5Vj180=";
+
hash = "sha256-KfNQWSmAf86AFoInKlNZoiSuSwVLaJVnfo7SjZVY/VU=";
};
postPatch = "patchShebangs *.sh";
-
buildInputs = [ libcap libconfig perl tcp_wrappers pcre2 ];
+
buildInputs = [ libcap libev libconfig perl tcp_wrappers pcre2 ];
makeFlags = [ "USELIBCAP=1" "USELIBWRAP=1" ];
+
+
postInstall = ''
+
# install all flavours
+
install -p sslh-fork "$out/sbin/sslh-fork"
+
install -p sslh-select "$out/sbin/sslh-select"
+
install -p sslh-ev "$out/sbin/sslh-ev"
+
ln -sf sslh-fork "$out/sbin/sslh"
+
'';
installFlags = [ "PREFIX=$(out)" ];