]> Git — Sourcephile - sourcephile-nix.git/blob - nixpkgs/patches/tor.diff
mermet: unbound: provide a DNS cache for iodine users
[sourcephile-nix.git] / nixpkgs / patches / tor.diff
1 diff --git a/nixos/modules/services/networking/privoxy.nix b/nixos/modules/services/networking/privoxy.nix
2 index e3b34cb0c61..7caae328203 100644
3 --- a/nixos/modules/services/networking/privoxy.nix
4 +++ b/nixos/modules/services/networking/privoxy.nix
5 @@ -16,7 +16,7 @@ let
6 ${concatMapStrings (f: "actionsfile ${f}\n") cfg.actionsFiles}
7 ${concatMapStrings (f: "filterfile ${f}\n") cfg.filterFiles}
8 '' + optionalString cfg.enableTor ''
9 - forward-socks4a / ${config.services.tor.client.socksListenAddressFaster} .
10 + forward-socks5t / 127.0.0.1:9063 .
11 toggle 1
12 enable-remote-toggle 0
13 enable-edit-actions 0
14 @@ -123,6 +123,11 @@ in
15 serviceConfig.ProtectSystem = "full";
16 };
17
18 + services.tor.settings.SOCKSPort = mkIf cfg.enableTor [
19 + # Route HTTP traffic over a faster port (without IsolateDestAddr).
20 + { addr = "127.0.0.1"; port = 9063; IsolateDestAddr = false; }
21 + ];
22 +
23 };
24
25 meta.maintainers = with lib.maintainers; [ rnhmjoj ];
26 diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix
27 index 1cceee065b1..2f89d6bc1df 100644
28 --- a/nixos/modules/services/security/tor.nix
29 +++ b/nixos/modules/services/security/tor.nix
30 @@ -1,297 +1,299 @@
31 { config, lib, pkgs, ... }:
32
33 +with builtins;
34 with lib;
35
36 let
37 cfg = config.services.tor;
38 - torDirectory = "/var/lib/tor";
39 - torRunDirectory = "/run/tor";
40 -
41 - opt = name: value: optionalString (value != null) "${name} ${value}";
42 - optint = name: value: optionalString (value != null && value != 0) "${name} ${toString value}";
43 -
44 - isolationOptions = {
45 - type = types.listOf (types.enum [
46 - "IsolateClientAddr"
47 - "IsolateSOCKSAuth"
48 - "IsolateClientProtocol"
49 - "IsolateDestPort"
50 - "IsolateDestAddr"
51 + stateDir = "/var/lib/tor";
52 + runDir = "/run/tor";
53 + descriptionGeneric = option: ''
54 + See <link xlink:href="https://2019.www.torproject.org/docs/tor-manual.html.en#${option}">torrc manual</link>.
55 + '';
56 + bindsPrivilegedPort =
57 + any (p0:
58 + let p1 = if p0 ? "port" then p0.port else p0; in
59 + if p1 == "auto" then false
60 + else let p2 = if isInt p1 then p1 else toInt p1; in
61 + p1 != null && 0 < p2 && p2 < 1024)
62 + (flatten [
63 + cfg.settings.ORPort
64 + cfg.settings.DirPort
65 + cfg.settings.DNSPort
66 + cfg.settings.ExtORPort
67 + cfg.settings.HTTPTunnelPort
68 + cfg.settings.NATDPort
69 + cfg.settings.SOCKSPort
70 + cfg.settings.TransPort
71 ]);
72 + optionBool = optionName: mkOption {
73 + type = with types; nullOr bool;
74 + default = null;
75 + description = descriptionGeneric optionName;
76 + };
77 + optionInt = optionName: mkOption {
78 + type = with types; nullOr int;
79 + default = null;
80 + description = descriptionGeneric optionName;
81 + };
82 + optionString = optionName: mkOption {
83 + type = with types; nullOr str;
84 + default = null;
85 + description = descriptionGeneric optionName;
86 + };
87 + optionStrings = optionName: mkOption {
88 + type = with types; listOf str;
89 default = [];
90 - example = [
91 - "IsolateClientAddr"
92 - "IsolateSOCKSAuth"
93 - "IsolateClientProtocol"
94 - "IsolateDestPort"
95 - "IsolateDestAddr"
96 + description = descriptionGeneric optionName;
97 + };
98 + optionAddress = mkOption {
99 + type = with types; nullOr str;
100 + default = null;
101 + example = "0.0.0.0";
102 + description = ''
103 + IPv4 or IPv6 (if between brackets) address.
104 + '';
105 + };
106 + optionUnix = mkOption {
107 + type = with types; nullOr path;
108 + default = null;
109 + description = ''
110 + Unix domain socket path to use.
111 + '';
112 + };
113 + optionPort = mkOption {
114 + type = with types; nullOr (oneOf [port (enum ["auto"])]);
115 + default = null;
116 + };
117 + optionPorts = optionName: mkOption {
118 + type = with types; listOf port;
119 + default = [];
120 + description = descriptionGeneric optionName;
121 + };
122 + optionIsolablePort = with types; oneOf [
123 + port (enum ["auto"])
124 + (submodule ({config, ...}: {
125 + options = {
126 + addr = optionAddress;
127 + port = optionPort;
128 + flags = optionFlags;
129 + SessionGroup = mkOption { type = nullOr int; default = null; };
130 + } // genAttrs isolateFlags (name: mkOption { type = types.bool; default = false; });
131 + config = {
132 + flags = filter (name: config.${name} == true) isolateFlags ++
133 + optional (config.SessionGroup != null) "SessionGroup=${toString config.SessionGroup}";
134 + };
135 + }))
136 + ];
137 + optionIsolablePorts = optionName: mkOption {
138 + default = [];
139 + type = with types; either optionIsolablePort (listOf optionIsolablePort);
140 + description = descriptionGeneric optionName;
141 + };
142 + isolateFlags = [
143 + "IsolateClientAddr"
144 + "IsolateClientProtocol"
145 + "IsolateDestAddr"
146 + "IsolateDestPort"
147 + "IsolateSOCKSAuth"
148 + "KeepAliveIsolateSOCKSAuth"
149 + ];
150 + optionSOCKSPort = doConfig: let
151 + flags = [
152 + "CacheDNS" "CacheIPv4DNS" "CacheIPv6DNS" "GroupWritable" "IPv6Traffic"
153 + "NoDNSRequest" "NoIPv4Traffic" "NoOnionTraffic" "OnionTrafficOnly"
154 + "PreferIPv6" "PreferIPv6Automap" "PreferSOCKSNoAuth" "UseDNSCache"
155 + "UseIPv4Cache" "UseIPv6Cache" "WorldWritable"
156 + ] ++ isolateFlags;
157 + in with types; oneOf [
158 + port (submodule ({config, ...}: {
159 + options = {
160 + unix = optionUnix;
161 + addr = optionAddress;
162 + port = optionPort;
163 + flags = optionFlags;
164 + SessionGroup = mkOption { type = nullOr int; default = null; };
165 + } // genAttrs flags (name: mkOption { type = types.bool; default = false; });
166 + config = mkIf doConfig { # Only add flags in SOCKSPort to avoid duplicates
167 + flags = filter (name: config.${name} == true) flags ++
168 + optional (config.SessionGroup != null) "SessionGroup=${toString config.SessionGroup}";
169 + };
170 + }))
171 ];
172 - description = "Tor isolation options";
173 + optionFlags = mkOption {
174 + type = with types; listOf str;
175 + default = [];
176 + };
177 + optionORPort = optionName: mkOption {
178 + default = [];
179 + example = 443;
180 + type = with types; oneOf [port (enum ["auto"]) (listOf (oneOf [
181 + port
182 + (enum ["auto"])
183 + (submodule ({config, ...}:
184 + let flags = [ "IPv4Only" "IPv6Only" "NoAdvertise" "NoListen" ];
185 + in {
186 + options = {
187 + addr = optionAddress;
188 + port = optionPort;
189 + flags = optionFlags;
190 + } // genAttrs flags (name: mkOption { type = types.bool; default = false; });
191 + config = {
192 + flags = filter (name: config.${name} == true) flags;
193 + };
194 + }))
195 + ]))];
196 + description = descriptionGeneric optionName;
197 + };
198 + optionBandwith = optionName: mkOption {
199 + type = with types; nullOr (either int str);
200 + default = null;
201 + description = descriptionGeneric optionName;
202 + };
203 + optionPath = optionName: mkOption {
204 + type = with types; nullOr path;
205 + default = null;
206 + description = descriptionGeneric optionName;
207 };
208
209 -
210 - torRc = ''
211 - User tor
212 - DataDirectory ${torDirectory}
213 - ${optionalString cfg.enableGeoIP ''
214 - GeoIPFile ${cfg.package.geoip}/share/tor/geoip
215 - GeoIPv6File ${cfg.package.geoip}/share/tor/geoip6
216 - ''}
217 -
218 - ${optint "ControlPort" cfg.controlPort}
219 - ${optionalString cfg.controlSocket.enable "ControlPort unix:${torRunDirectory}/control GroupWritable RelaxDirModeCheck"}
220 - ''
221 - # Client connection config
222 - + optionalString cfg.client.enable ''
223 - SOCKSPort ${cfg.client.socksListenAddress} ${toString cfg.client.socksIsolationOptions}
224 - SOCKSPort ${cfg.client.socksListenAddressFaster}
225 - ${opt "SocksPolicy" cfg.client.socksPolicy}
226 -
227 - ${optionalString cfg.client.transparentProxy.enable ''
228 - TransPort ${cfg.client.transparentProxy.listenAddress} ${toString cfg.client.transparentProxy.isolationOptions}
229 - ''}
230 -
231 - ${optionalString cfg.client.dns.enable ''
232 - DNSPort ${cfg.client.dns.listenAddress} ${toString cfg.client.dns.isolationOptions}
233 - AutomapHostsOnResolve 1
234 - AutomapHostsSuffixes ${concatStringsSep "," cfg.client.dns.automapHostsSuffixes}
235 - ''}
236 - ''
237 - # Explicitly disable the SOCKS server if the client is disabled. In
238 - # particular, this makes non-anonymous hidden services possible.
239 - + optionalString (! cfg.client.enable) ''
240 - SOCKSPort 0
241 - ''
242 - # Relay config
243 - + optionalString cfg.relay.enable ''
244 - ORPort ${toString cfg.relay.port}
245 - ${opt "Address" cfg.relay.address}
246 - ${opt "Nickname" cfg.relay.nickname}
247 - ${opt "ContactInfo" cfg.relay.contactInfo}
248 -
249 - ${optint "RelayBandwidthRate" cfg.relay.bandwidthRate}
250 - ${optint "RelayBandwidthBurst" cfg.relay.bandwidthBurst}
251 - ${opt "AccountingMax" cfg.relay.accountingMax}
252 - ${opt "AccountingStart" cfg.relay.accountingStart}
253 -
254 - ${if (cfg.relay.role == "exit") then
255 - opt "ExitPolicy" cfg.relay.exitPolicy
256 - else
257 - "ExitPolicy reject *:*"}
258 -
259 - ${optionalString (elem cfg.relay.role ["bridge" "private-bridge"]) ''
260 - BridgeRelay 1
261 - ServerTransportPlugin ${concatStringsSep "," cfg.relay.bridgeTransports} exec ${pkgs.obfs4}/bin/obfs4proxy managed
262 - ExtORPort auto
263 - ${optionalString (cfg.relay.role == "private-bridge") ''
264 - ExtraInfoStatistics 0
265 - PublishServerDescriptor 0
266 - ''}
267 - ''}
268 - ''
269 - # Hidden services
270 - + concatStrings (flip mapAttrsToList cfg.hiddenServices (n: v: ''
271 - HiddenServiceDir ${torDirectory}/onion/${v.name}
272 - ${optionalString (v.version != null) "HiddenServiceVersion ${toString v.version}"}
273 - ${flip concatMapStrings v.map (p: ''
274 - HiddenServicePort ${toString p.port} ${p.destination}
275 - '')}
276 - ${optionalString (v.authorizeClient != null) ''
277 - HiddenServiceAuthorizeClient ${v.authorizeClient.authType} ${concatStringsSep "," v.authorizeClient.clientNames}
278 - ''}
279 - ''))
280 - + cfg.extraConfig;
281 -
282 - torRcFile = pkgs.writeText "torrc" torRc;
283 -
284 + mkValueString = k: v:
285 + if v == null then ""
286 + else if isBool v then
287 + (if v then "1" else "0")
288 + else if v ? "unix" && v.unix != null then
289 + "unix:"+v.unix +
290 + optionalString (v ? "flags") (" " + concatStringsSep " " v.flags)
291 + else if v ? "port" && v.port != null then
292 + optionalString (v ? "addr" && v.addr != null) "${v.addr}:" +
293 + toString v.port +
294 + optionalString (v ? "flags") (" " + concatStringsSep " " v.flags)
295 + else if k == "ServerTransportPlugin" then
296 + optionalString (v.transports != []) "${concatStringsSep "," v.transports} exec ${v.exec}"
297 + else if k == "HidServAuth" then
298 + concatMapStringsSep "\n${k} " (settings: settings.onion + " " settings.auth) v
299 + else generators.mkValueStringDefault {} v;
300 + genTorrc = settings:
301 + generators.toKeyValue {
302 + listsAsDuplicateKeys = true;
303 + mkKeyValue = k: generators.mkKeyValueDefault { mkValueString = mkValueString k; } " " k;
304 + }
305 + (lib.mapAttrs (k: v:
306 + # Not necesssary, but prettier rendering
307 + if elem k [ "AutomapHostsSuffixes" "DirPolicy" "ExitPolicy" "SocksPolicy" ]
308 + && v != []
309 + then concatStringsSep "," v
310 + else v)
311 + (lib.filterAttrs (k: v: !(v == null || v == ""))
312 + settings));
313 + torrc = pkgs.writeText "torrc" (
314 + genTorrc cfg.settings +
315 + concatStrings (mapAttrsToList (name: onion:
316 + "HiddenServiceDir ${onion.path}\n" +
317 + genTorrc onion.settings) cfg.relay.onionServices)
318 + );
319 in
320 {
321 imports = [
322 - (mkRemovedOptionModule [ "services" "tor" "client" "privoxy" "enable" ] ''
323 - Use services.privoxy.enable and services.privoxy.enableTor instead.
324 - '')
325 - (mkRenamedOptionModule [ "services" "tor" "relay" "portSpec" ] [ "services" "tor" "relay" "port" ])
326 + (mkRenamedOptionModule [ "services" "tor" "client" "dns" "automapHostsSuffixes" ] [ "services" "tor" "settings" "AutomapHostsSuffixes" ])
327 + (mkRemovedOptionModule [ "services" "tor" "client" "dns" "isolationOptions" ] "Use services.tor.settings.DNSPort instead.")
328 + (mkRemovedOptionModule [ "services" "tor" "client" "dns" "listenAddress" ] "Use services.tor.settings.DNSPort instead.")
329 + (mkRemovedOptionModule [ "services" "tor" "client" "privoxy" "enable" ] "Use services.privoxy.enable and services.privoxy.enableTor instead.")
330 + (mkRemovedOptionModule [ "services" "tor" "client" "socksIsolationOptions" ] "Use services.tor.settings.SOCKSPort")
331 + (mkRenamedOptionModule [ "services" "tor" "client" "socksPolicy" ] [ "services" "tor" "settings" "SocksPolicy" ])
332 + (mkRemovedOptionModule [ "services" "tor" "client" "transparentProxy" "isolationOptions" ] "Use services.tor.settings.TransPort instead.")
333 + (mkRemovedOptionModule [ "services" "tor" "client" "transparentProxy" "listenAddress" ] "Use services.tor.settings.TransPort instead.")
334 + (mkRenamedOptionModule [ "services" "tor" "controlPort" ] [ "services" "tor" "settings" "ControlPort" ])
335 + (mkRemovedOptionModule [ "services" "tor" "extraConfig" ] "Plese use services.tor.settings instead.")
336 + (mkRenamedOptionModule [ "services" "tor" "hiddenServices" ] [ "services" "tor" "relay" "onionServices" ])
337 + (mkRenamedOptionModule [ "services" "tor" "relay" "accountingMax" ] [ "services" "tor" "settings" "AccountingMax" ])
338 + (mkRenamedOptionModule [ "services" "tor" "relay" "accountingStart" ] [ "services" "tor" "settings" "AccountingStart" ])
339 + (mkRenamedOptionModule [ "services" "tor" "relay" "address" ] [ "services" "tor" "settings" "Address" ])
340 + (mkRenamedOptionModule [ "services" "tor" "relay" "bandwidthBurst" ] [ "services" "tor" "settings" "BandwidthBurst" ])
341 + (mkRenamedOptionModule [ "services" "tor" "relay" "bandwidthRate" ] [ "services" "tor" "settings" "BandwidthRate" ])
342 + (mkRenamedOptionModule [ "services" "tor" "relay" "bridgeTransports" ] [ "services" "tor" "settings" "ServerTransportPlugin" "transports" ])
343 + (mkRenamedOptionModule [ "services" "tor" "relay" "contactInfo" ] [ "services" "tor" "settings" "ContactInfo" ])
344 + (mkRenamedOptionModule [ "services" "tor" "relay" "exitPolicy" ] [ "services" "tor" "settings" "ExitPolicy" ])
345 (mkRemovedOptionModule [ "services" "tor" "relay" "isBridge" ] "Use services.tor.relay.role instead.")
346 (mkRemovedOptionModule [ "services" "tor" "relay" "isExit" ] "Use services.tor.relay.role instead.")
347 + (mkRenamedOptionModule [ "services" "tor" "relay" "nickname" ] [ "services" "tor" "settings" "Nickname" ])
348 + (mkRenamedOptionModule [ "services" "tor" "relay" "port" ] [ "services" "tor" "settings" "ORPort" ])
349 + (mkRenamedOptionModule [ "services" "tor" "relay" "portSpec" ] [ "services" "tor" "settings" "ORPort" ])
350 ];
351
352 options = {
353 services.tor = {
354 - enable = mkOption {
355 - type = types.bool;
356 - default = false;
357 - description = ''
358 - Enable the Tor daemon. By default, the daemon is run without
359 - relay, exit, bridge or client connectivity.
360 - '';
361 - };
362 + enable = mkEnableOption ''Tor daemon.
363 + By default, the daemon is run without
364 + relay, exit, bridge or client connectivity'';
365 +
366 + openFirewall = mkEnableOption "opening of the relay port(s) in the firewall";
367
368 package = mkOption {
369 type = types.package;
370 default = pkgs.tor;
371 defaultText = "pkgs.tor";
372 example = literalExample "pkgs.tor";
373 - description = ''
374 - Tor package to use
375 - '';
376 + description = "Tor package to use.";
377 };
378
379 - enableGeoIP = mkOption {
380 - type = types.bool;
381 - default = true;
382 - description = ''
383 - Whenever to configure Tor daemon to use GeoIP databases.
384 + enableGeoIP = mkEnableOption ''use of GeoIP databases.
385 + Disabling this will disable by-country statistics for bridges and relays
386 + and some client and third-party software functionality'' // { default = true; };
387
388 - Disabling this will disable by-country statistics for
389 - bridges and relays and some client and third-party software
390 - functionality.
391 - '';
392 - };
393 -
394 - extraConfig = mkOption {
395 - type = types.lines;
396 - default = "";
397 - description = ''
398 - Extra configuration. Contents will be added verbatim to the
399 - configuration file at the end.
400 - '';
401 - };
402 -
403 - controlPort = mkOption {
404 - type = types.nullOr (types.either types.int types.str);
405 - default = null;
406 - example = 9051;
407 - description = ''
408 - If set, Tor will accept connections on the specified port
409 - and allow them to control the tor process.
410 - '';
411 - };
412 -
413 - controlSocket = {
414 - enable = mkOption {
415 - type = types.bool;
416 - default = false;
417 - description = ''
418 - Whether to enable Tor control socket. Control socket is created
419 - in <literal>${torRunDirectory}/control</literal>
420 - '';
421 - };
422 - };
423 + controlSocket.enable = mkEnableOption ''control socket,
424 + created in <literal>${runDir}/control</literal>'';
425
426 client = {
427 - enable = mkOption {
428 - type = types.bool;
429 - default = false;
430 - description = ''
431 - Whether to enable Tor daemon to route application
432 - connections. You might want to disable this if you plan
433 - running a dedicated Tor relay.
434 - '';
435 - };
436 + enable = mkEnableOption ''the routing of application connections.
437 + You might want to disable this if you plan running a dedicated Tor relay'';
438 +
439 + transparentProxy.enable = mkEnableOption "transparent proxy";
440 + dns.enable = mkEnableOption "DNS resolver";
441
442 socksListenAddress = mkOption {
443 - type = types.str;
444 - default = "127.0.0.1:9050";
445 - example = "192.168.0.1:9100";
446 + type = optionSOCKSPort false;
447 + default = {addr = "127.0.0.1"; port = 9050; IsolateDestAddr = true;};
448 + example = {addr = "192.168.0.1"; port = 9090; IsolateDestAddr = true;};
449 description = ''
450 Bind to this address to listen for connections from
451 - Socks-speaking applications. Provides strong circuit
452 - isolation, separate circuit per IP address.
453 + Socks-speaking applications.
454 '';
455 };
456
457 - socksListenAddressFaster = mkOption {
458 - type = types.str;
459 - default = "127.0.0.1:9063";
460 - example = "192.168.0.1:9101";
461 - description = ''
462 - Bind to this address to listen for connections from
463 - Socks-speaking applications. Same as
464 - <option>socksListenAddress</option> but uses weaker
465 - circuit isolation to provide performance suitable for a
466 - web browser.
467 - '';
468 - };
469 -
470 - socksPolicy = mkOption {
471 - type = types.nullOr types.str;
472 - default = null;
473 - example = "accept 192.168.0.0/16, reject *";
474 - description = ''
475 - Entry policies to allow/deny SOCKS requests based on IP
476 - address. First entry that matches wins. If no SocksPolicy
477 - is set, we accept all (and only) requests from
478 - <option>socksListenAddress</option>.
479 - '';
480 - };
481 -
482 - socksIsolationOptions = mkOption (isolationOptions // {
483 - default = ["IsolateDestAddr"];
484 - });
485 -
486 - transparentProxy = {
487 - enable = mkOption {
488 - type = types.bool;
489 - default = false;
490 - description = "Whether to enable tor transparent proxy";
491 - };
492 -
493 - listenAddress = mkOption {
494 - type = types.str;
495 - default = "127.0.0.1:9040";
496 - example = "192.168.0.1:9040";
497 - description = ''
498 - Bind transparent proxy to this address.
499 - '';
500 - };
501 -
502 - isolationOptions = mkOption isolationOptions;
503 - };
504 -
505 - dns = {
506 - enable = mkOption {
507 - type = types.bool;
508 - default = false;
509 - description = "Whether to enable tor dns resolver";
510 - };
511 -
512 - listenAddress = mkOption {
513 - type = types.str;
514 - default = "127.0.0.1:9053";
515 - example = "192.168.0.1:9053";
516 - description = ''
517 - Bind tor dns to this address.
518 - '';
519 - };
520 -
521 - isolationOptions = mkOption isolationOptions;
522 -
523 - automapHostsSuffixes = mkOption {
524 - type = types.listOf types.str;
525 - default = [".onion" ".exit"];
526 - example = [".onion"];
527 - description = "List of suffixes to use with automapHostsOnResolve";
528 + onionServices = mkOption {
529 + description = descriptionGeneric "HiddenServiceDir";
530 + default = {};
531 + example = {
532 + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" = {
533 + clientAuthorizations = ["/run/keys/tor/alice.prv.x25519"];
534 + };
535 };
536 + type = types.attrsOf (types.submodule ({name, config, ...}: {
537 + options.clientAuthorizations = mkOption {
538 + description = ''
539 + Clients' authorizations for a v3 hidden service,
540 + as a list of files containing each one private key, in the format:
541 + <screen>descriptor:x25519:&lt;base32-private-key&gt;</screen>
542 + '' + descriptionGeneric "_client_authorization";
543 + type = with types; listOf path;
544 + default = [];
545 + example = ["/run/keys/tor/alice.prv.x25519"];
546 + };
547 + }));
548 };
549 };
550
551 relay = {
552 - enable = mkOption {
553 - type = types.bool;
554 - default = false;
555 - description = ''
556 - Whether to enable relaying TOR traffic for others.
557 + enable = mkEnableOption ''relaying of Tor traffic for others.
558
559 - See <link xlink:href="https://www.torproject.org/docs/tor-doc-relay" />
560 - for details.
561 + See <link xlink:href="https://www.torproject.org/docs/tor-doc-relay" />
562 + for details.
563
564 - Setting this to true requires setting
565 - <option>services.tor.relay.role</option>
566 - and
567 - <option>services.tor.relay.port</option>
568 - options.
569 - '';
570 - };
571 + Setting this to true requires setting
572 + <option>services.tor.relay.role</option>
573 + and
574 + <option>services.tor.settings.ORPort</option>
575 + options'';
576
577 role = mkOption {
578 type = types.enum [ "exit" "relay" "bridge" "private-bridge" ];
579 @@ -310,13 +312,13 @@ in
580 <important><para>
581 Running an exit relay may expose you to abuse
582 complaints. See
583 - <link xlink:href="https://www.torproject.org/faq.html.en#ExitPolicies" />
584 + <link xlink:href="https://www.torproject.org/faq.html.en#ExitPolicies"/>
585 for more info.
586 </para></important>
587
588 <para>
589 You can specify which services Tor users may access via
590 - your exit relay using <option>exitPolicy</option> option.
591 + your exit relay using <option>settings.ExitPolicy</option> option.
592 </para>
593 </listitem>
594 </varlistentry>
595 @@ -369,15 +371,14 @@ in
596 <important>
597 <para>
598 WARNING: THE FOLLOWING PARAGRAPH IS NOT LEGAL ADVICE.
599 - Consult with your lawer when in doubt.
600 + Consult with your lawyer when in doubt.
601 </para>
602
603 <para>
604 This role should be safe to use in most situations
605 (unless the act of forwarding traffic for others is
606 a punishable offence under your local laws, which
607 - would be pretty insane as it would make ISP
608 - illegal).
609 + would be pretty insane as it would make ISP illegal).
610 </para>
611 </important>
612
613 @@ -404,7 +405,7 @@ in
614
615 <para>
616 Use this if you want to run a private bridge, for
617 - example because you'll give out your bridge address
618 + example because you'll give out your bridge addr
619 manually to your friends.
620 </para>
621
622 @@ -426,269 +427,393 @@ in
623 '';
624 };
625
626 - bridgeTransports = mkOption {
627 - type = types.listOf types.str;
628 - default = ["obfs4"];
629 - example = ["obfs2" "obfs3" "obfs4" "scramblesuit"];
630 - description = "List of pluggable transports";
631 - };
632 -
633 - nickname = mkOption {
634 - type = types.str;
635 - default = "anonymous";
636 - description = ''
637 - A unique handle for your TOR relay.
638 - '';
639 - };
640 -
641 - contactInfo = mkOption {
642 - type = types.nullOr types.str;
643 - default = null;
644 - example = "admin@relay.com";
645 - description = ''
646 - Contact information for the relay owner (e.g. a mail
647 - address and GPG key ID).
648 - '';
649 - };
650 -
651 - accountingMax = mkOption {
652 - type = types.nullOr types.str;
653 - default = null;
654 - example = "450 GBytes";
655 - description = ''
656 - Specify maximum bandwidth allowed during an accounting period. This
657 - allows you to limit overall tor bandwidth over some time period.
658 - See the <literal>AccountingMax</literal> option by looking at the
659 - tor manual <citerefentry><refentrytitle>tor</refentrytitle>
660 - <manvolnum>1</manvolnum></citerefentry> for more.
661 -
662 - Note this limit applies individually to upload and
663 - download; if you specify <literal>"500 GBytes"</literal>
664 - here, then you may transfer up to 1 TBytes of overall
665 - bandwidth (500 GB upload, 500 GB download).
666 - '';
667 - };
668 -
669 - accountingStart = mkOption {
670 - type = types.nullOr types.str;
671 - default = null;
672 - example = "month 1 1:00";
673 - description = ''
674 - Specify length of an accounting period. This allows you to limit
675 - overall tor bandwidth over some time period. See the
676 - <literal>AccountingStart</literal> option by looking at the tor
677 - manual <citerefentry><refentrytitle>tor</refentrytitle>
678 - <manvolnum>1</manvolnum></citerefentry> for more.
679 - '';
680 - };
681 -
682 - bandwidthRate = mkOption {
683 - type = types.nullOr types.int;
684 - default = null;
685 - example = 100;
686 - description = ''
687 - Specify this to limit the bandwidth usage of relayed (server)
688 - traffic. Your own traffic is still unthrottled. Units: bytes/second.
689 - '';
690 - };
691 -
692 - bandwidthBurst = mkOption {
693 - type = types.nullOr types.int;
694 - default = cfg.relay.bandwidthRate;
695 - example = 200;
696 - description = ''
697 - Specify this to allow bursts of the bandwidth usage of relayed (server)
698 - traffic. The average usage will still be as specified in relayBandwidthRate.
699 - Your own traffic is still unthrottled. Units: bytes/second.
700 - '';
701 - };
702 -
703 - address = mkOption {
704 - type = types.nullOr types.str;
705 - default = null;
706 - example = "noname.example.com";
707 - description = ''
708 - The IP address or full DNS name for advertised address of your relay.
709 - Leave unset and Tor will guess.
710 - '';
711 - };
712 -
713 - port = mkOption {
714 - type = types.either types.int types.str;
715 - example = 143;
716 - description = ''
717 - What port to advertise for Tor connections. This corresponds to the
718 - <literal>ORPort</literal> section in the Tor manual; see
719 - <citerefentry><refentrytitle>tor</refentrytitle>
720 - <manvolnum>1</manvolnum></citerefentry> for more details.
721 -
722 - At a minimum, you should just specify the port for the
723 - relay to listen on; a common one like 143, 22, 80, or 443
724 - to help Tor users who may have very restrictive port-based
725 - firewalls.
726 - '';
727 - };
728 -
729 - exitPolicy = mkOption {
730 - type = types.nullOr types.str;
731 - default = null;
732 - example = "accept *:6660-6667,reject *:*";
733 - description = ''
734 - A comma-separated list of exit policies. They're
735 - considered first to last, and the first match wins. If you
736 - want to _replace_ the default exit policy, end this with
737 - either a reject *:* or an accept *:*. Otherwise, you're
738 - _augmenting_ (prepending to) the default exit policy.
739 - Leave commented to just use the default, which is
740 - available in the man page or at
741 - <link xlink:href="https://www.torproject.org/documentation.html" />.
742 -
743 - Look at
744 - <link xlink:href="https://www.torproject.org/faq-abuse.html#TypicalAbuses" />
745 - for issues you might encounter if you use the default
746 - exit policy.
747 -
748 - If certain IPs and ports are blocked externally, e.g. by
749 - your firewall, you should update your exit policy to
750 - reflect this -- otherwise Tor users will be told that
751 - those destinations are down.
752 - '';
753 + onionServices = mkOption {
754 + description = descriptionGeneric "HiddenServiceDir";
755 + default = {};
756 + example = {
757 + "example.org/www" = {
758 + map = [ 80 ];
759 + authorizedClients = [
760 + "descriptor:x25519:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
761 + ];
762 + };
763 + };
764 + type = types.attrsOf (types.submodule ({name, config, ...}: {
765 + options.path = mkOption {
766 + type = types.path;
767 + description = ''
768 + Path where to store the data files of the hidden service.
769 + If the <option>secretKey</option> is null
770 + this defaults to <literal>${stateDir}/onion/$onion</literal>,
771 + otherwise to <literal>${runDir}/onion/$onion</literal>.
772 + '';
773 + };
774 + options.secretKey = mkOption {
775 + type = with types; nullOr path;
776 + default = null;
777 + example = "/run/keys/tor/onion/expyuzz4wqqyqhjn/hs_ed25519_secret_key";
778 + description = ''
779 + Secret key of the onion service.
780 + If null, Tor reuses any preexisting secret key (in <option>path</option>)
781 + or generates a new one.
782 + The associated public key and hostname are deterministically regenerated
783 + from this file if they do not exist.
784 + '';
785 + };
786 + options.authorizeClient = mkOption {
787 + description = descriptionGeneric "HiddenServiceAuthorizeClient";
788 + default = null;
789 + type = types.nullOr (types.submodule ({...}: {
790 + options = {
791 + authType = mkOption {
792 + type = types.enum [ "basic" "stealth" ];
793 + description = ''
794 + Either <literal>"basic"</literal> for a general-purpose authorization protocol
795 + or <literal>"stealth"</literal> for a less scalable protocol
796 + that also hides service activity from unauthorized clients.
797 + '';
798 + };
799 + clientNames = mkOption {
800 + type = with types; nonEmptyListOf (strMatching "[A-Za-z0-9+-_]+");
801 + description = ''
802 + Only clients that are listed here are authorized to access the hidden service.
803 + Generated authorization data can be found in <filename>${stateDir}/onion/$name/hostname</filename>.
804 + Clients need to put this authorization data in their configuration file using
805 + <xref linkend="opt-services.tor.settings.HidServAuth"/>.
806 + '';
807 + };
808 + };
809 + }));
810 + };
811 + options.authorizedClients = mkOption {
812 + description = ''
813 + Authorized clients for a v3 hidden service,
814 + as a list of public key, in the format:
815 + <screen>descriptor:x25519:&lt;base32-public-key&gt;</screen>
816 + '' + descriptionGeneric "_client_authorization";
817 + type = with types; listOf str;
818 + default = [];
819 + example = ["descriptor:x25519:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"];
820 + };
821 + options.map = mkOption {
822 + description = descriptionGeneric "HiddenServicePort";
823 + type = with types; listOf (oneOf [
824 + port (submodule ({...}: {
825 + options = {
826 + port = optionPort;
827 + target = mkOption {
828 + default = null;
829 + type = nullOr (submodule ({...}: {
830 + options = {
831 + unix = optionUnix;
832 + addr = optionAddress;
833 + port = optionPort;
834 + };
835 + }));
836 + };
837 + };
838 + }))
839 + ]);
840 + apply = map (v: if isInt v then {port=v; target=null;} else v);
841 + };
842 + options.version = mkOption {
843 + description = descriptionGeneric "HiddenServiceVersion";
844 + type = with types; nullOr (enum [2 3]);
845 + default = null;
846 + };
847 + options.settings = mkOption {
848 + description = ''
849 + Settings of the onion service.
850 + '' + descriptionGeneric "_hidden_service_options";
851 + default = {};
852 + type = types.submodule {
853 + freeformType = with types;
854 + (attrsOf (nullOr (oneOf [str int bool (listOf str)]))) // {
855 + description = "settings option";
856 + };
857 + options.HiddenServiceAllowUnknownPorts = optionBool "HiddenServiceAllowUnknownPorts";
858 + options.HiddenServiceDirGroupReadable = optionBool "HiddenServiceDirGroupReadable";
859 + options.HiddenServiceExportCircuitID = mkOption {
860 + description = descriptionGeneric "HiddenServiceExportCircuitID";
861 + type = with types; nullOr (enum ["haproxy"]);
862 + default = null;
863 + };
864 + options.HiddenServiceMaxStreams = mkOption {
865 + description = descriptionGeneric "HiddenServiceMaxStreams";
866 + type = with types; nullOr (ints.between 0 65535);
867 + default = null;
868 + };
869 + options.HiddenServiceMaxStreamsCloseCircuit = optionBool "HiddenServiceMaxStreamsCloseCircuit";
870 + options.HiddenServiceNumIntroductionPoints = mkOption {
871 + description = descriptionGeneric "HiddenServiceNumIntroductionPoints";
872 + type = with types; nullOr (ints.between 0 20);
873 + default = null;
874 + };
875 + options.HiddenServiceSingleHopMode = optionBool "HiddenServiceSingleHopMode";
876 + options.RendPostPeriod = optionString "RendPostPeriod";
877 + };
878 + };
879 + config = {
880 + path = mkDefault ((if config.secretKey == null then stateDir else runDir) + "/onion/${name}");
881 + settings.HiddenServiceVersion = config.version;
882 + settings.HiddenServiceAuthorizeClient =
883 + if config.authorizeClient != null then
884 + config.authorizeClient.authType + " " +
885 + concatStringsSep "," config.authorizeClient.clientNames
886 + else null;
887 + settings.HiddenServicePort = map (p: mkValueString "" p.port + " " + mkValueString "" p.target) config.map;
888 + };
889 + }));
890 };
891 };
892
893 - hiddenServices = mkOption {
894 + settings = mkOption {
895 description = ''
896 - A set of static hidden services that terminate their Tor
897 - circuits at this node.
898 -
899 - Every element in this set declares a virtual onion host.
900 -
901 - You can specify your onion address by putting corresponding
902 - private key to an appropriate place in ${torDirectory}.
903 -
904 - For services without private keys in ${torDirectory} Tor
905 - daemon will generate random key pairs (which implies random
906 - onion addresses) on restart. The latter could take a while,
907 - please be patient.
908 -
909 - <note><para>
910 - Hidden services can be useful even if you don't intend to
911 - actually <emphasis>hide</emphasis> them, since they can
912 - also be seen as a kind of NAT traversal mechanism.
913 -
914 - E.g. the example will make your sshd, whatever runs on
915 - "8080" and your mail server available from anywhere where
916 - the Tor network is available (which, with the help from
917 - bridges, is pretty much everywhere), even if both client
918 - and server machines are behind NAT you have no control
919 - over.
920 - </para></note>
921 + See <link xlink:href="https://2019.www.torproject.org/docs/tor-manual.html.en">torrc manual</link>
922 + for documentation.
923 '';
924 default = {};
925 - example = literalExample ''
926 - { "my-hidden-service-example".map = [
927 - { port = 22; } # map ssh port to this machine's ssh
928 - { port = 80; toPort = 8080; } # map http port to whatever runs on 8080
929 - { port = "sip"; toHost = "mail.example.com"; toPort = "imap"; } # because we can
930 - ];
931 - }
932 - '';
933 - type = types.attrsOf (types.submodule ({name, ...}: {
934 - options = {
935 -
936 - name = mkOption {
937 - type = types.str;
938 - description = ''
939 - Name of this tor hidden service.
940 -
941 - This is purely descriptive.
942 -
943 - After restarting Tor daemon you should be able to
944 - find your .onion address in
945 - <literal>${torDirectory}/onion/$name/hostname</literal>.
946 - '';
947 - };
948 -
949 - map = mkOption {
950 - default = [];
951 - description = "Port mapping for this hidden service.";
952 - type = types.listOf (types.submodule ({config, ...}: {
953 - options = {
954 -
955 - port = mkOption {
956 - type = types.either types.int types.str;
957 - example = 80;
958 - description = ''
959 - Hidden service port to "bind to".
960 - '';
961 - };
962 -
963 - destination = mkOption {
964 - internal = true;
965 - type = types.str;
966 - description = "Forward these connections where?";
967 - };
968 -
969 - toHost = mkOption {
970 - type = types.str;
971 - default = "127.0.0.1";
972 - description = "Mapping destination host.";
973 - };
974 -
975 - toPort = mkOption {
976 - type = types.either types.int types.str;
977 - example = 8080;
978 - description = "Mapping destination port.";
979 - };
980 -
981 - };
982 -
983 - config = {
984 - toPort = mkDefault config.port;
985 - destination = mkDefault "${config.toHost}:${toString config.toPort}";
986 - };
987 - }));
988 - };
989 -
990 - authorizeClient = mkOption {
991 - default = null;
992 - description = "If configured, the hidden service is accessible for authorized clients only.";
993 - type = types.nullOr (types.submodule ({...}: {
994 -
995 - options = {
996 -
997 - authType = mkOption {
998 - type = types.enum [ "basic" "stealth" ];
999 - description = ''
1000 - Either <literal>"basic"</literal> for a general-purpose authorization protocol
1001 - or <literal>"stealth"</literal> for a less scalable protocol
1002 - that also hides service activity from unauthorized clients.
1003 - '';
1004 - };
1005 -
1006 - clientNames = mkOption {
1007 - type = types.nonEmptyListOf (types.strMatching "[A-Za-z0-9+-_]+");
1008 - description = ''
1009 - Only clients that are listed here are authorized to access the hidden service.
1010 - Generated authorization data can be found in <filename>${torDirectory}/onion/$name/hostname</filename>.
1011 - Clients need to put this authorization data in their configuration file using <literal>HidServAuth</literal>.
1012 - '';
1013 - };
1014 - };
1015 - }));
1016 - };
1017 -
1018 - version = mkOption {
1019 - default = null;
1020 - description = "Rendezvous service descriptor version to publish for the hidden service. Currently, versions 2 and 3 are supported. (Default: 2)";
1021 - type = types.nullOr (types.enum [ 2 3 ]);
1022 - };
1023 + type = types.submodule {
1024 + freeformType = with types;
1025 + (attrsOf (nullOr (oneOf [str int bool (listOf str)]))) // {
1026 + description = "settings option";
1027 + };
1028 + options.Address = optionString "Address";
1029 + options.AssumeReachable = optionBool "AssumeReachable";
1030 + options.AccountingMax = optionBandwith "AccountingMax";
1031 + options.AccountingStart = optionString "AccountingStart";
1032 + options.AuthDirHasIPv6Connectivity = optionBool "AuthDirHasIPv6Connectivity";
1033 + options.AuthDirListBadExits = optionBool "AuthDirListBadExits";
1034 + options.AuthDirPinKeys = optionBool "AuthDirPinKeys";
1035 + options.AuthDirSharedRandomness = optionBool "AuthDirSharedRandomness";
1036 + options.AuthDirTestEd25519LinkKeys = optionBool "AuthDirTestEd25519LinkKeys";
1037 + options.AuthoritativeDirectory = optionBool "AuthoritativeDirectory";
1038 + options.AutomapHostsOnResolve = optionBool "AutomapHostsOnResolve";
1039 + options.AutomapHostsSuffixes = optionStrings "AutomapHostsSuffixes" // {
1040 + default = [".onion" ".exit"];
1041 + example = [".onion"];
1042 };
1043 -
1044 - config = {
1045 - name = mkDefault name;
1046 + options.BandwidthBurst = optionBandwith "BandwidthBurst";
1047 + options.BandwidthRate = optionBandwith "BandwidthRate";
1048 + options.BridgeAuthoritativeDir = optionBool "BridgeAuthoritativeDir";
1049 + options.BridgeRecordUsageByCountry = optionBool "BridgeRecordUsageByCountry";
1050 + options.BridgeRelay = optionBool "BridgeRelay" // { default = false; };
1051 + options.CacheDirectory = optionPath "CacheDirectory";
1052 + options.CacheDirectoryGroupReadable = optionBool "CacheDirectoryGroupReadable"; # default is null and like "auto"
1053 + options.CellStatistics = optionBool "CellStatistics";
1054 + options.ClientAutoIPv6ORPort = optionBool "ClientAutoIPv6ORPort";
1055 + options.ClientDNSRejectInternalAddresses = optionBool "ClientDNSRejectInternalAddresses";
1056 + options.ClientOnionAuthDir = mkOption {
1057 + description = descriptionGeneric "ClientOnionAuthDir";
1058 + default = null;
1059 + type = with types; nullOr path;
1060 };
1061 - }));
1062 + options.ClientPreferIPv6DirPort = optionBool "ClientPreferIPv6DirPort"; # default is null and like "auto"
1063 + options.ClientPreferIPv6ORPort = optionBool "ClientPreferIPv6ORPort"; # default is null and like "auto"
1064 + options.ClientRejectInternalAddresses = optionBool "ClientRejectInternalAddresses";
1065 + options.ClientUseIPv4 = optionBool "ClientUseIPv4";
1066 + options.ClientUseIPv6 = optionBool "ClientUseIPv6";
1067 + options.ConnDirectionStatistics = optionBool "ConnDirectionStatistics";
1068 + options.ConstrainedSockets = optionBool "ConstrainedSockets";
1069 + options.ContactInfo = optionString "ContactInfo";
1070 + options.ControlPort = mkOption rec {
1071 + description = descriptionGeneric "ControlPort";
1072 + default = [];
1073 + example = [{port = 9051;}];
1074 + type = with types; oneOf [port (enum ["auto"]) (listOf (oneOf [
1075 + port (enum ["auto"]) (submodule ({config, ...}: let
1076 + flags = ["GroupWritable" "RelaxDirModeCheck" "WorldWritable"];
1077 + in {
1078 + options = {
1079 + unix = optionUnix;
1080 + flags = optionFlags;
1081 + addr = optionAddress;
1082 + port = optionPort;
1083 + } // genAttrs flags (name: mkOption { type = types.bool; default = false; });
1084 + config = {
1085 + flags = filter (name: config.${name} == true) flags;
1086 + };
1087 + }))
1088 + ]))];
1089 + };
1090 + options.ControlPortFileGroupReadable= optionBool "ControlPortFileGroupReadable";
1091 + options.ControlPortWriteToFile = optionPath "ControlPortWriteToFile";
1092 + options.ControlSocket = optionPath "ControlSocket";
1093 + options.ControlSocketsGroupWritable = optionBool "ControlSocketsGroupWritable";
1094 + options.CookieAuthFile = optionPath "CookieAuthFile";
1095 + options.CookieAuthFileGroupReadable = optionBool "CookieAuthFileGroupReadable";
1096 + options.CookieAuthentication = optionBool "CookieAuthentication";
1097 + options.DataDirectory = optionPath "DataDirectory" // { default = stateDir; };
1098 + options.DataDirectoryGroupReadable = optionBool "DataDirectoryGroupReadable";
1099 + options.DirPortFrontPage = optionPath "DirPortFrontPage";
1100 + options.DirAllowPrivateAddresses = optionBool "DirAllowPrivateAddresses";
1101 + options.DormantCanceledByStartup = optionBool "DormantCanceledByStartup";
1102 + options.DormantOnFirstStartup = optionBool "DormantOnFirstStartup";
1103 + options.DormantTimeoutDisabledByIdleStreams = optionBool "DormantTimeoutDisabledByIdleStreams";
1104 + options.DirCache = optionBool "DirCache";
1105 + options.DirPolicy = mkOption {
1106 + description = descriptionGeneric "DirPolicy";
1107 + type = with types; listOf str;
1108 + default = [];
1109 + example = ["accept *:*"];
1110 + };
1111 + options.DirPort = optionORPort "DirPort";
1112 + options.DirReqStatistics = optionBool "DirReqStatistics";
1113 + options.DisableAllSwap = optionBool "DisableAllSwap";
1114 + options.DisableDebuggerAttachment = optionBool "DisableDebuggerAttachment";
1115 + options.DisableNetwork = optionBool "DisableNetwork";
1116 + options.DisableOOSCheck = optionBool "DisableOOSCheck";
1117 + options.DNSPort = optionIsolablePorts "DNSPort";
1118 + options.DoSCircuitCreationEnabled = optionBool "DoSCircuitCreationEnabled";
1119 + options.DoSConnectionEnabled = optionBool "DoSConnectionEnabled"; # default is null and like "auto"
1120 + options.DoSRefuseSingleHopClientRendezvous = optionBool "DoSRefuseSingleHopClientRendezvous";
1121 + options.DownloadExtraInfo = optionBool "DownloadExtraInfo";
1122 + options.EnforceDistinctSubnets = optionBool "EnforceDistinctSubnets";
1123 + options.EntryStatistics = optionBool "EntryStatistics";
1124 + options.ExitPolicy = optionStrings "ExitPolicy" // {
1125 + default = ["reject *:*"];
1126 + example = ["accept *:*"];
1127 + };
1128 + options.ExitPolicyRejectLocalInterfaces = optionBool "ExitPolicyRejectLocalInterfaces";
1129 + options.ExitPolicyRejectPrivate = optionBool "ExitPolicyRejectPrivate";
1130 + options.ExitPortStatistics = optionBool "ExitPortStatistics";
1131 + options.ExitRelay = optionBool "ExitRelay"; # default is null and like "auto"
1132 + options.ExtORPort = mkOption {
1133 + description = descriptionGeneric "ExtORPort";
1134 + default = null;
1135 + type = with types; nullOr (oneOf [
1136 + port (enum ["auto"]) (submodule ({...}: {
1137 + options = {
1138 + addr = optionAddress;
1139 + port = optionPort;
1140 + };
1141 + }))
1142 + ]);
1143 + apply = p: if isInt p || isString p then { port = p; } else p;
1144 + };
1145 + options.ExtORPortCookieAuthFile = optionPath "ExtORPortCookieAuthFile";
1146 + options.ExtORPortCookieAuthFileGroupReadable = optionBool "ExtORPortCookieAuthFileGroupReadable";
1147 + options.ExtendAllowPrivateAddresses = optionBool "ExtendAllowPrivateAddresses";
1148 + options.ExtraInfoStatistics = optionBool "ExtraInfoStatistics";
1149 + options.FascistFirewall = optionBool "FascistFirewall";
1150 + options.FetchDirInfoEarly = optionBool "FetchDirInfoEarly";
1151 + options.FetchDirInfoExtraEarly = optionBool "FetchDirInfoExtraEarly";
1152 + options.FetchHidServDescriptors = optionBool "FetchHidServDescriptors";
1153 + options.FetchServerDescriptors = optionBool "FetchServerDescriptors";
1154 + options.FetchUselessDescriptors = optionBool "FetchUselessDescriptors";
1155 + options.ReachableAddresses = optionStrings "ReachableAddresses";
1156 + options.ReachableDirAddresses = optionStrings "ReachableDirAddresses";
1157 + options.ReachableORAddresses = optionStrings "ReachableORAddresses";
1158 + options.GeoIPFile = optionPath "GeoIPFile";
1159 + options.GeoIPv6File = optionPath "GeoIPv6File";
1160 + options.GuardfractionFile = optionPath "GuardfractionFile";
1161 + options.HidServAuth = mkOption {
1162 + description = descriptionGeneric "HidServAuth";
1163 + default = [];
1164 + type = with types; listOf (oneOf [
1165 + (submodule {
1166 + options = {
1167 + onion = mkOption {
1168 + type = strMatching "[a-z2-7]{16}(\\.onion)?";
1169 + description = "Onion address.";
1170 + example = "xxxxxxxxxxxxxxxx.onion";
1171 + };
1172 + auth = mkOption {
1173 + type = strMatching "[A-Za-z0-9+/]{22}";
1174 + description = "Authentication cookie.";
1175 + };
1176 + };
1177 + })
1178 + ]);
1179 + };
1180 + options.HiddenServiceNonAnonymousMode = optionBool "HiddenServiceNonAnonymousMode";
1181 + options.HiddenServiceStatistics = optionBool "HiddenServiceStatistics";
1182 + options.HSLayer2Nodes = optionStrings "HSLayer2Nodes";
1183 + options.HSLayer3Nodes = optionStrings "HSLayer3Nodes";
1184 + options.HTTPTunnelPort = optionIsolablePorts "HTTPTunnelPort";
1185 + options.IPv6Exit = optionBool "IPv6Exit";
1186 + options.KeyDirectory = optionPath "KeyDirectory";
1187 + options.KeyDirectoryGroupReadable = optionBool "KeyDirectoryGroupReadable";
1188 + options.LogMessageDomains = optionBool "LogMessageDomains";
1189 + options.LongLivedPorts = optionPorts "LongLivedPorts";
1190 + options.MainloopStats = optionBool "MainloopStats";
1191 + options.MaxAdvertisedBandwidth = optionBandwith "MaxAdvertisedBandwidth";
1192 + options.MaxCircuitDirtiness = optionInt "MaxCircuitDirtiness";
1193 + options.MaxClientCircuitsPending = optionInt "MaxClientCircuitsPending";
1194 + options.NATDPort = optionIsolablePorts "NATDPort";
1195 + options.NewCircuitPeriod = optionInt "NewCircuitPeriod";
1196 + options.Nickname = optionString "Nickname";
1197 + options.ORPort = optionORPort "ORPort";
1198 + options.OfflineMasterKey = optionBool "OfflineMasterKey";
1199 + options.OptimisticData = optionBool "OptimisticData"; # default is null and like "auto"
1200 + options.PaddingStatistics = optionBool "PaddingStatistics";
1201 + options.PerConnBWBurst = optionBandwith "PerConnBWBurst";
1202 + options.PerConnBWRate = optionBandwith "PerConnBWRate";
1203 + options.PidFile = optionPath "PidFile";
1204 + options.ProtocolWarnings = optionBool "ProtocolWarnings";
1205 + options.PublishHidServDescriptors = optionBool "PublishHidServDescriptors";
1206 + options.PublishServerDescriptor = mkOption {
1207 + description = descriptionGeneric "PublishServerDescriptor";
1208 + type = with types; nullOr (enum [false true 0 1 "0" "1" "v3" "bridge"]);
1209 + default = null;
1210 + };
1211 + options.ReducedExitPolicy = optionBool "ReducedExitPolicy";
1212 + options.RefuseUnknownExits = optionBool "RefuseUnknownExits"; # default is null and like "auto"
1213 + options.RejectPlaintextPorts = optionPorts "RejectPlaintextPorts";
1214 + options.RelayBandwidthBurst = optionBandwith "RelayBandwidthBurst";
1215 + options.RelayBandwidthRate = optionBandwith "RelayBandwidthRate";
1216 + #options.RunAsDaemon
1217 + options.Sandbox = optionBool "Sandbox";
1218 + options.ServerDNSAllowBrokenConfig = optionBool "ServerDNSAllowBrokenConfig";
1219 + options.ServerDNSAllowNonRFC953Hostnames = optionBool "ServerDNSAllowNonRFC953Hostnames";
1220 + options.ServerDNSDetectHijacking = optionBool "ServerDNSDetectHijacking";
1221 + options.ServerDNSRandomizeCase = optionBool "ServerDNSRandomizeCase";
1222 + options.ServerDNSResolvConfFile = optionPath "ServerDNSResolvConfFile";
1223 + options.ServerDNSSearchDomains = optionBool "ServerDNSSearchDomains";
1224 + options.ServerTransportPlugin = mkOption {
1225 + description = descriptionGeneric "ServerTransportPlugin";
1226 + default = null;
1227 + type = with types; nullOr (submodule ({...}: {
1228 + options = {
1229 + transports = mkOption {
1230 + description = "List of pluggable transports.";
1231 + type = listOf str;
1232 + example = ["obfs2" "obfs3" "obfs4" "scramblesuit"];
1233 + };
1234 + exec = mkOption {
1235 + type = types.str;
1236 + description = "Command of pluggable transport.";
1237 + };
1238 + };
1239 + }));
1240 + };
1241 + options.SocksPolicy = optionStrings "SocksPolicy" // {
1242 + example = ["accept *:*"];
1243 + };
1244 + options.SOCKSPort = mkOption {
1245 + description = descriptionGeneric "SOCKSPort";
1246 + default = if cfg.settings.HiddenServiceNonAnonymousMode == true then [{port = 0;}] else [];
1247 + example = [{port = 9090;}];
1248 + type = types.listOf (optionSOCKSPort true);
1249 + };
1250 + options.TestingTorNetwork = optionBool "TestingTorNetwork";
1251 + options.TransPort = optionIsolablePorts "TransPort";
1252 + options.TransProxyType = mkOption {
1253 + description = descriptionGeneric "TransProxyType";
1254 + type = with types; nullOr (enum ["default" "TPROXY" "ipfw" "pf-divert"]);
1255 + default = null;
1256 + };
1257 + #options.TruncateLogFile
1258 + options.UnixSocksGroupWritable = optionBool "UnixSocksGroupWritable";
1259 + options.UseDefaultFallbackDirs = optionBool "UseDefaultFallbackDirs";
1260 + options.UseMicrodescriptors = optionBool "UseMicrodescriptors";
1261 + options.V3AuthUseLegacyKey = optionBool "V3AuthUseLegacyKey";
1262 + options.V3AuthoritativeDirectory = optionBool "V3AuthoritativeDirectory";
1263 + options.VersioningAuthoritativeDirectory = optionBool "VersioningAuthoritativeDirectory";
1264 + options.VirtualAddrNetworkIPv4 = optionString "VirtualAddrNetworkIPv4";
1265 + options.VirtualAddrNetworkIPv6 = optionString "VirtualAddrNetworkIPv6";
1266 + options.WarnPlaintextPorts = optionPorts "WarnPlaintextPorts";
1267 + };
1268 };
1269 };
1270 };
1271 @@ -696,79 +821,217 @@ in
1272 config = mkIf cfg.enable {
1273 # Not sure if `cfg.relay.role == "private-bridge"` helps as tor
1274 # sends a lot of stats
1275 - warnings = optional (cfg.relay.enable && cfg.hiddenServices != {})
1276 + warnings = optional (cfg.settings.BridgeRelay &&
1277 + flatten (mapAttrsToList (n: o: o.map) cfg.relay.onionServices) != [])
1278 ''
1279 Running Tor hidden services on a public relay makes the
1280 presence of hidden services visible through simple statistical
1281 analysis of publicly available data.
1282 + See https://trac.torproject.org/projects/tor/ticket/8742
1283
1284 You can safely ignore this warning if you don't intend to
1285 actually hide your hidden services. In either case, you can
1286 always create a container/VM with a separate Tor daemon instance.
1287 - '';
1288 + '' ++
1289 + flatten (mapAttrsToList (n: o:
1290 + optional (o.settings.HiddenServiceVersion == 2) [
1291 + (optional (o.settings.HiddenServiceExportCircuitID != null) ''
1292 + HiddenServiceExportCircuitID is used in the HiddenService: ${n}
1293 + but this option is only for v3 hidden services.
1294 + '')
1295 + ] ++
1296 + optional (o.settings.HiddenServiceVersion != 2) [
1297 + (optional (o.settings.HiddenServiceAuthorizeClient != null) ''
1298 + HiddenServiceAuthorizeClient is used in the HiddenService: ${n}
1299 + but this option is only for v2 hidden services.
1300 + '')
1301 + (optional (o.settings.RendPostPeriod != null) ''
1302 + RendPostPeriod is used in the HiddenService: ${n}
1303 + but this option is only for v2 hidden services.
1304 + '')
1305 + ]
1306 + ) cfg.relay.onionServices);
1307
1308 users.groups.tor.gid = config.ids.gids.tor;
1309 users.users.tor =
1310 { description = "Tor Daemon User";
1311 createHome = true;
1312 - home = torDirectory;
1313 + home = stateDir;
1314 group = "tor";
1315 uid = config.ids.uids.tor;
1316 };
1317
1318 - # We have to do this instead of using RuntimeDirectory option in
1319 - # the service below because systemd has no way to set owners of
1320 - # RuntimeDirectory and putting this into the service below
1321 - # requires that service to relax it's sandbox since this needs
1322 - # writable /run
1323 - systemd.services.tor-init =
1324 - { description = "Tor Daemon Init";
1325 - wantedBy = [ "tor.service" ];
1326 - script = ''
1327 - install -m 0700 -o tor -g tor -d ${torDirectory} ${torDirectory}/onion
1328 - install -m 0750 -o tor -g tor -d ${torRunDirectory}
1329 - '';
1330 - serviceConfig = {
1331 - Type = "oneshot";
1332 - RemainAfterExit = true;
1333 - };
1334 - };
1335 -
1336 - systemd.services.tor =
1337 - { description = "Tor Daemon";
1338 - path = [ pkgs.tor ];
1339 -
1340 - wantedBy = [ "multi-user.target" ];
1341 - after = [ "tor-init.service" "network.target" ];
1342 - restartTriggers = [ torRcFile ];
1343 -
1344 - serviceConfig =
1345 - { Type = "simple";
1346 - # Translated from the upstream contrib/dist/tor.service.in
1347 - ExecStartPre = "${cfg.package}/bin/tor -f ${torRcFile} --verify-config";
1348 - ExecStart = "${cfg.package}/bin/tor -f ${torRcFile}";
1349 - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
1350 - KillSignal = "SIGINT";
1351 - TimeoutSec = 30;
1352 - Restart = "on-failure";
1353 - LimitNOFILE = 32768;
1354 -
1355 - # Hardening
1356 - # this seems to unshare /run despite what systemd.exec(5) says
1357 - PrivateTmp = mkIf (!cfg.controlSocket.enable) "yes";
1358 - PrivateDevices = "yes";
1359 - ProtectHome = "yes";
1360 - ProtectSystem = "strict";
1361 - InaccessiblePaths = "/home";
1362 - ReadOnlyPaths = "/";
1363 - ReadWritePaths = [ torDirectory torRunDirectory ];
1364 - NoNewPrivileges = "yes";
1365 -
1366 - # tor.service.in has this in, but this line it fails to spawn a namespace when using hidden services
1367 - #CapabilityBoundingSet = "CAP_SETUID CAP_SETGID CAP_NET_BIND_SERVICE";
1368 - };
1369 + services.tor.settings = mkMerge [
1370 + (mkIf cfg.enableGeoIP {
1371 + GeoIPFile = "${cfg.package.geoip}/share/tor/geoip";
1372 + GeoIPv6File = "${cfg.package.geoip}/share/tor/geoip6";
1373 + })
1374 + (mkIf cfg.controlSocket.enable {
1375 + ControlPort = [ { unix = runDir + "/control"; GroupWritable=true; RelaxDirModeCheck=true; } ];
1376 + })
1377 + (mkIf cfg.relay.enable (
1378 + optionalAttrs (cfg.relay.role != "exit") {
1379 + ExitPolicy = mkForce ["reject *:*"];
1380 + } //
1381 + optionalAttrs (elem cfg.relay.role ["bridge" "private-bridge"]) {
1382 + BridgeRelay = true;
1383 + ExtORPort.port = mkDefault "auto";
1384 + ServerTransportPlugin.transports = mkDefault ["obfs4"];
1385 + ServerTransportPlugin.exec = mkDefault "${pkgs.obfs4}/bin/obfs4proxy managed";
1386 + } // optionalAttrs (cfg.relay.role == "private-bridge") {
1387 + ExtraInfoStatistics = false;
1388 + PublishServerDescriptor = false;
1389 + }
1390 + ))
1391 + (mkIf (!cfg.relay.enable) {
1392 + # Avoid surprises when leaving ORPort/DirPort configurations in cfg.settings,
1393 + # because it would still enable Tor as a relay,
1394 + # which can trigger all sort of problems when not carefully done,
1395 + # like the blocklisting of the machine's IP addresses
1396 + # by some hosting providers...
1397 + DirPort = mkForce [];
1398 + ORPort = mkForce [];
1399 + PublishServerDescriptor = mkForce false;
1400 + })
1401 + (mkIf cfg.client.enable (
1402 + { SOCKSPort = [ cfg.client.socksListenAddress ];
1403 + } // optionalAttrs cfg.client.transparentProxy.enable {
1404 + TransPort = [{ addr = "127.0.0.1"; port = 9040; }];
1405 + } // optionalAttrs cfg.client.dns.enable {
1406 + DNSPort = [{ addr = "127.0.0.1"; port = 9053; }];
1407 + AutomapHostsOnResolve = true;
1408 + AutomapHostsSuffixes = cfg.client.dns.automapHostsSuffixes;
1409 + } // optionalAttrs (flatten (mapAttrsToList (n: o: o.clientAuthorizations) cfg.client.onionServices) != []) {
1410 + ClientOnionAuthDir = runDir + "/ClientOnionAuthDir";
1411 + }
1412 + ))
1413 + ];
1414 +
1415 + networking.firewall = mkIf cfg.openFirewall {
1416 + allowedTCPPorts =
1417 + concatMap (o: optional (isInt o && o > 0 || o ? "port" && isInt o.port && o.port > 0) o.port)
1418 + (flatten [
1419 + cfg.settings.ORPort
1420 + cfg.settings.DirPort
1421 + ]);
1422 + };
1423 +
1424 + systemd.services.tor = {
1425 + description = "Tor Daemon";
1426 + path = [ pkgs.tor ];
1427 +
1428 + wantedBy = [ "multi-user.target" ];
1429 + after = [ "network.target" ];
1430 + restartTriggers = [ torrc ];
1431 +
1432 + serviceConfig = {
1433 + Type = "simple";
1434 + User = "tor";
1435 + Group = "tor";
1436 + ExecStartPre = [
1437 + "${cfg.package}/bin/tor -f ${torrc} --verify-config"
1438 + # DOC: Appendix G of https://spec.torproject.org/rend-spec-v3
1439 + ("+" + pkgs.writeShellScript "ExecStartPre" (concatStringsSep "\n" (flatten (["set -eu"] ++
1440 + mapAttrsToList (name: onion:
1441 + optional (onion.authorizedClients != []) ''
1442 + rm -rf ${escapeShellArg onion.path}/authorized_clients
1443 + install -d -o tor -g tor -m 0700 ${escapeShellArg onion.path} ${escapeShellArg onion.path}/authorized_clients
1444 + '' ++
1445 + imap0 (i: pubKey: ''
1446 + echo ${pubKey} |
1447 + install -o tor -g tor -m 0400 /dev/stdin ${escapeShellArg onion.path}/authorized_clients/${toString i}.auth
1448 + '') onion.authorizedClients ++
1449 + optional (onion.secretKey != null) ''
1450 + install -d -o tor -g tor -m 0700 ${escapeShellArg onion.path}
1451 + key="$(cut -f1 -d: ${escapeShellArg onion.secretKey})"
1452 + case "$key" in
1453 + ("== ed25519v"*"-secret")
1454 + install -o tor -g tor -m 0400 ${escapeShellArg onion.secretKey} ${escapeShellArg onion.path}/hs_ed25519_secret_key;;
1455 + (*) echo >&2 "NixOS does not (yet) support secret key type for onion: ${name}"; exit 1;;
1456 + esac
1457 + ''
1458 + ) cfg.relay.onionServices ++
1459 + mapAttrsToList (name: onion: imap0 (i: prvKeyPath:
1460 + let hostname = removeSuffix ".onion" name; in ''
1461 + printf "%s:" ${escapeShellArg hostname} | cat - ${escapeShellArg prvKeyPath} |
1462 + install -o tor -g tor -m 0700 /dev/stdin \
1463 + ${runDir}/ClientOnionAuthDir/${escapeShellArg hostname}.${toString i}.auth_private
1464 + '') onion.clientAuthorizations)
1465 + cfg.client.onionServices
1466 + ))))
1467 + ];
1468 + ExecStart = "${cfg.package}/bin/tor -f ${torrc}";
1469 + ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
1470 + KillSignal = "SIGINT";
1471 + TimeoutSec = 30;
1472 + Restart = "on-failure";
1473 + LimitNOFILE = 32768;
1474 + RuntimeDirectory = [
1475 + # g+x allows access to the control socket
1476 + "tor"
1477 + "tor/root"
1478 + # g+x can't be removed in ExecStart=, but will be removed by Tor
1479 + "tor/ClientOnionAuthDir"
1480 + ];
1481 + RuntimeDirectoryMode = "0710";
1482 + StateDirectoryMode = "0700";
1483 + StateDirectory = [
1484 + "tor"
1485 + "tor/onion"
1486 + ] ++
1487 + flatten (mapAttrsToList (name: onion:
1488 + optional (onion.secretKey == null) "tor/onion/${name}"
1489 + ) cfg.relay.onionServices);
1490 + # The following options are only to optimize:
1491 + # systemd-analyze security tor
1492 + RootDirectory = runDir + "/root";
1493 + RootDirectoryStartOnly = true;
1494 + #InaccessiblePaths = [ "-+${runDir}/root" ];
1495 + UMask = "0066";
1496 + BindPaths = [ stateDir ];
1497 + BindReadOnlyPaths = [ storeDir "/etc" ];
1498 + AmbientCapabilities = [""] ++ lib.optional bindsPrivilegedPort "CAP_NET_BIND_SERVICE";
1499 + CapabilityBoundingSet = [""] ++ lib.optional bindsPrivilegedPort "CAP_NET_BIND_SERVICE";
1500 + # ProtectClock= adds DeviceAllow=char-rtc r
1501 + DeviceAllow = "";
1502 + LockPersonality = true;
1503 + MemoryDenyWriteExecute = true;
1504 + NoNewPrivileges = true;
1505 + PrivateDevices = true;
1506 + PrivateMounts = true;
1507 + PrivateNetwork = mkDefault false;
1508 + PrivateTmp = true;
1509 + # Tor cannot currently bind privileged port when PrivateUsers=true,
1510 + # see https://gitlab.torproject.org/legacy/trac/-/issues/20930
1511 + PrivateUsers = !bindsPrivilegedPort;
1512 + ProtectClock = true;
1513 + ProtectControlGroups = true;
1514 + ProtectHome = true;
1515 + ProtectHostname = true;
1516 + ProtectKernelLogs = true;
1517 + ProtectKernelModules = true;
1518 + ProtectKernelTunables = true;
1519 + ProtectSystem = "strict";
1520 + RemoveIPC = true;
1521 + RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
1522 + RestrictNamespaces = true;
1523 + RestrictRealtime = true;
1524 + RestrictSUIDSGID = true;
1525 + # See also the finer but experimental option settings.Sandbox
1526 + SystemCallFilter = [
1527 + "@system-service"
1528 + # Groups in @system-service which do not contain a syscall listed by:
1529 + # perf stat -x, 2>perf.log -e 'syscalls:sys_enter_*' tor
1530 + # in tests, and seem likely not necessary for tor.
1531 + "~@aio" "~@chown" "~@keyring" "~@memlock" "~@resources" "~@setuid" "~@timer"
1532 + ];
1533 + SystemCallArchitectures = "native";
1534 + SystemCallErrorNumber = "EPERM";
1535 };
1536 + };
1537
1538 environment.systemPackages = [ cfg.package ];
1539 };
1540 +
1541 + meta.maintainers = with lib.maintainers; [ julm ];
1542 }
1543 diff --git a/nixos/tests/tor.nix b/nixos/tests/tor.nix
1544 index ad07231557c..c061f59226c 100644
1545 --- a/nixos/tests/tor.nix
1546 +++ b/nixos/tests/tor.nix
1547 @@ -17,7 +17,7 @@ rec {
1548 environment.systemPackages = with pkgs; [ netcat ];
1549 services.tor.enable = true;
1550 services.tor.client.enable = true;
1551 - services.tor.controlPort = 9051;
1552 + services.tor.settings.ControlPort = 9051;
1553 };
1554
1555 testScript = ''
1556 diff --git a/pkgs/tools/security/tor/default.nix b/pkgs/tools/security/tor/default.nix
1557 index 04bf598d132..e46fd4790a3 100644
1558 --- a/pkgs/tools/security/tor/default.nix
1559 +++ b/pkgs/tools/security/tor/default.nix
1560 @@ -1,5 +1,6 @@
1561 { stdenv, fetchurl, pkgconfig, libevent, openssl, zlib, torsocks
1562 , libseccomp, systemd, libcap, lzma, zstd, scrypt, nixosTests
1563 +, writeShellScript
1564
1565 # for update.nix
1566 , writeScript
1567 @@ -12,7 +13,21 @@
1568 , gnused
1569 , nix
1570 }:
1571 +let
1572 + tor-client-auth-gen = writeShellScript "tor-client-auth-gen" ''
1573 + PATH="${stdenv.lib.makeBinPath [coreutils gnugrep openssl]}"
1574 + pem="$(openssl genpkey -algorithm x25519)"
1575
1576 + printf private_key=descriptor:x25519:
1577 + echo "$pem" | grep -v " PRIVATE KEY" |
1578 + base64 -d | tail --bytes=32 | base32 | tr -d =
1579 +
1580 + printf public_key=descriptor:x25519:
1581 + echo "$pem" | openssl pkey -in /dev/stdin -pubout |
1582 + grep -v " PUBLIC KEY" |
1583 + base64 -d | tail --bytes=32 | base32 | tr -d =
1584 + '';
1585 +in
1586 stdenv.mkDerivation rec {
1587 pname = "tor";
1588 version = "0.4.4.6";
1589 @@ -52,6 +67,7 @@ stdenv.mkDerivation rec {
1590 mkdir -p $geoip/share/tor
1591 mv $out/share/tor/geoip{,6} $geoip/share/tor
1592 rm -rf $out/share/tor
1593 + ln -s ${tor-client-auth-gen} $out/bin/tor-client-auth-gen
1594 '';
1595
1596 passthru = {