diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index 436bd5101233..8bf84c2d32c5 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -111,6 +111,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m - [Pretix](https://pretix.eu/about/en/), an open source ticketing software for events. Available as [services.pretix]($opt-services-pretix.enable). +- [microsocks](https://github.com/rofl0r/microsocks), a tiny, portable SOCKS5 server with very moderate resource usage. Available as [services.microsocks]($opt-services-microsocks.enable). + - [Clevis](https://github.com/latchset/clevis), a pluggable framework for automated decryption, used to unlock encrypted devices in initrd. Available as [boot.initrd.clevis.enable](#opt-boot.initrd.clevis.enable). - [fritz-exporter](https://github.com/pdreker/fritz_exporter), a Prometheus exporter for extracting metrics from [FRITZ!](https://avm.de/produkte/) devices. Available as [services.prometheus.exporters.fritz](#opt-services.prometheus.exporters.fritz.enable). diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 299b163844f8..439341f44357 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1020,6 +1020,7 @@ ./services/networking/lxd-image-server.nix ./services/networking/magic-wormhole-mailbox-server.nix ./services/networking/matterbridge.nix + ./services/networking/microsocks.nix ./services/networking/mihomo.nix ./services/networking/minidlna.nix ./services/networking/miniupnpd.nix diff --git a/nixos/modules/services/networking/microsocks.nix b/nixos/modules/services/networking/microsocks.nix new file mode 100644 index 000000000000..be79a8495636 --- /dev/null +++ b/nixos/modules/services/networking/microsocks.nix @@ -0,0 +1,146 @@ +{ config, + lib, + pkgs, + ... +}: + +let + cfg = config.services.microsocks; + + cmd = + if cfg.execWrapper != null + then "${cfg.execWrapper} ${cfg.package}/bin/microsocks" + else "${cfg.package}/bin/microsocks"; + args = + [ "-i" cfg.ip "-p" (toString cfg.port) ] + ++ lib.optionals (cfg.authOnce) [ "-1" ] + ++ lib.optionals (cfg.disableLogging) [ "-q" ] + ++ lib.optionals (cfg.outgoingBindIp != null) [ "-b" cfg.outgoingBindIp ] + ++ lib.optionals (cfg.authUsername != null) [ "-u" cfg.authUsername ]; +in { + options.services.microsocks = { + enable = lib.mkEnableOption (lib.mdDoc "Tiny, portable SOCKS5 server with very moderate resource usage"); + user = lib.mkOption { + default = "microsocks"; + description = lib.mdDoc "User microsocks runs as."; + type = lib.types.str; + }; + group = lib.mkOption { + default = "microsocks"; + description = lib.mdDoc "Group microsocks runs as."; + type = lib.types.str; + }; + package = lib.mkPackageOption pkgs "microsocks" {}; + ip = lib.mkOption { + type = lib.types.str; + default = "127.0.0.1"; + description = lib.mdDoc '' + IP on which microsocks should listen. Defaults to 127.0.0.1 for + security reasons. + ''; + }; + port = lib.mkOption { + type = lib.types.port; + default = 1080; + description = lib.mdDoc "Port on which microsocks should listen."; + }; + disableLogging = lib.mkOption { + type = lib.types.bool; + default = false; + description = lib.mdDoc "If true, microsocks will not log any messages to stdout/stderr."; + }; + authOnce = lib.mkOption { + type = lib.types.bool; + default = false; + description = lib.mdDoc '' + If true, once a specific ip address authed successfully with user/pass, + it is added to a whitelist and may use the proxy without auth. + ''; + }; + outgoingBindIp = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + description = lib.mdDoc "Specifies which ip outgoing connections are bound to"; + }; + authUsername = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = "alice"; + description = lib.mdDoc "Optional username to use for authentication."; + }; + authPasswordFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + example = "/run/secrets/microsocks-password"; + description = lib.mdDoc "Path to a file containing the password for authentication."; + }; + execWrapper = lib.mkOption { + type = lib.types.nullOr lib.types.str; + default = null; + example = '' + ''${pkgs.mullvad-vpn}/bin/mullvad-exclude + ''; + description = lib.mdDoc '' + An optional command to prepend to the microsocks command (such as proxychains, or a VPN exclude command). + ''; + }; + }; + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = (cfg.authUsername != null) == (cfg.authPasswordFile != null); + message = "Need to set both authUsername and authPasswordFile for microsocks"; + } + ]; + users = { + users = lib.mkIf (cfg.user == "microsocks") { + microsocks = { + group = cfg.group; + isSystemUser = true; + }; + }; + groups = lib.mkIf (cfg.group == "microsocks") { + microsocks = {}; + }; + }; + systemd.services.microsocks = { + enable = true; + description = "a tiny socks server"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + User = cfg.user; + Group = cfg.group; + Restart = "on-failure"; + RestartSec = 10; + LoadCredential = lib.optionalString (cfg.authPasswordFile != null) "MICROSOCKS_PASSWORD_FILE:${cfg.authPasswordFile}"; + MemoryDenyWriteExecute = true; + SystemCallArchitectures = "native"; + PrivateTmp = true; + NoNewPrivileges = true; + ProtectSystem = "strict"; + ProtectHome = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + PrivateDevices = true; + RestrictSUIDSGID = true; + RestrictNamespaces = [ + "cgroup" + "ipc" + "pid" + "user" + "uts" + ]; + }; + script = + if cfg.authPasswordFile != null + then '' + PASSWORD=$(cat "$CREDENTIALS_DIRECTORY/MICROSOCKS_PASSWORD_FILE") + ${cmd} ${lib.escapeShellArgs args} -P "$PASSWORD" + '' + else '' + ${cmd} ${lib.escapeShellArgs args} + ''; + }; + }; +}