at v206 5.4 kB view raw
1{ config, lib, pkgs, ... }: 2with lib; 3 4let 5 apparmorEnabled = config.security.apparmor.enable; 6 dnscrypt-proxy = pkgs.dnscrypt-proxy; 7 cfg = config.services.dnscrypt-proxy; 8 resolverListFile = "${dnscrypt-proxy}/share/dnscrypt-proxy/dnscrypt-resolvers.csv"; 9 localAddress = "${cfg.localAddress}:${toString cfg.localPort}"; 10 daemonArgs = 11 [ "--local-address=${localAddress}" 12 (optionalString cfg.tcpOnly "--tcp-only") 13 ] 14 ++ resolverArgs; 15 resolverArgs = if (cfg.customResolver != null) 16 then 17 [ "--resolver-address=${cfg.customResolver.address}:${toString cfg.customResolver.port}" 18 "--provider-name=${cfg.customResolver.name}" 19 "--provider-key=${cfg.customResolver.key}" 20 ] 21 else 22 [ "--resolvers-list=${resolverListFile}" 23 "--resolver-name=${toString cfg.resolverName}" 24 ]; 25in 26 27{ 28 options = { 29 services.dnscrypt-proxy = { 30 enable = mkEnableOption '' 31 Enable dnscrypt-proxy. The proxy relays regular DNS queries to a 32 DNSCrypt enabled upstream resolver. The traffic between the 33 client and the upstream resolver is encrypted and authenticated, 34 which may mitigate the risk of MITM attacks and third-party 35 snooping (assuming the upstream is trustworthy). 36 ''; 37 localAddress = mkOption { 38 default = "127.0.0.1"; 39 type = types.string; 40 description = '' 41 Listen for DNS queries on this address. 42 ''; 43 }; 44 localPort = mkOption { 45 default = 53; 46 type = types.int; 47 description = '' 48 Listen on this port. 49 ''; 50 }; 51 resolverName = mkOption { 52 default = "opendns"; 53 type = types.nullOr types.string; 54 description = '' 55 The name of the upstream DNSCrypt resolver to use. 56 ''; 57 }; 58 customResolver = mkOption { 59 default = null; 60 description = '' 61 Use a resolver not listed in the upstream list (e.g., 62 a private DNSCrypt provider). For advanced users only. 63 If specified, this option takes precedence. 64 ''; 65 type = types.nullOr (types.submodule ({ ... }: { options = { 66 address = mkOption { 67 type = types.str; 68 description = "Resolver IP address"; 69 example = "208.67.220.220"; 70 }; 71 port = mkOption { 72 type = types.int; 73 description = "Resolver port"; 74 default = 443; 75 }; 76 name = mkOption { 77 type = types.str; 78 description = "Provider fully qualified domain name"; 79 example = "2.dnscrypt-cert.opendns.com"; 80 }; 81 key = mkOption { 82 type = types.str; 83 description = "Provider public key"; 84 example = "B735:1140:206F:225D:3E2B:D822:D7FD:691E:A1C3:3CC8:D666:8D0C:BE04:BFAB:CA43:FB79"; 85 }; }; })); 86 }; 87 tcpOnly = mkOption { 88 default = false; 89 type = types.bool; 90 description = '' 91 Force sending encrypted DNS queries to the upstream resolver 92 over TCP instead of UDP (on port 443). Enabling this option may 93 help circumvent filtering, but should not be used otherwise. 94 ''; 95 }; 96 }; 97 }; 98 99 config = mkIf cfg.enable { 100 101 assertions = [ 102 { assertion = (cfg.customResolver != null) || (cfg.resolverName != null); 103 message = "please configure upstream DNSCrypt resolver"; 104 } 105 ]; 106 107 security.apparmor.profiles = mkIf apparmorEnabled (singleton (pkgs.writeText "apparmor-dnscrypt-proxy" '' 108 ${dnscrypt-proxy}/bin/dnscrypt-proxy { 109 /dev/null rw, 110 /dev/urandom r, 111 112 /etc/passwd r, 113 /etc/group r, 114 ${config.environment.etc."nsswitch.conf".source} r, 115 116 ${pkgs.glibc}/lib/*.so mr, 117 ${pkgs.tzdata}/share/zoneinfo/** r, 118 119 network inet stream, 120 network inet6 stream, 121 network inet dgram, 122 network inet6 dgram, 123 124 ${pkgs.gcc.cc}/lib/libssp.so.* mr, 125 ${pkgs.libsodium}/lib/libsodium.so.* mr, 126 ${pkgs.systemd}/lib/libsystemd.so.* mr, 127 ${pkgs.xz}/lib/liblzma.so.* mr, 128 ${pkgs.libgcrypt}/lib/libgcrypt.so.* mr, 129 ${pkgs.libgpgerror}/lib/libgpg-error.so.* mr, 130 131 ${resolverListFile} r, 132 } 133 '')); 134 135 users.extraUsers.dnscrypt-proxy = { 136 uid = config.ids.uids.dnscrypt-proxy; 137 description = "dnscrypt-proxy daemon user"; 138 }; 139 users.extraGroups.dnscrypt-proxy.gid = config.ids.gids.dnscrypt-proxy; 140 141 systemd.sockets.dnscrypt-proxy = { 142 description = "dnscrypt-proxy listening socket"; 143 socketConfig = { 144 ListenStream = "${localAddress}"; 145 ListenDatagram = "${localAddress}"; 146 }; 147 wantedBy = [ "sockets.target" ]; 148 }; 149 150 systemd.services.dnscrypt-proxy = { 151 description = "dnscrypt-proxy daemon"; 152 after = [ "network.target" ] ++ optional apparmorEnabled "apparmor.service"; 153 requires = [ "dnscrypt-proxy.socket "] ++ optional apparmorEnabled "apparmor.service"; 154 serviceConfig = { 155 Type = "simple"; 156 NonBlocking = "true"; 157 ExecStart = "${dnscrypt-proxy}/bin/dnscrypt-proxy ${toString daemonArgs}"; 158 User = "dnscrypt-proxy"; 159 Group = "dnscrypt-proxy"; 160 PrivateTmp = true; 161 PrivateDevices = true; 162 }; 163 }; 164 }; 165}