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