]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolvectl.c
resolve: make PrivateDNS configurable per link
[thirdparty/systemd.git] / src / resolve / resolvectl.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2014 Zbigniew Jędrzejewski-Szmek
6 ***/
7
8 #include <getopt.h>
9 #include <net/if.h>
10
11 #include "sd-bus.h"
12 #include "sd-netlink.h"
13
14 #include "af-list.h"
15 #include "alloc-util.h"
16 #include "bus-common-errors.h"
17 #include "bus-error.h"
18 #include "bus-util.h"
19 #include "dns-domain.h"
20 #include "escape.h"
21 #include "gcrypt-util.h"
22 #include "in-addr-util.h"
23 #include "netlink-util.h"
24 #include "pager.h"
25 #include "parse-util.h"
26 #include "resolvconf-compat.h"
27 #include "resolvectl.h"
28 #include "resolved-def.h"
29 #include "resolved-dns-packet.h"
30 #include "string-table.h"
31 #include "strv.h"
32 #include "terminal-util.h"
33 #include "verbs.h"
34
35 static int arg_family = AF_UNSPEC;
36 int arg_ifindex = 0;
37 const char *arg_ifname = NULL;
38 static uint16_t arg_type = 0;
39 static uint16_t arg_class = 0;
40 static bool arg_legend = true;
41 static uint64_t arg_flags = 0;
42 static bool arg_no_pager = false;
43 bool arg_ifindex_permissive = false; /* If true, don't generate an error if the specified interface index doesn't exist */
44 static const char *arg_service_family = NULL;
45
46 typedef enum RawType {
47 RAW_NONE,
48 RAW_PAYLOAD,
49 RAW_PACKET,
50 } RawType;
51 static RawType arg_raw = RAW_NONE;
52
53 ExecutionMode arg_mode = MODE_RESOLVE_HOST;
54
55 char **arg_set_dns = NULL;
56 char **arg_set_domain = NULL;
57 static const char *arg_set_llmnr = NULL;
58 static const char *arg_set_mdns = NULL;
59 static const char *arg_set_private_dns = NULL;
60 static const char *arg_set_dnssec = NULL;
61 static char **arg_set_nta = NULL;
62
63 typedef enum StatusMode {
64 STATUS_ALL,
65 STATUS_DNS,
66 STATUS_DOMAIN,
67 STATUS_LLMNR,
68 STATUS_MDNS,
69 STATUS_PRIVATE,
70 STATUS_DNSSEC,
71 STATUS_NTA,
72 } StatusMode;
73
74 static int parse_ifindex_with_warn(const char *s) {
75 int ifi;
76
77 assert(s);
78
79 if (parse_ifindex(s, &ifi) < 0) {
80 ifi = if_nametoindex(s);
81 if (ifi <= 0)
82 return log_error_errno(errno, "Unknown interface %s: %m", s);
83 }
84
85 return ifi;
86 }
87
88 static void print_source(uint64_t flags, usec_t rtt) {
89 char rtt_str[FORMAT_TIMESTAMP_MAX];
90
91 if (!arg_legend)
92 return;
93
94 if (flags == 0)
95 return;
96
97 fputs("\n-- Information acquired via", stdout);
98
99 if (flags != 0)
100 printf(" protocol%s%s%s%s%s",
101 flags & SD_RESOLVED_DNS ? " DNS" :"",
102 flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
103 flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "",
104 flags & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4" : "",
105 flags & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6" : "");
106
107 assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100));
108
109 printf(" in %s", rtt_str);
110
111 fputc('.', stdout);
112 fputc('\n', stdout);
113
114 printf("-- Data is authenticated: %s\n", yes_no(flags & SD_RESOLVED_AUTHENTICATED));
115 }
116
117 static int resolve_host(sd_bus *bus, const char *name) {
118 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
119 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
120 const char *canonical = NULL;
121 char ifname[IF_NAMESIZE] = "";
122 unsigned c = 0;
123 int r;
124 uint64_t flags;
125 usec_t ts;
126
127 assert(name);
128
129 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
130 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
131
132 log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
133
134 r = sd_bus_message_new_method_call(
135 bus,
136 &req,
137 "org.freedesktop.resolve1",
138 "/org/freedesktop/resolve1",
139 "org.freedesktop.resolve1.Manager",
140 "ResolveHostname");
141 if (r < 0)
142 return bus_log_create_error(r);
143
144 r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
145 if (r < 0)
146 return bus_log_create_error(r);
147
148 ts = now(CLOCK_MONOTONIC);
149
150 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
151 if (r < 0)
152 return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(&error, r));
153
154 ts = now(CLOCK_MONOTONIC) - ts;
155
156 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
157 if (r < 0)
158 return bus_log_parse_error(r);
159
160 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
161 _cleanup_free_ char *pretty = NULL;
162 int ifindex, family;
163 const void *a;
164 size_t sz;
165
166 assert_cc(sizeof(int) == sizeof(int32_t));
167
168 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
169 if (r < 0)
170 return bus_log_parse_error(r);
171
172 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
173 if (r < 0)
174 return bus_log_parse_error(r);
175
176 r = sd_bus_message_exit_container(reply);
177 if (r < 0)
178 return bus_log_parse_error(r);
179
180 if (!IN_SET(family, AF_INET, AF_INET6)) {
181 log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
182 continue;
183 }
184
185 if (sz != FAMILY_ADDRESS_SIZE(family)) {
186 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
187 return -EINVAL;
188 }
189
190 ifname[0] = 0;
191 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
192 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
193
194 r = in_addr_ifindex_to_string(family, a, ifindex, &pretty);
195 if (r < 0)
196 return log_error_errno(r, "Failed to print address for %s: %m", name);
197
198 printf("%*s%s %s%s%s\n",
199 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
200 pretty,
201 isempty(ifname) ? "" : "%", ifname);
202
203 c++;
204 }
205 if (r < 0)
206 return bus_log_parse_error(r);
207
208 r = sd_bus_message_exit_container(reply);
209 if (r < 0)
210 return bus_log_parse_error(r);
211
212 r = sd_bus_message_read(reply, "st", &canonical, &flags);
213 if (r < 0)
214 return bus_log_parse_error(r);
215
216 if (!streq(name, canonical))
217 printf("%*s%s (%s)\n",
218 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
219 canonical);
220
221 if (c == 0) {
222 log_error("%s: no addresses found", name);
223 return -ESRCH;
224 }
225
226 print_source(flags, ts);
227
228 return 0;
229 }
230
231 static int resolve_address(sd_bus *bus, int family, const union in_addr_union *address, int ifindex) {
232 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
233 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
234 _cleanup_free_ char *pretty = NULL;
235 char ifname[IF_NAMESIZE] = "";
236 uint64_t flags;
237 unsigned c = 0;
238 usec_t ts;
239 int r;
240
241 assert(bus);
242 assert(IN_SET(family, AF_INET, AF_INET6));
243 assert(address);
244
245 if (ifindex <= 0)
246 ifindex = arg_ifindex;
247
248 r = in_addr_ifindex_to_string(family, address, ifindex, &pretty);
249 if (r < 0)
250 return log_oom();
251
252 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
253 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
254
255 log_debug("Resolving %s%s%s.", pretty, isempty(ifname) ? "" : "%", ifname);
256
257 r = sd_bus_message_new_method_call(
258 bus,
259 &req,
260 "org.freedesktop.resolve1",
261 "/org/freedesktop/resolve1",
262 "org.freedesktop.resolve1.Manager",
263 "ResolveAddress");
264 if (r < 0)
265 return bus_log_create_error(r);
266
267 r = sd_bus_message_append(req, "ii", ifindex, family);
268 if (r < 0)
269 return bus_log_create_error(r);
270
271 r = sd_bus_message_append_array(req, 'y', address, FAMILY_ADDRESS_SIZE(family));
272 if (r < 0)
273 return bus_log_create_error(r);
274
275 r = sd_bus_message_append(req, "t", arg_flags);
276 if (r < 0)
277 return bus_log_create_error(r);
278
279 ts = now(CLOCK_MONOTONIC);
280
281 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
282 if (r < 0) {
283 log_error("%s: resolve call failed: %s", pretty, bus_error_message(&error, r));
284 return r;
285 }
286
287 ts = now(CLOCK_MONOTONIC) - ts;
288
289 r = sd_bus_message_enter_container(reply, 'a', "(is)");
290 if (r < 0)
291 return bus_log_create_error(r);
292
293 while ((r = sd_bus_message_enter_container(reply, 'r', "is")) > 0) {
294 const char *n;
295
296 assert_cc(sizeof(int) == sizeof(int32_t));
297
298 r = sd_bus_message_read(reply, "is", &ifindex, &n);
299 if (r < 0)
300 return r;
301
302 r = sd_bus_message_exit_container(reply);
303 if (r < 0)
304 return r;
305
306 ifname[0] = 0;
307 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
308 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
309
310 printf("%*s%*s%*s%s %s\n",
311 (int) strlen(pretty), c == 0 ? pretty : "",
312 isempty(ifname) ? 0 : 1, c > 0 || isempty(ifname) ? "" : "%",
313 (int) strlen(ifname), c == 0 ? ifname : "",
314 c == 0 ? ":" : " ",
315 n);
316
317 c++;
318 }
319 if (r < 0)
320 return bus_log_parse_error(r);
321
322 r = sd_bus_message_exit_container(reply);
323 if (r < 0)
324 return bus_log_parse_error(r);
325
326 r = sd_bus_message_read(reply, "t", &flags);
327 if (r < 0)
328 return bus_log_parse_error(r);
329
330 if (c == 0) {
331 log_error("%s: no names found", pretty);
332 return -ESRCH;
333 }
334
335 print_source(flags, ts);
336
337 return 0;
338 }
339
340 static int output_rr_packet(const void *d, size_t l, int ifindex) {
341 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
342 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
343 int r;
344 char ifname[IF_NAMESIZE] = "";
345
346 r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX);
347 if (r < 0)
348 return log_oom();
349
350 p->refuse_compression = true;
351
352 r = dns_packet_append_blob(p, d, l, NULL);
353 if (r < 0)
354 return log_oom();
355
356 r = dns_packet_read_rr(p, &rr, NULL, NULL);
357 if (r < 0)
358 return log_error_errno(r, "Failed to parse RR: %m");
359
360 if (arg_raw == RAW_PAYLOAD) {
361 void *data;
362 ssize_t k;
363
364 k = dns_resource_record_payload(rr, &data);
365 if (k < 0)
366 return log_error_errno(k, "Cannot dump RR: %m");
367 fwrite(data, 1, k, stdout);
368 } else {
369 const char *s;
370
371 s = dns_resource_record_to_string(rr);
372 if (!s)
373 return log_oom();
374
375 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
376 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
377
378 printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
379 }
380
381 return 0;
382 }
383
384 static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type, bool warn_missing) {
385 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
386 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
387 char ifname[IF_NAMESIZE] = "";
388 unsigned n = 0;
389 uint64_t flags;
390 int r;
391 usec_t ts;
392 bool needs_authentication = false;
393
394 assert(name);
395
396 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
397 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
398
399 log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(ifname) ? "*" : ifname);
400
401 r = sd_bus_message_new_method_call(
402 bus,
403 &req,
404 "org.freedesktop.resolve1",
405 "/org/freedesktop/resolve1",
406 "org.freedesktop.resolve1.Manager",
407 "ResolveRecord");
408 if (r < 0)
409 return bus_log_create_error(r);
410
411 r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, class, type, arg_flags);
412 if (r < 0)
413 return bus_log_create_error(r);
414
415 ts = now(CLOCK_MONOTONIC);
416
417 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
418 if (r < 0) {
419 if (warn_missing || r != -ENXIO)
420 log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
421 return r;
422 }
423
424 ts = now(CLOCK_MONOTONIC) - ts;
425
426 r = sd_bus_message_enter_container(reply, 'a', "(iqqay)");
427 if (r < 0)
428 return bus_log_parse_error(r);
429
430 while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
431 uint16_t c, t;
432 int ifindex;
433 const void *d;
434 size_t l;
435
436 assert_cc(sizeof(int) == sizeof(int32_t));
437
438 r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t);
439 if (r < 0)
440 return bus_log_parse_error(r);
441
442 r = sd_bus_message_read_array(reply, 'y', &d, &l);
443 if (r < 0)
444 return bus_log_parse_error(r);
445
446 r = sd_bus_message_exit_container(reply);
447 if (r < 0)
448 return bus_log_parse_error(r);
449
450 if (arg_raw == RAW_PACKET) {
451 uint64_t u64 = htole64(l);
452
453 fwrite(&u64, sizeof(u64), 1, stdout);
454 fwrite(d, 1, l, stdout);
455 } else {
456 r = output_rr_packet(d, l, ifindex);
457 if (r < 0)
458 return r;
459 }
460
461 if (dns_type_needs_authentication(t))
462 needs_authentication = true;
463
464 n++;
465 }
466 if (r < 0)
467 return bus_log_parse_error(r);
468
469 r = sd_bus_message_exit_container(reply);
470 if (r < 0)
471 return bus_log_parse_error(r);
472
473 r = sd_bus_message_read(reply, "t", &flags);
474 if (r < 0)
475 return bus_log_parse_error(r);
476
477 if (n == 0) {
478 if (warn_missing)
479 log_error("%s: no records found", name);
480 return -ESRCH;
481 }
482
483 print_source(flags, ts);
484
485 if ((flags & SD_RESOLVED_AUTHENTICATED) == 0 && needs_authentication) {
486 fflush(stdout);
487
488 fprintf(stderr, "\n%s"
489 "WARNING: The resources shown contain cryptographic key data which could not be\n"
490 " authenticated. It is not suitable to authenticate any communication.\n"
491 " This is usually indication that DNSSEC authentication was not enabled\n"
492 " or is not available for the selected protocol or DNS servers.%s\n",
493 ansi_highlight_red(),
494 ansi_normal());
495 }
496
497 return 0;
498 }
499
500 static int resolve_rfc4501(sd_bus *bus, const char *name) {
501 uint16_t type = 0, class = 0;
502 const char *p, *q, *n;
503 int r;
504
505 assert(bus);
506 assert(name);
507 assert(startswith(name, "dns:"));
508
509 /* Parse RFC 4501 dns: URIs */
510
511 p = name + 4;
512
513 if (p[0] == '/') {
514 const char *e;
515
516 if (p[1] != '/')
517 goto invalid;
518
519 e = strchr(p + 2, '/');
520 if (!e)
521 goto invalid;
522
523 if (e != p + 2)
524 log_warning("DNS authority specification not supported; ignoring specified authority.");
525
526 p = e + 1;
527 }
528
529 q = strchr(p, '?');
530 if (q) {
531 n = strndupa(p, q - p);
532 q++;
533
534 for (;;) {
535 const char *f;
536
537 f = startswith_no_case(q, "class=");
538 if (f) {
539 _cleanup_free_ char *t = NULL;
540 const char *e;
541
542 if (class != 0) {
543 log_error("DNS class specified twice.");
544 return -EINVAL;
545 }
546
547 e = strchrnul(f, ';');
548 t = strndup(f, e - f);
549 if (!t)
550 return log_oom();
551
552 r = dns_class_from_string(t);
553 if (r < 0) {
554 log_error("Unknown DNS class %s.", t);
555 return -EINVAL;
556 }
557
558 class = r;
559
560 if (*e == ';') {
561 q = e + 1;
562 continue;
563 }
564
565 break;
566 }
567
568 f = startswith_no_case(q, "type=");
569 if (f) {
570 _cleanup_free_ char *t = NULL;
571 const char *e;
572
573 if (type != 0) {
574 log_error("DNS type specified twice.");
575 return -EINVAL;
576 }
577
578 e = strchrnul(f, ';');
579 t = strndup(f, e - f);
580 if (!t)
581 return log_oom();
582
583 r = dns_type_from_string(t);
584 if (r < 0) {
585 log_error("Unknown DNS type %s.", t);
586 return -EINVAL;
587 }
588
589 type = r;
590
591 if (*e == ';') {
592 q = e + 1;
593 continue;
594 }
595
596 break;
597 }
598
599 goto invalid;
600 }
601 } else
602 n = p;
603
604 if (class == 0)
605 class = arg_class ?: DNS_CLASS_IN;
606 if (type == 0)
607 type = arg_type ?: DNS_TYPE_A;
608
609 return resolve_record(bus, n, class, type, true);
610
611 invalid:
612 log_error("Invalid DNS URI: %s", name);
613 return -EINVAL;
614 }
615
616 static int verb_query(int argc, char **argv, void *userdata) {
617 sd_bus *bus = userdata;
618 char **p;
619 int q, r = 0;
620
621 if (arg_type != 0)
622 STRV_FOREACH(p, argv + 1) {
623 q = resolve_record(bus, *p, arg_class, arg_type, true);
624 if (q < 0)
625 r = q;
626 }
627
628 else
629 STRV_FOREACH(p, argv + 1) {
630 if (startswith(*p, "dns:"))
631 q = resolve_rfc4501(bus, *p);
632 else {
633 int family, ifindex;
634 union in_addr_union a;
635
636 q = in_addr_ifindex_from_string_auto(*p, &family, &a, &ifindex);
637 if (q >= 0)
638 q = resolve_address(bus, family, &a, ifindex);
639 else
640 q = resolve_host(bus, *p);
641 }
642 if (q < 0)
643 r = q;
644 }
645
646 return r;
647 }
648
649 static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) {
650 const char *canonical_name, *canonical_type, *canonical_domain;
651 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
652 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
653 char ifname[IF_NAMESIZE] = "";
654 size_t indent, sz;
655 uint64_t flags;
656 const char *p;
657 unsigned c;
658 usec_t ts;
659 int r;
660
661 assert(bus);
662 assert(domain);
663
664 name = empty_to_null(name);
665 type = empty_to_null(type);
666
667 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
668 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
669
670 if (name)
671 log_debug("Resolving service \"%s\" of type %s in %s (family %s, interface %s).", name, type, domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
672 else if (type)
673 log_debug("Resolving service type %s of %s (family %s, interface %s).", type, domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
674 else
675 log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
676
677 r = sd_bus_message_new_method_call(
678 bus,
679 &req,
680 "org.freedesktop.resolve1",
681 "/org/freedesktop/resolve1",
682 "org.freedesktop.resolve1.Manager",
683 "ResolveService");
684 if (r < 0)
685 return bus_log_create_error(r);
686
687 r = sd_bus_message_append(req, "isssit", arg_ifindex, name, type, domain, arg_family, arg_flags);
688 if (r < 0)
689 return bus_log_create_error(r);
690
691 ts = now(CLOCK_MONOTONIC);
692
693 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
694 if (r < 0)
695 return log_error_errno(r, "Resolve call failed: %s", bus_error_message(&error, r));
696
697 ts = now(CLOCK_MONOTONIC) - ts;
698
699 r = sd_bus_message_enter_container(reply, 'a', "(qqqsa(iiay)s)");
700 if (r < 0)
701 return bus_log_parse_error(r);
702
703 indent =
704 (name ? strlen(name) + 1 : 0) +
705 (type ? strlen(type) + 1 : 0) +
706 strlen(domain) + 2;
707
708 c = 0;
709 while ((r = sd_bus_message_enter_container(reply, 'r', "qqqsa(iiay)s")) > 0) {
710 uint16_t priority, weight, port;
711 const char *hostname, *canonical;
712
713 r = sd_bus_message_read(reply, "qqqs", &priority, &weight, &port, &hostname);
714 if (r < 0)
715 return bus_log_parse_error(r);
716
717 if (name)
718 printf("%*s%s", (int) strlen(name), c == 0 ? name : "", c == 0 ? "/" : " ");
719 if (type)
720 printf("%*s%s", (int) strlen(type), c == 0 ? type : "", c == 0 ? "/" : " ");
721
722 printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
723 (int) strlen(domain), c == 0 ? domain : "",
724 c == 0 ? ":" : " ",
725 hostname, port,
726 priority, weight);
727
728 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
729 if (r < 0)
730 return bus_log_parse_error(r);
731
732 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
733 _cleanup_free_ char *pretty = NULL;
734 int ifindex, family;
735 const void *a;
736
737 assert_cc(sizeof(int) == sizeof(int32_t));
738
739 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
740 if (r < 0)
741 return bus_log_parse_error(r);
742
743 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
744 if (r < 0)
745 return bus_log_parse_error(r);
746
747 r = sd_bus_message_exit_container(reply);
748 if (r < 0)
749 return bus_log_parse_error(r);
750
751 if (!IN_SET(family, AF_INET, AF_INET6)) {
752 log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
753 continue;
754 }
755
756 if (sz != FAMILY_ADDRESS_SIZE(family)) {
757 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
758 return -EINVAL;
759 }
760
761 ifname[0] = 0;
762 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
763 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
764
765 r = in_addr_to_string(family, a, &pretty);
766 if (r < 0)
767 return log_error_errno(r, "Failed to print address for %s: %m", name);
768
769 printf("%*s%s%s%s\n", (int) indent, "", pretty, isempty(ifname) ? "" : "%s", ifname);
770 }
771 if (r < 0)
772 return bus_log_parse_error(r);
773
774 r = sd_bus_message_exit_container(reply);
775 if (r < 0)
776 return bus_log_parse_error(r);
777
778 r = sd_bus_message_read(reply, "s", &canonical);
779 if (r < 0)
780 return bus_log_parse_error(r);
781
782 if (!streq(hostname, canonical))
783 printf("%*s(%s)\n", (int) indent, "", canonical);
784
785 r = sd_bus_message_exit_container(reply);
786 if (r < 0)
787 return bus_log_parse_error(r);
788
789 c++;
790 }
791 if (r < 0)
792 return bus_log_parse_error(r);
793
794 r = sd_bus_message_exit_container(reply);
795 if (r < 0)
796 return bus_log_parse_error(r);
797
798 r = sd_bus_message_enter_container(reply, 'a', "ay");
799 if (r < 0)
800 return bus_log_parse_error(r);
801
802 while ((r = sd_bus_message_read_array(reply, 'y', (const void**) &p, &sz)) > 0) {
803 _cleanup_free_ char *escaped = NULL;
804
805 escaped = cescape_length(p, sz);
806 if (!escaped)
807 return log_oom();
808
809 printf("%*s%s\n", (int) indent, "", escaped);
810 }
811 if (r < 0)
812 return bus_log_parse_error(r);
813
814 r = sd_bus_message_exit_container(reply);
815 if (r < 0)
816 return bus_log_parse_error(r);
817
818 r = sd_bus_message_read(reply, "ssst", &canonical_name, &canonical_type, &canonical_domain, &flags);
819 if (r < 0)
820 return bus_log_parse_error(r);
821
822 canonical_name = empty_to_null(canonical_name);
823 canonical_type = empty_to_null(canonical_type);
824
825 if (!streq_ptr(name, canonical_name) ||
826 !streq_ptr(type, canonical_type) ||
827 !streq_ptr(domain, canonical_domain)) {
828
829 printf("%*s(", (int) indent, "");
830
831 if (canonical_name)
832 printf("%s/", canonical_name);
833 if (canonical_type)
834 printf("%s/", canonical_type);
835
836 printf("%s)\n", canonical_domain);
837 }
838
839 print_source(flags, ts);
840
841 return 0;
842 }
843
844 static int verb_service(int argc, char **argv, void *userdata) {
845 sd_bus *bus = userdata;
846
847 if (argc == 2)
848 return resolve_service(bus, NULL, NULL, argv[1]);
849 else if (argc == 3)
850 return resolve_service(bus, NULL, argv[1], argv[2]);
851 else
852 return resolve_service(bus, argv[1], argv[2], argv[3]);
853 }
854
855 static int resolve_openpgp(sd_bus *bus, const char *address) {
856 const char *domain, *full;
857 int r;
858 _cleanup_free_ char *hashed = NULL;
859
860 assert(bus);
861 assert(address);
862
863 domain = strrchr(address, '@');
864 if (!domain) {
865 log_error("Address does not contain '@': \"%s\"", address);
866 return -EINVAL;
867 } else if (domain == address || domain[1] == '\0') {
868 log_error("Address starts or ends with '@': \"%s\"", address);
869 return -EINVAL;
870 }
871 domain++;
872
873 r = string_hashsum_sha256(address, domain - 1 - address, &hashed);
874 if (r < 0)
875 return log_error_errno(r, "Hashing failed: %m");
876
877 strshorten(hashed, 56);
878
879 full = strjoina(hashed, "._openpgpkey.", domain);
880 log_debug("Looking up \"%s\".", full);
881
882 r = resolve_record(bus, full,
883 arg_class ?: DNS_CLASS_IN,
884 arg_type ?: DNS_TYPE_OPENPGPKEY, false);
885
886 if (IN_SET(r, -ENXIO, -ESRCH)) { /* NXDOMAIN or NODATA? */
887 hashed = NULL;
888 r = string_hashsum_sha224(address, domain - 1 - address, &hashed);
889 if (r < 0)
890 return log_error_errno(r, "Hashing failed: %m");
891
892 full = strjoina(hashed, "._openpgpkey.", domain);
893 log_debug("Looking up \"%s\".", full);
894
895 return resolve_record(bus, full,
896 arg_class ?: DNS_CLASS_IN,
897 arg_type ?: DNS_TYPE_OPENPGPKEY, true);
898 }
899
900 return r;
901 }
902
903 static int verb_openpgp(int argc, char **argv, void *userdata) {
904 sd_bus *bus = userdata;
905 char **p;
906 int q, r = 0;
907
908 STRV_FOREACH(p, argv + 1) {
909 q = resolve_openpgp(bus, *p);
910 if (q < 0)
911 r = q;
912 }
913
914 return r;
915 }
916
917 static int resolve_tlsa(sd_bus *bus, const char *family, const char *address) {
918 const char *port;
919 uint16_t port_num = 443;
920 _cleanup_free_ char *full = NULL;
921 int r;
922
923 assert(bus);
924 assert(address);
925
926 port = strrchr(address, ':');
927 if (port) {
928 r = parse_ip_port(port + 1, &port_num);
929 if (r < 0)
930 return log_error_errno(r, "Invalid port \"%s\".", port + 1);
931
932 address = strndupa(address, port - address);
933 }
934
935 r = asprintf(&full, "_%u._%s.%s",
936 port_num,
937 family,
938 address);
939 if (r < 0)
940 return log_oom();
941
942 log_debug("Looking up \"%s\".", full);
943
944 return resolve_record(bus, full,
945 arg_class ?: DNS_CLASS_IN,
946 arg_type ?: DNS_TYPE_TLSA, true);
947 }
948
949 static bool service_family_is_valid(const char *s) {
950 return STR_IN_SET(s, "tcp", "udp", "sctp");
951 }
952
953 static int verb_tlsa(int argc, char **argv, void *userdata) {
954 sd_bus *bus = userdata;
955 char **p, **args = argv + 1;
956 const char *family = "tcp";
957 int q, r = 0;
958
959 if (service_family_is_valid(argv[1])) {
960 family = argv[1];
961 args++;
962 }
963
964 STRV_FOREACH(p, args) {
965 q = resolve_tlsa(bus, family, *p);
966 if (q < 0)
967 r = q;
968 }
969
970 return r;
971 }
972
973 static int show_statistics(int argc, char **argv, void *userdata) {
974 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
975 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
976 sd_bus *bus = userdata;
977 uint64_t n_current_transactions, n_total_transactions,
978 cache_size, n_cache_hit, n_cache_miss,
979 n_dnssec_secure, n_dnssec_insecure, n_dnssec_bogus, n_dnssec_indeterminate;
980 int r, dnssec_supported;
981
982 assert(bus);
983
984 r = sd_bus_get_property_trivial(bus,
985 "org.freedesktop.resolve1",
986 "/org/freedesktop/resolve1",
987 "org.freedesktop.resolve1.Manager",
988 "DNSSECSupported",
989 &error,
990 'b',
991 &dnssec_supported);
992 if (r < 0)
993 return log_error_errno(r, "Failed to get DNSSEC supported state: %s", bus_error_message(&error, r));
994
995 printf("DNSSEC supported by current servers: %s%s%s\n\n",
996 ansi_highlight(),
997 yes_no(dnssec_supported),
998 ansi_normal());
999
1000 r = sd_bus_get_property(bus,
1001 "org.freedesktop.resolve1",
1002 "/org/freedesktop/resolve1",
1003 "org.freedesktop.resolve1.Manager",
1004 "TransactionStatistics",
1005 &error,
1006 &reply,
1007 "(tt)");
1008 if (r < 0)
1009 return log_error_errno(r, "Failed to get transaction statistics: %s", bus_error_message(&error, r));
1010
1011 r = sd_bus_message_read(reply, "(tt)",
1012 &n_current_transactions,
1013 &n_total_transactions);
1014 if (r < 0)
1015 return bus_log_parse_error(r);
1016
1017 printf("%sTransactions%s\n"
1018 "Current Transactions: %" PRIu64 "\n"
1019 " Total Transactions: %" PRIu64 "\n",
1020 ansi_highlight(),
1021 ansi_normal(),
1022 n_current_transactions,
1023 n_total_transactions);
1024
1025 reply = sd_bus_message_unref(reply);
1026
1027 r = sd_bus_get_property(bus,
1028 "org.freedesktop.resolve1",
1029 "/org/freedesktop/resolve1",
1030 "org.freedesktop.resolve1.Manager",
1031 "CacheStatistics",
1032 &error,
1033 &reply,
1034 "(ttt)");
1035 if (r < 0)
1036 return log_error_errno(r, "Failed to get cache statistics: %s", bus_error_message(&error, r));
1037
1038 r = sd_bus_message_read(reply, "(ttt)",
1039 &cache_size,
1040 &n_cache_hit,
1041 &n_cache_miss);
1042 if (r < 0)
1043 return bus_log_parse_error(r);
1044
1045 printf("\n%sCache%s\n"
1046 " Current Cache Size: %" PRIu64 "\n"
1047 " Cache Hits: %" PRIu64 "\n"
1048 " Cache Misses: %" PRIu64 "\n",
1049 ansi_highlight(),
1050 ansi_normal(),
1051 cache_size,
1052 n_cache_hit,
1053 n_cache_miss);
1054
1055 reply = sd_bus_message_unref(reply);
1056
1057 r = sd_bus_get_property(bus,
1058 "org.freedesktop.resolve1",
1059 "/org/freedesktop/resolve1",
1060 "org.freedesktop.resolve1.Manager",
1061 "DNSSECStatistics",
1062 &error,
1063 &reply,
1064 "(tttt)");
1065 if (r < 0)
1066 return log_error_errno(r, "Failed to get DNSSEC statistics: %s", bus_error_message(&error, r));
1067
1068 r = sd_bus_message_read(reply, "(tttt)",
1069 &n_dnssec_secure,
1070 &n_dnssec_insecure,
1071 &n_dnssec_bogus,
1072 &n_dnssec_indeterminate);
1073 if (r < 0)
1074 return bus_log_parse_error(r);
1075
1076 printf("\n%sDNSSEC Verdicts%s\n"
1077 " Secure: %" PRIu64 "\n"
1078 " Insecure: %" PRIu64 "\n"
1079 " Bogus: %" PRIu64 "\n"
1080 " Indeterminate: %" PRIu64 "\n",
1081 ansi_highlight(),
1082 ansi_normal(),
1083 n_dnssec_secure,
1084 n_dnssec_insecure,
1085 n_dnssec_bogus,
1086 n_dnssec_indeterminate);
1087
1088 return 0;
1089 }
1090
1091 static int reset_statistics(int argc, char **argv, void *userdata) {
1092 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1093 sd_bus *bus = userdata;
1094 int r;
1095
1096 r = sd_bus_call_method(bus,
1097 "org.freedesktop.resolve1",
1098 "/org/freedesktop/resolve1",
1099 "org.freedesktop.resolve1.Manager",
1100 "ResetStatistics",
1101 &error,
1102 NULL,
1103 NULL);
1104 if (r < 0)
1105 return log_error_errno(r, "Failed to reset statistics: %s", bus_error_message(&error, r));
1106
1107 return 0;
1108 }
1109
1110 static int flush_caches(int argc, char **argv, void *userdata) {
1111 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1112 sd_bus *bus = userdata;
1113 int r;
1114
1115 r = sd_bus_call_method(bus,
1116 "org.freedesktop.resolve1",
1117 "/org/freedesktop/resolve1",
1118 "org.freedesktop.resolve1.Manager",
1119 "FlushCaches",
1120 &error,
1121 NULL,
1122 NULL);
1123 if (r < 0)
1124 return log_error_errno(r, "Failed to flush caches: %s", bus_error_message(&error, r));
1125
1126 return 0;
1127 }
1128
1129 static int reset_server_features(int argc, char **argv, void *userdata) {
1130 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1131 sd_bus *bus = userdata;
1132 int r;
1133
1134 r = sd_bus_call_method(bus,
1135 "org.freedesktop.resolve1",
1136 "/org/freedesktop/resolve1",
1137 "org.freedesktop.resolve1.Manager",
1138 "ResetServerFeatures",
1139 &error,
1140 NULL,
1141 NULL);
1142 if (r < 0)
1143 return log_error_errno(r, "Failed to reset server features: %s", bus_error_message(&error, r));
1144
1145 return 0;
1146 }
1147
1148 static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, char **ret) {
1149 _cleanup_free_ char *pretty = NULL;
1150 int ifindex, family, r;
1151 const void *a;
1152 size_t sz;
1153
1154 assert(m);
1155 assert(ret);
1156
1157 r = sd_bus_message_enter_container(m, 'r', with_ifindex ? "iiay" : "iay");
1158 if (r <= 0)
1159 return r;
1160
1161 if (with_ifindex) {
1162 r = sd_bus_message_read(m, "i", &ifindex);
1163 if (r < 0)
1164 return r;
1165 }
1166
1167 r = sd_bus_message_read(m, "i", &family);
1168 if (r < 0)
1169 return r;
1170
1171 r = sd_bus_message_read_array(m, 'y', &a, &sz);
1172 if (r < 0)
1173 return r;
1174
1175 r = sd_bus_message_exit_container(m);
1176 if (r < 0)
1177 return r;
1178
1179 if (with_ifindex && ifindex != 0) {
1180 /* only show the global ones here */
1181 *ret = NULL;
1182 return 1;
1183 }
1184
1185 if (!IN_SET(family, AF_INET, AF_INET6)) {
1186 log_debug("Unexpected family, ignoring: %i", family);
1187
1188 *ret = NULL;
1189 return 1;
1190 }
1191
1192 if (sz != FAMILY_ADDRESS_SIZE(family)) {
1193 log_debug("Address size mismatch, ignoring.");
1194
1195 *ret = NULL;
1196 return 1;
1197 }
1198
1199 r = in_addr_to_string(family, a, &pretty);
1200 if (r < 0)
1201 return r;
1202
1203 *ret = TAKE_PTR(pretty);
1204
1205 return 1;
1206 }
1207
1208 static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1209 char ***l = userdata;
1210 int r;
1211
1212 assert(bus);
1213 assert(member);
1214 assert(m);
1215 assert(l);
1216
1217 r = sd_bus_message_enter_container(m, 'a', "(iay)");
1218 if (r < 0)
1219 return r;
1220
1221 for (;;) {
1222 char *pretty = NULL;
1223
1224 r = read_dns_server_one(m, false, &pretty);
1225 if (r < 0)
1226 return r;
1227 if (r == 0)
1228 break;
1229
1230 if (isempty(pretty))
1231 continue;
1232
1233 r = strv_consume(l, pretty);
1234 if (r < 0)
1235 return r;
1236 }
1237
1238 r = sd_bus_message_exit_container(m);
1239 if (r < 0)
1240 return r;
1241
1242 return 0;
1243 }
1244
1245 static int map_link_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1246 assert(m);
1247 assert(userdata);
1248
1249 return read_dns_server_one(m, false, userdata);
1250 }
1251
1252 static int read_domain_one(sd_bus_message *m, bool with_ifindex, char **ret) {
1253 _cleanup_free_ char *str = NULL;
1254 int ifindex, route_only, r;
1255 const char *domain;
1256
1257 assert(m);
1258 assert(ret);
1259
1260 if (with_ifindex)
1261 r = sd_bus_message_read(m, "(isb)", &ifindex, &domain, &route_only);
1262 else
1263 r = sd_bus_message_read(m, "(sb)", &domain, &route_only);
1264 if (r <= 0)
1265 return r;
1266
1267 if (with_ifindex && ifindex != 0) {
1268 /* only show the global ones here */
1269 *ret = NULL;
1270 return 1;
1271 }
1272
1273 if (route_only)
1274 str = strappend("~", domain);
1275 else
1276 str = strdup(domain);
1277 if (!str)
1278 return -ENOMEM;
1279
1280 *ret = TAKE_PTR(str);
1281
1282 return 1;
1283 }
1284
1285 static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1286 char ***l = userdata;
1287 int r;
1288
1289 assert(bus);
1290 assert(member);
1291 assert(m);
1292 assert(l);
1293
1294 r = sd_bus_message_enter_container(m, 'a', "(sb)");
1295 if (r < 0)
1296 return r;
1297
1298 for (;;) {
1299 char *pretty = NULL;
1300
1301 r = read_domain_one(m, false, &pretty);
1302 if (r < 0)
1303 return r;
1304 if (r == 0)
1305 break;
1306
1307 if (isempty(pretty))
1308 continue;
1309
1310 r = strv_consume(l, pretty);
1311 if (r < 0)
1312 return r;
1313 }
1314
1315 r = sd_bus_message_exit_container(m);
1316 if (r < 0)
1317 return r;
1318
1319 return 0;
1320 }
1321
1322 static int status_print_strv_ifindex(int ifindex, const char *ifname, char **p) {
1323 char **i;
1324
1325 printf("%sLink %i (%s)%s:",
1326 ansi_highlight(), ifindex, ifname, ansi_normal());
1327
1328 STRV_FOREACH(i, p)
1329 printf(" %s", *i);
1330
1331 printf("\n");
1332
1333 return 0;
1334 }
1335
1336 static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode mode, bool *empty_line) {
1337
1338 struct link_info {
1339 uint64_t scopes_mask;
1340 const char *llmnr;
1341 const char *mdns;
1342 const char *private_dns;
1343 const char *dnssec;
1344 char *current_dns;
1345 char **dns;
1346 char **domains;
1347 char **ntas;
1348 bool dnssec_supported;
1349 } link_info = {};
1350
1351 static const struct bus_properties_map property_map[] = {
1352 { "ScopesMask", "t", NULL, offsetof(struct link_info, scopes_mask) },
1353 { "DNS", "a(iay)", map_link_dns_servers, offsetof(struct link_info, dns) },
1354 { "CurrentDNSServer", "(iay)", map_link_current_dns_server, offsetof(struct link_info, current_dns) },
1355 { "Domains", "a(sb)", map_link_domains, offsetof(struct link_info, domains) },
1356 { "LLMNR", "s", NULL, offsetof(struct link_info, llmnr) },
1357 { "MulticastDNS", "s", NULL, offsetof(struct link_info, mdns) },
1358 { "PrivateDNS", "s", NULL, offsetof(struct link_info, private_dns) },
1359 { "DNSSEC", "s", NULL, offsetof(struct link_info, dnssec) },
1360 { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct link_info, ntas) },
1361 { "DNSSECSupported", "b", NULL, offsetof(struct link_info, dnssec_supported) },
1362 {}
1363 };
1364
1365 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1366 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1367 _cleanup_free_ char *ifi = NULL, *p = NULL;
1368 char ifname[IF_NAMESIZE] = "";
1369 char **i;
1370 int r;
1371
1372 assert(bus);
1373 assert(ifindex > 0);
1374
1375 if (!name) {
1376 if (!if_indextoname(ifindex, ifname))
1377 return log_error_errno(errno, "Failed to resolve interface name for %i: %m", ifindex);
1378
1379 name = ifname;
1380 }
1381
1382 if (asprintf(&ifi, "%i", ifindex) < 0)
1383 return log_oom();
1384
1385 r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifi, &p);
1386 if (r < 0)
1387 return log_oom();
1388
1389 r = bus_map_all_properties(bus,
1390 "org.freedesktop.resolve1",
1391 p,
1392 property_map,
1393 BUS_MAP_BOOLEAN_AS_BOOL,
1394 &error,
1395 &m,
1396 &link_info);
1397 if (r < 0) {
1398 log_error_errno(r, "Failed to get link data for %i: %s", ifindex, bus_error_message(&error, r));
1399 goto finish;
1400 }
1401
1402 (void) pager_open(arg_no_pager, false);
1403
1404 if (mode == STATUS_DNS) {
1405 r = status_print_strv_ifindex(ifindex, name, link_info.dns);
1406 goto finish;
1407 }
1408
1409 if (mode == STATUS_DOMAIN) {
1410 r = status_print_strv_ifindex(ifindex, name, link_info.domains);
1411 goto finish;
1412 }
1413
1414 if (mode == STATUS_NTA) {
1415 r = status_print_strv_ifindex(ifindex, name, link_info.ntas);
1416 goto finish;
1417 }
1418
1419 if (mode == STATUS_LLMNR) {
1420 printf("%sLink %i (%s)%s: %s\n",
1421 ansi_highlight(), ifindex, name, ansi_normal(),
1422 strna(link_info.llmnr));
1423
1424 r = 0;
1425 goto finish;
1426 }
1427
1428 if (mode == STATUS_MDNS) {
1429 printf("%sLink %i (%s)%s: %s\n",
1430 ansi_highlight(), ifindex, name, ansi_normal(),
1431 strna(link_info.mdns));
1432
1433 r = 0;
1434 goto finish;
1435 }
1436
1437 if (mode == STATUS_PRIVATE) {
1438 printf("%sLink %i (%s)%s: %s\n",
1439 ansi_highlight(), ifindex, name, ansi_normal(),
1440 strna(link_info.private_dns));
1441
1442 r = 0;
1443 goto finish;
1444 }
1445
1446 if (mode == STATUS_DNSSEC) {
1447 printf("%sLink %i (%s)%s: %s\n",
1448 ansi_highlight(), ifindex, name, ansi_normal(),
1449 strna(link_info.dnssec));
1450
1451 r = 0;
1452 goto finish;
1453 }
1454
1455 if (empty_line && *empty_line)
1456 fputc('\n', stdout);
1457
1458 printf("%sLink %i (%s)%s\n",
1459 ansi_highlight(), ifindex, name, ansi_normal());
1460
1461 if (link_info.scopes_mask == 0)
1462 printf(" Current Scopes: none\n");
1463 else
1464 printf(" Current Scopes:%s%s%s%s%s\n",
1465 link_info.scopes_mask & SD_RESOLVED_DNS ? " DNS" : "",
1466 link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
1467 link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "",
1468 link_info.scopes_mask & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4" : "",
1469 link_info.scopes_mask & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6" : "");
1470
1471 printf(" LLMNR setting: %s\n"
1472 "MulticastDNS setting: %s\n"
1473 " PrivateDNS setting: %s\n"
1474 " DNSSEC setting: %s\n"
1475 " DNSSEC supported: %s\n",
1476 strna(link_info.llmnr),
1477 strna(link_info.mdns),
1478 strna(link_info.private_dns),
1479 strna(link_info.dnssec),
1480 yes_no(link_info.dnssec_supported));
1481
1482 if (link_info.current_dns)
1483 printf(" Current DNS Server: %s\n", link_info.current_dns);
1484
1485 STRV_FOREACH(i, link_info.dns) {
1486 printf(" %s %s\n",
1487 i == link_info.dns ? "DNS Servers:" : " ",
1488 *i);
1489 }
1490
1491 STRV_FOREACH(i, link_info.domains) {
1492 printf(" %s %s\n",
1493 i == link_info.domains ? "DNS Domain:" : " ",
1494 *i);
1495 }
1496
1497 STRV_FOREACH(i, link_info.ntas) {
1498 printf(" %s %s\n",
1499 i == link_info.ntas ? "DNSSEC NTA:" : " ",
1500 *i);
1501 }
1502
1503 if (empty_line)
1504 *empty_line = true;
1505
1506 r = 0;
1507
1508 finish:
1509 free(link_info.current_dns);
1510 strv_free(link_info.dns);
1511 strv_free(link_info.domains);
1512 strv_free(link_info.ntas);
1513 return r;
1514 }
1515
1516 static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1517 char ***l = userdata;
1518 int r;
1519
1520 assert(bus);
1521 assert(member);
1522 assert(m);
1523 assert(l);
1524
1525 r = sd_bus_message_enter_container(m, 'a', "(iiay)");
1526 if (r < 0)
1527 return r;
1528
1529 for (;;) {
1530 char *pretty = NULL;
1531
1532 r = read_dns_server_one(m, true, &pretty);
1533 if (r < 0)
1534 return r;
1535 if (r == 0)
1536 break;
1537
1538 if (isempty(pretty))
1539 continue;
1540
1541 r = strv_consume(l, pretty);
1542 if (r < 0)
1543 return r;
1544 }
1545
1546 r = sd_bus_message_exit_container(m);
1547 if (r < 0)
1548 return r;
1549
1550 return 0;
1551 }
1552
1553 static int map_global_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1554 assert(m);
1555 assert(userdata);
1556
1557 return read_dns_server_one(m, true, userdata);
1558 }
1559
1560 static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1561 char ***l = userdata;
1562 int r;
1563
1564 assert(bus);
1565 assert(member);
1566 assert(m);
1567 assert(l);
1568
1569 r = sd_bus_message_enter_container(m, 'a', "(isb)");
1570 if (r < 0)
1571 return r;
1572
1573 for (;;) {
1574 char *pretty = NULL;
1575
1576 r = read_domain_one(m, true, &pretty);
1577 if (r < 0)
1578 return r;
1579 if (r == 0)
1580 break;
1581
1582 if (isempty(pretty))
1583 continue;
1584
1585 r = strv_consume(l, pretty);
1586 if (r < 0)
1587 return r;
1588 }
1589
1590 r = sd_bus_message_exit_container(m);
1591 if (r < 0)
1592 return r;
1593
1594 return 0;
1595 }
1596
1597 static int status_print_strv_global(char **p) {
1598 char **i;
1599
1600 printf("%sGlobal%s:", ansi_highlight(), ansi_normal());
1601
1602 STRV_FOREACH(i, p)
1603 printf(" %s", *i);
1604
1605 printf("\n");
1606
1607 return 0;
1608 }
1609
1610 static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
1611
1612 struct global_info {
1613 char *current_dns;
1614 char **dns;
1615 char **fallback_dns;
1616 char **domains;
1617 char **ntas;
1618 const char *llmnr;
1619 const char *mdns;
1620 const char *private_dns;
1621 const char *dnssec;
1622 bool dnssec_supported;
1623 } global_info = {};
1624
1625 static const struct bus_properties_map property_map[] = {
1626 { "DNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, dns) },
1627 { "FallbackDNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, fallback_dns) },
1628 { "CurrentDNSServer", "(iiay)", map_global_current_dns_server, offsetof(struct global_info, current_dns) },
1629 { "Domains", "a(isb)", map_global_domains, offsetof(struct global_info, domains) },
1630 { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct global_info, ntas) },
1631 { "LLMNR", "s", NULL, offsetof(struct global_info, llmnr) },
1632 { "MulticastDNS", "s", NULL, offsetof(struct global_info, mdns) },
1633 { "PrivateDNS", "s", NULL, offsetof(struct global_info, private_dns) },
1634 { "DNSSEC", "s", NULL, offsetof(struct global_info, dnssec) },
1635 { "DNSSECSupported", "b", NULL, offsetof(struct global_info, dnssec_supported) },
1636 {}
1637 };
1638
1639 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1640 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
1641 char **i;
1642 int r;
1643
1644 assert(bus);
1645 assert(empty_line);
1646
1647 r = bus_map_all_properties(bus,
1648 "org.freedesktop.resolve1",
1649 "/org/freedesktop/resolve1",
1650 property_map,
1651 BUS_MAP_BOOLEAN_AS_BOOL,
1652 &error,
1653 &m,
1654 &global_info);
1655 if (r < 0) {
1656 log_error_errno(r, "Failed to get global data: %s", bus_error_message(&error, r));
1657 goto finish;
1658 }
1659
1660 (void) pager_open(arg_no_pager, false);
1661
1662 if (mode == STATUS_DNS) {
1663 r = status_print_strv_global(global_info.dns);
1664 goto finish;
1665 }
1666
1667 if (mode == STATUS_DOMAIN) {
1668 r = status_print_strv_global(global_info.domains);
1669 goto finish;
1670 }
1671
1672 if (mode == STATUS_NTA) {
1673 r = status_print_strv_global(global_info.ntas);
1674 goto finish;
1675 }
1676
1677 if (mode == STATUS_LLMNR) {
1678 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
1679 strna(global_info.llmnr));
1680
1681 r = 0;
1682 goto finish;
1683 }
1684
1685 if (mode == STATUS_MDNS) {
1686 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
1687 strna(global_info.mdns));
1688
1689 r = 0;
1690 goto finish;
1691 }
1692
1693 if (mode == STATUS_PRIVATE) {
1694 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
1695 strna(global_info.private_dns));
1696
1697 r = 0;
1698 goto finish;
1699 }
1700
1701 if (mode == STATUS_DNSSEC) {
1702 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
1703 strna(global_info.dnssec));
1704
1705 r = 0;
1706 goto finish;
1707 }
1708
1709 printf("%sGlobal%s\n", ansi_highlight(), ansi_normal());
1710
1711 printf(" LLMNR setting: %s\n"
1712 "MulticastDNS setting: %s\n"
1713 " PrivateDNS setting: %s\n"
1714 " DNSSEC setting: %s\n"
1715 " DNSSEC supported: %s\n",
1716 strna(global_info.llmnr),
1717 strna(global_info.mdns),
1718 strna(global_info.private_dns),
1719 strna(global_info.dnssec),
1720 yes_no(global_info.dnssec_supported));
1721
1722 if (global_info.current_dns)
1723 printf(" Current DNS Server: %s\n", global_info.current_dns);
1724
1725 STRV_FOREACH(i, global_info.dns) {
1726 printf(" %s %s\n",
1727 i == global_info.dns ? "DNS Servers:" : " ",
1728 *i);
1729 }
1730
1731 STRV_FOREACH(i, global_info.fallback_dns) {
1732 printf("%s %s\n",
1733 i == global_info.fallback_dns ? "Fallback DNS Servers:" : " ",
1734 *i);
1735 }
1736
1737 STRV_FOREACH(i, global_info.domains) {
1738 printf(" %s %s\n",
1739 i == global_info.domains ? "DNS Domain:" : " ",
1740 *i);
1741 }
1742
1743 strv_sort(global_info.ntas);
1744 STRV_FOREACH(i, global_info.ntas) {
1745 printf(" %s %s\n",
1746 i == global_info.ntas ? "DNSSEC NTA:" : " ",
1747 *i);
1748 }
1749
1750 *empty_line = true;
1751
1752 r = 0;
1753
1754 finish:
1755 free(global_info.current_dns);
1756 strv_free(global_info.dns);
1757 strv_free(global_info.fallback_dns);
1758 strv_free(global_info.domains);
1759 strv_free(global_info.ntas);
1760
1761 return r;
1762 }
1763
1764 static int status_all(sd_bus *bus, StatusMode mode) {
1765 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
1766 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
1767 sd_netlink_message *i;
1768 bool empty_line = false;
1769 int r;
1770
1771 assert(bus);
1772
1773 r = status_global(bus, mode, &empty_line);
1774 if (r < 0)
1775 return r;
1776
1777 r = sd_netlink_open(&rtnl);
1778 if (r < 0)
1779 return log_error_errno(r, "Failed to connect to netlink: %m");
1780
1781 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
1782 if (r < 0)
1783 return rtnl_log_create_error(r);
1784
1785 r = sd_netlink_message_request_dump(req, true);
1786 if (r < 0)
1787 return rtnl_log_create_error(r);
1788
1789 r = sd_netlink_call(rtnl, req, 0, &reply);
1790 if (r < 0)
1791 return log_error_errno(r, "Failed to enumerate links: %m");
1792
1793 r = 0;
1794 for (i = reply; i; i = sd_netlink_message_next(i)) {
1795 const char *name;
1796 int ifindex, q;
1797 uint16_t type;
1798
1799 q = sd_netlink_message_get_type(i, &type);
1800 if (q < 0)
1801 return rtnl_log_parse_error(q);
1802
1803 if (type != RTM_NEWLINK)
1804 continue;
1805
1806 q = sd_rtnl_message_link_get_ifindex(i, &ifindex);
1807 if (q < 0)
1808 return rtnl_log_parse_error(q);
1809
1810 if (ifindex == LOOPBACK_IFINDEX)
1811 continue;
1812
1813 q = sd_netlink_message_read_string(i, IFLA_IFNAME, &name);
1814 if (q < 0)
1815 return rtnl_log_parse_error(q);
1816
1817 q = status_ifindex(bus, ifindex, name, mode, &empty_line);
1818 if (q < 0 && r >= 0)
1819 r = q;
1820 }
1821
1822 return r;
1823 }
1824
1825 static int verb_status(int argc, char **argv, void *userdata) {
1826 sd_bus *bus = userdata;
1827 int q, r = 0;
1828
1829 if (argc > 1) {
1830 char **ifname;
1831 bool empty_line = false;
1832
1833 STRV_FOREACH(ifname, argv + 1) {
1834 int ifindex;
1835
1836 ifindex = parse_ifindex_with_warn(*ifname);
1837 if (ifindex < 0)
1838 continue;
1839
1840 q = status_ifindex(bus, ifindex, NULL, STATUS_ALL, &empty_line);
1841 if (q < 0)
1842 r = q;
1843 }
1844 } else
1845 r = status_all(bus, STATUS_ALL);
1846
1847 return r;
1848 }
1849
1850 static int log_interface_is_managed(int r, int ifindex) {
1851 char ifname[IFNAMSIZ];
1852
1853 return log_error_errno(r,
1854 "The specified interface %s is managed by systemd-networkd. Operation refused.\n"
1855 "Please configure DNS settings for systemd-networkd managed interfaces directly in their .network files.",
1856 strna(if_indextoname(ifindex, ifname)));
1857 }
1858
1859 static int verb_dns(int argc, char **argv, void *userdata) {
1860 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1861 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
1862 sd_bus *bus = userdata;
1863 int ifindex, r;
1864 char **p;
1865
1866 assert(bus);
1867
1868 if (argc <= 1)
1869 return status_all(bus, STATUS_DNS);
1870
1871 ifindex = parse_ifindex_with_warn(argv[1]);
1872 if (ifindex < 0)
1873 return ifindex;
1874
1875 if (ifindex == LOOPBACK_IFINDEX) {
1876 log_error("Interface can't be the loopback interface (lo). Sorry.");
1877 return -EINVAL;
1878 }
1879
1880 if (argc == 2)
1881 return status_ifindex(bus, ifindex, NULL, STATUS_DNS, NULL);
1882
1883 r = sd_bus_message_new_method_call(
1884 bus,
1885 &req,
1886 "org.freedesktop.resolve1",
1887 "/org/freedesktop/resolve1",
1888 "org.freedesktop.resolve1.Manager",
1889 "SetLinkDNS");
1890 if (r < 0)
1891 return bus_log_create_error(r);
1892
1893 r = sd_bus_message_append(req, "i", ifindex);
1894 if (r < 0)
1895 return bus_log_create_error(r);
1896
1897 r = sd_bus_message_open_container(req, 'a', "(iay)");
1898 if (r < 0)
1899 return bus_log_create_error(r);
1900
1901 STRV_FOREACH(p, argv + 2) {
1902 struct in_addr_data data;
1903
1904 r = in_addr_from_string_auto(*p, &data.family, &data.address);
1905 if (r < 0)
1906 return log_error_errno(r, "Failed to parse DNS server address: %s", *p);
1907
1908 r = sd_bus_message_open_container(req, 'r', "iay");
1909 if (r < 0)
1910 return bus_log_create_error(r);
1911
1912 r = sd_bus_message_append(req, "i", data.family);
1913 if (r < 0)
1914 return bus_log_create_error(r);
1915
1916 r = sd_bus_message_append_array(req, 'y', &data.address, FAMILY_ADDRESS_SIZE(data.family));
1917 if (r < 0)
1918 return bus_log_create_error(r);
1919
1920 r = sd_bus_message_close_container(req);
1921 if (r < 0)
1922 return bus_log_create_error(r);
1923 }
1924
1925 r = sd_bus_message_close_container(req);
1926 if (r < 0)
1927 return bus_log_create_error(r);
1928
1929 r = sd_bus_call(bus, req, 0, &error, NULL);
1930 if (r < 0) {
1931 if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
1932 return log_interface_is_managed(r, ifindex);
1933
1934 if (arg_ifindex_permissive &&
1935 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
1936 return 0;
1937
1938 return log_error_errno(r, "Failed to set DNS configuration: %s", bus_error_message(&error, r));
1939 }
1940
1941 return 0;
1942 }
1943
1944 static int verb_domain(int argc, char **argv, void *userdata) {
1945 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1946 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
1947 sd_bus *bus = userdata;
1948 int ifindex, r;
1949 char **p;
1950
1951 assert(bus);
1952
1953 if (argc <= 1)
1954 return status_all(bus, STATUS_DOMAIN);
1955
1956 ifindex = parse_ifindex_with_warn(argv[1]);
1957 if (ifindex < 0)
1958 return ifindex;
1959
1960 if (ifindex == LOOPBACK_IFINDEX) {
1961 log_error("Interface can't be the loopback interface (lo). Sorry.");
1962 return -EINVAL;
1963 }
1964
1965 if (argc == 2)
1966 return status_ifindex(bus, ifindex, NULL, STATUS_DOMAIN, NULL);
1967
1968 r = sd_bus_message_new_method_call(
1969 bus,
1970 &req,
1971 "org.freedesktop.resolve1",
1972 "/org/freedesktop/resolve1",
1973 "org.freedesktop.resolve1.Manager",
1974 "SetLinkDomains");
1975 if (r < 0)
1976 return bus_log_create_error(r);
1977
1978 r = sd_bus_message_append(req, "i", ifindex);
1979 if (r < 0)
1980 return bus_log_create_error(r);
1981
1982 r = sd_bus_message_open_container(req, 'a', "(sb)");
1983 if (r < 0)
1984 return bus_log_create_error(r);
1985
1986 STRV_FOREACH(p, argv + 2) {
1987 const char *n;
1988
1989 n = **p == '~' ? *p + 1 : *p;
1990
1991 r = dns_name_is_valid(n);
1992 if (r < 0)
1993 return log_error_errno(r, "Failed to validate specified domain %s: %m", n);
1994 if (r == 0) {
1995 log_error("Domain not valid: %s", n);
1996 return -EINVAL;
1997 }
1998
1999 r = sd_bus_message_append(req, "(sb)", n, **p == '~');
2000 if (r < 0)
2001 return bus_log_create_error(r);
2002 }
2003
2004 r = sd_bus_message_close_container(req);
2005 if (r < 0)
2006 return bus_log_create_error(r);
2007
2008 r = sd_bus_call(bus, req, 0, &error, NULL);
2009 if (r < 0) {
2010 if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
2011 return log_interface_is_managed(r, ifindex);
2012
2013 if (arg_ifindex_permissive &&
2014 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2015 return 0;
2016
2017 return log_error_errno(r, "Failed to set domain configuration: %s", bus_error_message(&error, r));
2018 }
2019
2020 return 0;
2021 }
2022
2023 static int verb_llmnr(int argc, char **argv, void *userdata) {
2024 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2025 sd_bus *bus = userdata;
2026 int ifindex, r;
2027
2028 assert(bus);
2029
2030 if (argc <= 1)
2031 return status_all(bus, STATUS_LLMNR);
2032
2033 ifindex = parse_ifindex_with_warn(argv[1]);
2034 if (ifindex < 0)
2035 return ifindex;
2036
2037 if (ifindex == LOOPBACK_IFINDEX) {
2038 log_error("Interface can't be the loopback interface (lo). Sorry.");
2039 return -EINVAL;
2040 }
2041
2042 if (argc == 2)
2043 return status_ifindex(bus, ifindex, NULL, STATUS_LLMNR, NULL);
2044
2045 r = sd_bus_call_method(bus,
2046 "org.freedesktop.resolve1",
2047 "/org/freedesktop/resolve1",
2048 "org.freedesktop.resolve1.Manager",
2049 "SetLinkLLMNR",
2050 &error,
2051 NULL,
2052 "is", ifindex, argv[2]);
2053 if (r < 0) {
2054 if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
2055 return log_interface_is_managed(r, ifindex);
2056
2057 if (arg_ifindex_permissive &&
2058 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2059 return 0;
2060
2061 return log_error_errno(r, "Failed to set LLMNR configuration: %s", bus_error_message(&error, r));
2062 }
2063
2064 return 0;
2065 }
2066
2067 static int verb_mdns(int argc, char **argv, void *userdata) {
2068 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2069 sd_bus *bus = userdata;
2070 int ifindex, r;
2071
2072 assert(bus);
2073
2074 if (argc <= 1)
2075 return status_all(bus, STATUS_MDNS);
2076
2077 ifindex = parse_ifindex_with_warn(argv[1]);
2078 if (ifindex < 0)
2079 return ifindex;
2080
2081 if (ifindex == LOOPBACK_IFINDEX) {
2082 log_error("Interface can't be the loopback interface (lo). Sorry.");
2083 return -EINVAL;
2084 }
2085
2086 if (argc == 2)
2087 return status_ifindex(bus, ifindex, NULL, STATUS_MDNS, NULL);
2088
2089 r = sd_bus_call_method(bus,
2090 "org.freedesktop.resolve1",
2091 "/org/freedesktop/resolve1",
2092 "org.freedesktop.resolve1.Manager",
2093 "SetLinkMulticastDNS",
2094 &error,
2095 NULL,
2096 "is", ifindex, argv[2]);
2097 if (r < 0) {
2098 if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
2099 return log_interface_is_managed(r, ifindex);
2100
2101 if (arg_ifindex_permissive &&
2102 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2103 return 0;
2104
2105 return log_error_errno(r, "Failed to set MulticastDNS configuration: %s", bus_error_message(&error, r));
2106 }
2107
2108 return 0;
2109 }
2110
2111 static int verb_private_dns(int argc, char **argv, void *userdata) {
2112 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2113 sd_bus *bus = userdata;
2114 int ifindex, r;
2115
2116 assert(bus);
2117
2118 if (argc <= 1)
2119 return status_all(bus, STATUS_PRIVATE);
2120
2121 ifindex = parse_ifindex_with_warn(argv[1]);
2122 if (ifindex < 0)
2123 return ifindex;
2124
2125 if (ifindex == LOOPBACK_IFINDEX) {
2126 log_error("Interface can't be the loopback interface (lo). Sorry.");
2127 return -EINVAL;
2128 }
2129
2130 if (argc == 2)
2131 return status_ifindex(bus, ifindex, NULL, STATUS_PRIVATE, NULL);
2132
2133 r = sd_bus_call_method(bus,
2134 "org.freedesktop.resolve1",
2135 "/org/freedesktop/resolve1",
2136 "org.freedesktop.resolve1.Manager",
2137 "SetLinkPrivateDNS",
2138 &error,
2139 NULL,
2140 "is", ifindex, argv[2]);
2141 if (r < 0) {
2142 if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
2143 return log_interface_is_managed(r, ifindex);
2144
2145 if (arg_ifindex_permissive &&
2146 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2147 return 0;
2148
2149 return log_error_errno(r, "Failed to set PrivateDNS configuration: %s", bus_error_message(&error, r));
2150 }
2151
2152 return 0;
2153 }
2154
2155 static int verb_dnssec(int argc, char **argv, void *userdata) {
2156 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2157 sd_bus *bus = userdata;
2158 int ifindex, r;
2159
2160 assert(bus);
2161
2162 if (argc <= 1)
2163 return status_all(bus, STATUS_DNSSEC);
2164
2165 ifindex = parse_ifindex_with_warn(argv[1]);
2166 if (ifindex < 0)
2167 return ifindex;
2168
2169 if (ifindex == LOOPBACK_IFINDEX) {
2170 log_error("Interface can't be the loopback interface (lo). Sorry.");
2171 return -EINVAL;
2172 }
2173
2174 if (argc == 2)
2175 return status_ifindex(bus, ifindex, NULL, STATUS_DNSSEC, NULL);
2176
2177 r = sd_bus_call_method(bus,
2178 "org.freedesktop.resolve1",
2179 "/org/freedesktop/resolve1",
2180 "org.freedesktop.resolve1.Manager",
2181 "SetLinkDNSSEC",
2182 &error,
2183 NULL,
2184 "is", ifindex, argv[2]);
2185 if (r < 0) {
2186 if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
2187 return log_interface_is_managed(r, ifindex);
2188
2189 if (arg_ifindex_permissive &&
2190 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2191 return 0;
2192
2193 return log_error_errno(r, "Failed to set DNSSEC configuration: %s", bus_error_message(&error, r));
2194 }
2195
2196 return 0;
2197 }
2198
2199 static int verb_nta(int argc, char **argv, void *userdata) {
2200 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2201 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
2202 sd_bus *bus = userdata;
2203 int ifindex, i, r;
2204
2205 assert(bus);
2206
2207 if (argc <= 1)
2208 return status_all(bus, STATUS_NTA);
2209
2210 ifindex = parse_ifindex_with_warn(argv[1]);
2211 if (ifindex < 0)
2212 return ifindex;
2213
2214 if (ifindex == LOOPBACK_IFINDEX) {
2215 log_error("Interface can't be the loopback interface (lo). Sorry.");
2216 return -EINVAL;
2217 }
2218
2219 if (argc == 2)
2220 return status_ifindex(bus, ifindex, NULL, STATUS_NTA, NULL);
2221
2222 for (i = 2; i < argc; i++) {
2223 r = dns_name_is_valid(argv[i]);
2224 if (r < 0)
2225 return log_error_errno(r, "Failed to validate specified domain %s: %m", argv[i]);
2226 if (r == 0) {
2227 log_error("Domain not valid: %s", argv[i]);
2228 return -EINVAL;
2229 }
2230 }
2231
2232 r = sd_bus_message_new_method_call(
2233 bus,
2234 &req,
2235 "org.freedesktop.resolve1",
2236 "/org/freedesktop/resolve1",
2237 "org.freedesktop.resolve1.Manager",
2238 "SetLinkDNSSECNegativeTrustAnchors");
2239 if (r < 0)
2240 return bus_log_create_error(r);
2241
2242 r = sd_bus_message_append(req, "i", ifindex);
2243 if (r < 0)
2244 return bus_log_create_error(r);
2245
2246 r = sd_bus_message_append_strv(req, argv + 2);
2247 if (r < 0)
2248 return bus_log_create_error(r);
2249
2250 r = sd_bus_call(bus, req, 0, &error, NULL);
2251 if (r < 0) {
2252 if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
2253 return log_interface_is_managed(r, ifindex);
2254
2255 if (arg_ifindex_permissive &&
2256 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2257 return 0;
2258
2259 return log_error_errno(r, "Failed to set DNSSEC NTA configuration: %s", bus_error_message(&error, r));
2260 }
2261
2262 return 0;
2263 }
2264
2265 static int verb_revert_link(int argc, char **argv, void *userdata) {
2266 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2267 sd_bus *bus = userdata;
2268 int ifindex, r;
2269
2270 assert(bus);
2271
2272 ifindex = parse_ifindex_with_warn(argv[1]);
2273 if (ifindex < 0)
2274 return ifindex;
2275
2276 if (ifindex == LOOPBACK_IFINDEX) {
2277 log_error("Interface can't be the loopback interface (lo). Sorry.");
2278 return -EINVAL;
2279 }
2280
2281 r = sd_bus_call_method(bus,
2282 "org.freedesktop.resolve1",
2283 "/org/freedesktop/resolve1",
2284 "org.freedesktop.resolve1.Manager",
2285 "RevertLink",
2286 &error,
2287 NULL,
2288 "i", ifindex);
2289 if (r < 0) {
2290 if (arg_ifindex_permissive &&
2291 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2292 return 0;
2293
2294 return log_error_errno(r, "Failed to revert interface configuration: %s", bus_error_message(&error, r));
2295 }
2296
2297 return 0;
2298 }
2299
2300 static void help_protocol_types(void) {
2301 if (arg_legend)
2302 puts("Known protocol types:");
2303 puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6\nmdns\nmdns-ipv4\nmdns-ipv6");
2304 }
2305
2306 static void help_dns_types(void) {
2307 if (arg_legend)
2308 puts("Known DNS RR types:");
2309
2310 DUMP_STRING_TABLE(dns_type, int, _DNS_TYPE_MAX);
2311 }
2312
2313 static void help_dns_classes(void) {
2314 if (arg_legend)
2315 puts("Known DNS RR classes:");
2316
2317 DUMP_STRING_TABLE(dns_class, int, _DNS_CLASS_MAX);
2318 }
2319
2320 static void compat_help(void) {
2321 printf("%1$s [OPTIONS...] HOSTNAME|ADDRESS...\n"
2322 "%1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n"
2323 "%1$s [OPTIONS...] --openpgp EMAIL@DOMAIN...\n"
2324 "%1$s [OPTIONS...] --statistics\n"
2325 "%1$s [OPTIONS...] --reset-statistics\n"
2326 "\n"
2327 "Resolve domain names, IPv4 and IPv6 addresses, DNS records, and services.\n\n"
2328 " -h --help Show this help\n"
2329 " --version Show package version\n"
2330 " --no-pager Do not pipe output into a pager\n"
2331 " -4 Resolve IPv4 addresses\n"
2332 " -6 Resolve IPv6 addresses\n"
2333 " -i --interface=INTERFACE Look on interface\n"
2334 " -p --protocol=PROTO|help Look via protocol\n"
2335 " -t --type=TYPE|help Query RR with DNS type\n"
2336 " -c --class=CLASS|help Query RR with DNS class\n"
2337 " --service Resolve service (SRV)\n"
2338 " --service-address=BOOL Resolve address for services (default: yes)\n"
2339 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
2340 " --openpgp Query OpenPGP public key\n"
2341 " --tlsa Query TLS public key\n"
2342 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
2343 " --search=BOOL Use search domains for single-label names\n"
2344 " (default: yes)\n"
2345 " --raw[=payload|packet] Dump the answer as binary data\n"
2346 " --legend=BOOL Print headers and additional info (default: yes)\n"
2347 " --statistics Show resolver statistics\n"
2348 " --reset-statistics Reset resolver statistics\n"
2349 " --status Show link and server status\n"
2350 " --flush-caches Flush all local DNS caches\n"
2351 " --reset-server-features\n"
2352 " Forget learnt DNS server feature levels\n"
2353 " --set-dns=SERVER Set per-interface DNS server address\n"
2354 " --set-domain=DOMAIN Set per-interface search domain\n"
2355 " --set-llmnr=MODE Set per-interface LLMNR mode\n"
2356 " --set-mdns=MODE Set per-interface MulticastDNS mode\n"
2357 " --set-privatedns=MODE Set per-interface PrivateDNS mode\n"
2358 " --set-dnssec=MODE Set per-interface DNSSEC mode\n"
2359 " --set-nta=DOMAIN Set per-interface DNSSEC NTA\n"
2360 " --revert Revert per-interface configuration\n"
2361 , program_invocation_short_name);
2362 }
2363
2364 static void native_help(void) {
2365 printf("%1$s [OPTIONS...] {COMMAND} ...\n"
2366 "\n"
2367 "Send control commands to the network name resolution manager, or\n"
2368 "resolve domain names, IPv4 and IPv6 addresses, DNS records, and services.\n"
2369 "\n"
2370 " -h --help Show this help\n"
2371 " --version Show package version\n"
2372 " --no-pager Do not pipe output into a pager\n"
2373 " -4 Resolve IPv4 addresses\n"
2374 " -6 Resolve IPv6 addresses\n"
2375 " -i --interface=INTERFACE Look on interface\n"
2376 " -p --protocol=PROTO|help Look via protocol\n"
2377 " -t --type=TYPE|help Query RR with DNS type\n"
2378 " -c --class=CLASS|help Query RR with DNS class\n"
2379 " --service-address=BOOL Resolve address for services (default: yes)\n"
2380 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
2381 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
2382 " --search=BOOL Use search domains for single-label names\n"
2383 " (default: yes)\n"
2384 " --raw[=payload|packet] Dump the answer as binary data\n"
2385 " --legend=BOOL Print headers and additional info (default: yes)\n"
2386 "\n"
2387 "Commands:\n"
2388 " query HOSTNAME|ADDRESS... Resolve domain names, IPv4 and IPv6 addresses\n"
2389 " service [[NAME] TYPE] DOMAIN Resolve service (SRV)\n"
2390 " openpgp EMAIL@DOMAIN... Query OpenPGP public key\n"
2391 " tlsa DOMAIN[:PORT]... Query TLS public key\n"
2392 " status [LINK...] Show link and server status\n"
2393 " statistics Show resolver statistics\n"
2394 " reset-statistics Reset resolver statistics\n"
2395 " flush-caches Flush all local DNS caches\n"
2396 " reset-server-features Forget learnt DNS server feature levels\n"
2397 " dns [LINK [SERVER...]] Get/set per-interface DNS server address\n"
2398 " domain [LINK [DOMAIN...]] Get/set per-interface search domain\n"
2399 " llmnr [LINK [MODE]] Get/set per-interface LLMNR mode\n"
2400 " mdns [LINK [MODE]] Get/set per-interface MulticastDNS mode\n"
2401 " privatedns [LINK [MODE]] Get/set per-interface PrivateDNS mode\n"
2402 " dnssec [LINK [MODE]] Get/set per-interface DNSSEC mode\n"
2403 " nta [LINK [DOMAIN...]] Get/set per-interface DNSSEC NTA\n"
2404 " revert LINK Revert per-interface configuration\n"
2405 , program_invocation_short_name);
2406 }
2407
2408 static int verb_help(int argc, char **argv, void *userdata) {
2409 native_help();
2410 return 0;
2411 }
2412
2413 static int compat_parse_argv(int argc, char *argv[]) {
2414 enum {
2415 ARG_VERSION = 0x100,
2416 ARG_LEGEND,
2417 ARG_SERVICE,
2418 ARG_CNAME,
2419 ARG_SERVICE_ADDRESS,
2420 ARG_SERVICE_TXT,
2421 ARG_OPENPGP,
2422 ARG_TLSA,
2423 ARG_RAW,
2424 ARG_SEARCH,
2425 ARG_STATISTICS,
2426 ARG_RESET_STATISTICS,
2427 ARG_STATUS,
2428 ARG_FLUSH_CACHES,
2429 ARG_RESET_SERVER_FEATURES,
2430 ARG_NO_PAGER,
2431 ARG_SET_DNS,
2432 ARG_SET_DOMAIN,
2433 ARG_SET_LLMNR,
2434 ARG_SET_MDNS,
2435 ARG_SET_PRIVATE,
2436 ARG_SET_DNSSEC,
2437 ARG_SET_NTA,
2438 ARG_REVERT_LINK,
2439 };
2440
2441 static const struct option options[] = {
2442 { "help", no_argument, NULL, 'h' },
2443 { "version", no_argument, NULL, ARG_VERSION },
2444 { "type", required_argument, NULL, 't' },
2445 { "class", required_argument, NULL, 'c' },
2446 { "legend", required_argument, NULL, ARG_LEGEND },
2447 { "interface", required_argument, NULL, 'i' },
2448 { "protocol", required_argument, NULL, 'p' },
2449 { "cname", required_argument, NULL, ARG_CNAME },
2450 { "service", no_argument, NULL, ARG_SERVICE },
2451 { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
2452 { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
2453 { "openpgp", no_argument, NULL, ARG_OPENPGP },
2454 { "tlsa", optional_argument, NULL, ARG_TLSA },
2455 { "raw", optional_argument, NULL, ARG_RAW },
2456 { "search", required_argument, NULL, ARG_SEARCH },
2457 { "statistics", no_argument, NULL, ARG_STATISTICS, },
2458 { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
2459 { "status", no_argument, NULL, ARG_STATUS },
2460 { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES },
2461 { "reset-server-features", no_argument, NULL, ARG_RESET_SERVER_FEATURES },
2462 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
2463 { "set-dns", required_argument, NULL, ARG_SET_DNS },
2464 { "set-domain", required_argument, NULL, ARG_SET_DOMAIN },
2465 { "set-llmnr", required_argument, NULL, ARG_SET_LLMNR },
2466 { "set-mdns", required_argument, NULL, ARG_SET_MDNS },
2467 { "set-privatedns", required_argument, NULL, ARG_SET_PRIVATE },
2468 { "set-dnssec", required_argument, NULL, ARG_SET_DNSSEC },
2469 { "set-nta", required_argument, NULL, ARG_SET_NTA },
2470 { "revert", no_argument, NULL, ARG_REVERT_LINK },
2471 {}
2472 };
2473
2474 int c, r;
2475
2476 assert(argc >= 0);
2477 assert(argv);
2478
2479 while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
2480 switch(c) {
2481
2482 case 'h':
2483 compat_help();
2484 return 0; /* done */;
2485
2486 case ARG_VERSION:
2487 return version();
2488
2489 case '4':
2490 arg_family = AF_INET;
2491 break;
2492
2493 case '6':
2494 arg_family = AF_INET6;
2495 break;
2496
2497 case 'i':
2498 r = parse_ifindex_with_warn(optarg);
2499 if (r < 0)
2500 return r;
2501
2502 arg_ifname = optarg;
2503 arg_ifindex = r;
2504 break;
2505
2506 case 't':
2507 if (streq(optarg, "help")) {
2508 help_dns_types();
2509 return 0;
2510 }
2511
2512 r = dns_type_from_string(optarg);
2513 if (r < 0) {
2514 log_error("Failed to parse RR record type %s", optarg);
2515 return r;
2516 }
2517 arg_type = (uint16_t) r;
2518 assert((int) arg_type == r);
2519
2520 arg_mode = MODE_RESOLVE_RECORD;
2521 break;
2522
2523 case 'c':
2524 if (streq(optarg, "help")) {
2525 help_dns_classes();
2526 return 0;
2527 }
2528
2529 r = dns_class_from_string(optarg);
2530 if (r < 0) {
2531 log_error("Failed to parse RR record class %s", optarg);
2532 return r;
2533 }
2534 arg_class = (uint16_t) r;
2535 assert((int) arg_class == r);
2536
2537 break;
2538
2539 case ARG_LEGEND:
2540 r = parse_boolean(optarg);
2541 if (r < 0)
2542 return log_error_errno(r, "Failed to parse --legend= argument");
2543
2544 arg_legend = r;
2545 break;
2546
2547 case 'p':
2548 if (streq(optarg, "help")) {
2549 help_protocol_types();
2550 return 0;
2551 } else if (streq(optarg, "dns"))
2552 arg_flags |= SD_RESOLVED_DNS;
2553 else if (streq(optarg, "llmnr"))
2554 arg_flags |= SD_RESOLVED_LLMNR;
2555 else if (streq(optarg, "llmnr-ipv4"))
2556 arg_flags |= SD_RESOLVED_LLMNR_IPV4;
2557 else if (streq(optarg, "llmnr-ipv6"))
2558 arg_flags |= SD_RESOLVED_LLMNR_IPV6;
2559 else if (streq(optarg, "mdns"))
2560 arg_flags |= SD_RESOLVED_MDNS;
2561 else if (streq(optarg, "mdns-ipv4"))
2562 arg_flags |= SD_RESOLVED_MDNS_IPV4;
2563 else if (streq(optarg, "mdns-ipv6"))
2564 arg_flags |= SD_RESOLVED_MDNS_IPV6;
2565 else {
2566 log_error("Unknown protocol specifier: %s", optarg);
2567 return -EINVAL;
2568 }
2569
2570 break;
2571
2572 case ARG_SERVICE:
2573 arg_mode = MODE_RESOLVE_SERVICE;
2574 break;
2575
2576 case ARG_OPENPGP:
2577 arg_mode = MODE_RESOLVE_OPENPGP;
2578 break;
2579
2580 case ARG_TLSA:
2581 arg_mode = MODE_RESOLVE_TLSA;
2582 if (!optarg || service_family_is_valid(optarg))
2583 arg_service_family = optarg;
2584 else {
2585 log_error("Unknown service family \"%s\".", optarg);
2586 return -EINVAL;
2587 }
2588 break;
2589
2590 case ARG_RAW:
2591 if (on_tty()) {
2592 log_error("Refusing to write binary data to tty.");
2593 return -ENOTTY;
2594 }
2595
2596 if (optarg == NULL || streq(optarg, "payload"))
2597 arg_raw = RAW_PAYLOAD;
2598 else if (streq(optarg, "packet"))
2599 arg_raw = RAW_PACKET;
2600 else {
2601 log_error("Unknown --raw specifier \"%s\".", optarg);
2602 return -EINVAL;
2603 }
2604
2605 arg_legend = false;
2606 break;
2607
2608 case ARG_CNAME:
2609 r = parse_boolean(optarg);
2610 if (r < 0)
2611 return log_error_errno(r, "Failed to parse --cname= argument.");
2612 SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0);
2613 break;
2614
2615 case ARG_SERVICE_ADDRESS:
2616 r = parse_boolean(optarg);
2617 if (r < 0)
2618 return log_error_errno(r, "Failed to parse --service-address= argument.");
2619 SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0);
2620 break;
2621
2622 case ARG_SERVICE_TXT:
2623 r = parse_boolean(optarg);
2624 if (r < 0)
2625 return log_error_errno(r, "Failed to parse --service-txt= argument.");
2626 SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
2627 break;
2628
2629 case ARG_SEARCH:
2630 r = parse_boolean(optarg);
2631 if (r < 0)
2632 return log_error_errno(r, "Failed to parse --search argument.");
2633 SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0);
2634 break;
2635
2636 case ARG_STATISTICS:
2637 arg_mode = MODE_STATISTICS;
2638 break;
2639
2640 case ARG_RESET_STATISTICS:
2641 arg_mode = MODE_RESET_STATISTICS;
2642 break;
2643
2644 case ARG_FLUSH_CACHES:
2645 arg_mode = MODE_FLUSH_CACHES;
2646 break;
2647
2648 case ARG_RESET_SERVER_FEATURES:
2649 arg_mode = MODE_RESET_SERVER_FEATURES;
2650 break;
2651
2652 case ARG_STATUS:
2653 arg_mode = MODE_STATUS;
2654 break;
2655
2656 case ARG_NO_PAGER:
2657 arg_no_pager = true;
2658 break;
2659
2660 case ARG_SET_DNS:
2661 r = strv_extend(&arg_set_dns, optarg);
2662 if (r < 0)
2663 return log_oom();
2664
2665 arg_mode = MODE_SET_LINK;
2666 break;
2667
2668 case ARG_SET_DOMAIN:
2669 r = strv_extend(&arg_set_domain, optarg);
2670 if (r < 0)
2671 return log_oom();
2672
2673 arg_mode = MODE_SET_LINK;
2674 break;
2675
2676 case ARG_SET_LLMNR:
2677 arg_set_llmnr = optarg;
2678 arg_mode = MODE_SET_LINK;
2679 break;
2680
2681 case ARG_SET_MDNS:
2682 arg_set_mdns = optarg;
2683 arg_mode = MODE_SET_LINK;
2684 break;
2685
2686 case ARG_SET_PRIVATE:
2687 arg_set_private_dns = optarg;
2688 arg_mode = MODE_SET_LINK;
2689 break;
2690
2691 case ARG_SET_DNSSEC:
2692 arg_set_dnssec = optarg;
2693 arg_mode = MODE_SET_LINK;
2694 break;
2695
2696 case ARG_SET_NTA:
2697 r = strv_extend(&arg_set_nta, optarg);
2698 if (r < 0)
2699 return log_oom();
2700
2701 arg_mode = MODE_SET_LINK;
2702 break;
2703
2704 case ARG_REVERT_LINK:
2705 arg_mode = MODE_REVERT_LINK;
2706 break;
2707
2708 case '?':
2709 return -EINVAL;
2710
2711 default:
2712 assert_not_reached("Unhandled option");
2713 }
2714
2715 if (arg_type == 0 && arg_class != 0) {
2716 log_error("--class= may only be used in conjunction with --type=.");
2717 return -EINVAL;
2718 }
2719
2720 if (arg_type != 0 && arg_mode == MODE_RESOLVE_SERVICE) {
2721 log_error("--service and --type= may not be combined.");
2722 return -EINVAL;
2723 }
2724
2725 if (arg_type != 0 && arg_class == 0)
2726 arg_class = DNS_CLASS_IN;
2727
2728 if (arg_class != 0 && arg_type == 0)
2729 arg_type = DNS_TYPE_A;
2730
2731 if (IN_SET(arg_mode, MODE_SET_LINK, MODE_REVERT_LINK)) {
2732
2733 if (arg_ifindex <= 0) {
2734 log_error("--set-dns=, --set-domain=, --set-llmnr=, --set-mdns=, --set-privatedns=, --set-dnssec=, --set-nta= and --revert require --interface=.");
2735 return -EINVAL;
2736 }
2737
2738 if (arg_ifindex == LOOPBACK_IFINDEX) {
2739 log_error("Interface can't be the loopback interface (lo). Sorry.");
2740 return -EINVAL;
2741 }
2742 }
2743
2744 return 1 /* work to do */;
2745 }
2746
2747 static int native_parse_argv(int argc, char *argv[]) {
2748 enum {
2749 ARG_VERSION = 0x100,
2750 ARG_LEGEND,
2751 ARG_CNAME,
2752 ARG_SERVICE_ADDRESS,
2753 ARG_SERVICE_TXT,
2754 ARG_RAW,
2755 ARG_SEARCH,
2756 ARG_NO_PAGER,
2757 };
2758
2759 static const struct option options[] = {
2760 { "help", no_argument, NULL, 'h' },
2761 { "version", no_argument, NULL, ARG_VERSION },
2762 { "type", required_argument, NULL, 't' },
2763 { "class", required_argument, NULL, 'c' },
2764 { "legend", required_argument, NULL, ARG_LEGEND },
2765 { "interface", required_argument, NULL, 'i' },
2766 { "protocol", required_argument, NULL, 'p' },
2767 { "cname", required_argument, NULL, ARG_CNAME },
2768 { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
2769 { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
2770 { "raw", optional_argument, NULL, ARG_RAW },
2771 { "search", required_argument, NULL, ARG_SEARCH },
2772 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
2773 {}
2774 };
2775
2776 int c, r;
2777
2778 assert(argc >= 0);
2779 assert(argv);
2780
2781 while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
2782 switch(c) {
2783
2784 case 'h':
2785 native_help();
2786 return 0; /* done */;
2787
2788 case ARG_VERSION:
2789 return version();
2790
2791 case '4':
2792 arg_family = AF_INET;
2793 break;
2794
2795 case '6':
2796 arg_family = AF_INET6;
2797 break;
2798
2799 case 'i':
2800 r = parse_ifindex_with_warn(optarg);
2801 if (r < 0)
2802 return r;
2803
2804 arg_ifindex = r;
2805 break;
2806
2807 case 't':
2808 if (streq(optarg, "help")) {
2809 help_dns_types();
2810 return 0;
2811 }
2812
2813 r = dns_type_from_string(optarg);
2814 if (r < 0) {
2815 log_error("Failed to parse RR record type %s", optarg);
2816 return r;
2817 }
2818 arg_type = (uint16_t) r;
2819 assert((int) arg_type == r);
2820
2821 break;
2822
2823 case 'c':
2824 if (streq(optarg, "help")) {
2825 help_dns_classes();
2826 return 0;
2827 }
2828
2829 r = dns_class_from_string(optarg);
2830 if (r < 0) {
2831 log_error("Failed to parse RR record class %s", optarg);
2832 return r;
2833 }
2834 arg_class = (uint16_t) r;
2835 assert((int) arg_class == r);
2836
2837 break;
2838
2839 case ARG_LEGEND:
2840 r = parse_boolean(optarg);
2841 if (r < 0)
2842 return log_error_errno(r, "Failed to parse --legend= argument");
2843
2844 arg_legend = r;
2845 break;
2846
2847 case 'p':
2848 if (streq(optarg, "help")) {
2849 help_protocol_types();
2850 return 0;
2851 } else if (streq(optarg, "dns"))
2852 arg_flags |= SD_RESOLVED_DNS;
2853 else if (streq(optarg, "llmnr"))
2854 arg_flags |= SD_RESOLVED_LLMNR;
2855 else if (streq(optarg, "llmnr-ipv4"))
2856 arg_flags |= SD_RESOLVED_LLMNR_IPV4;
2857 else if (streq(optarg, "llmnr-ipv6"))
2858 arg_flags |= SD_RESOLVED_LLMNR_IPV6;
2859 else if (streq(optarg, "mdns"))
2860 arg_flags |= SD_RESOLVED_MDNS;
2861 else if (streq(optarg, "mdns-ipv4"))
2862 arg_flags |= SD_RESOLVED_MDNS_IPV4;
2863 else if (streq(optarg, "mdns-ipv6"))
2864 arg_flags |= SD_RESOLVED_MDNS_IPV6;
2865 else {
2866 log_error("Unknown protocol specifier: %s", optarg);
2867 return -EINVAL;
2868 }
2869
2870 break;
2871
2872 case ARG_RAW:
2873 if (on_tty()) {
2874 log_error("Refusing to write binary data to tty.");
2875 return -ENOTTY;
2876 }
2877
2878 if (optarg == NULL || streq(optarg, "payload"))
2879 arg_raw = RAW_PAYLOAD;
2880 else if (streq(optarg, "packet"))
2881 arg_raw = RAW_PACKET;
2882 else {
2883 log_error("Unknown --raw specifier \"%s\".", optarg);
2884 return -EINVAL;
2885 }
2886
2887 arg_legend = false;
2888 break;
2889
2890 case ARG_CNAME:
2891 r = parse_boolean(optarg);
2892 if (r < 0)
2893 return log_error_errno(r, "Failed to parse --cname= argument.");
2894 SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0);
2895 break;
2896
2897 case ARG_SERVICE_ADDRESS:
2898 r = parse_boolean(optarg);
2899 if (r < 0)
2900 return log_error_errno(r, "Failed to parse --service-address= argument.");
2901 SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0);
2902 break;
2903
2904 case ARG_SERVICE_TXT:
2905 r = parse_boolean(optarg);
2906 if (r < 0)
2907 return log_error_errno(r, "Failed to parse --service-txt= argument.");
2908 SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
2909 break;
2910
2911 case ARG_SEARCH:
2912 r = parse_boolean(optarg);
2913 if (r < 0)
2914 return log_error_errno(r, "Failed to parse --search argument.");
2915 SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0);
2916 break;
2917
2918 case ARG_NO_PAGER:
2919 arg_no_pager = true;
2920 break;
2921
2922 case '?':
2923 return -EINVAL;
2924
2925 default:
2926 assert_not_reached("Unhandled option");
2927 }
2928
2929 if (arg_type == 0 && arg_class != 0) {
2930 log_error("--class= may only be used in conjunction with --type=.");
2931 return -EINVAL;
2932 }
2933
2934 if (arg_type != 0 && arg_class == 0)
2935 arg_class = DNS_CLASS_IN;
2936
2937 if (arg_class != 0 && arg_type == 0)
2938 arg_type = DNS_TYPE_A;
2939
2940 return 1 /* work to do */;
2941 }
2942
2943 static int native_main(int argc, char *argv[], sd_bus *bus) {
2944
2945 static const Verb verbs[] = {
2946 { "help", VERB_ANY, VERB_ANY, 0, verb_help },
2947 { "status", VERB_ANY, VERB_ANY, VERB_DEFAULT, verb_status },
2948 { "query", 2, VERB_ANY, 0, verb_query },
2949 { "service", 2, 4, 0, verb_service },
2950 { "openpgp", 2, VERB_ANY, 0, verb_openpgp },
2951 { "tlsa", 2, VERB_ANY, 0, verb_tlsa },
2952 { "statistics", VERB_ANY, 1, 0, show_statistics },
2953 { "reset-statistics", VERB_ANY, 1, 0, reset_statistics },
2954 { "flush-caches", VERB_ANY, 1, 0, flush_caches },
2955 { "reset-server-features", VERB_ANY, 1, 0, reset_server_features },
2956 { "dns", VERB_ANY, VERB_ANY, 0, verb_dns },
2957 { "domain", VERB_ANY, VERB_ANY, 0, verb_domain },
2958 { "llmnr", VERB_ANY, 3, 0, verb_llmnr },
2959 { "mdns", VERB_ANY, 3, 0, verb_mdns },
2960 { "privatedns", VERB_ANY, 3, 0, verb_private_dns },
2961 { "dnssec", VERB_ANY, 3, 0, verb_dnssec },
2962 { "nta", VERB_ANY, VERB_ANY, 0, verb_nta },
2963 { "revert", 2, 2, 0, verb_revert_link },
2964 {}
2965 };
2966
2967 return dispatch_verb(argc, argv, verbs, bus);
2968 }
2969
2970 static int translate(const char *verb, const char *single_arg, size_t num_args, char **args, sd_bus *bus) {
2971 char **fake, **p;
2972 size_t num, i;
2973
2974 assert(verb);
2975 assert(num_args == 0 || args);
2976
2977 num = !!single_arg + num_args + 1;
2978
2979 p = fake = newa0(char *, num + 1);
2980 *p++ = (char *) verb;
2981 if (single_arg)
2982 *p++ = (char *) single_arg;
2983 for (i = 0; i < num_args; i++)
2984 *p++ = args[i];
2985
2986 optind = 0;
2987 return native_main((int) num, fake, bus);
2988 }
2989
2990 static int compat_main(int argc, char *argv[], sd_bus *bus) {
2991 int r = 0;
2992
2993 switch (arg_mode) {
2994 case MODE_RESOLVE_HOST:
2995 case MODE_RESOLVE_RECORD:
2996 return translate("query", NULL, argc - optind, argv + optind, bus);
2997
2998 case MODE_RESOLVE_SERVICE:
2999 return translate("service", NULL, argc - optind, argv + optind, bus);
3000
3001 case MODE_RESOLVE_OPENPGP:
3002 return translate("openpgp", NULL, argc - optind, argv + optind, bus);
3003
3004 case MODE_RESOLVE_TLSA:
3005 return translate("tlsa", arg_service_family, argc - optind, argv + optind, bus);
3006
3007 case MODE_STATISTICS:
3008 return translate("statistics", NULL, 0, NULL, bus);
3009
3010 case MODE_RESET_STATISTICS:
3011 return translate("reset-statistics", NULL, 0, NULL, bus);
3012
3013 case MODE_FLUSH_CACHES:
3014 return translate("flush-caches", NULL, 0, NULL, bus);
3015
3016 case MODE_RESET_SERVER_FEATURES:
3017 return translate("reset-server-features", NULL, 0, NULL, bus);
3018
3019 case MODE_STATUS:
3020 return translate("status", NULL, argc - optind, argv + optind, bus);
3021
3022 case MODE_SET_LINK:
3023 if (arg_set_dns) {
3024 r = translate("dns", arg_ifname, strv_length(arg_set_dns), arg_set_dns, bus);
3025 if (r < 0)
3026 return r;
3027 }
3028
3029 if (arg_set_domain) {
3030 r = translate("domain", arg_ifname, strv_length(arg_set_domain), arg_set_domain, bus);
3031 if (r < 0)
3032 return r;
3033 }
3034
3035 if (arg_set_nta) {
3036 r = translate("nta", arg_ifname, strv_length(arg_set_nta), arg_set_nta, bus);
3037 if (r < 0)
3038 return r;
3039 }
3040
3041 if (arg_set_llmnr) {
3042 r = translate("llmnr", arg_ifname, 1, (char **) &arg_set_llmnr, bus);
3043 if (r < 0)
3044 return r;
3045 }
3046
3047 if (arg_set_mdns) {
3048 r = translate("mdns", arg_ifname, 1, (char **) &arg_set_mdns, bus);
3049 if (r < 0)
3050 return r;
3051 }
3052
3053 if (arg_set_private_dns) {
3054 r = translate("privatedns", arg_ifname, 1, (char **) &arg_set_private_dns, bus);
3055 if (r < 0)
3056 return r;
3057 }
3058
3059 if (arg_set_dnssec) {
3060 r = translate("dnssec", arg_ifname, 1, (char **) &arg_set_dnssec, bus);
3061 if (r < 0)
3062 return r;
3063 }
3064
3065 return r;
3066
3067 case MODE_REVERT_LINK:
3068 return translate("revert", arg_ifname, 0, NULL, bus);
3069
3070 case _MODE_INVALID:
3071 assert_not_reached("invalid mode");
3072 }
3073
3074 return 0;
3075 }
3076
3077 int main(int argc, char **argv) {
3078 sd_bus *bus = NULL;
3079 int r;
3080
3081 setlocale(LC_ALL, "");
3082 log_parse_environment();
3083 log_open();
3084
3085 if (streq(program_invocation_short_name, "resolvconf"))
3086 r = resolvconf_parse_argv(argc, argv);
3087 else if (streq(program_invocation_short_name, "systemd-resolve"))
3088 r = compat_parse_argv(argc, argv);
3089 else
3090 r = native_parse_argv(argc, argv);
3091 if (r <= 0)
3092 goto finish;
3093
3094 r = sd_bus_open_system(&bus);
3095 if (r < 0) {
3096 log_error_errno(r, "sd_bus_open_system: %m");
3097 goto finish;
3098 }
3099
3100 if (streq(program_invocation_short_name, "systemd-resolve"))
3101 r = compat_main(argc, argv, bus);
3102 else
3103 r = native_main(argc, argv, bus);
3104
3105 finish:
3106 /* make sure we terminate the bus connection first, and then close the
3107 * pager, see issue #3543 for the details. */
3108 sd_bus_flush_close_unref(bus);
3109 pager_close();
3110
3111 strv_free(arg_set_dns);
3112 strv_free(arg_set_domain);
3113 strv_free(arg_set_nta);
3114
3115 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
3116 }