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