at 24.11-pre 6.8 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4let 5 cfg = config.services.resolved; 6 7 dnsmasqResolve = config.services.dnsmasq.enable && 8 config.services.dnsmasq.resolveLocalQueries; 9 10in 11{ 12 13 options = { 14 15 services.resolved.enable = mkOption { 16 default = false; 17 type = types.bool; 18 description = '' 19 Whether to enable the systemd DNS resolver daemon, `systemd-resolved`. 20 21 Search for `services.resolved` to see all options. 22 ''; 23 }; 24 25 services.resolved.fallbackDns = mkOption { 26 default = null; 27 example = [ "8.8.8.8" "2001:4860:4860::8844" ]; 28 type = types.nullOr (types.listOf types.str); 29 description = '' 30 A list of IPv4 and IPv6 addresses to use as the fallback DNS servers. 31 If this option is null, a compiled-in list of DNS servers is used instead. 32 Setting this option to an empty list will override the built-in list to an empty list, disabling fallback. 33 ''; 34 }; 35 36 services.resolved.domains = mkOption { 37 default = config.networking.search; 38 defaultText = literalExpression "config.networking.search"; 39 example = [ "example.com" ]; 40 type = types.listOf types.str; 41 description = '' 42 A list of domains. These domains are used as search suffixes 43 when resolving single-label host names (domain names which 44 contain no dot), in order to qualify them into fully-qualified 45 domain names (FQDNs). 46 47 For compatibility reasons, if this setting is not specified, 48 the search domains listed in 49 {file}`/etc/resolv.conf` are used instead, if 50 that file exists and any domains are configured in it. 51 ''; 52 }; 53 54 services.resolved.llmnr = mkOption { 55 default = "true"; 56 example = "false"; 57 type = types.enum [ "true" "resolve" "false" ]; 58 description = '' 59 Controls Link-Local Multicast Name Resolution support 60 (RFC 4795) on the local host. 61 62 If set to 63 - `"true"`: Enables full LLMNR responder and resolver support. 64 - `"false"`: Disables both. 65 - `"resolve"`: Only resolution support is enabled, but responding is disabled. 66 ''; 67 }; 68 69 services.resolved.dnssec = mkOption { 70 default = "false"; 71 example = "true"; 72 type = types.enum [ "true" "allow-downgrade" "false" ]; 73 description = '' 74 If set to 75 - `"true"`: 76 all DNS lookups are DNSSEC-validated locally (excluding 77 LLMNR and Multicast DNS). Note that this mode requires a 78 DNS server that supports DNSSEC. If the DNS server does 79 not properly support DNSSEC all validations will fail. 80 - `"allow-downgrade"`: 81 DNSSEC validation is attempted, but if the server does not 82 support DNSSEC properly, DNSSEC mode is automatically 83 disabled. Note that this mode makes DNSSEC validation 84 vulnerable to "downgrade" attacks, where an attacker might 85 be able to trigger a downgrade to non-DNSSEC mode by 86 synthesizing a DNS response that suggests DNSSEC was not 87 supported. 88 - `"false"`: DNS lookups are not DNSSEC validated. 89 90 At the time of September 2023, systemd upstream advise 91 to disable DNSSEC by default as the current code 92 is not robust enough to deal with "in the wild" non-compliant 93 servers, which will usually give you a broken bad experience 94 in addition of insecure. 95 ''; 96 }; 97 98 services.resolved.dnsovertls = mkOption { 99 default = "false"; 100 example = "true"; 101 type = types.enum [ "true" "opportunistic" "false" ]; 102 description = '' 103 If set to 104 - `"true"`: 105 all DNS lookups will be encrypted. This requires 106 that the DNS server supports DNS-over-TLS and 107 has a valid certificate. If the hostname was specified 108 via the `address#hostname` format in {option}`services.resolved.domains` 109 then the specified hostname is used to validate its certificate. 110 - `"opportunistic"`: 111 all DNS lookups will attempt to be encrypted, but will fallback 112 to unecrypted requests if the server does not support DNS-over-TLS. 113 Note that this mode does allow for a malicious party to conduct a 114 downgrade attack by immitating the DNS server and pretending to not 115 support encryption. 116 - `"false"`: 117 all DNS lookups are done unencrypted. 118 ''; 119 }; 120 121 services.resolved.extraConfig = mkOption { 122 default = ""; 123 type = types.lines; 124 description = '' 125 Extra config to append to resolved.conf. 126 ''; 127 }; 128 129 }; 130 131 config = mkIf cfg.enable { 132 133 assertions = [ 134 { assertion = !config.networking.useHostResolvConf; 135 message = "Using host resolv.conf is not supported with systemd-resolved"; 136 } 137 ]; 138 139 users.users.systemd-resolve.group = "systemd-resolve"; 140 141 # add resolve to nss hosts database if enabled and nscd enabled 142 # system.nssModules is configured in nixos/modules/system/boot/systemd.nix 143 # added with order 501 to allow modules to go before with mkBefore 144 system.nssDatabases.hosts = (mkOrder 501 ["resolve [!UNAVAIL=return]"]); 145 146 systemd.additionalUpstreamSystemUnits = [ 147 "systemd-resolved.service" 148 ]; 149 150 systemd.services.systemd-resolved = { 151 wantedBy = [ "multi-user.target" ]; 152 aliases = [ "dbus-org.freedesktop.resolve1.service" ]; 153 restartTriggers = [ config.environment.etc."systemd/resolved.conf".source ]; 154 }; 155 156 environment.etc = { 157 "systemd/resolved.conf".text = '' 158 [Resolve] 159 ${optionalString (config.networking.nameservers != []) 160 "DNS=${concatStringsSep " " config.networking.nameservers}"} 161 ${optionalString (cfg.fallbackDns != null) 162 "FallbackDNS=${concatStringsSep " " cfg.fallbackDns}"} 163 ${optionalString (cfg.domains != []) 164 "Domains=${concatStringsSep " " cfg.domains}"} 165 LLMNR=${cfg.llmnr} 166 DNSSEC=${cfg.dnssec} 167 DNSOverTLS=${cfg.dnsovertls} 168 ${config.services.resolved.extraConfig} 169 ''; 170 171 # symlink the dynamic stub resolver of resolv.conf as recommended by upstream: 172 # https://www.freedesktop.org/software/systemd/man/systemd-resolved.html#/etc/resolv.conf 173 "resolv.conf".source = "/run/systemd/resolve/stub-resolv.conf"; 174 } // optionalAttrs dnsmasqResolve { 175 "dnsmasq-resolv.conf".source = "/run/systemd/resolve/resolv.conf"; 176 }; 177 178 # If networkmanager is enabled, ask it to interface with resolved. 179 networking.networkmanager.dns = "systemd-resolved"; 180 181 networking.resolvconf.package = pkgs.systemd; 182 183 }; 184 185}