1{ config, lib, ... }:
2
3with lib;
4let
5 cfg = config.services.resolved;
6in
7{
8
9 options = {
10
11 services.resolved.enable = mkOption {
12 default = false;
13 type = types.bool;
14 description = ''
15 Whether to enable the systemd DNS resolver daemon.
16 '';
17 };
18
19 services.resolved.fallbackDns = mkOption {
20 default = [ ];
21 example = [ "8.8.8.8" "2001:4860:4860::8844" ];
22 type = types.listOf types.str;
23 description = ''
24 A list of IPv4 and IPv6 addresses to use as the fallback DNS servers.
25 If this option is empty, a compiled-in list of DNS servers is used instead.
26 '';
27 };
28
29 services.resolved.domains = mkOption {
30 default = config.networking.search;
31 example = [ "example.com" ];
32 type = types.listOf types.str;
33 description = ''
34 A list of domains. These domains are used as search suffixes
35 when resolving single-label host names (domain names which
36 contain no dot), in order to qualify them into fully-qualified
37 domain names (FQDNs).
38 </para><para>
39 For compatibility reasons, if this setting is not specified,
40 the search domains listed in
41 <filename>/etc/resolv.conf</filename> are used instead, if
42 that file exists and any domains are configured in it.
43 '';
44 };
45
46 services.resolved.llmnr = mkOption {
47 default = "true";
48 example = "false";
49 type = types.enum [ "true" "resolve" "false" ];
50 description = ''
51 Controls Link-Local Multicast Name Resolution support
52 (RFC 4795) on the local host.
53 </para><para>
54 If set to
55 <variablelist>
56 <varlistentry>
57 <term><literal>"true"</literal></term>
58 <listitem><para>
59 Enables full LLMNR responder and resolver support.
60 </para></listitem>
61 </varlistentry>
62 <varlistentry>
63 <term><literal>"false"</literal></term>
64 <listitem><para>
65 Disables both.
66 </para></listitem>
67 </varlistentry>
68 <varlistentry>
69 <term><literal>"resolve"</literal></term>
70 <listitem><para>
71 Only resolution support is enabled, but responding is disabled.
72 </para></listitem>
73 </varlistentry>
74 </variablelist>
75 '';
76 };
77
78 services.resolved.dnssec = mkOption {
79 default = "allow-downgrade";
80 example = "true";
81 type = types.enum [ "true" "allow-downgrade" "false" ];
82 description = ''
83 If set to
84 <variablelist>
85 <varlistentry>
86 <term><literal>"true"</literal></term>
87 <listitem><para>
88 all DNS lookups are DNSSEC-validated locally (excluding
89 LLMNR and Multicast DNS). Note that this mode requires a
90 DNS server that supports DNSSEC. If the DNS server does
91 not properly support DNSSEC all validations will fail.
92 </para></listitem>
93 </varlistentry>
94 <varlistentry>
95 <term><literal>"allow-downgrade"</literal></term>
96 <listitem><para>
97 DNSSEC validation is attempted, but if the server does not
98 support DNSSEC properly, DNSSEC mode is automatically
99 disabled. Note that this mode makes DNSSEC validation
100 vulnerable to "downgrade" attacks, where an attacker might
101 be able to trigger a downgrade to non-DNSSEC mode by
102 synthesizing a DNS response that suggests DNSSEC was not
103 supported.
104 </para></listitem>
105 </varlistentry>
106 <varlistentry>
107 <term><literal>"false"</literal></term>
108 <listitem><para>
109 DNS lookups are not DNSSEC validated.
110 </para></listitem>
111 </varlistentry>
112 </variablelist>
113 '';
114 };
115
116 services.resolved.extraConfig = mkOption {
117 default = "";
118 type = types.lines;
119 description = ''
120 Extra config to append to resolved.conf.
121 '';
122 };
123
124 };
125
126 config = mkIf cfg.enable {
127
128 systemd.additionalUpstreamSystemUnits = [
129 "systemd-resolved.service"
130 ];
131
132 systemd.services.systemd-resolved = {
133 wantedBy = [ "multi-user.target" ];
134 restartTriggers = [ config.environment.etc."systemd/resolved.conf".source ];
135 };
136
137 environment.etc."systemd/resolved.conf".text = ''
138 [Resolve]
139 ${optionalString (config.networking.nameservers != [])
140 "DNS=${concatStringsSep " " config.networking.nameservers}"}
141 ${optionalString (cfg.fallbackDns != [])
142 "FallbackDNS=${concatStringsSep " " cfg.fallbackDns}"}
143 ${optionalString (cfg.domains != [])
144 "Domains=${concatStringsSep " " cfg.domains}"}
145 LLMNR=${cfg.llmnr}
146 DNSSEC=${cfg.dnssec}
147 ${config.services.resolved.extraConfig}
148 '';
149
150 # If networkmanager is enabled, ask it to interface with resolved.
151 networking.networkmanager.dns = "systemd-resolved";
152 };
153
154}