From 62098739941c973c9cb844082b43a5154d413cf6 Mon Sep 17 00:00:00 2001 From: Jonas Nick Date: Thu, 6 Dec 2018 11:37:26 +0000 Subject: [PATCH] Use nixpkgs tor module --- configuration.nix | 1 - modules/nixbitcoin.nix | 2 +- modules/tor.nix | 776 ----------------------------------------- 3 files changed, 1 insertion(+), 778 deletions(-) delete mode 100644 modules/tor.nix diff --git a/configuration.nix b/configuration.nix index 91d5033..f943098 100644 --- a/configuration.nix +++ b/configuration.nix @@ -10,7 +10,6 @@ let nanopos = import pkgs/nanopos.nix { inherit pkgs; }; liquidd = import pkgs/liquidd.nix; in { - disabledModules = [ "services/security/tor.nix" ]; imports = [ diff --git a/modules/nixbitcoin.nix b/modules/nixbitcoin.nix index 1ba0530..326337b 100644 --- a/modules/nixbitcoin.nix +++ b/modules/nixbitcoin.nix @@ -5,6 +5,7 @@ with lib; let cfg = config.services.nixbitcoin; minimalPackages = with pkgs; [ + tor bitcoin clightning nodeinfo @@ -21,7 +22,6 @@ in { imports = [ # Tor module from nixpkgs but with HiddenService v3 - ./tor.nix ./bitcoind.nix ./clightning.nix ./lightning-charge.nix diff --git a/modules/tor.nix b/modules/tor.nix deleted file mode 100644 index 9c72e01..0000000 --- a/modules/tor.nix +++ /dev/null @@ -1,776 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - cfg = config.services.tor; - torDirectory = "/var/lib/tor"; - torRunDirectory = "/run/tor"; - - opt = name: value: optionalString (value != null) "${name} ${value}"; - optint = name: value: optionalString (value != null && value != 0) "${name} ${toString value}"; - - isolationOptions = { - type = types.listOf (types.enum [ - "IsolateClientAddr" - "IsolateSOCKSAuth" - "IsolateClientProtocol" - "IsolateDestPort" - "IsolateDestAddr" - ]); - default = []; - example = [ - "IsolateClientAddr" - "IsolateSOCKSAuth" - "IsolateClientProtocol" - "IsolateDestPort" - "IsolateDestAddr" - ]; - description = "Tor isolation options"; - }; - - - torRc = '' - User tor - DataDirectory ${torDirectory} - ${optionalString cfg.enableGeoIP '' - GeoIPFile ${pkgs.tor.geoip}/share/tor/geoip - GeoIPv6File ${pkgs.tor.geoip}/share/tor/geoip6 - ''} - - ${optint "ControlPort" cfg.controlPort} - ${optionalString cfg.controlSocket.enable "ControlPort unix:${torRunDirectory}/control GroupWritable RelaxDirModeCheck"} - '' - # Client connection config - + optionalString cfg.client.enable '' - SOCKSPort ${cfg.client.socksListenAddress} ${toString cfg.client.socksIsolationOptions} - SOCKSPort ${cfg.client.socksListenAddressFaster} - ${opt "SocksPolicy" cfg.client.socksPolicy} - - ${optionalString cfg.client.transparentProxy.enable '' - TransPort ${cfg.client.transparentProxy.listenAddress} ${toString cfg.client.transparentProxy.isolationOptions} - ''} - - ${optionalString cfg.client.dns.enable '' - DNSPort ${cfg.client.dns.listenAddress} ${toString cfg.client.dns.isolationOptions} - AutomapHostsOnResolve 1 - AutomapHostsSuffixes ${concatStringsSep "," cfg.client.dns.automapHostsSuffixes} - ''} - '' - # Explicitly disable the SOCKS server if the client is disabled. In - # particular, this makes non-anonymous hidden services possible. - + optionalString (! cfg.client.enable) '' - SOCKSPort 0 - '' - # Relay config - + optionalString cfg.relay.enable '' - ORPort ${toString cfg.relay.port} - ${opt "Address" cfg.relay.address} - ${opt "Nickname" cfg.relay.nickname} - ${opt "ContactInfo" cfg.relay.contactInfo} - - ${optint "RelayBandwidthRate" cfg.relay.bandwidthRate} - ${optint "RelayBandwidthBurst" cfg.relay.bandwidthBurst} - ${opt "AccountingMax" cfg.relay.accountingMax} - ${opt "AccountingStart" cfg.relay.accountingStart} - - ${if (cfg.relay.role == "exit") then - opt "ExitPolicy" cfg.relay.exitPolicy - else - "ExitPolicy reject *:*"} - - ${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 - ''} - ''} - '' - # Hidden services - + concatStrings (flip mapAttrsToList cfg.hiddenServices (n: v: '' - HiddenServiceDir ${torDirectory}/onion/${v.name} - ${optionalString (v.version != null) "HiddenServiceVersion ${toString v.version}"} - ${flip concatMapStrings v.map (p: '' - HiddenServicePort ${toString p.port} ${p.destination} - '')} - ${optionalString (v.authorizeClient != null) '' - HiddenServiceAuthorizeClient ${v.authorizeClient.authType} ${concatStringsSep "," v.authorizeClient.clientNames} - ''} - '')) - + cfg.extraConfig; - - torRcFile = pkgs.writeText "torrc" torRc; - -in -{ - options = { - services.tor = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Enable the Tor daemon. By default, the daemon is run without - relay, exit, bridge or client connectivity. - ''; - }; - - enableGeoIP = mkOption { - type = types.bool; - default = true; - description = '' - Whenever to configure Tor daemon to use GeoIP databases. - - Disabling this will disable by-country statistics for - bridges and relays and some client and third-party software - functionality. - ''; - }; - - extraConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Extra configuration. Contents will be added verbatim to the - configuration file at the end. - ''; - }; - - controlPort = mkOption { - type = types.nullOr (types.either types.int types.str); - default = null; - example = 9051; - description = '' - If set, Tor will accept connections on the specified port - and allow them to control the tor process. - ''; - }; - - controlSocket = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Wheter to enable Tor control socket. Control socket is created - in ${torRunDirectory}/control - ''; - }; - }; - - client = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Whether to enable Tor daemon to route application - connections. You might want to disable this if you plan - running a dedicated Tor relay. - ''; - }; - - socksListenAddress = mkOption { - type = types.str; - default = "127.0.0.1:9050"; - example = "192.168.0.1:9100"; - description = '' - Bind to this address to listen for connections from - Socks-speaking applications. Provides strong circuit - isolation, separate circuit per IP address. - ''; - }; - - socksListenAddressFaster = mkOption { - type = types.str; - default = "127.0.0.1:9063"; - example = "192.168.0.1:9101"; - description = '' - Bind to this address to listen for connections from - Socks-speaking applications. Same as - but uses weaker - circuit isolation to provide performance suitable for a - web browser. - ''; - }; - - socksPolicy = mkOption { - type = types.nullOr types.str; - default = null; - 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 - is set, we accept all (and only) requests from - . - ''; - }; - - socksIsolationOptions = mkOption (isolationOptions // { - default = ["IsolateDestAddr"]; - }); - - transparentProxy = { - enable = mkOption { - type = types.bool; - default = false; - description = "Whether to enable tor transparent proxy"; - }; - - listenAddress = mkOption { - type = types.str; - default = "127.0.0.1:9040"; - example = "192.168.0.1:9040"; - description = '' - Bind transparent proxy to this address. - ''; - }; - - isolationOptions = mkOption isolationOptions; - }; - - dns = { - enable = mkOption { - type = types.bool; - default = false; - description = "Whether to enable tor dns resolver"; - }; - - listenAddress = mkOption { - type = types.str; - default = "127.0.0.1:9053"; - example = "192.168.0.1:9053"; - description = '' - Bind tor dns to this address. - ''; - }; - - isolationOptions = mkOption isolationOptions; - - automapHostsSuffixes = mkOption { - type = types.listOf types.str; - default = [".onion" ".exit"]; - example = [".onion"]; - description = "List of suffixes to use with automapHostsOnResolve"; - }; - }; - - privoxy.enable = mkOption { - type = types.bool; - default = true; - description = '' - Whether to enable and configure the system Privoxy to use Tor's - faster port, suitable for HTTP. - - To have anonymity, protocols need to be scrubbed of identifying - information, and this can be accomplished for HTTP by Privoxy. - - Privoxy can also be useful for KDE torification. A good setup would be: - setting SOCKS proxy to the default Tor port, providing maximum - circuit isolation where possible; and setting HTTP proxy to Privoxy - to route HTTP traffic over faster, but less isolated port. - ''; - }; - }; - - relay = { - enable = mkOption { - type = types.bool; - default = false; - description = '' - Whether to enable relaying TOR traffic for others. - - See - for details. - - Setting this to true requires setting - - and - - options. - ''; - }; - - role = mkOption { - type = types.enum [ "exit" "relay" "bridge" "private-bridge" ]; - description = '' - Your role in Tor network. There're several options: - - - - exit - - - An exit relay. This allows Tor users to access regular - Internet services through your public IP. - - - - Running an exit relay may expose you to abuse - complaints. See - - for more info. - - - - You can specify which services Tor users may access via - your exit relay using option. - - - - - - relay - - - Regular relay. This allows Tor users to relay onion - traffic to other Tor nodes, but not to public - Internet. - - - - 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!). - - - - See - - for more info. - - - - - - bridge - - - Regular bridge. Works like a regular relay, but - doesn't list you in the public relay directory and - hides your Tor node behind obfsproxy. - - - - Using this option will make Tor advertise your bridge - to users through various mechanisms like - , though. - - - - - WARNING: THE FOLLOWING PARAGRAPH IS NOT LEGAL ADVICE. - Consult with your lawer when in doubt. - - - - 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). - - - - - See - for more info. - - - - - - private-bridge - - - Private bridge. Works like regular bridge, but does - not advertise your node in any way. - - - - Using this role means that you won't contribute to Tor - network in any way unless you advertise your node - yourself in some way. - - - - Use this if you want to run a private bridge, for - example because you'll give out your bridge address - manually to your friends. - - - - 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. - - - - See - for more info. - - - - - ''; - }; - - nickname = mkOption { - type = types.str; - default = "anonymous"; - description = '' - A unique handle for your TOR relay. - ''; - }; - - contactInfo = mkOption { - type = types.nullOr types.str; - default = null; - example = "admin@relay.com"; - description = '' - Contact information for the relay owner (e.g. a mail - address and GPG key ID). - ''; - }; - - accountingMax = mkOption { - type = types.nullOr types.str; - default = null; - example = "450 GBytes"; - description = '' - Specify maximum bandwidth allowed during an accounting period. This - allows you to limit overall tor bandwidth over some time period. - See the AccountingMax option by looking at the - tor manual tor - 1 for more. - - Note this limit applies individually to upload and - download; if you specify "500 GBytes" - here, then you may transfer up to 1 TBytes of overall - bandwidth (500 GB upload, 500 GB download). - ''; - }; - - accountingStart = mkOption { - type = types.nullOr types.str; - default = null; - example = "month 1 1:00"; - description = '' - Specify length of an accounting period. This allows you to limit - overall tor bandwidth over some time period. See the - AccountingStart option by looking at the tor - manual tor - 1 for more. - ''; - }; - - bandwidthRate = mkOption { - type = types.nullOr types.int; - default = null; - example = 100; - description = '' - Specify this to limit the bandwidth usage of relayed (server) - traffic. Your own traffic is still unthrottled. Units: bytes/second. - ''; - }; - - bandwidthBurst = mkOption { - type = types.nullOr types.int; - default = cfg.relay.bandwidthRate; - example = 200; - description = '' - Specify this to allow bursts of the bandwidth usage of relayed (server) - traffic. The average usage will still be as specified in relayBandwidthRate. - Your own traffic is still unthrottled. Units: bytes/second. - ''; - }; - - 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 - ORPort section in the Tor manual; see - tor - 1 for more details. - - At a minimum, you should just specify the port for the - relay to listen on; a common one like 143, 22, 80, or 443 - to help Tor users who may have very restrictive port-based - firewalls. - ''; - }; - - exitPolicy = mkOption { - type = types.nullOr types.str; - default = null; - example = "accept *:6660-6667,reject *:*"; - description = '' - A comma-separated list of exit policies. They're - 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 - available in the man page or at - . - - Look at - - 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 - reflect this -- otherwise Tor users will be told that - those destinations are down. - ''; - }; - }; - - hiddenServices = mkOption { - 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 = 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, ...}: { - 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.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}"; - }; - })); - }; - - authorizeClient = mkOption { - default = null; - description = "If configured, the hidden service is accessible for authorized clients only."; - type = types.nullOr (types.submodule ({...}: { - - options = { - - authType = mkOption { - type = types.enum [ "basic" "stealth" ]; - description = '' - Either "basic" for a general-purpose authorization protocol - or "stealth" for a less scalable protocol - that also hides service activity from unauthorized clients. - ''; - }; - - clientNames = mkOption { - type = types.nonEmptyListOf (types.strMatching "[A-Za-z0-9+-_]+"); - description = '' - Only clients that are listed here are authorized to access the hidden service. - Generated authorization data can be found in ${torDirectory}/onion/$name/hostname. - Clients need to put this authorization data in their configuration file using HidServAuth. - ''; - }; - }; - })); - }; - version = mkOption { - default = null; - description = "If configured, the hidden service uses version 3"; - type = types.nullOr (types.enum [ 2 3 ]); - }; - }; - - 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.groups.tor.gid = config.ids.gids.tor; - users.users.tor = - { description = "Tor Daemon User"; - createHome = true; - home = torDirectory; - group = "tor"; - uid = config.ids.uids.tor; - }; - - # We have to do this instead of using RuntimeDirectory option in - # the service below because systemd has no way to set owners of - # RuntimeDirectory and putting this into the service below - # requires that service to relax it's sandbox since this needs - # writable /run - systemd.services.tor-init = - { description = "Tor Daemon Init"; - wantedBy = [ "tor.service" ]; - after = [ "local-fs.target" ]; - script = '' - install -m 0700 -o tor -g tor -d ${torDirectory} ${torDirectory}/onion - install -m 0750 -o tor -g tor -d ${torRunDirectory} - ''; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - }; - }; - - systemd.services.tor = - { description = "Tor Daemon"; - path = [ pkgs.tor ]; - - wantedBy = [ "multi-user.target" ]; - after = [ "tor-init.service" "network.target" ]; - restartTriggers = [ torRcFile ]; - - serviceConfig = - { Type = "simple"; - # Translated from the upstream contrib/dist/tor.service.in - ExecStartPre = "${pkgs.tor}/bin/tor -f ${torRcFile} --verify-config"; - ExecStart = "${pkgs.tor}/bin/tor -f ${torRcFile}"; - ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; - KillSignal = "SIGINT"; - TimeoutSec = 30; - Restart = "on-failure"; - LimitNOFILE = 32768; - - # Hardening - # this seems to unshare /run despite what systemd.exec(5) says - PrivateTmp = mkIf (!cfg.controlSocket.enable) "yes"; - PrivateDevices = "yes"; - ProtectHome = "yes"; - ProtectSystem = "strict"; - InaccessiblePaths = "/home"; - ReadOnlyPaths = "/"; - ReadWritePaths = [ torDirectory torRunDirectory ]; - NoNewPrivileges = "yes"; - - # tor.service.in has this in, but this line it fails to spawn a namespace when using hidden services - #CapabilityBoundingSet = "CAP_SETUID CAP_SETGID CAP_NET_BIND_SERVICE"; - }; - }; - - environment.systemPackages = [ pkgs.tor ]; - - services.privoxy = mkIf (cfg.client.enable && cfg.client.privoxy.enable) { - enable = true; - extraConfig = '' - forward-socks4a / ${cfg.client.socksListenAddressFaster} . - toggle 1 - enable-remote-toggle 0 - enable-edit-actions 0 - enable-remote-http-toggle 0 - ''; - }; - }; -}