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