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