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