Unverified Commit cef226e5 authored by Casey Link's avatar Casey Link
Browse files

nixos/microsocks: init

parent 4d16584c
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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).
+1 −0
Original line number Diff line number Diff line
@@ -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
+146 −0
Original line number Diff line number Diff line
{ 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}
        '';
    };
  };
}