]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolved-conf.c
network: fix typo in log message
[thirdparty/systemd.git] / src / resolve / resolved-conf.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
4e945a6f
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2014 Tom Gundersen <teg@jklm.no>
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
b5efdb8a 21#include "alloc-util.h"
4e945a6f 22#include "conf-parser.h"
a0f29c76 23#include "def.h"
b5efdb8a 24#include "extract-word.h"
6501dd31 25#include "hexdecoct.h"
6bedfcbb 26#include "parse-util.h"
4e945a6f 27#include "resolved-conf.h"
6501dd31
DR
28#include "resolved-dnssd.h"
29#include "specifier.h"
1ae43295 30#include "string-table.h"
6bedfcbb 31#include "string-util.h"
6501dd31 32#include "utf8.h"
4e945a6f 33
1ae43295
DM
34DEFINE_CONFIG_PARSE_ENUM(config_parse_dns_stub_listener_mode, dns_stub_listener_mode, DnsStubListenerMode, "Failed to parse DNS stub listener mode setting");
35
36static const char* const dns_stub_listener_mode_table[_DNS_STUB_LISTENER_MODE_MAX] = {
37 [DNS_STUB_LISTENER_NO] = "no",
38 [DNS_STUB_LISTENER_UDP] = "udp",
39 [DNS_STUB_LISTENER_TCP] = "tcp",
40 [DNS_STUB_LISTENER_YES] = "yes",
41};
42DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(dns_stub_listener_mode, DnsStubListenerMode, DNS_STUB_LISTENER_YES);
43
636e813d
LP
44int manager_add_dns_server_by_string(Manager *m, DnsServerType type, const char *word) {
45 union in_addr_union address;
2817157b 46 int family, r, ifindex = 0;
0eac4623 47 DnsServer *s;
4e945a6f
LP
48
49 assert(m);
636e813d
LP
50 assert(word);
51
2817157b 52 r = in_addr_ifindex_from_string_auto(word, &family, &address, &ifindex);
636e813d
LP
53 if (r < 0)
54 return r;
4e945a6f 55
b30bf55d
LP
56 /* Silently filter out 0.0.0.0 and 127.0.0.53 (our own stub DNS listener) */
57 if (!dns_server_address_valid(family, &address))
58 return 0;
59
636e813d 60 /* Filter out duplicates */
2817157b 61 s = dns_server_find(manager_get_first_dns_server(m, type), family, &address, ifindex);
636e813d
LP
62 if (s) {
63 /*
64 * Drop the marker. This is used to find the servers
65 * that ceased to exist, see
66 * manager_mark_dns_servers() and
67 * manager_flush_marked_dns_servers().
68 */
0b58db65 69 dns_server_move_back_and_unmark(s);
636e813d
LP
70 return 0;
71 }
72
2817157b 73 return dns_server_new(m, NULL, type, NULL, family, &address, ifindex);
636e813d
LP
74}
75
76int manager_parse_dns_server_string_and_warn(Manager *m, DnsServerType type, const char *string) {
77 int r;
78
79 assert(m);
80 assert(string);
81
9ed794a3 82 for (;;) {
b5efdb8a 83 _cleanup_free_ char *word = NULL;
880603a1
SS
84
85 r = extract_first_word(&string, &word, NULL, 0);
86 if (r < 0)
636e813d 87 return r;
880603a1
SS
88 if (r == 0)
89 break;
4e945a6f 90
636e813d 91 r = manager_add_dns_server_by_string(m, type, word);
a51c1048 92 if (r < 0)
2817157b 93 log_warning_errno(r, "Failed to add DNS server address '%s', ignoring: %m", word);
a51c1048
LP
94 }
95
96 return 0;
97}
98
99int manager_add_search_domain_by_string(Manager *m, const char *domain) {
100 DnsSearchDomain *d;
adc800a6 101 bool route_only;
a51c1048
LP
102 int r;
103
104 assert(m);
105 assert(domain);
106
adc800a6
LP
107 route_only = *domain == '~';
108 if (route_only)
109 domain++;
110
111 if (dns_name_is_root(domain) || streq(domain, "*")) {
112 route_only = true;
113 domain = ".";
114 }
115
a51c1048
LP
116 r = dns_search_domain_find(m->search_domains, domain, &d);
117 if (r < 0)
118 return r;
adc800a6 119 if (r > 0)
a51c1048 120 dns_search_domain_move_back_and_unmark(d);
adc800a6
LP
121 else {
122 r = dns_search_domain_new(m, &d, DNS_SEARCH_DOMAIN_SYSTEM, NULL, domain);
123 if (r < 0)
124 return r;
a51c1048
LP
125 }
126
adc800a6
LP
127 d->route_only = route_only;
128 return 0;
a51c1048
LP
129}
130
131int manager_parse_search_domains_and_warn(Manager *m, const char *string) {
132 int r;
133
134 assert(m);
135 assert(string);
136
9ed794a3 137 for (;;) {
a51c1048
LP
138 _cleanup_free_ char *word = NULL;
139
140 r = extract_first_word(&string, &word, NULL, EXTRACT_QUOTES);
141 if (r < 0)
142 return r;
143 if (r == 0)
144 break;
145
146 r = manager_add_search_domain_by_string(m, word);
147 if (r < 0)
2817157b 148 log_warning_errno(r, "Failed to add search domain '%s', ignoring: %m", word);
4e945a6f
LP
149 }
150
151 return 0;
152}
153
636e813d 154int config_parse_dns_servers(
4e945a6f
LP
155 const char *unit,
156 const char *filename,
157 unsigned line,
158 const char *section,
159 unsigned section_line,
160 const char *lvalue,
161 int ltype,
162 const char *rvalue,
163 void *data,
164 void *userdata) {
165
166 Manager *m = userdata;
4e945a6f
LP
167 int r;
168
169 assert(filename);
170 assert(lvalue);
171 assert(rvalue);
172 assert(m);
173
3e684349 174 if (isempty(rvalue))
5cb36f41 175 /* Empty assignment means clear the list */
4b95f179 176 dns_server_unlink_all(manager_get_first_dns_server(m, ltype));
3e684349 177 else {
b938cb90 178 /* Otherwise, add to the list */
636e813d 179 r = manager_parse_dns_server_string_and_warn(m, ltype, rvalue);
5cb36f41 180 if (r < 0) {
12ca818f 181 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNS server string '%s'. Ignoring.", rvalue);
5cb36f41
LP
182 return 0;
183 }
4e945a6f
LP
184 }
185
5cb36f41
LP
186 /* If we have a manual setting, then we stop reading
187 * /etc/resolv.conf */
188 if (ltype == DNS_SERVER_SYSTEM)
189 m->read_resolv_conf = false;
00fa60ae
LP
190 if (ltype == DNS_SERVER_FALLBACK)
191 m->need_builtin_fallbacks = false;
5cb36f41 192
4e945a6f
LP
193 return 0;
194}
195
a51c1048
LP
196int config_parse_search_domains(
197 const char *unit,
198 const char *filename,
199 unsigned line,
200 const char *section,
201 unsigned section_line,
202 const char *lvalue,
203 int ltype,
204 const char *rvalue,
205 void *data,
206 void *userdata) {
207
208 Manager *m = userdata;
209 int r;
210
211 assert(filename);
212 assert(lvalue);
213 assert(rvalue);
214 assert(m);
215
216 if (isempty(rvalue))
217 /* Empty assignment means clear the list */
218 dns_search_domain_unlink_all(m->search_domains);
219 else {
220 /* Otherwise, add to the list */
221 r = manager_parse_search_domains_and_warn(m, rvalue);
222 if (r < 0) {
223 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse search domains string '%s'. Ignoring.", rvalue);
224 return 0;
225 }
226 }
227
228 /* If we have a manual setting, then we stop reading
229 * /etc/resolv.conf */
230 m->read_resolv_conf = false;
6501dd31
DR
231
232 return 0;
233}
234
235int config_parse_dnssd_service_name(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
236 static const Specifier specifier_table[] = {
237 { 'b', specifier_boot_id, NULL },
238 { 'H', specifier_host_name, NULL },
239 { 'm', specifier_machine_id, NULL },
240 { 'v', specifier_kernel_release, NULL },
241 {}
242 };
243 DnssdService *s = userdata;
244 _cleanup_free_ char *name = NULL;
245 int r;
246
247 assert(filename);
248 assert(lvalue);
249 assert(rvalue);
250 assert(s);
251
252 if (isempty(rvalue)) {
253 log_syntax(unit, LOG_ERR, filename, line, 0, "Service instance name can't be empty. Ignoring.");
254 return -EINVAL;
255 }
256
257 r = free_and_strdup(&s->name_template, rvalue);
258 if (r < 0)
259 return log_oom();
260
261 r = specifier_printf(s->name_template, specifier_table, NULL, &name);
262 if (r < 0)
263 return log_debug_errno(r, "Failed to replace specifiers: %m");
264
265 if (!dns_service_name_is_valid(name)) {
266 log_syntax(unit, LOG_ERR, filename, line, 0, "Service instance name template renders to invalid name '%s'. Ignoring.", name);
267 return -EINVAL;
268 }
269
270 return 0;
271}
272
273int config_parse_dnssd_service_type(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
274 DnssdService *s = userdata;
275 int r;
276
277 assert(filename);
278 assert(lvalue);
279 assert(rvalue);
280 assert(s);
281
282 if (isempty(rvalue)) {
283 log_syntax(unit, LOG_ERR, filename, line, 0, "Service type can't be empty. Ignoring.");
284 return -EINVAL;
285 }
286
287 if (!dnssd_srv_type_is_valid(rvalue)) {
288 log_syntax(unit, LOG_ERR, filename, line, 0, "Service type is invalid. Ignoring.");
289 return -EINVAL;
290 }
291
292 r = free_and_strdup(&s->type, rvalue);
293 if (r < 0)
294 return log_oom();
295
296 return 0;
297}
298
299int config_parse_dnssd_txt(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
400f54fb 300 _cleanup_(dnssd_txtdata_freep) DnssdTxtData *txt_data = NULL;
6501dd31
DR
301 DnssdService *s = userdata;
302 DnsTxtItem *last = NULL;
303
304 assert(filename);
305 assert(lvalue);
306 assert(rvalue);
307 assert(s);
308
400f54fb
DR
309 if (isempty(rvalue)) {
310 /* Flush out collected items */
311 s->txt_data_items = dnssd_txtdata_free_all(s->txt_data_items);
6501dd31 312 return 0;
400f54fb
DR
313 }
314
315 txt_data = new0(DnssdTxtData, 1);
316 if (!txt_data)
317 return log_oom();
6501dd31
DR
318
319 for (;;) {
320 _cleanup_free_ char *word = NULL;
321 _cleanup_free_ char *key = NULL;
322 _cleanup_free_ char *value = NULL;
323 _cleanup_free_ void *decoded = NULL;
324 size_t length = 0;
325 DnsTxtItem *i;
326 int r;
327
328 r = extract_first_word(&rvalue, &word, NULL,
329 EXTRACT_QUOTES|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX);
330 if (r == 0)
331 break;
332 if (r == -ENOMEM)
333 return log_oom();
334 if (r < 0)
335 return log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
336
337 r = split_pair(word, "=", &key, &value);
338 if (r == -ENOMEM)
339 return log_oom();
340 if (r == -EINVAL) {
341 key = word;
342 word = NULL;
343 }
344
345 if (!ascii_is_valid(key)) {
346 log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring: %s", key);
347 return -EINVAL;
348 }
349
350 switch (ltype) {
351
352 case DNS_TXT_ITEM_DATA:
353 if (value) {
354 r = unbase64mem(value, strlen(value), &decoded, &length);
355 if (r == -ENOMEM)
356 return log_oom();
357 if (r < 0)
358 return log_syntax(unit, LOG_ERR, filename, line, r,
359 "Invalid base64 encoding, ignoring: %s", value);
360 }
361
362 r = dnssd_txt_item_new_from_data(key, decoded, length, &i);
363 if (r < 0)
364 return log_oom();
365 break;
366
367 case DNS_TXT_ITEM_TEXT:
368 r = dnssd_txt_item_new_from_string(key, value, &i);
369 if (r < 0)
370 return log_oom();
371 break;
372
373 default:
374 assert_not_reached("Unknown type of Txt config");
375 }
376
400f54fb 377 LIST_INSERT_AFTER(items, txt_data->txt, last, i);
6501dd31
DR
378 last = i;
379 }
400f54fb
DR
380
381 if (!LIST_IS_EMPTY(txt_data->txt)) {
382 LIST_PREPEND(items, s->txt_data_items, txt_data);
383 txt_data = NULL;
384 }
a51c1048
LP
385
386 return 0;
387}
388
4e945a6f 389int manager_parse_config_file(Manager *m) {
00fa60ae
LP
390 int r;
391
4e945a6f
LP
392 assert(m);
393
43688c49 394 r = config_parse_many_nulstr(PKGSYSCONFDIR "/resolved.conf",
da412854
YW
395 CONF_PATHS_NULSTR("systemd/resolved.conf.d"),
396 "Resolve\0",
397 config_item_perf_lookup, resolved_gperf_lookup,
bcde742e 398 CONFIG_PARSE_WARN, m);
00fa60ae
LP
399 if (r < 0)
400 return r;
401
402 if (m->need_builtin_fallbacks) {
403 r = manager_parse_dns_server_string_and_warn(m, DNS_SERVER_FALLBACK, DNS_SERVERS);
404 if (r < 0)
405 return r;
406 }
407
349cc4a5 408#if ! HAVE_GCRYPT
42303dcb
YW
409 if (m->dnssec_mode != DNSSEC_NO) {
410 log_warning("DNSSEC option cannot be enabled or set to allow-downgrade when systemd-resolved is built without gcrypt support. Turning off DNSSEC support.");
411 m->dnssec_mode = DNSSEC_NO;
412 }
413#endif
00fa60ae
LP
414 return 0;
415
4e945a6f 416}