From 30a3cccd07914155703e9376d9470ef5f24f9a5c Mon Sep 17 00:00:00 2001 From: SLNOS Date: Wed, 1 Mar 2017 00:00:00 +0000 Subject: nixos: tor: better submodule for hidden services Rebased onto master with a different implementation. Originally: "add support for serving hidden services". --- nixos/modules/services/security/tor.nix | 194 ++++++++++++++++++++------------ 1 file changed, 121 insertions(+), 73 deletions(-) (limited to 'nixos/modules/services/security/tor.nix') diff --git a/nixos/modules/services/security/tor.nix b/nixos/modules/services/security/tor.nix index 5f208fdf842..c2851b1dd60 100644 --- a/nixos/modules/services/security/tor.nix +++ b/nixos/modules/services/security/tor.nix @@ -52,20 +52,15 @@ let ''} ''} '' - + hiddenServices + # Hidden services + + concatStrings (flip mapAttrsToList cfg.hiddenServices (n: v: '' + HiddenServiceDir ${torDirectory}/onion/${v.name} + ${flip concatMapStrings v.map (p: '' + HiddenServicePort ${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 @@ -452,74 +447,123 @@ 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 null the virtual port is mapped - to the same port on 127.0.0.1 over TCP. You may use - target to overwrite this behaviour (see - description of target). - - This corresponds to the HiddenServicePort VIRTPORT - [TARGET] option by looking at the tor manual - tor - 1 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. + + + Hidden services can be useful even if you don't intend to + actually hide 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. + + ''; 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 + ${torDirectory}/onion/$name/hostname. + ''; + }; + + map = mkOption { + default = []; + description = "Port mapping for this hidden service."; + type = types.listOf (types.submodule ({config, ...}: { + options = { + + port = mkOption { + type = 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.str; + example = "8080"; + description = "Mapping destination port."; + }; + + }; + + config = { + toPort = mkDefault config.port; + destination = mkDefault "${config.toHost}:${config.toPort}"; + }; + })); + }; + }; - }; - description = '' - Configure hidden services. - Please consult the tor manual - tor - 1 for a more detailed - explanation. (search for 'HIDDEN'). - ''; + config = { + name = mkDefault name; + }; + })); }; }; }; config = mkIf cfg.enable { + # 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 = { description = "Tor Daemon User"; @@ -538,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"; -- cgit 1.4.1