at 23.11-beta 5.6 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 = lib.mdDoc '' 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 = [ ]; 27 example = [ "8.8.8.8" "2001:4860:4860::8844" ]; 28 type = types.listOf types.str; 29 description = lib.mdDoc '' 30 A list of IPv4 and IPv6 addresses to use as the fallback DNS servers. 31 If this option is empty, a compiled-in list of DNS servers is used instead. 32 ''; 33 }; 34 35 services.resolved.domains = mkOption { 36 default = config.networking.search; 37 defaultText = literalExpression "config.networking.search"; 38 example = [ "example.com" ]; 39 type = types.listOf types.str; 40 description = lib.mdDoc '' 41 A list of domains. These domains are used as search suffixes 42 when resolving single-label host names (domain names which 43 contain no dot), in order to qualify them into fully-qualified 44 domain names (FQDNs). 45 46 For compatibility reasons, if this setting is not specified, 47 the search domains listed in 48 {file}`/etc/resolv.conf` are used instead, if 49 that file exists and any domains are configured in it. 50 ''; 51 }; 52 53 services.resolved.llmnr = mkOption { 54 default = "true"; 55 example = "false"; 56 type = types.enum [ "true" "resolve" "false" ]; 57 description = lib.mdDoc '' 58 Controls Link-Local Multicast Name Resolution support 59 (RFC 4795) on the local host. 60 61 If set to 62 - `"true"`: Enables full LLMNR responder and resolver support. 63 - `"false"`: Disables both. 64 - `"resolve"`: Only resolution support is enabled, but responding is disabled. 65 ''; 66 }; 67 68 services.resolved.dnssec = mkOption { 69 default = "false"; 70 example = "true"; 71 type = types.enum [ "true" "allow-downgrade" "false" ]; 72 description = lib.mdDoc '' 73 If set to 74 - `"true"`: 75 all DNS lookups are DNSSEC-validated locally (excluding 76 LLMNR and Multicast DNS). Note that this mode requires a 77 DNS server that supports DNSSEC. If the DNS server does 78 not properly support DNSSEC all validations will fail. 79 - `"allow-downgrade"`: 80 DNSSEC validation is attempted, but if the server does not 81 support DNSSEC properly, DNSSEC mode is automatically 82 disabled. Note that this mode makes DNSSEC validation 83 vulnerable to "downgrade" attacks, where an attacker might 84 be able to trigger a downgrade to non-DNSSEC mode by 85 synthesizing a DNS response that suggests DNSSEC was not 86 supported. 87 - `"false"`: DNS lookups are not DNSSEC validated. 88 89 At the time of September 2023, systemd upstream advise 90 to disable DNSSEC by default as the current code 91 is not robust enough to deal with "in the wild" non-compliant 92 servers, which will usually give you a broken bad experience 93 in addition of insecure. 94 ''; 95 }; 96 97 services.resolved.extraConfig = mkOption { 98 default = ""; 99 type = types.lines; 100 description = lib.mdDoc '' 101 Extra config to append to resolved.conf. 102 ''; 103 }; 104 105 }; 106 107 config = mkIf cfg.enable { 108 109 assertions = [ 110 { assertion = !config.networking.useHostResolvConf; 111 message = "Using host resolv.conf is not supported with systemd-resolved"; 112 } 113 ]; 114 115 users.users.systemd-resolve.group = "systemd-resolve"; 116 117 # add resolve to nss hosts database if enabled and nscd enabled 118 # system.nssModules is configured in nixos/modules/system/boot/systemd.nix 119 # added with order 501 to allow modules to go before with mkBefore 120 system.nssDatabases.hosts = (mkOrder 501 ["resolve [!UNAVAIL=return]"]); 121 122 systemd.additionalUpstreamSystemUnits = [ 123 "systemd-resolved.service" 124 ]; 125 126 systemd.services.systemd-resolved = { 127 wantedBy = [ "multi-user.target" ]; 128 aliases = [ "dbus-org.freedesktop.resolve1.service" ]; 129 restartTriggers = [ config.environment.etc."systemd/resolved.conf".source ]; 130 }; 131 132 environment.etc = { 133 "systemd/resolved.conf".text = '' 134 [Resolve] 135 ${optionalString (config.networking.nameservers != []) 136 "DNS=${concatStringsSep " " config.networking.nameservers}"} 137 ${optionalString (cfg.fallbackDns != []) 138 "FallbackDNS=${concatStringsSep " " cfg.fallbackDns}"} 139 ${optionalString (cfg.domains != []) 140 "Domains=${concatStringsSep " " cfg.domains}"} 141 LLMNR=${cfg.llmnr} 142 DNSSEC=${cfg.dnssec} 143 ${config.services.resolved.extraConfig} 144 ''; 145 146 # symlink the dynamic stub resolver of resolv.conf as recommended by upstream: 147 # https://www.freedesktop.org/software/systemd/man/systemd-resolved.html#/etc/resolv.conf 148 "resolv.conf".source = "/run/systemd/resolve/stub-resolv.conf"; 149 } // optionalAttrs dnsmasqResolve { 150 "dnsmasq-resolv.conf".source = "/run/systemd/resolve/resolv.conf"; 151 }; 152 153 # If networkmanager is enabled, ask it to interface with resolved. 154 networking.networkmanager.dns = "systemd-resolved"; 155 156 networking.resolvconf.package = pkgs.systemd; 157 158 }; 159 160}