diff options
author | Joachim F <joachifm@users.noreply.github.com> | 2017-08-24 08:12:59 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-08-24 08:12:59 +0000 |
commit | 9447b8b9cd9ac1ff8e5d051de752e7f78c8bbca5 (patch) | |
tree | 3b92d337794dcac8a20f8a74da259757a4e04997 /nixos/modules | |
parent | ab3de8ed6c976caecf4fda637aa25d5c64ffa5b2 (diff) | |
parent | 2c4a925ab07e4ebfd932730b358771e3547be605 (diff) | |
download | nixlib-9447b8b9cd9ac1ff8e5d051de752e7f78c8bbca5.tar nixlib-9447b8b9cd9ac1ff8e5d051de752e7f78c8bbca5.tar.gz nixlib-9447b8b9cd9ac1ff8e5d051de752e7f78c8bbca5.tar.bz2 nixlib-9447b8b9cd9ac1ff8e5d051de752e7f78c8bbca5.tar.lz nixlib-9447b8b9cd9ac1ff8e5d051de752e7f78c8bbca5.tar.xz nixlib-9447b8b9cd9ac1ff8e5d051de752e7f78c8bbca5.tar.zst nixlib-9447b8b9cd9ac1ff8e5d051de752e7f78c8bbca5.zip |
Merge pull request #28338 from oxij/nixos/better-tor
nixos: better tor config
Diffstat (limited to 'nixos/modules')
-rw-r--r-- | nixos/modules/rename.nix | 3 | ||||
-rw-r--r-- | nixos/modules/services/security/tor.nix | 434 |
2 files changed, 302 insertions, 135 deletions
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 08146d1f5687..2079ed544aee 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -25,6 +25,7 @@ with lib; (mkRenamedOptionModule [ "services" "sslh" "host" ] [ "services" "sslh" "listenAddress" ]) (mkRenamedOptionModule [ "services" "statsd" "host" ] [ "services" "statsd" "listenAddress" ]) (mkRenamedOptionModule [ "services" "subsonic" "host" ] [ "services" "subsonic" "listenAddress" ]) + (mkRenamedOptionModule [ "services" "tor" "relay" "portSpec" ] [ "services" "tor" "relay" "port" ]) (mkRenamedOptionModule [ "jobs" ] [ "systemd" "services" ]) (mkRenamedOptionModule [ "services" "gitlab" "stateDir" ] [ "services" "gitlab" "statePath" ]) @@ -195,6 +196,8 @@ with lib; (mkRemovedOptionModule [ "services" "openvpn" "enable" ] "") (mkRemovedOptionModule [ "services" "printing" "cupsFilesConf" ] "") (mkRemovedOptionModule [ "services" "printing" "cupsdConf" ] "") + (mkRemovedOptionModule [ "services" "tor" "relay" "isBridge" ] "Use services.tor.relay.role instead.") + (mkRemovedOptionModule [ "services" "tor" "relay" "isExit" ] "Use services.tor.relay.role instead.") (mkRemovedOptionModule [ "services" "xserver" "startGnuPGAgent" ] "See the 16.09 release notes for more information.") (mkRemovedOptionModule [ "services" "phpfpm" "phpIni" ] "") diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix index 3f1450ebfbd7..04b065f6ae4b 100644 --- a/nixos/modules/services/security/tor.nix +++ b/nixos/modules/services/security/tor.nix @@ -7,7 +7,7 @@ let torDirectory = "/var/lib/tor"; opt = name: value: optionalString (value != null) "${name} ${value}"; - optint = name: value: optionalString (value != 0) "${name} ${toString value}"; + optint = name: value: optionalString (value != null && value != 0) "${name} ${toString value}"; torRc = '' User tor @@ -17,7 +17,7 @@ let GeoIPv6File ${pkgs.tor.geoip}/share/tor/geoip6 ''} - ${optint "ControlPort" cfg.controlPort} + ${optint "ControlPort" (toString cfg.controlPort)} '' # Client connection config + optionalString cfg.client.enable '' @@ -27,7 +27,8 @@ let '' # Relay config + optionalString cfg.relay.enable '' - ORPort ${cfg.relay.portSpec} + ORPort ${toString cfg.relay.port} + ${opt "Address" cfg.relay.address} ${opt "Nickname" cfg.relay.nickname} ${opt "ContactInfo" cfg.relay.contactInfo} @@ -36,31 +37,32 @@ let ${opt "AccountingMax" cfg.relay.accountingMax} ${opt "AccountingStart" cfg.relay.accountingStart} - ${if cfg.relay.isExit then + ${if (cfg.relay.role == "exit") then opt "ExitPolicy" cfg.relay.exitPolicy else "ExitPolicy reject *:*"} - ${optionalString cfg.relay.isBridge '' + ${optionalString (elem cfg.relay.role ["bridge" "private-bridge"]) '' BridgeRelay 1 ServerTransportPlugin obfs2,obfs3 exec ${pkgs.pythonPackages.obfsproxy}/bin/obfsproxy managed + ExtORPort auto + ${optionalString (cfg.relay.role == "private-bridge") '' + ExtraInfoStatistics 0 + PublishServerDescriptor 0 + ''} ''} '' - + hiddenServices + # Hidden services + + concatStrings (flip mapAttrsToList cfg.hiddenServices (n: v: '' + HiddenServiceDir ${torDirectory}/onion/${v.name} + ${flip concatMapStrings v.map (p: '' + HiddenServicePort ${toString p.port} ${p.destination} + '')} + '')) + cfg.extraConfig; - hiddenServices = concatStrings (mapAttrsToList (hiddenServiceDir: hs: - let - hsports = concatStringsSep "\n" (map mkHiddenServicePort hs.hiddenServicePorts); - in - "HiddenServiceDir ${hiddenServiceDir}\n${hsports}\n${hs.extraConfig}\n" - ) cfg.hiddenServices); - - mkHiddenServicePort = hsport: let - trgt = optionalString (hsport.target != null) (" " + hsport.target); - in "HiddenServicePort ${toString hsport.virtualPort}${trgt}"; - torRcFile = pkgs.writeText "torrc" torRc; + in { options = { @@ -96,8 +98,8 @@ in }; controlPort = mkOption { - type = types.int; - default = 0; + type = types.nullOr (types.either types.int types.str); + default = null; example = 9051; description = '' If set, Tor will accept connections on the specified port @@ -133,9 +135,10 @@ in example = "192.168.0.1:9101"; description = '' Bind to this address to listen for connections from - Socks-speaking applications. Same as socksListenAddress - but uses weaker circuit isolation to provide performance - suitable for a web browser. + Socks-speaking applications. Same as + <option>socksListenAddress</option> but uses weaker + circuit isolation to provide performance suitable for a + web browser. ''; }; @@ -145,9 +148,9 @@ in example = "accept 192.168.0.0/16, reject *"; description = '' Entry policies to allow/deny SOCKS requests based on IP - address. First entry that matches wins. If no SocksPolicy + address. First entry that matches wins. If no SocksPolicy is set, we accept all (and only) requests from - SocksListenAddress. + <option>socksListenAddress</option>. ''; }; @@ -176,45 +179,147 @@ in description = '' Whether to enable relaying TOR traffic for others. - See https://www.torproject.org/docs/tor-doc-relay for details. - ''; - }; - - isBridge = mkOption { - type = types.bool; - default = false; - description = '' - Bridge relays (or "bridges") are Tor relays that aren't - listed in the main directory. Since there is no complete - public list of them, even if an ISP is filtering - connections to all the known Tor relays, they probably - won't be able to block all the bridges. - - A bridge relay can't be an exit relay. - - You need to set relay.enable to true for this option to - take effect. + See <link xlink:href="https://www.torproject.org/docs/tor-doc-relay" /> + for details. - The bridge is set up with an obfuscated transport proxy. - - See https://www.torproject.org/bridges.html.en for more info. + Setting this to true requires setting + <option>services.tor.relay.role</option> + and + <option>services.tor.relay.port</option> + options. ''; }; - isExit = mkOption { - type = types.bool; - default = false; + role = mkOption { + type = types.enum [ "exit" "relay" "bridge" "private-bridge" ]; description = '' - An exit relay allows Tor users to access regular Internet - services. - - Unlike running a non-exit relay, running an exit relay may - expose you to abuse complaints. See - https://www.torproject.org/faq.html.en#ExitPolicies for - more info. - - You can specify which services Tor users may access via - your exit relay using exitPolicy option. + Your role in Tor network. There're several options: + + <variablelist> + <varlistentry> + <term><literal>exit</literal></term> + <listitem> + <para> + An exit relay. This allows Tor users to access regular + Internet services through your public IP. + </para> + + <important><para> + Running an exit relay may expose you to abuse + complaints. See + <link xlink:href="https://www.torproject.org/faq.html.en#ExitPolicies" /> + for more info. + </para></important> + + <para> + You can specify which services Tor users may access via + your exit relay using <option>exitPolicy</option> option. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>relay</literal></term> + <listitem> + <para> + Regular relay. This allows Tor users to relay onion + traffic to other Tor nodes, but not to public + Internet. + </para> + + <important><para> + Note that some misconfigured and/or disrespectful + towards privacy sites will block you even if your + relay is not an exit relay. That is, just being listed + in a public relay directory can have unwanted + consequences. + + Which means you might not want to use + this role if you browse public Internet from the same + network as your relay, unless you want to write + e-mails to those sites (you should!). + </para></important> + + <para> + See + <link xlink:href="https://www.torproject.org/docs/tor-doc-relay.html.en" /> + for more info. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>bridge</literal></term> + <listitem> + <para> + Regular bridge. Works like a regular relay, but + doesn't list you in the public relay directory and + hides your Tor node behind obfsproxy. + </para> + + <para> + Using this option will make Tor advertise your bridge + to users through various mechanisms like + <link xlink:href="https://bridges.torproject.org/" />, though. + </para> + + <important> + <para> + WARNING: THE FOLLOWING PARAGRAPH IS NOT LEGAL ADVISE. + Consult with your lawer when in doubt. + </para> + + <para> + This role should be safe to use in most situations + (unless the act of forwarding traffic for others is + a punishable offence under your local laws, which + would be pretty insane as it would make ISP + illegal). + </para> + </important> + + <para> + See <link xlink:href="https://www.torproject.org/docs/bridges.html.en" /> + for more info. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term><literal>private-bridge</literal></term> + <listitem> + <para> + Private bridge. Works like regular bridge, but does + not advertise your node in any way. + </para> + + <para> + Using this role means that you won't contribute to Tor + network in any way unless you advertise your node + yourself in some way. + </para> + + <para> + Use this if you want to run a private bridge, for + example because you'll give out your bridge address + manually to your friends. + </para> + + <para> + Switching to this role after measurable time in + "bridge" role is pretty useless as some Tor users + would have learned about your node already. In the + latter case you can still change + <option>port</option> option. + </para> + + <para> + See <link xlink:href="https://www.torproject.org/docs/bridges.html.en" /> + for more info. + </para> + </listitem> + </varlistentry> + </variablelist> ''; }; @@ -268,8 +373,8 @@ in }; bandwidthRate = mkOption { - type = types.int; - default = 0; + type = types.nullOr types.int; + default = null; example = 100; description = '' Specify this to limit the bandwidth usage of relayed (server) @@ -278,7 +383,7 @@ in }; bandwidthBurst = mkOption { - type = types.int; + type = types.nullOr types.int; default = cfg.relay.bandwidthRate; example = 200; description = '' @@ -288,9 +393,19 @@ in ''; }; - portSpec = mkOption { - type = types.str; - example = "143"; + address = mkOption { + type = types.nullOr types.str; + default = null; + example = "noname.example.com"; + description = '' + The IP address or full DNS name for advertised address of your relay. + Leave unset and Tor will guess. + ''; + }; + + port = mkOption { + type = types.either types.int types.str; + example = 143; description = '' What port to advertise for Tor connections. This corresponds to the <literal>ORPort</literal> section in the Tor manual; see @@ -313,13 +428,15 @@ in considered first to last, and the first match wins. If you want to _replace_ the default exit policy, end this with either a reject *:* or an accept *:*. Otherwise, you're - _augmenting_ (prepending to) the default exit - policy. Leave commented to just use the default, which is + _augmenting_ (prepending to) the default exit policy. + Leave commented to just use the default, which is available in the man page or at - https://www.torproject.org/documentation.html + <link xlink:href="https://www.torproject.org/documentation.html" />. - Look at https://www.torproject.org/faq-abuse.html#TypicalAbuses - for issues you might encounter if you use the default exit policy. + Look at + <link xlink:href="https://www.torproject.org/faq-abuse.html#TypicalAbuses" /> + for issues you might encounter if you use the default + exit policy. If certain IPs and ports are blocked externally, e.g. by your firewall, you should update your exit policy to @@ -330,79 +447,122 @@ in }; hiddenServices = mkOption { - type = types.attrsOf (types.submodule ({ - options = { - hiddenServicePorts = mkOption { - type = types.listOf (types.submodule { - options = { - virtualPort = mkOption { - type = types.int; - example = 80; - description = "Virtual port."; - }; - target = mkOption { - type = types.nullOr types.str; - default = null; - example = "127.0.0.1:8080"; - description = '' - Target virtual Port shall be mapped to. - - You may override the target port, address, or both by - specifying a target of addr, port, addr:port, or - unix:path. (You can specify an IPv6 target as - [addr]:port. Unix paths may be quoted, and may use - standard C escapes.) - ''; - }; - }; - }); - example = [ { virtualPort = 80; target = "127.0.0.1:8080"; } { virtualPort = 6667; } ]; - description = '' - If target is <literal>null</literal> the virtual port is mapped - to the same port on 127.0.0.1 over TCP. You may use - <literal>target</literal> to overwrite this behaviour (see - description of target). - - This corresponds to the <literal>HiddenServicePort VIRTPORT - [TARGET]</literal> option by looking at the tor manual - <citerefentry><refentrytitle>tor</refentrytitle> - <manvolnum>1</manvolnum></citerefentry> for more information. - ''; - }; - extraConfig = mkOption { - type = types.str; - default = ""; - description = '' - Extra configuration. Contents will be added in the current - hidden service context. - ''; - }; - }; - })); + description = '' + A set of static hidden services that terminate their Tor + circuits at this node. + + Every element in this set declares a virtual onion host. + + You can specify your onion address by putting corresponding + private key to an appropriate place in ${torDirectory}. + + For services without private keys in ${torDirectory} Tor + daemon will generate random key pairs (which implies random + onion addresses) on restart. The latter could take a while, + please be patient. + + <note><para> + Hidden services can be useful even if you don't intend to + actually <emphasis>hide</emphasis> them, since they can + also be seen as a kind of NAT traversal mechanism. + + E.g. the example will make your sshd, whatever runs on + "8080" and your mail server available from anywhere where + the Tor network is available (which, with the help from + bridges, is pretty much everywhere), even if both client + and server machines are behind NAT you have no control + over. + </para></note> + ''; default = {}; - example = { - "/var/lib/tor/webserver" = { - hiddenServicePorts = [ { virtualPort = 80; } ]; + example = literalExample '' + { "my-hidden-service-example".map = [ + { port = 22; } # map ssh port to this machine's ssh + { port = 80; toPort = 8080; } # map http port to whatever runs on 8080 + { port = "sip"; toHost = "mail.example.com"; toPort = "imap"; } # because we can + ]; + } + ''; + type = types.loaOf (types.submodule ({name, config, ...}: { + options = { + + name = mkOption { + type = types.str; + description = '' + Name of this tor hidden service. + + This is purely descriptive. + + After restarting Tor daemon you should be able to + find your .onion address in + <literal>${torDirectory}/onion/$name/hostname</literal>. + ''; + }; + + map = mkOption { + default = []; + description = "Port mapping for this hidden service."; + type = types.listOf (types.submodule ({config, ...}: { + options = { + + port = mkOption { + type = types.either types.int types.str; + example = 80; + description = '' + Hidden service port to "bind to". + ''; + }; + + destination = mkOption { + internal = true; + type = types.str; + description = "Forward these connections where?"; + }; + + toHost = mkOption { + type = types.str; + default = "127.0.0.1"; + description = "Mapping destination host."; + }; + + toPort = mkOption { + type = types.either types.int types.str; + example = 8080; + description = "Mapping destination port."; + }; + + }; + + config = { + toPort = mkDefault config.port; + destination = mkDefault "${config.toHost}:${toString config.toPort}"; + }; + })); + }; + }; - }; - description = '' - Configure hidden services. - Please consult the tor manual - <citerefentry><refentrytitle>tor</refentrytitle> - <manvolnum>1</manvolnum></citerefentry> for a more detailed - explanation. (search for 'HIDDEN'). - ''; + config = { + name = mkDefault name; + }; + })); }; }; }; config = mkIf cfg.enable { - assertions = singleton - { message = "Can't be both an exit and a bridge relay at the same time"; - assertion = - cfg.relay.enable -> !(cfg.relay.isBridge && cfg.relay.isExit); - }; + # Not sure if `cfg.relay.role == "private-bridge"` helps as tor + # sends a lot of stats + warnings = optional (cfg.relay.enable && cfg.hiddenServices != {}) + '' + Running Tor hidden services on a public relay makes the + presence of hidden services visible through simple statistical + analysis of publicly available data. + + You can safely ignore this warning if you don't intend to + actually hide your hidden services. In either case, you can + always create a container/VM with a separate Tor daemon instance. + ''; users.extraGroups.tor.gid = config.ids.gids.tor; users.extraUsers.tor = @@ -422,9 +582,13 @@ in restartTriggers = [ torRcFile ]; # Translated from the upstream contrib/dist/tor.service.in + preStart = '' + install -o tor -g tor -d ${torDirectory}/onion + ${pkgs.tor}/bin/tor -f ${torRcFile} --verify-config + ''; + serviceConfig = { Type = "simple"; - ExecStartPre = "${pkgs.tor}/bin/tor -f ${torRcFile} --verify-config"; ExecStart = "${pkgs.tor}/bin/tor -f ${torRcFile} --RunAsDaemon 0"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; KillSignal = "SIGINT"; |