]> Git — Sourcephile - sourcephile-nix.git/blob - nixos/modules/services/security/tor.nix
tor: preparation
[sourcephile-nix.git] / nixos / modules / services / security / tor.nix
1 { config, lib, pkgs, ... }:
2
3 with lib;
4
5 let
6 cfg = config.services.tor;
7 torDirectory = "/var/lib/tor";
8 torRunDirectory = "/run/tor";
9
10 opt = name: value: optionalString (value != null) "${name} ${value}";
11 optint = name: value: optionalString (value != null && value != 0) "${name} ${toString value}";
12
13 isolationOptions = {
14 type = types.listOf (types.enum [
15 "IsolateClientAddr"
16 "IsolateSOCKSAuth"
17 "IsolateClientProtocol"
18 "IsolateDestPort"
19 "IsolateDestAddr"
20 ]);
21 default = [];
22 example = [
23 "IsolateClientAddr"
24 "IsolateSOCKSAuth"
25 "IsolateClientProtocol"
26 "IsolateDestPort"
27 "IsolateDestAddr"
28 ];
29 description = "Tor isolation options";
30 };
31
32
33 torRc = ''
34 User tor
35 DataDirectory ${torDirectory}
36 ${optionalString cfg.enableGeoIP ''
37 GeoIPFile ${cfg.package.geoip}/share/tor/geoip
38 GeoIPv6File ${cfg.package.geoip}/share/tor/geoip6
39 ''}
40
41 ${optint "ControlPort" cfg.controlPort}
42 ${optionalString cfg.controlSocket.enable "ControlPort unix:${torRunDirectory}/control GroupWritable RelaxDirModeCheck"}
43 ''
44 # Client connection config
45 + optionalString cfg.client.enable ''
46 SOCKSPort ${cfg.client.socksListenAddress} ${toString cfg.client.socksIsolationOptions}
47 SOCKSPort ${cfg.client.socksListenAddressFaster}
48 ${opt "SocksPolicy" cfg.client.socksPolicy}
49
50 ${optionalString cfg.client.transparentProxy.enable ''
51 TransPort ${cfg.client.transparentProxy.listenAddress} ${toString cfg.client.transparentProxy.isolationOptions}
52 ''}
53
54 ${optionalString cfg.client.dns.enable ''
55 DNSPort ${cfg.client.dns.listenAddress} ${toString cfg.client.dns.isolationOptions}
56 AutomapHostsOnResolve 1
57 AutomapHostsSuffixes ${concatStringsSep "," cfg.client.dns.automapHostsSuffixes}
58 ''}
59 ''
60 # Explicitly disable the SOCKS server if the client is disabled. In
61 # particular, this makes non-anonymous hidden services possible.
62 + optionalString (! cfg.client.enable) ''
63 SOCKSPort 0
64 ''
65 # Relay config
66 + optionalString cfg.relay.enable ''
67 ORPort ${toString cfg.relay.port}
68 ${opt "Address" cfg.relay.address}
69 ${opt "Nickname" cfg.relay.nickname}
70 ${opt "ContactInfo" cfg.relay.contactInfo}
71
72 ${optint "RelayBandwidthRate" cfg.relay.bandwidthRate}
73 ${optint "RelayBandwidthBurst" cfg.relay.bandwidthBurst}
74 ${opt "AccountingMax" cfg.relay.accountingMax}
75 ${opt "AccountingStart" cfg.relay.accountingStart}
76
77 ${if (cfg.relay.role == "exit") then
78 opt "ExitPolicy" cfg.relay.exitPolicy
79 else
80 "ExitPolicy reject *:*"}
81
82 ${optionalString (elem cfg.relay.role ["bridge" "private-bridge"]) ''
83 BridgeRelay 1
84 ServerTransportPlugin ${concatStringsSep "," cfg.relay.bridgeTransports} exec ${pkgs.obfs4}/bin/obfs4proxy managed
85 ExtORPort auto
86 ${optionalString (cfg.relay.role == "private-bridge") ''
87 ExtraInfoStatistics 0
88 PublishServerDescriptor 0
89 ''}
90 ''}
91 ''
92 # Hidden services
93 + concatStrings (flip mapAttrsToList cfg.hiddenServices (n: v: ''
94 HiddenServiceDir ${torDirectory}/onion/${v.name}
95 ${optionalString (v.version != null) "HiddenServiceVersion ${toString v.version}"}
96 ${flip concatMapStrings v.map (p: ''
97 HiddenServicePort ${toString p.port} ${p.destination}
98 '')}
99 ${optionalString (v.authorizeClient != null) ''
100 HiddenServiceAuthorizeClient ${v.authorizeClient.authType} ${concatStringsSep "," v.authorizeClient.clientNames}
101 ''}
102 ''))
103 + cfg.extraConfig;
104
105 torRcFile = pkgs.writeText "torrc" torRc;
106
107 in
108 {
109 imports = [
110 (mkRenamedOptionModule [ "services" "tor" "relay" "portSpec" ] [ "services" "tor" "relay" "port" ])
111 (mkRemovedOptionModule [ "services" "tor" "relay" "isBridge" ] "Use services.tor.relay.role instead.")
112 (mkRemovedOptionModule [ "services" "tor" "relay" "isExit" ] "Use services.tor.relay.role instead.")
113 ];
114
115 options = {
116 services.tor = {
117 enable = mkOption {
118 type = types.bool;
119 default = false;
120 description = ''
121 Enable the Tor daemon. By default, the daemon is run without
122 relay, exit, bridge or client connectivity.
123 '';
124 };
125
126 package = mkOption {
127 type = types.package;
128 default = pkgs.tor;
129 defaultText = "pkgs.tor";
130 example = literalExample "pkgs.tor";
131 description = ''
132 Tor package to use
133 '';
134 };
135
136 enableGeoIP = mkOption {
137 type = types.bool;
138 default = true;
139 description = ''
140 Whenever to configure Tor daemon to use GeoIP databases.
141
142 Disabling this will disable by-country statistics for
143 bridges and relays and some client and third-party software
144 functionality.
145 '';
146 };
147
148 extraConfig = mkOption {
149 type = types.lines;
150 default = "";
151 description = ''
152 Extra configuration. Contents will be added verbatim to the
153 configuration file at the end.
154 '';
155 };
156
157 controlPort = mkOption {
158 type = types.nullOr (types.either types.int types.str);
159 default = null;
160 example = 9051;
161 description = ''
162 If set, Tor will accept connections on the specified port
163 and allow them to control the tor process.
164 '';
165 };
166
167 controlSocket = {
168 enable = mkOption {
169 type = types.bool;
170 default = false;
171 description = ''
172 Whether to enable Tor control socket. Control socket is created
173 in <literal>${torRunDirectory}/control</literal>
174 '';
175 };
176 };
177
178 client = {
179 enable = mkOption {
180 type = types.bool;
181 default = false;
182 description = ''
183 Whether to enable Tor daemon to route application
184 connections. You might want to disable this if you plan
185 running a dedicated Tor relay.
186 '';
187 };
188
189 socksListenAddress = mkOption {
190 type = types.str;
191 default = "127.0.0.1:9050";
192 example = "192.168.0.1:9100";
193 description = ''
194 Bind to this address to listen for connections from
195 Socks-speaking applications. Provides strong circuit
196 isolation, separate circuit per IP address.
197 '';
198 };
199
200 socksListenAddressFaster = mkOption {
201 type = types.str;
202 default = "127.0.0.1:9063";
203 example = "192.168.0.1:9101";
204 description = ''
205 Bind to this address to listen for connections from
206 Socks-speaking applications. Same as
207 <option>socksListenAddress</option> but uses weaker
208 circuit isolation to provide performance suitable for a
209 web browser.
210 '';
211 };
212
213 socksPolicy = mkOption {
214 type = types.nullOr types.str;
215 default = null;
216 example = "accept 192.168.0.0/16, reject *";
217 description = ''
218 Entry policies to allow/deny SOCKS requests based on IP
219 address. First entry that matches wins. If no SocksPolicy
220 is set, we accept all (and only) requests from
221 <option>socksListenAddress</option>.
222 '';
223 };
224
225 socksIsolationOptions = mkOption (isolationOptions // {
226 default = ["IsolateDestAddr"];
227 });
228
229 transparentProxy = {
230 enable = mkOption {
231 type = types.bool;
232 default = false;
233 description = "Whether to enable tor transparent proxy";
234 };
235
236 listenAddress = mkOption {
237 type = types.str;
238 default = "127.0.0.1:9040";
239 example = "192.168.0.1:9040";
240 description = ''
241 Bind transparent proxy to this address.
242 '';
243 };
244
245 isolationOptions = mkOption isolationOptions;
246 };
247
248 dns = {
249 enable = mkOption {
250 type = types.bool;
251 default = false;
252 description = "Whether to enable tor dns resolver";
253 };
254
255 listenAddress = mkOption {
256 type = types.str;
257 default = "127.0.0.1:9053";
258 example = "192.168.0.1:9053";
259 description = ''
260 Bind tor dns to this address.
261 '';
262 };
263
264 isolationOptions = mkOption isolationOptions;
265
266 automapHostsSuffixes = mkOption {
267 type = types.listOf types.str;
268 default = [".onion" ".exit"];
269 example = [".onion"];
270 description = "List of suffixes to use with automapHostsOnResolve";
271 };
272 };
273
274 privoxy.enable = mkOption {
275 type = types.bool;
276 default = true;
277 description = ''
278 Whether to enable and configure the system Privoxy to use Tor's
279 faster port, suitable for HTTP.
280
281 To have anonymity, protocols need to be scrubbed of identifying
282 information, and this can be accomplished for HTTP by Privoxy.
283
284 Privoxy can also be useful for KDE torification. A good setup would be:
285 setting SOCKS proxy to the default Tor port, providing maximum
286 circuit isolation where possible; and setting HTTP proxy to Privoxy
287 to route HTTP traffic over faster, but less isolated port.
288 '';
289 };
290 };
291
292 relay = {
293 enable = mkOption {
294 type = types.bool;
295 default = false;
296 description = ''
297 Whether to enable relaying TOR traffic for others.
298
299 See <link xlink:href="https://www.torproject.org/docs/tor-doc-relay" />
300 for details.
301
302 Setting this to true requires setting
303 <option>services.tor.relay.role</option>
304 and
305 <option>services.tor.relay.port</option>
306 options.
307 '';
308 };
309
310 role = mkOption {
311 type = types.enum [ "exit" "relay" "bridge" "private-bridge" ];
312 description = ''
313 Your role in Tor network. There're several options:
314
315 <variablelist>
316 <varlistentry>
317 <term><literal>exit</literal></term>
318 <listitem>
319 <para>
320 An exit relay. This allows Tor users to access regular
321 Internet services through your public IP.
322 </para>
323
324 <important><para>
325 Running an exit relay may expose you to abuse
326 complaints. See
327 <link xlink:href="https://www.torproject.org/faq.html.en#ExitPolicies" />
328 for more info.
329 </para></important>
330
331 <para>
332 You can specify which services Tor users may access via
333 your exit relay using <option>exitPolicy</option> option.
334 </para>
335 </listitem>
336 </varlistentry>
337
338 <varlistentry>
339 <term><literal>relay</literal></term>
340 <listitem>
341 <para>
342 Regular relay. This allows Tor users to relay onion
343 traffic to other Tor nodes, but not to public
344 Internet.
345 </para>
346
347 <important><para>
348 Note that some misconfigured and/or disrespectful
349 towards privacy sites will block you even if your
350 relay is not an exit relay. That is, just being listed
351 in a public relay directory can have unwanted
352 consequences.
353
354 Which means you might not want to use
355 this role if you browse public Internet from the same
356 network as your relay, unless you want to write
357 e-mails to those sites (you should!).
358 </para></important>
359
360 <para>
361 See
362 <link xlink:href="https://www.torproject.org/docs/tor-doc-relay.html.en" />
363 for more info.
364 </para>
365 </listitem>
366 </varlistentry>
367
368 <varlistentry>
369 <term><literal>bridge</literal></term>
370 <listitem>
371 <para>
372 Regular bridge. Works like a regular relay, but
373 doesn't list you in the public relay directory and
374 hides your Tor node behind obfs4proxy.
375 </para>
376
377 <para>
378 Using this option will make Tor advertise your bridge
379 to users through various mechanisms like
380 <link xlink:href="https://bridges.torproject.org/" />, though.
381 </para>
382
383 <important>
384 <para>
385 WARNING: THE FOLLOWING PARAGRAPH IS NOT LEGAL ADVICE.
386 Consult with your lawer when in doubt.
387 </para>
388
389 <para>
390 This role should be safe to use in most situations
391 (unless the act of forwarding traffic for others is
392 a punishable offence under your local laws, which
393 would be pretty insane as it would make ISP
394 illegal).
395 </para>
396 </important>
397
398 <para>
399 See <link xlink:href="https://www.torproject.org/docs/bridges.html.en" />
400 for more info.
401 </para>
402 </listitem>
403 </varlistentry>
404
405 <varlistentry>
406 <term><literal>private-bridge</literal></term>
407 <listitem>
408 <para>
409 Private bridge. Works like regular bridge, but does
410 not advertise your node in any way.
411 </para>
412
413 <para>
414 Using this role means that you won't contribute to Tor
415 network in any way unless you advertise your node
416 yourself in some way.
417 </para>
418
419 <para>
420 Use this if you want to run a private bridge, for
421 example because you'll give out your bridge address
422 manually to your friends.
423 </para>
424
425 <para>
426 Switching to this role after measurable time in
427 "bridge" role is pretty useless as some Tor users
428 would have learned about your node already. In the
429 latter case you can still change
430 <option>port</option> option.
431 </para>
432
433 <para>
434 See <link xlink:href="https://www.torproject.org/docs/bridges.html.en" />
435 for more info.
436 </para>
437 </listitem>
438 </varlistentry>
439 </variablelist>
440 '';
441 };
442
443 bridgeTransports = mkOption {
444 type = types.listOf types.str;
445 default = ["obfs4"];
446 example = ["obfs2" "obfs3" "obfs4" "scramblesuit"];
447 description = "List of pluggable transports";
448 };
449
450 nickname = mkOption {
451 type = types.str;
452 default = "anonymous";
453 description = ''
454 A unique handle for your TOR relay.
455 '';
456 };
457
458 contactInfo = mkOption {
459 type = types.nullOr types.str;
460 default = null;
461 example = "admin@relay.com";
462 description = ''
463 Contact information for the relay owner (e.g. a mail
464 address and GPG key ID).
465 '';
466 };
467
468 accountingMax = mkOption {
469 type = types.nullOr types.str;
470 default = null;
471 example = "450 GBytes";
472 description = ''
473 Specify maximum bandwidth allowed during an accounting period. This
474 allows you to limit overall tor bandwidth over some time period.
475 See the <literal>AccountingMax</literal> option by looking at the
476 tor manual <citerefentry><refentrytitle>tor</refentrytitle>
477 <manvolnum>1</manvolnum></citerefentry> for more.
478
479 Note this limit applies individually to upload and
480 download; if you specify <literal>"500 GBytes"</literal>
481 here, then you may transfer up to 1 TBytes of overall
482 bandwidth (500 GB upload, 500 GB download).
483 '';
484 };
485
486 accountingStart = mkOption {
487 type = types.nullOr types.str;
488 default = null;
489 example = "month 1 1:00";
490 description = ''
491 Specify length of an accounting period. This allows you to limit
492 overall tor bandwidth over some time period. See the
493 <literal>AccountingStart</literal> option by looking at the tor
494 manual <citerefentry><refentrytitle>tor</refentrytitle>
495 <manvolnum>1</manvolnum></citerefentry> for more.
496 '';
497 };
498
499 bandwidthRate = mkOption {
500 type = types.nullOr types.int;
501 default = null;
502 example = 100;
503 description = ''
504 Specify this to limit the bandwidth usage of relayed (server)
505 traffic. Your own traffic is still unthrottled. Units: bytes/second.
506 '';
507 };
508
509 bandwidthBurst = mkOption {
510 type = types.nullOr types.int;
511 default = cfg.relay.bandwidthRate;
512 example = 200;
513 description = ''
514 Specify this to allow bursts of the bandwidth usage of relayed (server)
515 traffic. The average usage will still be as specified in relayBandwidthRate.
516 Your own traffic is still unthrottled. Units: bytes/second.
517 '';
518 };
519
520 address = mkOption {
521 type = types.nullOr types.str;
522 default = null;
523 example = "noname.example.com";
524 description = ''
525 The IP address or full DNS name for advertised address of your relay.
526 Leave unset and Tor will guess.
527 '';
528 };
529
530 port = mkOption {
531 type = types.either types.int types.str;
532 example = 143;
533 description = ''
534 What port to advertise for Tor connections. This corresponds to the
535 <literal>ORPort</literal> section in the Tor manual; see
536 <citerefentry><refentrytitle>tor</refentrytitle>
537 <manvolnum>1</manvolnum></citerefentry> for more details.
538
539 At a minimum, you should just specify the port for the
540 relay to listen on; a common one like 143, 22, 80, or 443
541 to help Tor users who may have very restrictive port-based
542 firewalls.
543 '';
544 };
545
546 exitPolicy = mkOption {
547 type = types.nullOr types.str;
548 default = null;
549 example = "accept *:6660-6667,reject *:*";
550 description = ''
551 A comma-separated list of exit policies. They're
552 considered first to last, and the first match wins. If you
553 want to _replace_ the default exit policy, end this with
554 either a reject *:* or an accept *:*. Otherwise, you're
555 _augmenting_ (prepending to) the default exit policy.
556 Leave commented to just use the default, which is
557 available in the man page or at
558 <link xlink:href="https://www.torproject.org/documentation.html" />.
559
560 Look at
561 <link xlink:href="https://www.torproject.org/faq-abuse.html#TypicalAbuses" />
562 for issues you might encounter if you use the default
563 exit policy.
564
565 If certain IPs and ports are blocked externally, e.g. by
566 your firewall, you should update your exit policy to
567 reflect this -- otherwise Tor users will be told that
568 those destinations are down.
569 '';
570 };
571 };
572
573 hiddenServices = mkOption {
574 description = ''
575 A set of static hidden services that terminate their Tor
576 circuits at this node.
577
578 Every element in this set declares a virtual onion host.
579
580 You can specify your onion address by putting corresponding
581 private key to an appropriate place in ${torDirectory}.
582
583 For services without private keys in ${torDirectory} Tor
584 daemon will generate random key pairs (which implies random
585 onion addresses) on restart. The latter could take a while,
586 please be patient.
587
588 <note><para>
589 Hidden services can be useful even if you don't intend to
590 actually <emphasis>hide</emphasis> them, since they can
591 also be seen as a kind of NAT traversal mechanism.
592
593 E.g. the example will make your sshd, whatever runs on
594 "8080" and your mail server available from anywhere where
595 the Tor network is available (which, with the help from
596 bridges, is pretty much everywhere), even if both client
597 and server machines are behind NAT you have no control
598 over.
599 </para></note>
600 '';
601 default = {};
602 example = literalExample ''
603 { "my-hidden-service-example".map = [
604 { port = 22; } # map ssh port to this machine's ssh
605 { port = 80; toPort = 8080; } # map http port to whatever runs on 8080
606 { port = "sip"; toHost = "mail.example.com"; toPort = "imap"; } # because we can
607 ];
608 }
609 '';
610 type = types.loaOf (types.submodule ({name, ...}: {
611 options = {
612
613 name = mkOption {
614 type = types.str;
615 description = ''
616 Name of this tor hidden service.
617
618 This is purely descriptive.
619
620 After restarting Tor daemon you should be able to
621 find your .onion address in
622 <literal>${torDirectory}/onion/$name/hostname</literal>.
623 '';
624 };
625
626 map = mkOption {
627 default = [];
628 description = "Port mapping for this hidden service.";
629 type = types.listOf (types.submodule ({config, ...}: {
630 options = {
631
632 port = mkOption {
633 type = types.either types.int types.str;
634 example = 80;
635 description = ''
636 Hidden service port to "bind to".
637 '';
638 };
639
640 destination = mkOption {
641 internal = true;
642 type = types.str;
643 description = "Forward these connections where?";
644 };
645
646 toHost = mkOption {
647 type = types.str;
648 default = "127.0.0.1";
649 description = "Mapping destination host.";
650 };
651
652 toPort = mkOption {
653 type = types.either types.int types.str;
654 example = 8080;
655 description = "Mapping destination port.";
656 };
657
658 };
659
660 config = {
661 toPort = mkDefault config.port;
662 destination = mkDefault "${config.toHost}:${toString config.toPort}";
663 };
664 }));
665 };
666
667 authorizeClient = mkOption {
668 default = null;
669 description = "If configured, the hidden service is accessible for authorized clients only.";
670 type = types.nullOr (types.submodule ({...}: {
671
672 options = {
673
674 authType = mkOption {
675 type = types.enum [ "basic" "stealth" ];
676 description = ''
677 Either <literal>"basic"</literal> for a general-purpose authorization protocol
678 or <literal>"stealth"</literal> for a less scalable protocol
679 that also hides service activity from unauthorized clients.
680 '';
681 };
682
683 clientNames = mkOption {
684 type = types.nonEmptyListOf (types.strMatching "[A-Za-z0-9+-_]+");
685 description = ''
686 Only clients that are listed here are authorized to access the hidden service.
687 Generated authorization data can be found in <filename>${torDirectory}/onion/$name/hostname</filename>.
688 Clients need to put this authorization data in their configuration file using <literal>HidServAuth</literal>.
689 '';
690 };
691 };
692 }));
693 };
694
695 version = mkOption {
696 default = null;
697 description = "Rendezvous service descriptor version to publish for the hidden service. Currently, versions 2 and 3 are supported. (Default: 2)";
698 type = types.nullOr (types.enum [ 2 3 ]);
699 };
700 };
701
702 config = {
703 name = mkDefault name;
704 };
705 }));
706 };
707 };
708 };
709
710 config = mkIf cfg.enable {
711 # Not sure if `cfg.relay.role == "private-bridge"` helps as tor
712 # sends a lot of stats
713 warnings = optional (cfg.relay.enable && cfg.hiddenServices != {})
714 ''
715 Running Tor hidden services on a public relay makes the
716 presence of hidden services visible through simple statistical
717 analysis of publicly available data.
718
719 You can safely ignore this warning if you don't intend to
720 actually hide your hidden services. In either case, you can
721 always create a container/VM with a separate Tor daemon instance.
722 '';
723
724 users.groups.tor.gid = config.ids.gids.tor;
725 users.users.tor =
726 { description = "Tor Daemon User";
727 createHome = true;
728 home = torDirectory;
729 group = "tor";
730 uid = config.ids.uids.tor;
731 };
732
733 # We have to do this instead of using RuntimeDirectory option in
734 # the service below because systemd has no way to set owners of
735 # RuntimeDirectory and putting this into the service below
736 # requires that service to relax it's sandbox since this needs
737 # writable /run
738 systemd.services.tor-init =
739 { description = "Tor Daemon Init";
740 wantedBy = [ "tor.service" ];
741 script = ''
742 install -m 0700 -o tor -g tor -d ${torDirectory} ${torDirectory}/onion
743 install -m 0750 -o tor -g tor -d ${torRunDirectory}
744 '';
745 serviceConfig = {
746 Type = "oneshot";
747 RemainAfterExit = true;
748 };
749 };
750
751 systemd.services.tor =
752 { description = "Tor Daemon";
753 path = [ pkgs.tor ];
754
755 wantedBy = [ "multi-user.target" ];
756 after = [ "tor-init.service" "network.target" ];
757 restartTriggers = [ torRcFile ];
758
759 serviceConfig =
760 { Type = "simple";
761 # Translated from the upstream contrib/dist/tor.service.in
762 ExecStartPre = "${cfg.package}/bin/tor -f ${torRcFile} --verify-config";
763 ExecStart = "${cfg.package}/bin/tor -f ${torRcFile}";
764 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
765 KillSignal = "SIGINT";
766 TimeoutSec = 30;
767 Restart = "on-failure";
768 LimitNOFILE = 32768;
769
770 # Hardening
771 # this seems to unshare /run despite what systemd.exec(5) says
772 PrivateTmp = mkIf (!cfg.controlSocket.enable) "yes";
773 PrivateDevices = "yes";
774 ProtectHome = "yes";
775 ProtectSystem = "strict";
776 InaccessiblePaths = "/home";
777 ReadOnlyPaths = "/";
778 ReadWritePaths = [ torDirectory torRunDirectory ];
779 NoNewPrivileges = "yes";
780
781 # tor.service.in has this in, but this line it fails to spawn a namespace when using hidden services
782 #CapabilityBoundingSet = "CAP_SETUID CAP_SETGID CAP_NET_BIND_SERVICE";
783 };
784 };
785
786 environment.systemPackages = [ cfg.package ];
787
788 services.privoxy = mkIf (cfg.client.enable && cfg.client.privoxy.enable) {
789 enable = true;
790 extraConfig = ''
791 forward-socks4a / ${cfg.client.socksListenAddressFaster} .
792 toggle 1
793 enable-remote-toggle 0
794 enable-edit-actions 0
795 enable-remote-http-toggle 0
796 '';
797 };
798 };
799 }