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