Merge #361424: refactor lib.packagesFromDirectoryRecursive (v2)
[NixPkgs.git] / nixos / modules / services / networking / microsocks.nix
blob9956b8f158eb8a691b980aee56e20bd32a2a6ea5
2   config,
3   lib,
4   pkgs,
5   ...
6 }:
8 let
9   cfg = config.services.microsocks;
11   cmd =
12     if cfg.execWrapper != null then
13       "${cfg.execWrapper} ${cfg.package}/bin/microsocks"
14     else
15       "${cfg.package}/bin/microsocks";
16   args =
17     [
18       "-i"
19       cfg.ip
20       "-p"
21       (toString cfg.port)
22     ]
23     ++ lib.optionals (cfg.authOnce) [ "-1" ]
24     ++ lib.optionals (cfg.disableLogging) [ "-q" ]
25     ++ lib.optionals (cfg.outgoingBindIp != null) [
26       "-b"
27       cfg.outgoingBindIp
28     ]
29     ++ lib.optionals (cfg.authUsername != null) [
30       "-u"
31       cfg.authUsername
32     ];
35   options.services.microsocks = {
36     enable = lib.mkEnableOption "Tiny, portable SOCKS5 server with very moderate resource usage";
37     user = lib.mkOption {
38       default = "microsocks";
39       description = "User microsocks runs as.";
40       type = lib.types.str;
41     };
42     group = lib.mkOption {
43       default = "microsocks";
44       description = "Group microsocks runs as.";
45       type = lib.types.str;
46     };
47     package = lib.mkPackageOption pkgs "microsocks" { };
48     ip = lib.mkOption {
49       type = lib.types.str;
50       default = "127.0.0.1";
51       description = ''
52         IP on which microsocks should listen. Defaults to 127.0.0.1 for
53         security reasons.
54       '';
55     };
56     port = lib.mkOption {
57       type = lib.types.port;
58       default = 1080;
59       description = "Port on which microsocks should listen.";
60     };
61     disableLogging = lib.mkOption {
62       type = lib.types.bool;
63       default = false;
64       description = "If true, microsocks will not log any messages to stdout/stderr.";
65     };
66     authOnce = lib.mkOption {
67       type = lib.types.bool;
68       default = false;
69       description = ''
70         If true, once a specific ip address authed successfully with user/pass,
71         it is added to a whitelist and may use the proxy without auth.
72       '';
73     };
74     outgoingBindIp = lib.mkOption {
75       type = lib.types.nullOr lib.types.str;
76       default = null;
77       description = "Specifies which ip outgoing connections are bound to";
78     };
79     authUsername = lib.mkOption {
80       type = lib.types.nullOr lib.types.str;
81       default = null;
82       example = "alice";
83       description = "Optional username to use for authentication.";
84     };
85     authPasswordFile = lib.mkOption {
86       type = lib.types.nullOr lib.types.path;
87       default = null;
88       example = "/run/secrets/microsocks-password";
89       description = "Path to a file containing the password for authentication.";
90     };
91     execWrapper = lib.mkOption {
92       type = lib.types.nullOr lib.types.str;
93       default = null;
94       example = ''
95         ''${pkgs.mullvad-vpn}/bin/mullvad-exclude
96       '';
97       description = ''
98         An optional command to prepend to the microsocks command (such as proxychains, or a VPN exclude command).
99       '';
100     };
101   };
102   config = lib.mkIf cfg.enable {
103     assertions = [
104       {
105         assertion = (cfg.authUsername != null) == (cfg.authPasswordFile != null);
106         message = "Need to set both authUsername and authPasswordFile for microsocks";
107       }
108     ];
109     users = {
110       users = lib.mkIf (cfg.user == "microsocks") {
111         microsocks = {
112           group = cfg.group;
113           isSystemUser = true;
114         };
115       };
116       groups = lib.mkIf (cfg.group == "microsocks") {
117         microsocks = { };
118       };
119     };
120     systemd.services.microsocks = {
121       enable = true;
122       description = "a tiny socks server";
123       after = [ "network.target" ];
124       wantedBy = [ "multi-user.target" ];
125       serviceConfig = {
126         User = cfg.user;
127         Group = cfg.group;
128         Restart = "on-failure";
129         RestartSec = 10;
130         LoadCredential = lib.optionalString (
131           cfg.authPasswordFile != null
132         ) "MICROSOCKS_PASSWORD_FILE:${cfg.authPasswordFile}";
133         MemoryDenyWriteExecute = true;
134         SystemCallArchitectures = "native";
135         PrivateTmp = true;
136         NoNewPrivileges = true;
137         ProtectSystem = "strict";
138         ProtectHome = true;
139         ProtectKernelModules = true;
140         ProtectKernelTunables = true;
141         PrivateDevices = true;
142         RestrictSUIDSGID = true;
143         RestrictNamespaces = [
144           "cgroup"
145           "ipc"
146           "pid"
147           "user"
148           "uts"
149         ];
150       };
151       script =
152         if cfg.authPasswordFile != null then
153           ''
154             PASSWORD=$(cat "$CREDENTIALS_DIRECTORY/MICROSOCKS_PASSWORD_FILE")
155             ${cmd} ${lib.escapeShellArgs args} -P "$PASSWORD"
156           ''
157         else
158           ''
159             ${cmd} ${lib.escapeShellArgs args}
160           '';
161     };
162   };