From dfe20de78257fb24fdea011eb3a9b71eb000241d Mon Sep 17 00:00:00 2001 From: Joachim Fasting Date: Mon, 23 Feb 2015 18:02:12 +0100 Subject: [PATCH 1/7] nixos: permit dnscrypt-proxy service to read basic user/group info If nscd is not running, dnscrypt-proxy crashes without read access to /etc/{password,group,nsswitch.conf}. --- nixos/modules/services/networking/dnscrypt-proxy.nix | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix index 5cc33f35adb..78e240e49ba 100644 --- a/nixos/modules/services/networking/dnscrypt-proxy.nix +++ b/nixos/modules/services/networking/dnscrypt-proxy.nix @@ -104,6 +104,10 @@ in /dev/null rw, /dev/urandom r, + /etc/passwd r, + /etc/group r, + ${config.environment.etc."nsswitch.conf".source} r, + ${pkgs.glibc}/lib/*.so mr, ${pkgs.tzdata}/share/zoneinfo/** r, From 114cb31b659271ad38e4717291622e88f0126ddb Mon Sep 17 00:00:00 2001 From: Joachim Fasting Date: Sat, 7 Mar 2015 19:09:52 +0100 Subject: [PATCH 2/7] dnscrypt-proxy: enable systemd support on linux This permits using socket activation in the NixOS service module. --- pkgs/tools/networking/dnscrypt-proxy/default.nix | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pkgs/tools/networking/dnscrypt-proxy/default.nix b/pkgs/tools/networking/dnscrypt-proxy/default.nix index 11dadf9dcd8..9d86f648470 100644 --- a/pkgs/tools/networking/dnscrypt-proxy/default.nix +++ b/pkgs/tools/networking/dnscrypt-proxy/default.nix @@ -1,4 +1,4 @@ -{ stdenv, fetchurl, libsodium }: +{ stdenv, fetchurl, libsodium, pkgconfig, systemd }: stdenv.mkDerivation rec { name = "dnscrypt-proxy-1.4.3"; @@ -8,7 +8,11 @@ stdenv.mkDerivation rec { sha256 = "0cij80ryxnikpmm6s79c2fqg6bdiz1wdy50xrnd7w954vw9mhr0b"; }; - buildInputs = [ libsodium ]; + configureFlags = '' + ${stdenv.lib.optionalString stdenv.isLinux "--with-systemd"} + ''; + + buildInputs = [ pkgconfig libsodium ] ++ stdenv.lib.optional stdenv.isLinux systemd; meta = { description = "A tool for securing communications between a client and a DNS resolver"; From 823bb5dd4d9fabf39a81c9374076b8ecdc209a61 Mon Sep 17 00:00:00 2001 From: Joachim Fasting Date: Sat, 7 Mar 2015 19:13:12 +0100 Subject: [PATCH 3/7] nixos: implement socket-activation for dnscrypt-proxy The socket definition is derived from upstream with the exception that it does not depend on network.target, as this creates a cycle between basic.target and sockets.target. The apparmor profile has been updated to account for additional runtime dependencies introduced by enabling systemd support. --- .../services/networking/dnscrypt-proxy.nix | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix index 78e240e49ba..2e3add3db85 100644 --- a/nixos/modules/services/networking/dnscrypt-proxy.nix +++ b/nixos/modules/services/networking/dnscrypt-proxy.nix @@ -7,8 +7,7 @@ let cfg = config.services.dnscrypt-proxy; uid = config.ids.uids.dnscrypt-proxy; daemonArgs = - [ "--daemonize" - "--user=dnscrypt-proxy" + [ "--user=dnscrypt-proxy" "--local-address=${cfg.localAddress}:${toString cfg.port}" (optionalString cfg.tcpOnly "--tcp-only") "--resolvers-list=${dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv" @@ -114,6 +113,10 @@ in ${dnscrypt-proxy}/share/dnscrypt-proxy/** r, ${pkgs.gcc.cc}/lib/libssp.so.* mr, ${pkgs.libsodium}/lib/libsodium.so.* mr, + ${pkgs.systemd}/lib/libsystemd.so.* mr, + ${pkgs.xz}/lib/liblzma.so.* mr, + ${pkgs.libgcrypt}/lib/libgcrypt.so.* mr, + ${pkgs.libgpgerror}/lib/libgpg-error.so.* mr, } '') ]; @@ -128,13 +131,27 @@ in ### Service definition + ## derived from upstream dnscrypt-proxy.socket + systemd.sockets.dnscrypt-proxy = { + description = "dnscrypt-proxy listening socket"; + + socketConfig = { + ListenStream = "${cfg.localAddress}:${toString cfg.port}"; + ListenDatagram = "${cfg.localAddress}:${toString cfg.port}"; + }; + + wantedBy = [ "sockets.target" ]; + }; + + # derived from upstream dnscrypt-proxy.service systemd.services.dnscrypt-proxy = { description = "dnscrypt-proxy daemon"; after = [ "network.target" ] ++ optional apparmorEnabled "apparmor.service"; - requires = mkIf apparmorEnabled [ "apparmor.service" ]; - wantedBy = [ "multi-user.target" ]; + requires = [ "dnscrypt-proxy.socket "] ++ optional apparmorEnabled "apparmor.service"; serviceConfig = { - Type = "forking"; + Type = "simple"; + ## note: NonBlocking is required for socket activation to work + NonBlocking = "true"; ExecStart = "${dnscrypt-proxy}/bin/dnscrypt-proxy ${toString daemonArgs}"; }; }; From a88a6bc676cc82c2a1050addd0d36b0064e70242 Mon Sep 17 00:00:00 2001 From: Joachim Fasting Date: Sun, 15 Mar 2015 22:19:48 +0100 Subject: [PATCH 4/7] nixos: additional hardening for dnscrypt-proxy - Run as unprivileged user/group via systemd, obviating the need to specify capabilities, etc. - Run with private tmp and minimal device name space --- nixos/modules/misc/ids.nix | 2 +- .../services/networking/dnscrypt-proxy.nix | 48 ++++++++----------- 2 files changed, 22 insertions(+), 28 deletions(-) diff --git a/nixos/modules/misc/ids.nix b/nixos/modules/misc/ids.nix index d283a633734..b66e95fd0d3 100644 --- a/nixos/modules/misc/ids.nix +++ b/nixos/modules/misc/ids.nix @@ -376,7 +376,7 @@ seeks = 148; prosody = 149; i2pd = 150; - #dnscrypt-proxy = 151; # unused + dnscrypt-proxy = 151; systemd-network = 152; systemd-resolve = 153; systemd-timesync = 154; diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix index 2e3add3db85..60016994016 100644 --- a/nixos/modules/services/networking/dnscrypt-proxy.nix +++ b/nixos/modules/services/networking/dnscrypt-proxy.nix @@ -5,12 +5,11 @@ let apparmorEnabled = config.security.apparmor.enable; dnscrypt-proxy = pkgs.dnscrypt-proxy; cfg = config.services.dnscrypt-proxy; - uid = config.ids.uids.dnscrypt-proxy; + resolverListFile = "${dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv"; daemonArgs = - [ "--user=dnscrypt-proxy" - "--local-address=${cfg.localAddress}:${toString cfg.port}" + [ "--local-address=${cfg.localAddress}:${toString cfg.port}" (optionalString cfg.tcpOnly "--tcp-only") - "--resolvers-list=${dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv" + "--resolvers-list=${resolverListFile}" "--resolver-name=${cfg.resolverName}" ]; in @@ -56,10 +55,10 @@ in default = "opendns"; type = types.string; description = '' - The name of the upstream DNSCrypt resolver to use. - See ${dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv - for alternative resolvers (e.g., if you are concerned about logging - and/or server location). + The name of the upstream DNSCrypt resolver to use. See + ${resolverListFile} for alternative resolvers + (e.g., if you are concerned about logging and/or server + location). ''; }; @@ -88,17 +87,6 @@ in (pkgs.writeText "apparmor-dnscrypt-proxy" '' ${dnscrypt-proxy}/bin/dnscrypt-proxy { - network inet stream, - network inet6 stream, - network inet dgram, - network inet6 dgram, - - capability ipc_lock, - capability net_bind_service, - capability net_admin, - capability sys_chroot, - capability setgid, - capability setuid, /dev/null rw, /dev/urandom r, @@ -110,26 +98,28 @@ in ${pkgs.glibc}/lib/*.so mr, ${pkgs.tzdata}/share/zoneinfo/** r, - ${dnscrypt-proxy}/share/dnscrypt-proxy/** r, + network inet stream, + network inet6 stream, + network inet dgram, + network inet6 dgram, + ${pkgs.gcc.cc}/lib/libssp.so.* mr, ${pkgs.libsodium}/lib/libsodium.so.* mr, ${pkgs.systemd}/lib/libsystemd.so.* mr, ${pkgs.xz}/lib/liblzma.so.* mr, ${pkgs.libgcrypt}/lib/libgcrypt.so.* mr, ${pkgs.libgpgerror}/lib/libgpg-error.so.* mr, + + ${resolverListFile} r, } '') ]; - ### User - - users.extraUsers = singleton { - inherit uid; - name = "dnscrypt-proxy"; + users.extraUsers.dnscrypt-proxy = { + uid = config.ids.uids.dnscrypt-proxy; description = "dnscrypt-proxy daemon user"; }; - - ### Service definition + users.extraGroups.dnscrypt-proxy.gid = config.ids.gids.dnscrypt-proxy; ## derived from upstream dnscrypt-proxy.socket systemd.sockets.dnscrypt-proxy = { @@ -153,6 +143,10 @@ in ## note: NonBlocking is required for socket activation to work NonBlocking = "true"; ExecStart = "${dnscrypt-proxy}/bin/dnscrypt-proxy ${toString daemonArgs}"; + User = "dnscrypt-proxy"; + Group = "dnscrypt-proxy"; + PrivateTmp = true; + PrivateDevices = true; }; }; From 2e8bc2bd5c264cf30bfb9b357e2a2b64416002e1 Mon Sep 17 00:00:00 2001 From: Joachim Fasting Date: Sun, 15 Mar 2015 22:22:45 +0100 Subject: [PATCH 5/7] nixos: cosmetic improvements to dnscrypt-proxy service module Remove superflous whitespace & comments --- .../services/networking/dnscrypt-proxy.nix | 85 +++++++------------ 1 file changed, 29 insertions(+), 56 deletions(-) diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix index 60016994016..4505ce31d0f 100644 --- a/nixos/modules/services/networking/dnscrypt-proxy.nix +++ b/nixos/modules/services/networking/dnscrypt-proxy.nix @@ -15,26 +15,19 @@ let in { - ##### interface - options = { - services.dnscrypt-proxy = { - enable = mkOption { default = false; type = types.bool; description = '' - Enable dnscrypt-proxy. - The proxy relays regular DNS queries to a DNSCrypt enabled - upstream resolver. - The traffic between the client and the upstream resolver is - encrypted and authenticated, which may mitigate the risk of MITM - attacks and third-party snooping (assuming the upstream is - trustworthy). + Enable dnscrypt-proxy. The proxy relays regular DNS queries to a + DNSCrypt enabled upstream resolver. The traffic between the + client and the upstream resolver is encrypted and authenticated, + which may mitigate the risk of MITM attacks and third-party + snooping (assuming the upstream is trustworthy). ''; }; - localAddress = mkOption { default = "127.0.0.1"; type = types.string; @@ -42,7 +35,6 @@ in Listen for DNS queries on this address. ''; }; - port = mkOption { default = 53; type = types.int; @@ -50,7 +42,6 @@ in Listen on this port. ''; }; - resolverName = mkOption { default = "opendns"; type = types.string; @@ -61,59 +52,47 @@ in location). ''; }; - tcpOnly = mkOption { default = false; type = types.bool; description = '' Force sending encrypted DNS queries to the upstream resolver - over TCP instead of UDP (on port 443). - Enabling this option may help circumvent filtering, but should - not be used otherwise. + over TCP instead of UDP (on port 443). Enabling this option may + help circumvent filtering, but should not be used otherwise. ''; }; - }; - }; - ##### implementation - config = mkIf cfg.enable { - ### AppArmor profile + security.apparmor.profiles = mkIf apparmorEnabled (singleton (pkgs.writeText "apparmor-dnscrypt-proxy" '' + ${dnscrypt-proxy}/bin/dnscrypt-proxy { + /dev/null rw, + /dev/urandom r, - security.apparmor.profiles = mkIf apparmorEnabled [ - (pkgs.writeText "apparmor-dnscrypt-proxy" '' + /etc/passwd r, + /etc/group r, + ${config.environment.etc."nsswitch.conf".source} r, - ${dnscrypt-proxy}/bin/dnscrypt-proxy { + ${pkgs.glibc}/lib/*.so mr, + ${pkgs.tzdata}/share/zoneinfo/** r, - /dev/null rw, - /dev/urandom r, + network inet stream, + network inet6 stream, + network inet dgram, + network inet6 dgram, - /etc/passwd r, - /etc/group r, - ${config.environment.etc."nsswitch.conf".source} r, + ${pkgs.gcc.cc}/lib/libssp.so.* mr, + ${pkgs.libsodium}/lib/libsodium.so.* mr, + ${pkgs.systemd}/lib/libsystemd.so.* mr, + ${pkgs.xz}/lib/liblzma.so.* mr, + ${pkgs.libgcrypt}/lib/libgcrypt.so.* mr, + ${pkgs.libgpgerror}/lib/libgpg-error.so.* mr, - ${pkgs.glibc}/lib/*.so mr, - ${pkgs.tzdata}/share/zoneinfo/** r, - - network inet stream, - network inet6 stream, - network inet dgram, - network inet6 dgram, - - ${pkgs.gcc.cc}/lib/libssp.so.* mr, - ${pkgs.libsodium}/lib/libsodium.so.* mr, - ${pkgs.systemd}/lib/libsystemd.so.* mr, - ${pkgs.xz}/lib/liblzma.so.* mr, - ${pkgs.libgcrypt}/lib/libgcrypt.so.* mr, - ${pkgs.libgpgerror}/lib/libgpg-error.so.* mr, - - ${resolverListFile} r, - } - '') - ]; + ${resolverListFile} r, + } + '')); users.extraUsers.dnscrypt-proxy = { uid = config.ids.uids.dnscrypt-proxy; @@ -121,26 +100,21 @@ in }; users.extraGroups.dnscrypt-proxy.gid = config.ids.gids.dnscrypt-proxy; - ## derived from upstream dnscrypt-proxy.socket systemd.sockets.dnscrypt-proxy = { description = "dnscrypt-proxy listening socket"; - socketConfig = { ListenStream = "${cfg.localAddress}:${toString cfg.port}"; ListenDatagram = "${cfg.localAddress}:${toString cfg.port}"; }; - wantedBy = [ "sockets.target" ]; }; - # derived from upstream dnscrypt-proxy.service systemd.services.dnscrypt-proxy = { description = "dnscrypt-proxy daemon"; after = [ "network.target" ] ++ optional apparmorEnabled "apparmor.service"; requires = [ "dnscrypt-proxy.socket "] ++ optional apparmorEnabled "apparmor.service"; serviceConfig = { Type = "simple"; - ## note: NonBlocking is required for socket activation to work NonBlocking = "true"; ExecStart = "${dnscrypt-proxy}/bin/dnscrypt-proxy ${toString daemonArgs}"; User = "dnscrypt-proxy"; @@ -149,6 +123,5 @@ in PrivateDevices = true; }; }; - }; } From 8131065b63601b40e21ad9e9f841b5e5fa2e0fd5 Mon Sep 17 00:00:00 2001 From: Joachim Fasting Date: Mon, 23 Mar 2015 20:44:55 +0100 Subject: [PATCH 6/7] dnscrypt-proxy service: use mkEnableOption --- .../services/networking/dnscrypt-proxy.nix | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix index 4505ce31d0f..b4801dc5551 100644 --- a/nixos/modules/services/networking/dnscrypt-proxy.nix +++ b/nixos/modules/services/networking/dnscrypt-proxy.nix @@ -17,17 +17,13 @@ in { options = { services.dnscrypt-proxy = { - enable = mkOption { - default = false; - type = types.bool; - description = '' - Enable dnscrypt-proxy. The proxy relays regular DNS queries to a - DNSCrypt enabled upstream resolver. The traffic between the - client and the upstream resolver is encrypted and authenticated, - which may mitigate the risk of MITM attacks and third-party - snooping (assuming the upstream is trustworthy). - ''; - }; + enable = mkEnableOption '' + Enable dnscrypt-proxy. The proxy relays regular DNS queries to a + DNSCrypt enabled upstream resolver. The traffic between the + client and the upstream resolver is encrypted and authenticated, + which may mitigate the risk of MITM attacks and third-party + snooping (assuming the upstream is trustworthy). + ''; localAddress = mkOption { default = "127.0.0.1"; type = types.string; From ffc6275e552b0fbc955ce96865de2fbb5a4c89d0 Mon Sep 17 00:00:00 2001 From: Joachim Fasting Date: Tue, 14 Apr 2015 23:11:28 +0200 Subject: [PATCH 7/7] dnscrypt-proxy service: support custom providers The primary use-case is private DNSCrypt providers. Also rename the `port` option to differentiate it from the `customResolver.port` option. --- nixos/modules/rename.nix | 3 + .../services/networking/dnscrypt-proxy.nix | 61 ++++++++++++++++--- 2 files changed, 56 insertions(+), 8 deletions(-) diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index fc83e7ed590..b3cd0c7f40b 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -141,6 +141,9 @@ in zipModules ([] ++ obsolete [ "services" "xserver" "windowManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ] ++ obsolete [ "services" "xserver" "desktopManager" "xbmc" ] [ "services" "xserver" "desktopManager" "kodi" ] +# DNSCrypt-proxy +++ obsolete [ "services" "dnscrypt-proxy" "port" ] [ "services" "dnscrypt-proxy" "localPort" ] + # Options that are obsolete and have no replacement. ++ obsolete' [ "boot" "loader" "grub" "bootDevice" ] ++ obsolete' [ "boot" "initrd" "luks" "enable" ] diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix index b4801dc5551..c724ee979c2 100644 --- a/nixos/modules/services/networking/dnscrypt-proxy.nix +++ b/nixos/modules/services/networking/dnscrypt-proxy.nix @@ -6,12 +6,22 @@ let dnscrypt-proxy = pkgs.dnscrypt-proxy; cfg = config.services.dnscrypt-proxy; resolverListFile = "${dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv"; + localAddress = "${cfg.localAddress}:${toString cfg.localPort}"; daemonArgs = - [ "--local-address=${cfg.localAddress}:${toString cfg.port}" + [ "--local-address=${localAddress}" (optionalString cfg.tcpOnly "--tcp-only") - "--resolvers-list=${resolverListFile}" - "--resolver-name=${cfg.resolverName}" - ]; + ] + ++ resolverArgs; + resolverArgs = if (cfg.customResolver != null) + then + [ "--resolver-address=${cfg.customResolver.address}:${toString cfg.customResolver.port}" + "--provider-name=${cfg.customResolver.name}" + "--provider-key=${cfg.customResolver.key}" + ] + else + [ "--resolvers-list=${resolverListFile}" + "--resolver-name=${toString cfg.resolverName}" + ]; in { @@ -31,7 +41,7 @@ in Listen for DNS queries on this address. ''; }; - port = mkOption { + localPort = mkOption { default = 53; type = types.int; description = '' @@ -40,7 +50,7 @@ in }; resolverName = mkOption { default = "opendns"; - type = types.string; + type = types.nullOr types.string; description = '' The name of the upstream DNSCrypt resolver to use. See ${resolverListFile} for alternative resolvers @@ -48,6 +58,35 @@ in location). ''; }; + customResolver = mkOption { + default = null; + description = '' + Use a resolver not listed in the upstream list (e.g., + a private DNSCrypt provider). For advanced users only. + If specified, this option takes precedence. + ''; + type = types.nullOr (types.submodule ({ ... }: { options = { + address = mkOption { + type = types.str; + description = "Resolver IP address"; + example = "208.67.220.220"; + }; + port = mkOption { + type = types.int; + description = "Resolver port"; + default = 443; + }; + name = mkOption { + type = types.str; + description = "Provider fully qualified domain name"; + example = "2.dnscrypt-cert.opendns.com"; + }; + key = mkOption { + type = types.str; + description = "Provider public key"; + example = "B735:1140:206F:225D:3E2B:D822:D7FD:691E:A1C3:3CC8:D666:8D0C:BE04:BFAB:CA43:FB79"; + }; }; })); + }; tcpOnly = mkOption { default = false; type = types.bool; @@ -62,6 +101,12 @@ in config = mkIf cfg.enable { + assertions = [ + { assertion = (cfg.customResolver != null) || (cfg.resolverName != null); + message = "please configure upstream DNSCrypt resolver"; + } + ]; + security.apparmor.profiles = mkIf apparmorEnabled (singleton (pkgs.writeText "apparmor-dnscrypt-proxy" '' ${dnscrypt-proxy}/bin/dnscrypt-proxy { /dev/null rw, @@ -99,8 +144,8 @@ in systemd.sockets.dnscrypt-proxy = { description = "dnscrypt-proxy listening socket"; socketConfig = { - ListenStream = "${cfg.localAddress}:${toString cfg.port}"; - ListenDatagram = "${cfg.localAddress}:${toString cfg.port}"; + ListenStream = "${localAddress}"; + ListenDatagram = "${localAddress}"; }; wantedBy = [ "sockets.target" ]; };