···77 torDirectory = "/var/lib/tor";
8899 opt = name: value: optionalString (value != null) "${name} ${value}";
1010- optint = name: value: optionalString (value != 0) "${name} ${toString value}";
1010+ optint = name: value: optionalString (value != null && value != 0) "${name} ${toString value}";
11111212 torRc = ''
1313 User tor
···1717 GeoIPv6File ${pkgs.tor.geoip}/share/tor/geoip6
1818 ''}
19192020- ${optint "ControlPort" cfg.controlPort}
2020+ ${optint "ControlPort" (toString cfg.controlPort)}
2121 ''
2222 # Client connection config
2323 + optionalString cfg.client.enable ''
···2727 ''
2828 # Relay config
2929 + optionalString cfg.relay.enable ''
3030- ORPort ${cfg.relay.portSpec}
3030+ ORPort ${toString cfg.relay.port}
3131+ ${opt "Address" cfg.relay.address}
3132 ${opt "Nickname" cfg.relay.nickname}
3233 ${opt "ContactInfo" cfg.relay.contactInfo}
3334···3637 ${opt "AccountingMax" cfg.relay.accountingMax}
3738 ${opt "AccountingStart" cfg.relay.accountingStart}
38393939- ${if cfg.relay.isExit then
4040+ ${if (cfg.relay.role == "exit") then
4041 opt "ExitPolicy" cfg.relay.exitPolicy
4142 else
4243 "ExitPolicy reject *:*"}
43444444- ${optionalString cfg.relay.isBridge ''
4545+ ${optionalString (elem cfg.relay.role ["bridge" "private-bridge"]) ''
4546 BridgeRelay 1
4647 ServerTransportPlugin obfs2,obfs3 exec ${pkgs.pythonPackages.obfsproxy}/bin/obfsproxy managed
4848+ ExtORPort auto
4949+ ${optionalString (cfg.relay.role == "private-bridge") ''
5050+ ExtraInfoStatistics 0
5151+ PublishServerDescriptor 0
5252+ ''}
4753 ''}
4854 ''
4949- + hiddenServices
5555+ # Hidden services
5656+ + concatStrings (flip mapAttrsToList cfg.hiddenServices (n: v: ''
5757+ HiddenServiceDir ${torDirectory}/onion/${v.name}
5858+ ${flip concatMapStrings v.map (p: ''
5959+ HiddenServicePort ${toString p.port} ${p.destination}
6060+ '')}
6161+ ''))
5062 + cfg.extraConfig;
51635252- hiddenServices = concatStrings (mapAttrsToList (hiddenServiceDir: hs:
5353- let
5454- hsports = concatStringsSep "\n" (map mkHiddenServicePort hs.hiddenServicePorts);
5555- in
5656- "HiddenServiceDir ${hiddenServiceDir}\n${hsports}\n${hs.extraConfig}\n"
5757- ) cfg.hiddenServices);
6464+ torRcFile = pkgs.writeText "torrc" torRc;
58655959- mkHiddenServicePort = hsport: let
6060- trgt = optionalString (hsport.target != null) (" " + hsport.target);
6161- in "HiddenServicePort ${toString hsport.virtualPort}${trgt}";
6262-6363- torRcFile = pkgs.writeText "torrc" torRc;
6466in
6567{
6668 options = {
···9698 };
979998100 controlPort = mkOption {
9999- type = types.int;
100100- default = 0;
101101+ type = types.nullOr (types.either types.int types.str);
102102+ default = null;
101103 example = 9051;
102104 description = ''
103105 If set, Tor will accept connections on the specified port
···133135 example = "192.168.0.1:9101";
134136 description = ''
135137 Bind to this address to listen for connections from
136136- Socks-speaking applications. Same as socksListenAddress
137137- but uses weaker circuit isolation to provide performance
138138- suitable for a web browser.
138138+ Socks-speaking applications. Same as
139139+ <option>socksListenAddress</option> but uses weaker
140140+ circuit isolation to provide performance suitable for a
141141+ web browser.
139142 '';
140143 };
141144···145148 example = "accept 192.168.0.0/16, reject *";
146149 description = ''
147150 Entry policies to allow/deny SOCKS requests based on IP
148148- address. First entry that matches wins. If no SocksPolicy
151151+ address. First entry that matches wins. If no SocksPolicy
149152 is set, we accept all (and only) requests from
150150- SocksListenAddress.
153153+ <option>socksListenAddress</option>.
151154 '';
152155 };
153156···176179 description = ''
177180 Whether to enable relaying TOR traffic for others.
178181179179- See https://www.torproject.org/docs/tor-doc-relay for details.
182182+ See <link xlink:href="https://www.torproject.org/docs/tor-doc-relay" />
183183+ for details.
184184+185185+ Setting this to true requires setting
186186+ <option>services.tor.relay.role</option>
187187+ and
188188+ <option>services.tor.relay.port</option>
189189+ options.
180190 '';
181191 };
182192183183- isBridge = mkOption {
184184- type = types.bool;
185185- default = false;
193193+ role = mkOption {
194194+ type = types.enum [ "exit" "relay" "bridge" "private-bridge" ];
186195 description = ''
187187- Bridge relays (or "bridges") are Tor relays that aren't
188188- listed in the main directory. Since there is no complete
189189- public list of them, even if an ISP is filtering
190190- connections to all the known Tor relays, they probably
191191- won't be able to block all the bridges.
196196+ Your role in Tor network. There're several options:
197197+198198+ <variablelist>
199199+ <varlistentry>
200200+ <term><literal>exit</literal></term>
201201+ <listitem>
202202+ <para>
203203+ An exit relay. This allows Tor users to access regular
204204+ Internet services through your public IP.
205205+ </para>
206206+207207+ <important><para>
208208+ Running an exit relay may expose you to abuse
209209+ complaints. See
210210+ <link xlink:href="https://www.torproject.org/faq.html.en#ExitPolicies" />
211211+ for more info.
212212+ </para></important>
213213+214214+ <para>
215215+ You can specify which services Tor users may access via
216216+ your exit relay using <option>exitPolicy</option> option.
217217+ </para>
218218+ </listitem>
219219+ </varlistentry>
220220+221221+ <varlistentry>
222222+ <term><literal>relay</literal></term>
223223+ <listitem>
224224+ <para>
225225+ Regular relay. This allows Tor users to relay onion
226226+ traffic to other Tor nodes, but not to public
227227+ Internet.
228228+ </para>
229229+230230+ <important><para>
231231+ Note that some misconfigured and/or disrespectful
232232+ towards privacy sites will block you even if your
233233+ relay is not an exit relay. That is, just being listed
234234+ in a public relay directory can have unwanted
235235+ consequences.
192236193193- A bridge relay can't be an exit relay.
237237+ Which means you might not want to use
238238+ this role if you browse public Internet from the same
239239+ network as your relay, unless you want to write
240240+ e-mails to those sites (you should!).
241241+ </para></important>
194242195195- You need to set relay.enable to true for this option to
196196- take effect.
243243+ <para>
244244+ See
245245+ <link xlink:href="https://www.torproject.org/docs/tor-doc-relay.html.en" />
246246+ for more info.
247247+ </para>
248248+ </listitem>
249249+ </varlistentry>
197250198198- The bridge is set up with an obfuscated transport proxy.
251251+ <varlistentry>
252252+ <term><literal>bridge</literal></term>
253253+ <listitem>
254254+ <para>
255255+ Regular bridge. Works like a regular relay, but
256256+ doesn't list you in the public relay directory and
257257+ hides your Tor node behind obfsproxy.
258258+ </para>
199259200200- See https://www.torproject.org/bridges.html.en for more info.
201201- '';
202202- };
260260+ <para>
261261+ Using this option will make Tor advertise your bridge
262262+ to users through various mechanisms like
263263+ <link xlink:href="https://bridges.torproject.org/" />, though.
264264+ </para>
203265204204- isExit = mkOption {
205205- type = types.bool;
206206- default = false;
207207- description = ''
208208- An exit relay allows Tor users to access regular Internet
209209- services.
266266+ <important>
267267+ <para>
268268+ WARNING: THE FOLLOWING PARAGRAPH IS NOT LEGAL ADVISE.
269269+ Consult with your lawer when in doubt.
270270+ </para>
210271211211- Unlike running a non-exit relay, running an exit relay may
212212- expose you to abuse complaints. See
213213- https://www.torproject.org/faq.html.en#ExitPolicies for
214214- more info.
272272+ <para>
273273+ This role should be safe to use in most situations
274274+ (unless the act of forwarding traffic for others is
275275+ a punishable offence under your local laws, which
276276+ would be pretty insane as it would make ISP
277277+ illegal).
278278+ </para>
279279+ </important>
215280216216- You can specify which services Tor users may access via
217217- your exit relay using exitPolicy option.
281281+ <para>
282282+ See <link xlink:href="https://www.torproject.org/docs/bridges.html.en" />
283283+ for more info.
284284+ </para>
285285+ </listitem>
286286+ </varlistentry>
287287+288288+ <varlistentry>
289289+ <term><literal>private-bridge</literal></term>
290290+ <listitem>
291291+ <para>
292292+ Private bridge. Works like regular bridge, but does
293293+ not advertise your node in any way.
294294+ </para>
295295+296296+ <para>
297297+ Using this role means that you won't contribute to Tor
298298+ network in any way unless you advertise your node
299299+ yourself in some way.
300300+ </para>
301301+302302+ <para>
303303+ Use this if you want to run a private bridge, for
304304+ example because you'll give out your bridge address
305305+ manually to your friends.
306306+ </para>
307307+308308+ <para>
309309+ Switching to this role after measurable time in
310310+ "bridge" role is pretty useless as some Tor users
311311+ would have learned about your node already. In the
312312+ latter case you can still change
313313+ <option>port</option> option.
314314+ </para>
315315+316316+ <para>
317317+ See <link xlink:href="https://www.torproject.org/docs/bridges.html.en" />
318318+ for more info.
319319+ </para>
320320+ </listitem>
321321+ </varlistentry>
322322+ </variablelist>
218323 '';
219324 };
220325···268373 };
269374270375 bandwidthRate = mkOption {
271271- type = types.int;
272272- default = 0;
376376+ type = types.nullOr types.int;
377377+ default = null;
273378 example = 100;
274379 description = ''
275380 Specify this to limit the bandwidth usage of relayed (server)
···278383 };
279384280385 bandwidthBurst = mkOption {
281281- type = types.int;
386386+ type = types.nullOr types.int;
282387 default = cfg.relay.bandwidthRate;
283388 example = 200;
284389 description = ''
···288393 '';
289394 };
290395291291- portSpec = mkOption {
292292- type = types.str;
293293- example = "143";
396396+ address = mkOption {
397397+ type = types.nullOr types.str;
398398+ default = null;
399399+ example = "noname.example.com";
400400+ description = ''
401401+ The IP address or full DNS name for advertised address of your relay.
402402+ Leave unset and Tor will guess.
403403+ '';
404404+ };
405405+406406+ port = mkOption {
407407+ type = types.either types.int types.str;
408408+ example = 143;
294409 description = ''
295410 What port to advertise for Tor connections. This corresponds to the
296411 <literal>ORPort</literal> section in the Tor manual; see
···313428 considered first to last, and the first match wins. If you
314429 want to _replace_ the default exit policy, end this with
315430 either a reject *:* or an accept *:*. Otherwise, you're
316316- _augmenting_ (prepending to) the default exit
317317- policy. Leave commented to just use the default, which is
431431+ _augmenting_ (prepending to) the default exit policy.
432432+ Leave commented to just use the default, which is
318433 available in the man page or at
319319- https://www.torproject.org/documentation.html
434434+ <link xlink:href="https://www.torproject.org/documentation.html" />.
320435321321- Look at https://www.torproject.org/faq-abuse.html#TypicalAbuses
322322- for issues you might encounter if you use the default exit policy.
436436+ Look at
437437+ <link xlink:href="https://www.torproject.org/faq-abuse.html#TypicalAbuses" />
438438+ for issues you might encounter if you use the default
439439+ exit policy.
323440324441 If certain IPs and ports are blocked externally, e.g. by
325442 your firewall, you should update your exit policy to
···330447 };
331448332449 hiddenServices = mkOption {
333333- type = types.attrsOf (types.submodule ({
450450+ description = ''
451451+ A set of static hidden services that terminate their Tor
452452+ circuits at this node.
453453+454454+ Every element in this set declares a virtual onion host.
455455+456456+ You can specify your onion address by putting corresponding
457457+ private key to an appropriate place in ${torDirectory}.
458458+459459+ For services without private keys in ${torDirectory} Tor
460460+ daemon will generate random key pairs (which implies random
461461+ onion addresses) on restart. The latter could take a while,
462462+ please be patient.
463463+464464+ <note><para>
465465+ Hidden services can be useful even if you don't intend to
466466+ actually <emphasis>hide</emphasis> them, since they can
467467+ also be seen as a kind of NAT traversal mechanism.
468468+469469+ E.g. the example will make your sshd, whatever runs on
470470+ "8080" and your mail server available from anywhere where
471471+ the Tor network is available (which, with the help from
472472+ bridges, is pretty much everywhere), even if both client
473473+ and server machines are behind NAT you have no control
474474+ over.
475475+ </para></note>
476476+ '';
477477+ default = {};
478478+ example = literalExample ''
479479+ { "my-hidden-service-example".map = [
480480+ { port = 22; } # map ssh port to this machine's ssh
481481+ { port = 80; toPort = 8080; } # map http port to whatever runs on 8080
482482+ { port = "sip"; toHost = "mail.example.com"; toPort = "imap"; } # because we can
483483+ ];
484484+ }
485485+ '';
486486+ type = types.loaOf (types.submodule ({name, config, ...}: {
334487 options = {
335335- hiddenServicePorts = mkOption {
336336- type = types.listOf (types.submodule {
337337- options = {
338338- virtualPort = mkOption {
339339- type = types.int;
340340- example = 80;
341341- description = "Virtual port.";
342342- };
343343- target = mkOption {
344344- type = types.nullOr types.str;
345345- default = null;
346346- example = "127.0.0.1:8080";
347347- description = ''
348348- Target virtual Port shall be mapped to.
488488+489489+ name = mkOption {
490490+ type = types.str;
491491+ description = ''
492492+ Name of this tor hidden service.
493493+494494+ This is purely descriptive.
495495+496496+ After restarting Tor daemon you should be able to
497497+ find your .onion address in
498498+ <literal>${torDirectory}/onion/$name/hostname</literal>.
499499+ '';
500500+ };
501501+502502+ map = mkOption {
503503+ default = [];
504504+ description = "Port mapping for this hidden service.";
505505+ type = types.listOf (types.submodule ({config, ...}: {
506506+ options = {
507507+508508+ port = mkOption {
509509+ type = types.either types.int types.str;
510510+ example = 80;
511511+ description = ''
512512+ Hidden service port to "bind to".
513513+ '';
514514+ };
515515+516516+ destination = mkOption {
517517+ internal = true;
518518+ type = types.str;
519519+ description = "Forward these connections where?";
520520+ };
349521350350- You may override the target port, address, or both by
351351- specifying a target of addr, port, addr:port, or
352352- unix:path. (You can specify an IPv6 target as
353353- [addr]:port. Unix paths may be quoted, and may use
354354- standard C escapes.)
355355- '';
356356- };
357357- };
358358- });
359359- example = [ { virtualPort = 80; target = "127.0.0.1:8080"; } { virtualPort = 6667; } ];
360360- description = ''
361361- If target is <literal>null</literal> the virtual port is mapped
362362- to the same port on 127.0.0.1 over TCP. You may use
363363- <literal>target</literal> to overwrite this behaviour (see
364364- description of target).
522522+ toHost = mkOption {
523523+ type = types.str;
524524+ default = "127.0.0.1";
525525+ description = "Mapping destination host.";
526526+ };
365527366366- This corresponds to the <literal>HiddenServicePort VIRTPORT
367367- [TARGET]</literal> option by looking at the tor manual
368368- <citerefentry><refentrytitle>tor</refentrytitle>
369369- <manvolnum>1</manvolnum></citerefentry> for more information.
370370- '';
371371- };
372372- extraConfig = mkOption {
373373- type = types.str;
374374- default = "";
375375- description = ''
376376- Extra configuration. Contents will be added in the current
377377- hidden service context.
378378- '';
379379- };
380380- };
381381- }));
382382- default = {};
383383- example = {
384384- "/var/lib/tor/webserver" = {
385385- hiddenServicePorts = [ { virtualPort = 80; } ];
528528+ toPort = mkOption {
529529+ type = types.either types.int types.str;
530530+ example = 8080;
531531+ description = "Mapping destination port.";
532532+ };
533533+534534+ };
535535+536536+ config = {
537537+ toPort = mkDefault config.port;
538538+ destination = mkDefault "${config.toHost}:${toString config.toPort}";
539539+ };
540540+ }));
541541+ };
542542+386543 };
387387- };
388388- description = ''
389389- Configure hidden services.
390544391391- Please consult the tor manual
392392- <citerefentry><refentrytitle>tor</refentrytitle>
393393- <manvolnum>1</manvolnum></citerefentry> for a more detailed
394394- explanation. (search for 'HIDDEN').
395395- '';
545545+ config = {
546546+ name = mkDefault name;
547547+ };
548548+ }));
396549 };
397550 };
398551 };
399552400553 config = mkIf cfg.enable {
401401- assertions = singleton
402402- { message = "Can't be both an exit and a bridge relay at the same time";
403403- assertion =
404404- cfg.relay.enable -> !(cfg.relay.isBridge && cfg.relay.isExit);
405405- };
554554+ # Not sure if `cfg.relay.role == "private-bridge"` helps as tor
555555+ # sends a lot of stats
556556+ warnings = optional (cfg.relay.enable && cfg.hiddenServices != {})
557557+ ''
558558+ Running Tor hidden services on a public relay makes the
559559+ presence of hidden services visible through simple statistical
560560+ analysis of publicly available data.
561561+562562+ You can safely ignore this warning if you don't intend to
563563+ actually hide your hidden services. In either case, you can
564564+ always create a container/VM with a separate Tor daemon instance.
565565+ '';
406566407567 users.extraGroups.tor.gid = config.ids.gids.tor;
408568 users.extraUsers.tor =
···422582 restartTriggers = [ torRcFile ];
423583424584 # Translated from the upstream contrib/dist/tor.service.in
585585+ preStart = ''
586586+ install -o tor -g tor -d ${torDirectory}/onion
587587+ ${pkgs.tor}/bin/tor -f ${torRcFile} --verify-config
588588+ '';
589589+425590 serviceConfig =
426591 { Type = "simple";
427427- ExecStartPre = "${pkgs.tor}/bin/tor -f ${torRcFile} --verify-config";
428592 ExecStart = "${pkgs.tor}/bin/tor -f ${torRcFile} --RunAsDaemon 0";
429593 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
430594 KillSignal = "SIGINT";