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