at 25.11-pre 5.4 kB view raw
1{ 2 config, 3 lib, 4 pkgs, 5 ... 6}: 7let 8 cfg = config.services.dnsdist; 9 10 toLua = lib.generators.toLua { }; 11 12 mkBind = cfg: toLua "${cfg.listenAddress}:${toString cfg.listenPort}"; 13 14 configFile = pkgs.writeText "dnsdist.conf" '' 15 setLocal(${mkBind cfg}) 16 ${lib.optionalString cfg.dnscrypt.enable dnscryptSetup} 17 ${cfg.extraConfig} 18 ''; 19 20 dnscryptSetup = '' 21 last_rotation = 0 22 cert_serial = 0 23 provider_key = ${toLua cfg.dnscrypt.providerKey} 24 cert_lifetime = ${toLua cfg.dnscrypt.certLifetime} * 60 25 26 function file_exists(name) 27 local f = io.open(name, "r") 28 return f ~= nil and io.close(f) 29 end 30 31 function dnscrypt_setup() 32 -- generate provider keys on first run 33 if provider_key == nil then 34 provider_key = "/var/lib/dnsdist/private.key" 35 if not file_exists(provider_key) then 36 generateDNSCryptProviderKeys("/var/lib/dnsdist/public.key", 37 "/var/lib/dnsdist/private.key") 38 print("DNSCrypt: generated provider keypair") 39 end 40 end 41 42 -- generate resolver certificate 43 local now = os.time() 44 generateDNSCryptCertificate( 45 provider_key, "/run/dnsdist/resolver.cert", "/run/dnsdist/resolver.key", 46 cert_serial, now - 60, now + cert_lifetime) 47 addDNSCryptBind( 48 ${mkBind cfg.dnscrypt}, ${toLua cfg.dnscrypt.providerName}, 49 "/run/dnsdist/resolver.cert", "/run/dnsdist/resolver.key") 50 end 51 52 function maintenance() 53 -- certificate rotation 54 local now = os.time() 55 local dnscrypt = getDNSCryptBind(0) 56 57 if ((now - last_rotation) > 0.9 * cert_lifetime) then 58 -- generate and start using a new certificate 59 dnscrypt:generateAndLoadInMemoryCertificate( 60 provider_key, cert_serial + 1, 61 now - 60, now + cert_lifetime) 62 63 -- stop advertising the last certificate 64 dnscrypt:markInactive(cert_serial) 65 66 -- remove the second to last certificate 67 if (cert_serial > 1) then 68 dnscrypt:removeInactiveCertificate(cert_serial - 1) 69 end 70 71 print("DNSCrypt: rotated certificate") 72 73 -- increment serial number 74 cert_serial = cert_serial + 1 75 last_rotation = now 76 end 77 end 78 79 dnscrypt_setup() 80 ''; 81 82in 83{ 84 options = { 85 services.dnsdist = { 86 enable = lib.mkEnableOption "dnsdist domain name server"; 87 88 listenAddress = lib.mkOption { 89 type = lib.types.str; 90 description = "Listen IP address"; 91 default = "0.0.0.0"; 92 }; 93 listenPort = lib.mkOption { 94 type = lib.types.port; 95 description = "Listen port"; 96 default = 53; 97 }; 98 99 dnscrypt = { 100 enable = lib.mkEnableOption "a DNSCrypt endpoint to dnsdist"; 101 102 listenAddress = lib.mkOption { 103 type = lib.types.str; 104 description = "Listen IP address of the endpoint"; 105 default = "0.0.0.0"; 106 }; 107 108 listenPort = lib.mkOption { 109 type = lib.types.port; 110 description = "Listen port of the endpoint"; 111 default = 443; 112 }; 113 114 providerName = lib.mkOption { 115 type = lib.types.str; 116 default = "2.dnscrypt-cert.${config.networking.hostName}"; 117 defaultText = lib.literalExpression "2.dnscrypt-cert.\${config.networking.hostName}"; 118 example = "2.dnscrypt-cert.myresolver"; 119 description = '' 120 The name that will be given to this DNSCrypt resolver. 121 122 ::: {.note} 123 The provider name must start with `2.dnscrypt-cert.`. 124 ::: 125 ''; 126 }; 127 128 providerKey = lib.mkOption { 129 type = lib.types.nullOr lib.types.path; 130 default = null; 131 description = '' 132 The filepath to the provider secret key. 133 If not given a new provider key pair will be generated in 134 /var/lib/dnsdist on the first run. 135 136 ::: {.note} 137 The file must be readable by the dnsdist user/group. 138 ::: 139 ''; 140 }; 141 142 certLifetime = lib.mkOption { 143 type = lib.types.ints.positive; 144 default = 15; 145 description = '' 146 The lifetime (in minutes) of the resolver certificate. 147 This will be automatically rotated before expiration. 148 ''; 149 }; 150 151 }; 152 153 extraConfig = lib.mkOption { 154 type = lib.types.lines; 155 default = ""; 156 description = '' 157 Extra lines to be added verbatim to dnsdist.conf. 158 ''; 159 }; 160 }; 161 }; 162 163 config = lib.mkIf cfg.enable { 164 users.users.dnsdist = { 165 description = "dnsdist daemons user"; 166 isSystemUser = true; 167 group = "dnsdist"; 168 }; 169 170 users.groups.dnsdist = { }; 171 172 systemd.packages = [ pkgs.dnsdist ]; 173 174 systemd.services.dnsdist = { 175 wantedBy = [ "multi-user.target" ]; 176 177 startLimitIntervalSec = 0; 178 serviceConfig = { 179 User = "dnsdist"; 180 Group = "dnsdist"; 181 RuntimeDirectory = "dnsdist"; 182 StateDirectory = "dnsdist"; 183 # upstream overrides for better nixos compatibility 184 ExecStartPre = [ 185 "" 186 "${pkgs.dnsdist}/bin/dnsdist --check-config --config ${configFile}" 187 ]; 188 ExecStart = [ 189 "" 190 "${pkgs.dnsdist}/bin/dnsdist --supervised --disable-syslog --config ${configFile}" 191 ]; 192 }; 193 }; 194 }; 195}