]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-conf.c
tree-wide: use ASSERT_PTR more
[thirdparty/systemd.git] / src / resolve / resolved-conf.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
4e945a6f 2
b5efdb8a 3#include "alloc-util.h"
4e945a6f 4#include "conf-parser.h"
a0f29c76 5#include "def.h"
b5efdb8a 6#include "extract-word.h"
6501dd31 7#include "hexdecoct.h"
6bedfcbb 8#include "parse-util.h"
4e945a6f 9#include "resolved-conf.h"
6501dd31 10#include "resolved-dnssd.h"
be28f72d
DDM
11#include "resolved-manager.h"
12#include "resolved-dns-search-domain.h"
1f05101f 13#include "resolved-dns-stub.h"
be28f72d 14#include "dns-domain.h"
2d95d81f 15#include "socket-netlink.h"
6501dd31 16#include "specifier.h"
1ae43295 17#include "string-table.h"
6bedfcbb 18#include "string-util.h"
1f05101f 19#include "strv.h"
6501dd31 20#include "utf8.h"
4e945a6f 21
1ae43295
DM
22DEFINE_CONFIG_PARSE_ENUM(config_parse_dns_stub_listener_mode, dns_stub_listener_mode, DnsStubListenerMode, "Failed to parse DNS stub listener mode setting");
23
8e97dc67 24static int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char *word) {
da9de738 25 _cleanup_free_ char *server_name = NULL;
636e813d 26 union in_addr_union address;
2817157b 27 int family, r, ifindex = 0;
da9de738 28 uint16_t port;
0eac4623 29 DnsServer *s;
4e945a6f
LP
30
31 assert(m);
636e813d
LP
32 assert(word);
33
da9de738 34 r = in_addr_port_ifindex_name_from_string_auto(word, &family, &address, &port, &ifindex, &server_name);
636e813d
LP
35 if (r < 0)
36 return r;
4e945a6f 37
281df579
LP
38 /* Silently filter out 0.0.0.0, 127.0.0.53, 127.0.0.54 (our own stub DNS listener) */
39 if (!dns_server_address_valid(family, &address))
40 return 0;
41
42 /* By default, the port number is determined with the transaction feature level.
da9de738
YW
43 * See dns_transaction_port() and dns_server_port(). */
44 if (IN_SET(port, 53, 853))
45 port = 0;
46
636e813d 47 /* Filter out duplicates */
1b860092 48 s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, port, ifindex, server_name);
636e813d 49 if (s) {
c4c6ee3a
ZJS
50 /* Drop the marker. This is used to find the servers that ceased to exist, see
51 * manager_mark_dns_servers() and manager_flush_marked_dns_servers(). */
0b58db65 52 dns_server_move_back_and_unmark(s);
636e813d
LP
53 return 0;
54 }
55
da9de738 56 return dns_server_new(m, NULL, type, NULL, family, &address, port, ifindex, server_name);
636e813d
LP
57}
58
281df579 59int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) {
636e813d
LP
60 int r;
61
62 assert(m);
63 assert(string);
64
9ed794a3 65 for (;;) {
b5efdb8a 66 _cleanup_free_ char *word = NULL;
880603a1
SS
67
68 r = extract_first_word(&string, &word, NULL, 0);
9d84fdec 69 if (r <= 0)
636e813d 70 return r;
4e945a6f 71
636e813d 72 r = manager_add_dns_server_by_string(m, type, word);
281df579 73 if (r < 0)
2817157b 74 log_warning_errno(r, "Failed to add DNS server address '%s', ignoring: %m", word);
a51c1048 75 }
a51c1048
LP
76}
77
8e97dc67 78static int manager_add_search_domain_by_string(Manager *m, const char *domain) {
a51c1048 79 DnsSearchDomain *d;
adc800a6 80 bool route_only;
a51c1048
LP
81 int r;
82
83 assert(m);
84 assert(domain);
85
adc800a6
LP
86 route_only = *domain == '~';
87 if (route_only)
88 domain++;
89
90 if (dns_name_is_root(domain) || streq(domain, "*")) {
91 route_only = true;
92 domain = ".";
93 }
94
a51c1048
LP
95 r = dns_search_domain_find(m->search_domains, domain, &d);
96 if (r < 0)
97 return r;
adc800a6 98 if (r > 0)
a51c1048 99 dns_search_domain_move_back_and_unmark(d);
adc800a6
LP
100 else {
101 r = dns_search_domain_new(m, &d, DNS_SEARCH_DOMAIN_SYSTEM, NULL, domain);
102 if (r < 0)
103 return r;
a51c1048
LP
104 }
105
adc800a6
LP
106 d->route_only = route_only;
107 return 0;
a51c1048
LP
108}
109
110int manager_parse_search_domains_and_warn(Manager *m, const char *string) {
111 int r;
112
113 assert(m);
114 assert(string);
115
9ed794a3 116 for (;;) {
a51c1048
LP
117 _cleanup_free_ char *word = NULL;
118
4ec85141 119 r = extract_first_word(&string, &word, NULL, EXTRACT_UNQUOTE);
9d84fdec 120 if (r <= 0)
a51c1048 121 return r;
a51c1048
LP
122
123 r = manager_add_search_domain_by_string(m, word);
124 if (r < 0)
2817157b 125 log_warning_errno(r, "Failed to add search domain '%s', ignoring: %m", word);
4e945a6f 126 }
4e945a6f
LP
127}
128
636e813d 129int config_parse_dns_servers(
4e945a6f
LP
130 const char *unit,
131 const char *filename,
132 unsigned line,
133 const char *section,
134 unsigned section_line,
135 const char *lvalue,
136 int ltype,
137 const char *rvalue,
138 void *data,
139 void *userdata) {
140
99534007 141 Manager *m = ASSERT_PTR(userdata);
4e945a6f
LP
142 int r;
143
144 assert(filename);
145 assert(lvalue);
146 assert(rvalue);
4e945a6f 147
3e684349 148 if (isempty(rvalue))
5cb36f41 149 /* Empty assignment means clear the list */
4b95f179 150 dns_server_unlink_all(manager_get_first_dns_server(m, ltype));
3e684349 151 else {
b938cb90 152 /* Otherwise, add to the list */
281df579 153 r = manager_parse_dns_server_string_and_warn(m, ltype, rvalue);
5cb36f41 154 if (r < 0) {
94069bef
YW
155 log_syntax(unit, LOG_WARNING, filename, line, r,
156 "Failed to parse DNS server string '%s', ignoring.", rvalue);
5cb36f41
LP
157 return 0;
158 }
4e945a6f
LP
159 }
160
281df579
LP
161 /* If we have a manual setting, then we stop reading
162 * /etc/resolv.conf */
5cb36f41
LP
163 if (ltype == DNS_SERVER_SYSTEM)
164 m->read_resolv_conf = false;
00fa60ae
LP
165 if (ltype == DNS_SERVER_FALLBACK)
166 m->need_builtin_fallbacks = false;
5cb36f41 167
4e945a6f
LP
168 return 0;
169}
170
a51c1048
LP
171int config_parse_search_domains(
172 const char *unit,
173 const char *filename,
174 unsigned line,
175 const char *section,
176 unsigned section_line,
177 const char *lvalue,
178 int ltype,
179 const char *rvalue,
180 void *data,
181 void *userdata) {
182
99534007 183 Manager *m = ASSERT_PTR(userdata);
a51c1048
LP
184 int r;
185
186 assert(filename);
187 assert(lvalue);
188 assert(rvalue);
a51c1048
LP
189
190 if (isempty(rvalue))
191 /* Empty assignment means clear the list */
192 dns_search_domain_unlink_all(m->search_domains);
193 else {
194 /* Otherwise, add to the list */
195 r = manager_parse_search_domains_and_warn(m, rvalue);
196 if (r < 0) {
94069bef
YW
197 log_syntax(unit, LOG_WARNING, filename, line, r,
198 "Failed to parse search domains string '%s', ignoring.", rvalue);
a51c1048
LP
199 return 0;
200 }
201 }
202
281df579
LP
203 /* If we have a manual setting, then we stop reading
204 * /etc/resolv.conf */
a51c1048 205 m->read_resolv_conf = false;
6501dd31
DR
206
207 return 0;
208}
209
d63542bc
YW
210int config_parse_dnssd_service_name(
211 const char *unit,
212 const char *filename,
213 unsigned line,
214 const char *section,
215 unsigned section_line,
216 const char *lvalue,
217 int ltype,
218 const char *rvalue,
219 void *data,
220 void *userdata) {
221
07e4a8dc 222 static const Specifier specifier_table[] = {
e93387f3 223 { 'a', specifier_architecture, NULL },
07e4a8dc 224 { 'b', specifier_boot_id, NULL },
e93387f3 225 { 'B', specifier_os_build_id, NULL },
9a5893e9 226 { 'H', specifier_hostname, NULL }, /* We will use specifier_dnssd_hostname(). */
e93387f3 227 { 'm', specifier_machine_id, NULL },
07e4a8dc 228 { 'o', specifier_os_id, NULL },
e93387f3 229 { 'v', specifier_kernel_release, NULL },
07e4a8dc 230 { 'w', specifier_os_version_id, NULL },
07e4a8dc
RB
231 { 'W', specifier_os_variant_id, NULL },
232 {}
233 };
99534007 234 DnssdService *s = ASSERT_PTR(userdata);
07e4a8dc 235 _cleanup_free_ char *name = NULL;
6501dd31
DR
236 int r;
237
238 assert(filename);
239 assert(lvalue);
240 assert(rvalue);
6501dd31
DR
241
242 if (isempty(rvalue)) {
0c949643
YW
243 s->name_template = mfree(s->name_template);
244 return 0;
34136e15 245 }
6501dd31 246
de61a04b 247 r = specifier_printf(rvalue, DNS_LABEL_MAX, specifier_table, NULL, NULL, &name);
dd2e9e1d
YW
248 if (r < 0) {
249 log_syntax(unit, LOG_WARNING, filename, line, r,
250 "Invalid service instance name template '%s', ignoring assignment: %m", rvalue);
251 return 0;
252 }
07e4a8dc
RB
253
254 if (!dns_service_name_is_valid(name)) {
dd2e9e1d
YW
255 log_syntax(unit, LOG_WARNING, filename, line, 0,
256 "Service instance name template '%s' renders to invalid name '%s'. Ignoring assignment.",
257 rvalue, name);
258 return 0;
07e4a8dc
RB
259 }
260
dd2e9e1d 261 return free_and_strdup_warn(&s->name_template, rvalue);
6501dd31
DR
262}
263
94069bef
YW
264int config_parse_dnssd_service_type(
265 const char *unit,
266 const char *filename,
267 unsigned line,
268 const char *section,
269 unsigned section_line,
270 const char *lvalue,
271 int ltype,
272 const char *rvalue,
273 void *data,
274 void *userdata) {
275
99534007 276 DnssdService *s = ASSERT_PTR(userdata);
6501dd31
DR
277 int r;
278
279 assert(filename);
280 assert(lvalue);
281 assert(rvalue);
6501dd31
DR
282
283 if (isempty(rvalue)) {
94069bef
YW
284 s->type = mfree(s->type);
285 return 0;
6501dd31
DR
286 }
287
288 if (!dnssd_srv_type_is_valid(rvalue)) {
94069bef
YW
289 log_syntax(unit, LOG_WARNING, filename, line, 0, "Service type is invalid. Ignoring.");
290 return 0;
6501dd31
DR
291 }
292
293 r = free_and_strdup(&s->type, rvalue);
294 if (r < 0)
295 return log_oom();
296
297 return 0;
298}
299
94069bef
YW
300int config_parse_dnssd_txt(
301 const char *unit,
302 const char *filename,
303 unsigned line,
304 const char *section,
305 unsigned section_line,
306 const char *lvalue,
307 int ltype,
308 const char *rvalue,
309 void *data,
310 void *userdata) {
311
400f54fb 312 _cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
99534007 313 DnssdService *s = ASSERT_PTR(userdata);
6501dd31
DR
314 DnsTxtItem *last = NULL;
315
316 assert(filename);
317 assert(lvalue);
318 assert(rvalue);
6501dd31 319
400f54fb
DR
320 if (isempty(rvalue)) {
321 /* Flush out collected items */
322 s->txt_data_items = dnssd_txtdata_free_all(s->txt_data_items);
6501dd31 323 return 0;
400f54fb
DR
324 }
325
326 txt_data = new0(DnssdTxtData, 1);
327 if (!txt_data)
328 return log_oom();
6501dd31
DR
329
330 for (;;) {
94069bef 331 _cleanup_free_ char *word = NULL, *key = NULL, *value = NULL;
6501dd31
DR
332 _cleanup_free_ void *decoded = NULL;
333 size_t length = 0;
334 DnsTxtItem *i;
335 int r;
336
337 r = extract_first_word(&rvalue, &word, NULL,
3141089f 338 EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX);
6501dd31
DR
339 if (r == 0)
340 break;
341 if (r == -ENOMEM)
342 return log_oom();
94069bef
YW
343 if (r < 0) {
344 log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
345 return 0;
346 }
6501dd31
DR
347
348 r = split_pair(word, "=", &key, &value);
349 if (r == -ENOMEM)
350 return log_oom();
1cc6c93a
YW
351 if (r == -EINVAL)
352 key = TAKE_PTR(word);
6501dd31
DR
353
354 if (!ascii_is_valid(key)) {
94069bef
YW
355 log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid key, ignoring: %s", key);
356 continue;
6501dd31
DR
357 }
358
359 switch (ltype) {
360
361 case DNS_TXT_ITEM_DATA:
362 if (value) {
363 r = unbase64mem(value, strlen(value), &decoded, &length);
364 if (r == -ENOMEM)
365 return log_oom();
94069bef
YW
366 if (r < 0) {
367 log_syntax(unit, LOG_WARNING, filename, line, r,
368 "Invalid base64 encoding, ignoring: %s", value);
369 continue;
370 }
6501dd31
DR
371 }
372
373 r = dnssd_txt_item_new_from_data(key, decoded, length, &i);
374 if (r < 0)
375 return log_oom();
376 break;
377
378 case DNS_TXT_ITEM_TEXT:
379 r = dnssd_txt_item_new_from_string(key, value, &i);
380 if (r < 0)
381 return log_oom();
382 break;
383
384 default:
04499a70 385 assert_not_reached();
6501dd31
DR
386 }
387
d70f15f5 388 LIST_INSERT_AFTER(items, txt_data->txts, last, i);
6501dd31
DR
389 last = i;
390 }
400f54fb 391
d70f15f5 392 if (txt_data->txts) {
400f54fb 393 LIST_PREPEND(items, s->txt_data_items, txt_data);
94069bef 394 TAKE_PTR(txt_data);
400f54fb 395 }
a51c1048
LP
396
397 return 0;
398}
399
1f05101f
SS
400int config_parse_dns_stub_listener_extra(
401 const char *unit,
402 const char *filename,
403 unsigned line,
404 const char *section,
405 unsigned section_line,
406 const char *lvalue,
407 int ltype,
408 const char *rvalue,
409 void *data,
410 void *userdata) {
411
36aaabc3 412 _cleanup_free_ DnsStubListenerExtra *stub = NULL;
1f05101f 413 Manager *m = userdata;
1f05101f
SS
414 const char *p;
415 int r;
416
417 assert(filename);
418 assert(lvalue);
419 assert(rvalue);
420 assert(data);
421
422 if (isempty(rvalue)) {
423 m->dns_extra_stub_listeners = ordered_set_free(m->dns_extra_stub_listeners);
424 return 0;
425 }
426
0354029b 427 r = dns_stub_listener_extra_new(m, &stub);
7314b397 428 if (r < 0)
1f05101f 429 return log_oom();
1f05101f 430
7314b397
YW
431 p = startswith(rvalue, "udp:");
432 if (p)
433 stub->mode = DNS_STUB_LISTENER_UDP;
434 else {
435 p = startswith(rvalue, "tcp:");
436 if (p)
437 stub->mode = DNS_STUB_LISTENER_TCP;
438 else {
439 stub->mode = DNS_STUB_LISTENER_YES;
440 p = rvalue;
1f05101f
SS
441 }
442 }
443
222eaaf9 444 r = in_addr_port_ifindex_name_from_string_auto(p, &stub->family, &stub->address, &stub->port, NULL, NULL);
7314b397
YW
445 if (r < 0) {
446 log_syntax(unit, LOG_WARNING, filename, line, r,
447 "Failed to parse address in %s=%s, ignoring assignment: %m",
448 lvalue, rvalue);
449 return 0;
1f05101f
SS
450 }
451
7314b397
YW
452 r = ordered_set_ensure_put(&m->dns_extra_stub_listeners, &dns_stub_listener_extra_hash_ops, stub);
453 if (r == -ENOMEM)
454 return log_oom();
455 if (r < 0) {
456 log_syntax(unit, LOG_WARNING, filename, line, r,
457 "Failed to store %s=%s, ignoring assignment: %m", lvalue, rvalue);
458 return 0;
1f05101f
SS
459 }
460
7314b397 461 TAKE_PTR(stub);
1f05101f
SS
462
463 return 0;
464}
465
4e945a6f 466int manager_parse_config_file(Manager *m) {
00fa60ae
LP
467 int r;
468
4e945a6f
LP
469 assert(m);
470
4f9ff96a
LP
471 r = config_parse_many_nulstr(
472 PKGSYSCONFDIR "/resolved.conf",
473 CONF_PATHS_NULSTR("systemd/resolved.conf.d"),
474 "Resolve\0",
475 config_item_perf_lookup, resolved_gperf_lookup,
476 CONFIG_PARSE_WARN,
477 m,
478 NULL);
00fa60ae
LP
479 if (r < 0)
480 return r;
481
482 if (m->need_builtin_fallbacks) {
281df579 483 r = manager_parse_dns_server_string_and_warn(m, DNS_SERVER_FALLBACK, DNS_SERVERS);
00fa60ae
LP
484 if (r < 0)
485 return r;
486 }
487
7e8facb3 488#if !HAVE_OPENSSL_OR_GCRYPT
42303dcb 489 if (m->dnssec_mode != DNSSEC_NO) {
7e8facb3 490 log_warning("DNSSEC option cannot be enabled or set to allow-downgrade when systemd-resolved is built without a cryptographic library. Turning off DNSSEC support.");
42303dcb
YW
491 m->dnssec_mode = DNSSEC_NO;
492 }
493#endif
5d67a7ae 494
7e8facb3 495#if !ENABLE_DNS_OVER_TLS
c9299be2 496 if (m->dns_over_tls_mode != DNS_OVER_TLS_NO) {
4310bfc2 497 log_warning("DNS-over-TLS option cannot be enabled or set to opportunistic when systemd-resolved is built without DNS-over-TLS support. Turning off DNS-over-TLS support.");
c9299be2 498 m->dns_over_tls_mode = DNS_OVER_TLS_NO;
5d67a7ae
IT
499 }
500#endif
00fa60ae
LP
501 return 0;
502
4e945a6f 503}