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