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