]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolve-tool.c
build-sys: fix build with libgrcypt disabled
[thirdparty/systemd.git] / src / resolve / resolve-tool.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2014 Zbigniew Jędrzejewski-Szmek
5
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
10
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
15
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20 #include <getopt.h>
21 #include <net/if.h>
22
23 #include "sd-bus.h"
24
25 #include "af-list.h"
26 #include "alloc-util.h"
27 #include "bus-error.h"
28 #include "bus-util.h"
29 #include "escape.h"
30 #include "in-addr-util.h"
31 #include "gcrypt-util.h"
32 #include "parse-util.h"
33 #include "resolved-def.h"
34 #include "resolved-dns-packet.h"
35 #include "terminal-util.h"
36
37 #define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC)
38
39 static int arg_family = AF_UNSPEC;
40 static int arg_ifindex = 0;
41 static uint16_t arg_type = 0;
42 static uint16_t arg_class = 0;
43 static bool arg_legend = true;
44 static uint64_t arg_flags = 0;
45
46 typedef enum ServiceFamily {
47 SERVICE_FAMILY_TCP,
48 SERVICE_FAMILY_UDP,
49 SERVICE_FAMILY_SCTP,
50 _SERVICE_FAMILY_INVALID = -1,
51 } ServiceFamily;
52 static ServiceFamily arg_service_family = SERVICE_FAMILY_TCP;
53
54 typedef enum RawType {
55 RAW_NONE,
56 RAW_PAYLOAD,
57 RAW_PACKET,
58 } RawType;
59 static RawType arg_raw = RAW_NONE;
60
61 static enum {
62 MODE_RESOLVE_HOST,
63 MODE_RESOLVE_RECORD,
64 MODE_RESOLVE_SERVICE,
65 MODE_RESOLVE_OPENPGP,
66 MODE_RESOLVE_TLSA,
67 MODE_STATISTICS,
68 MODE_RESET_STATISTICS,
69 } arg_mode = MODE_RESOLVE_HOST;
70
71 static ServiceFamily service_family_from_string(const char *s) {
72 if (s == NULL || streq(s, "tcp"))
73 return SERVICE_FAMILY_TCP;
74 if (streq(s, "udp"))
75 return SERVICE_FAMILY_UDP;
76 if (streq(s, "sctp"))
77 return SERVICE_FAMILY_SCTP;
78 return _SERVICE_FAMILY_INVALID;
79 }
80
81 static const char* service_family_to_string(ServiceFamily service) {
82 switch(service) {
83 case SERVICE_FAMILY_TCP:
84 return "_tcp";
85 case SERVICE_FAMILY_UDP:
86 return "_udp";
87 case SERVICE_FAMILY_SCTP:
88 return "_sctp";
89 default:
90 assert_not_reached("invalid service");
91 }
92 }
93
94 static void print_source(uint64_t flags, usec_t rtt) {
95 char rtt_str[FORMAT_TIMESTAMP_MAX];
96
97 if (!arg_legend)
98 return;
99
100 if (flags == 0)
101 return;
102
103 fputs("\n-- Information acquired via", stdout);
104
105 if (flags != 0)
106 printf(" protocol%s%s%s%s%s",
107 flags & SD_RESOLVED_DNS ? " DNS" :"",
108 flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
109 flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "",
110 flags & SD_RESOLVED_MDNS_IPV4 ? "mDNS/IPv4" : "",
111 flags & SD_RESOLVED_MDNS_IPV6 ? "mDNS/IPv6" : "");
112
113 assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100));
114
115 printf(" in %s", rtt_str);
116
117 fputc('.', stdout);
118 fputc('\n', stdout);
119
120 printf("-- Data is authenticated: %s\n", yes_no(flags & SD_RESOLVED_AUTHENTICATED));
121 }
122
123 static int resolve_host(sd_bus *bus, const char *name) {
124
125 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
126 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
127 const char *canonical = NULL;
128 char ifname[IF_NAMESIZE] = "";
129 unsigned c = 0;
130 int r;
131 uint64_t flags;
132 usec_t ts;
133
134 assert(name);
135
136 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
137 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
138
139 log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
140
141 r = sd_bus_message_new_method_call(
142 bus,
143 &req,
144 "org.freedesktop.resolve1",
145 "/org/freedesktop/resolve1",
146 "org.freedesktop.resolve1.Manager",
147 "ResolveHostname");
148 if (r < 0)
149 return bus_log_create_error(r);
150
151 r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
152 if (r < 0)
153 return bus_log_create_error(r);
154
155 ts = now(CLOCK_MONOTONIC);
156
157 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
158 if (r < 0)
159 return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(&error, r));
160
161 ts = now(CLOCK_MONOTONIC) - ts;
162
163 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
164 if (r < 0)
165 return bus_log_parse_error(r);
166
167 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
168 _cleanup_free_ char *pretty = NULL;
169 int ifindex, family;
170 const void *a;
171 size_t sz;
172
173 assert_cc(sizeof(int) == sizeof(int32_t));
174
175 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
176 if (r < 0)
177 return bus_log_parse_error(r);
178
179 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
180 if (r < 0)
181 return bus_log_parse_error(r);
182
183 r = sd_bus_message_exit_container(reply);
184 if (r < 0)
185 return bus_log_parse_error(r);
186
187 if (!IN_SET(family, AF_INET, AF_INET6)) {
188 log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
189 continue;
190 }
191
192 if (sz != FAMILY_ADDRESS_SIZE(family)) {
193 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
194 return -EINVAL;
195 }
196
197 ifname[0] = 0;
198 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
199 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
200
201 r = in_addr_to_string(family, a, &pretty);
202 if (r < 0)
203 return log_error_errno(r, "Failed to print address for %s: %m", name);
204
205 printf("%*s%s %s%s%s\n",
206 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
207 pretty,
208 isempty(ifname) ? "" : "%", ifname);
209
210 c++;
211 }
212 if (r < 0)
213 return bus_log_parse_error(r);
214
215 r = sd_bus_message_exit_container(reply);
216 if (r < 0)
217 return bus_log_parse_error(r);
218
219 r = sd_bus_message_read(reply, "st", &canonical, &flags);
220 if (r < 0)
221 return bus_log_parse_error(r);
222
223 if (!streq(name, canonical))
224 printf("%*s%s (%s)\n",
225 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
226 canonical);
227
228 if (c == 0) {
229 log_error("%s: no addresses found", name);
230 return -ESRCH;
231 }
232
233 print_source(flags, ts);
234
235 return 0;
236 }
237
238 static int resolve_address(sd_bus *bus, int family, const union in_addr_union *address, int ifindex) {
239 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
240 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
241 _cleanup_free_ char *pretty = NULL;
242 char ifname[IF_NAMESIZE] = "";
243 uint64_t flags;
244 unsigned c = 0;
245 usec_t ts;
246 int r;
247
248 assert(bus);
249 assert(IN_SET(family, AF_INET, AF_INET6));
250 assert(address);
251
252 if (ifindex <= 0)
253 ifindex = arg_ifindex;
254
255 r = in_addr_to_string(family, address, &pretty);
256 if (r < 0)
257 return log_oom();
258
259 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
260 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
261
262 log_debug("Resolving %s%s%s.", pretty, isempty(ifname) ? "" : "%", ifname);
263
264 r = sd_bus_message_new_method_call(
265 bus,
266 &req,
267 "org.freedesktop.resolve1",
268 "/org/freedesktop/resolve1",
269 "org.freedesktop.resolve1.Manager",
270 "ResolveAddress");
271 if (r < 0)
272 return bus_log_create_error(r);
273
274 r = sd_bus_message_append(req, "ii", ifindex, family);
275 if (r < 0)
276 return bus_log_create_error(r);
277
278 r = sd_bus_message_append_array(req, 'y', address, FAMILY_ADDRESS_SIZE(family));
279 if (r < 0)
280 return bus_log_create_error(r);
281
282 r = sd_bus_message_append(req, "t", arg_flags);
283 if (r < 0)
284 return bus_log_create_error(r);
285
286 ts = now(CLOCK_MONOTONIC);
287
288 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
289 if (r < 0) {
290 log_error("%s: resolve call failed: %s", pretty, bus_error_message(&error, r));
291 return r;
292 }
293
294 ts = now(CLOCK_MONOTONIC) - ts;
295
296 r = sd_bus_message_enter_container(reply, 'a', "(is)");
297 if (r < 0)
298 return bus_log_create_error(r);
299
300 while ((r = sd_bus_message_enter_container(reply, 'r', "is")) > 0) {
301 const char *n;
302
303 assert_cc(sizeof(int) == sizeof(int32_t));
304
305 r = sd_bus_message_read(reply, "is", &ifindex, &n);
306 if (r < 0)
307 return r;
308
309 r = sd_bus_message_exit_container(reply);
310 if (r < 0)
311 return r;
312
313 ifname[0] = 0;
314 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
315 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
316
317 printf("%*s%*s%*s%s %s\n",
318 (int) strlen(pretty), c == 0 ? pretty : "",
319 isempty(ifname) ? 0 : 1, c > 0 || isempty(ifname) ? "" : "%",
320 (int) strlen(ifname), c == 0 ? ifname : "",
321 c == 0 ? ":" : " ",
322 n);
323
324 c++;
325 }
326 if (r < 0)
327 return bus_log_parse_error(r);
328
329 r = sd_bus_message_exit_container(reply);
330 if (r < 0)
331 return bus_log_parse_error(r);
332
333 r = sd_bus_message_read(reply, "t", &flags);
334 if (r < 0)
335 return bus_log_parse_error(r);
336
337 if (c == 0) {
338 log_error("%s: no names found", pretty);
339 return -ESRCH;
340 }
341
342 print_source(flags, ts);
343
344 return 0;
345 }
346
347 static int parse_address(const char *s, int *family, union in_addr_union *address, int *ifindex) {
348 const char *percent, *a;
349 int ifi = 0;
350 int r;
351
352 percent = strchr(s, '%');
353 if (percent) {
354 if (parse_ifindex(percent+1, &ifi) < 0) {
355 ifi = if_nametoindex(percent+1);
356 if (ifi <= 0)
357 return -EINVAL;
358 }
359
360 a = strndupa(s, percent - s);
361 } else
362 a = s;
363
364 r = in_addr_from_string_auto(a, family, address);
365 if (r < 0)
366 return r;
367
368 *ifindex = ifi;
369 return 0;
370 }
371
372 static int output_rr_packet(const void *d, size_t l, int ifindex) {
373 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
374 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
375 int r;
376 char ifname[IF_NAMESIZE] = "";
377
378 r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
379 if (r < 0)
380 return log_oom();
381
382 p->refuse_compression = true;
383
384 r = dns_packet_append_blob(p, d, l, NULL);
385 if (r < 0)
386 return log_oom();
387
388 r = dns_packet_read_rr(p, &rr, NULL, NULL);
389 if (r < 0)
390 return log_error_errno(r, "Failed to parse RR: %m");
391
392 if (arg_raw == RAW_PAYLOAD) {
393 void *data;
394 ssize_t k;
395
396 k = dns_resource_record_payload(rr, &data);
397 if (k < 0)
398 return log_error_errno(k, "Cannot dump RR: %m");
399 fwrite(data, 1, k, stdout);
400 } else {
401 const char *s;
402
403 s = dns_resource_record_to_string(rr);
404 if (!s)
405 return log_oom();
406
407 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
408 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
409
410 printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
411 }
412
413 return 0;
414 }
415
416 static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type) {
417 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
418 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
419 char ifname[IF_NAMESIZE] = "";
420 unsigned n = 0;
421 uint64_t flags;
422 int r;
423 usec_t ts;
424 bool needs_authentication = false;
425
426 assert(name);
427
428 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
429 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
430
431 log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(ifname) ? "*" : ifname);
432
433 r = sd_bus_message_new_method_call(
434 bus,
435 &req,
436 "org.freedesktop.resolve1",
437 "/org/freedesktop/resolve1",
438 "org.freedesktop.resolve1.Manager",
439 "ResolveRecord");
440 if (r < 0)
441 return bus_log_create_error(r);
442
443 r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, class, type, arg_flags);
444 if (r < 0)
445 return bus_log_create_error(r);
446
447 ts = now(CLOCK_MONOTONIC);
448
449 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
450 if (r < 0) {
451 log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
452 return r;
453 }
454
455 ts = now(CLOCK_MONOTONIC) - ts;
456
457 r = sd_bus_message_enter_container(reply, 'a', "(iqqay)");
458 if (r < 0)
459 return bus_log_parse_error(r);
460
461 while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
462 uint16_t c, t;
463 int ifindex;
464 const void *d;
465 size_t l;
466
467 assert_cc(sizeof(int) == sizeof(int32_t));
468
469 r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t);
470 if (r < 0)
471 return bus_log_parse_error(r);
472
473 r = sd_bus_message_read_array(reply, 'y', &d, &l);
474 if (r < 0)
475 return bus_log_parse_error(r);
476
477 r = sd_bus_message_exit_container(reply);
478 if (r < 0)
479 return bus_log_parse_error(r);
480
481 if (arg_raw == RAW_PACKET) {
482 uint64_t u64 = htole64(l);
483
484 fwrite(&u64, sizeof(u64), 1, stdout);
485 fwrite(d, 1, l, stdout);
486 } else {
487 r = output_rr_packet(d, l, ifindex);
488 if (r < 0)
489 return r;
490 }
491
492 if (dns_type_needs_authentication(t))
493 needs_authentication = true;
494
495 n++;
496 }
497 if (r < 0)
498 return bus_log_parse_error(r);
499
500 r = sd_bus_message_exit_container(reply);
501 if (r < 0)
502 return bus_log_parse_error(r);
503
504 r = sd_bus_message_read(reply, "t", &flags);
505 if (r < 0)
506 return bus_log_parse_error(r);
507
508 if (n == 0) {
509 log_error("%s: no records found", name);
510 return -ESRCH;
511 }
512
513 print_source(flags, ts);
514
515 if ((flags & SD_RESOLVED_AUTHENTICATED) == 0 && needs_authentication) {
516 fflush(stdout);
517
518 fprintf(stderr, "\n%s"
519 "WARNING: The resources shown contain cryptographic key data which could not be\n"
520 " authenticated. It is not suitable to authenticate any communication.\n"
521 " This is usually indication that DNSSEC authentication was not enabled\n"
522 " or is not available for the selected protocol or DNS servers.%s\n",
523 ansi_highlight_red(),
524 ansi_normal());
525 }
526
527 return 0;
528 }
529
530 static int resolve_rfc4501(sd_bus *bus, const char *name) {
531 uint16_t type = 0, class = 0;
532 const char *p, *q, *n;
533 int r;
534
535 assert(bus);
536 assert(name);
537 assert(startswith(name, "dns:"));
538
539 /* Parse RFC 4501 dns: URIs */
540
541 p = name + 4;
542
543 if (p[0] == '/') {
544 const char *e;
545
546 if (p[1] != '/')
547 goto invalid;
548
549 e = strchr(p + 2, '/');
550 if (!e)
551 goto invalid;
552
553 if (e != p + 2)
554 log_warning("DNS authority specification not supported; ignoring specified authority.");
555
556 p = e + 1;
557 }
558
559 q = strchr(p, '?');
560 if (q) {
561 n = strndupa(p, q - p);
562 q++;
563
564 for (;;) {
565 const char *f;
566
567 f = startswith_no_case(q, "class=");
568 if (f) {
569 _cleanup_free_ char *t = NULL;
570 const char *e;
571
572 if (class != 0) {
573 log_error("DNS class specified twice.");
574 return -EINVAL;
575 }
576
577 e = strchrnul(f, ';');
578 t = strndup(f, e - f);
579 if (!t)
580 return log_oom();
581
582 r = dns_class_from_string(t);
583 if (r < 0) {
584 log_error("Unknown DNS class %s.", t);
585 return -EINVAL;
586 }
587
588 class = r;
589
590 if (*e == ';') {
591 q = e + 1;
592 continue;
593 }
594
595 break;
596 }
597
598 f = startswith_no_case(q, "type=");
599 if (f) {
600 _cleanup_free_ char *t = NULL;
601 const char *e;
602
603 if (type != 0) {
604 log_error("DNS type specified twice.");
605 return -EINVAL;
606 }
607
608 e = strchrnul(f, ';');
609 t = strndup(f, e - f);
610 if (!t)
611 return log_oom();
612
613 r = dns_type_from_string(t);
614 if (r < 0) {
615 log_error("Unknown DNS type %s.", t);
616 return -EINVAL;
617 }
618
619 type = r;
620
621 if (*e == ';') {
622 q = e + 1;
623 continue;
624 }
625
626 break;
627 }
628
629 goto invalid;
630 }
631 } else
632 n = p;
633
634 if (class == 0)
635 class = arg_class ?: DNS_CLASS_IN;
636 if (type == 0)
637 type = arg_type ?: DNS_TYPE_A;
638
639 return resolve_record(bus, n, class, type);
640
641 invalid:
642 log_error("Invalid DNS URI: %s", name);
643 return -EINVAL;
644 }
645
646 static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) {
647 const char *canonical_name, *canonical_type, *canonical_domain;
648 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
649 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
650 char ifname[IF_NAMESIZE] = "";
651 size_t indent, sz;
652 uint64_t flags;
653 const char *p;
654 unsigned c;
655 usec_t ts;
656 int r;
657
658 assert(bus);
659 assert(domain);
660
661 if (isempty(name))
662 name = NULL;
663 if (isempty(type))
664 type = NULL;
665
666 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
667 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
668
669 if (name)
670 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);
671 else if (type)
672 log_debug("Resolving service type %s of %s (family %s, interface %s).", type, domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
673 else
674 log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
675
676 r = sd_bus_message_new_method_call(
677 bus,
678 &req,
679 "org.freedesktop.resolve1",
680 "/org/freedesktop/resolve1",
681 "org.freedesktop.resolve1.Manager",
682 "ResolveService");
683 if (r < 0)
684 return bus_log_create_error(r);
685
686 r = sd_bus_message_append(req, "isssit", arg_ifindex, name, type, domain, arg_family, arg_flags);
687 if (r < 0)
688 return bus_log_create_error(r);
689
690 ts = now(CLOCK_MONOTONIC);
691
692 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
693 if (r < 0)
694 return log_error_errno(r, "Resolve call failed: %s", bus_error_message(&error, r));
695
696 ts = now(CLOCK_MONOTONIC) - ts;
697
698 r = sd_bus_message_enter_container(reply, 'a', "(qqqsa(iiay)s)");
699 if (r < 0)
700 return bus_log_parse_error(r);
701
702 indent =
703 (name ? strlen(name) + 1 : 0) +
704 (type ? strlen(type) + 1 : 0) +
705 strlen(domain) + 2;
706
707 c = 0;
708 while ((r = sd_bus_message_enter_container(reply, 'r', "qqqsa(iiay)s")) > 0) {
709 uint16_t priority, weight, port;
710 const char *hostname, *canonical;
711
712 r = sd_bus_message_read(reply, "qqqs", &priority, &weight, &port, &hostname);
713 if (r < 0)
714 return bus_log_parse_error(r);
715
716 if (name)
717 printf("%*s%s", (int) strlen(name), c == 0 ? name : "", c == 0 ? "/" : " ");
718 if (type)
719 printf("%*s%s", (int) strlen(type), c == 0 ? type : "", c == 0 ? "/" : " ");
720
721 printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
722 (int) strlen(domain), c == 0 ? domain : "",
723 c == 0 ? ":" : " ",
724 hostname, port,
725 priority, weight);
726
727 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
728 if (r < 0)
729 return bus_log_parse_error(r);
730
731 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
732 _cleanup_free_ char *pretty = NULL;
733 int ifindex, family;
734 const void *a;
735
736 assert_cc(sizeof(int) == sizeof(int32_t));
737
738 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
739 if (r < 0)
740 return bus_log_parse_error(r);
741
742 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
743 if (r < 0)
744 return bus_log_parse_error(r);
745
746 r = sd_bus_message_exit_container(reply);
747 if (r < 0)
748 return bus_log_parse_error(r);
749
750 if (!IN_SET(family, AF_INET, AF_INET6)) {
751 log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
752 continue;
753 }
754
755 if (sz != FAMILY_ADDRESS_SIZE(family)) {
756 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
757 return -EINVAL;
758 }
759
760 ifname[0] = 0;
761 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
762 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
763
764 r = in_addr_to_string(family, a, &pretty);
765 if (r < 0)
766 return log_error_errno(r, "Failed to print address for %s: %m", name);
767
768 printf("%*s%s%s%s\n", (int) indent, "", pretty, isempty(ifname) ? "" : "%s", ifname);
769 }
770 if (r < 0)
771 return bus_log_parse_error(r);
772
773 r = sd_bus_message_exit_container(reply);
774 if (r < 0)
775 return bus_log_parse_error(r);
776
777 r = sd_bus_message_read(reply, "s", &canonical);
778 if (r < 0)
779 return bus_log_parse_error(r);
780
781 if (!streq(hostname, canonical))
782 printf("%*s(%s)\n", (int) indent, "", canonical);
783
784 r = sd_bus_message_exit_container(reply);
785 if (r < 0)
786 return bus_log_parse_error(r);
787
788 c++;
789 }
790 if (r < 0)
791 return bus_log_parse_error(r);
792
793 r = sd_bus_message_exit_container(reply);
794 if (r < 0)
795 return bus_log_parse_error(r);
796
797 r = sd_bus_message_enter_container(reply, 'a', "ay");
798 if (r < 0)
799 return bus_log_parse_error(r);
800
801 c = 0;
802 while ((r = sd_bus_message_read_array(reply, 'y', (const void**) &p, &sz)) > 0) {
803 _cleanup_free_ char *escaped = NULL;
804
805 escaped = cescape_length(p, sz);
806 if (!escaped)
807 return log_oom();
808
809 printf("%*s%s\n", (int) indent, "", escaped);
810 c++;
811 }
812 if (r < 0)
813 return bus_log_parse_error(r);
814
815 r = sd_bus_message_exit_container(reply);
816 if (r < 0)
817 return bus_log_parse_error(r);
818
819 r = sd_bus_message_read(reply, "ssst", &canonical_name, &canonical_type, &canonical_domain, &flags);
820 if (r < 0)
821 return bus_log_parse_error(r);
822
823 if (isempty(canonical_name))
824 canonical_name = NULL;
825 if (isempty(canonical_type))
826 canonical_type = NULL;
827
828 if (!streq_ptr(name, canonical_name) ||
829 !streq_ptr(type, canonical_type) ||
830 !streq_ptr(domain, canonical_domain)) {
831
832 printf("%*s(", (int) indent, "");
833
834 if (canonical_name)
835 printf("%s/", canonical_name);
836 if (canonical_type)
837 printf("%s/", canonical_type);
838
839 printf("%s)\n", canonical_domain);
840 }
841
842 print_source(flags, ts);
843
844 return 0;
845 }
846
847 static int resolve_openpgp(sd_bus *bus, const char *address) {
848 const char *domain, *full;
849 int r;
850 _cleanup_free_ char *hashed = NULL;
851
852 assert(bus);
853 assert(address);
854
855 domain = strrchr(address, '@');
856 if (!domain) {
857 log_error("Address does not contain '@': \"%s\"", address);
858 return -EINVAL;
859 } else if (domain == address || domain[1] == '\0') {
860 log_error("Address starts or ends with '@': \"%s\"", address);
861 return -EINVAL;
862 }
863 domain++;
864
865 r = string_hashsum_sha224(address, domain - 1 - address, &hashed);
866 if (r < 0)
867 return log_error_errno(r, "Hashing failed: %m");
868
869 full = strjoina(hashed, "._openpgpkey.", domain);
870 log_debug("Looking up \"%s\".", full);
871
872 return resolve_record(bus, full,
873 arg_class ?: DNS_CLASS_IN,
874 arg_type ?: DNS_TYPE_OPENPGPKEY);
875 }
876
877 static int resolve_tlsa(sd_bus *bus, const char *address) {
878 const char *port;
879 uint16_t port_num = 443;
880 _cleanup_free_ char *full = NULL;
881 int r;
882
883 assert(bus);
884 assert(address);
885
886 port = strrchr(address, ':');
887 if (port) {
888 r = safe_atou16(port + 1, &port_num);
889 if (r < 0 || port_num == 0)
890 return log_error_errno(r, "Invalid port \"%s\".", port + 1);
891
892 address = strndupa(address, port - address);
893 }
894
895 r = asprintf(&full, "_%u.%s.%s",
896 port_num,
897 service_family_to_string(arg_service_family),
898 address);
899 if (r < 0)
900 return log_oom();
901
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_TLSA);
907 }
908
909 static int show_statistics(sd_bus *bus) {
910 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
911 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
912 uint64_t n_current_transactions, n_total_transactions,
913 cache_size, n_cache_hit, n_cache_miss,
914 n_dnssec_secure, n_dnssec_insecure, n_dnssec_bogus, n_dnssec_indeterminate;
915 int r, dnssec_supported;
916
917 assert(bus);
918
919 r = sd_bus_get_property_trivial(bus,
920 "org.freedesktop.resolve1",
921 "/org/freedesktop/resolve1",
922 "org.freedesktop.resolve1.Manager",
923 "DNSSECSupported",
924 &error,
925 'b',
926 &dnssec_supported);
927 if (r < 0)
928 return log_error_errno(r, "Failed to get DNSSEC supported state: %s", bus_error_message(&error, r));
929
930 printf("DNSSEC supported by current servers: %s%s%s\n\n",
931 ansi_highlight(),
932 yes_no(dnssec_supported),
933 ansi_normal());
934
935 r = sd_bus_get_property(bus,
936 "org.freedesktop.resolve1",
937 "/org/freedesktop/resolve1",
938 "org.freedesktop.resolve1.Manager",
939 "TransactionStatistics",
940 &error,
941 &reply,
942 "(tt)");
943 if (r < 0)
944 return log_error_errno(r, "Failed to get transaction statistics: %s", bus_error_message(&error, r));
945
946 r = sd_bus_message_read(reply, "(tt)",
947 &n_current_transactions,
948 &n_total_transactions);
949 if (r < 0)
950 return bus_log_parse_error(r);
951
952 printf("%sTransactions%s\n"
953 "Current Transactions: %" PRIu64 "\n"
954 " Total Transactions: %" PRIu64 "\n",
955 ansi_highlight(),
956 ansi_normal(),
957 n_current_transactions,
958 n_total_transactions);
959
960 reply = sd_bus_message_unref(reply);
961
962 r = sd_bus_get_property(bus,
963 "org.freedesktop.resolve1",
964 "/org/freedesktop/resolve1",
965 "org.freedesktop.resolve1.Manager",
966 "CacheStatistics",
967 &error,
968 &reply,
969 "(ttt)");
970 if (r < 0)
971 return log_error_errno(r, "Failed to get cache statistics: %s", bus_error_message(&error, r));
972
973 r = sd_bus_message_read(reply, "(ttt)",
974 &cache_size,
975 &n_cache_hit,
976 &n_cache_miss);
977 if (r < 0)
978 return bus_log_parse_error(r);
979
980 printf("\n%sCache%s\n"
981 " Current Cache Size: %" PRIu64 "\n"
982 " Cache Hits: %" PRIu64 "\n"
983 " Cache Misses: %" PRIu64 "\n",
984 ansi_highlight(),
985 ansi_normal(),
986 cache_size,
987 n_cache_hit,
988 n_cache_miss);
989
990 reply = sd_bus_message_unref(reply);
991
992 r = sd_bus_get_property(bus,
993 "org.freedesktop.resolve1",
994 "/org/freedesktop/resolve1",
995 "org.freedesktop.resolve1.Manager",
996 "DNSSECStatistics",
997 &error,
998 &reply,
999 "(tttt)");
1000 if (r < 0)
1001 return log_error_errno(r, "Failed to get DNSSEC statistics: %s", bus_error_message(&error, r));
1002
1003 r = sd_bus_message_read(reply, "(tttt)",
1004 &n_dnssec_secure,
1005 &n_dnssec_insecure,
1006 &n_dnssec_bogus,
1007 &n_dnssec_indeterminate);
1008 if (r < 0)
1009 return bus_log_parse_error(r);
1010
1011 printf("\n%sDNSSEC Verdicts%s\n"
1012 " Secure: %" PRIu64 "\n"
1013 " Insecure: %" PRIu64 "\n"
1014 " Bogus: %" PRIu64 "\n"
1015 " Indeterminate: %" PRIu64 "\n",
1016 ansi_highlight(),
1017 ansi_normal(),
1018 n_dnssec_secure,
1019 n_dnssec_insecure,
1020 n_dnssec_bogus,
1021 n_dnssec_indeterminate);
1022
1023 return 0;
1024 }
1025
1026 static int reset_statistics(sd_bus *bus) {
1027 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1028 int r;
1029
1030 r = sd_bus_call_method(bus,
1031 "org.freedesktop.resolve1",
1032 "/org/freedesktop/resolve1",
1033 "org.freedesktop.resolve1.Manager",
1034 "ResetStatistics",
1035 &error,
1036 NULL,
1037 NULL);
1038 if (r < 0)
1039 return log_error_errno(r, "Failed to reset statistics: %s", bus_error_message(&error, r));
1040
1041 return 0;
1042 }
1043
1044 static void help_protocol_types(void) {
1045 if (arg_legend)
1046 puts("Known protocol types:");
1047 puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6");
1048 }
1049
1050 static void help_dns_types(void) {
1051 int i;
1052 const char *t;
1053
1054 if (arg_legend)
1055 puts("Known DNS RR types:");
1056 for (i = 0; i < _DNS_TYPE_MAX; i++) {
1057 t = dns_type_to_string(i);
1058 if (t)
1059 puts(t);
1060 }
1061 }
1062
1063 static void help_dns_classes(void) {
1064 int i;
1065 const char *t;
1066
1067 if (arg_legend)
1068 puts("Known DNS RR classes:");
1069 for (i = 0; i < _DNS_CLASS_MAX; i++) {
1070 t = dns_class_to_string(i);
1071 if (t)
1072 puts(t);
1073 }
1074 }
1075
1076 static void help(void) {
1077 printf("%1$s [OPTIONS...] HOSTNAME|ADDRESS...\n"
1078 "%1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n"
1079 "%1$s [OPTIONS...] --openpgp EMAIL@DOMAIN...\n"
1080 "%1$s [OPTIONS...] --statistics\n"
1081 "%1$s [OPTIONS...] --reset-statistics\n"
1082 "\n"
1083 "Resolve domain names, IPv4 and IPv6 addresses, DNS resource records, and services.\n\n"
1084 " -h --help Show this help\n"
1085 " --version Show package version\n"
1086 " -4 Resolve IPv4 addresses\n"
1087 " -6 Resolve IPv6 addresses\n"
1088 " -i --interface=INTERFACE Look on interface\n"
1089 " -p --protocol=PROTO|help Look via protocol\n"
1090 " -t --type=TYPE|help Query RR with DNS type\n"
1091 " -c --class=CLASS|help Query RR with DNS class\n"
1092 " --service Resolve service (SRV)\n"
1093 " --service-address=BOOL Resolve address for services (default: yes)\n"
1094 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
1095 " --openpgp Query OpenPGP public key\n"
1096 " --tlsa Query TLS public key\n"
1097 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
1098 " --search=BOOL Use search domains for single-label names\n"
1099 " (default: yes)\n"
1100 " --raw[=payload|packet] Dump the answer as binary data\n"
1101 " --legend=BOOL Print headers and additional info (default: yes)\n"
1102 " --statistics Show resolver statistics\n"
1103 " --reset-statistics Reset resolver statistics\n"
1104 , program_invocation_short_name);
1105 }
1106
1107 static int parse_argv(int argc, char *argv[]) {
1108 enum {
1109 ARG_VERSION = 0x100,
1110 ARG_LEGEND,
1111 ARG_SERVICE,
1112 ARG_CNAME,
1113 ARG_SERVICE_ADDRESS,
1114 ARG_SERVICE_TXT,
1115 ARG_OPENPGP,
1116 ARG_TLSA,
1117 ARG_RAW,
1118 ARG_SEARCH,
1119 ARG_STATISTICS,
1120 ARG_RESET_STATISTICS,
1121 };
1122
1123 static const struct option options[] = {
1124 { "help", no_argument, NULL, 'h' },
1125 { "version", no_argument, NULL, ARG_VERSION },
1126 { "type", required_argument, NULL, 't' },
1127 { "class", required_argument, NULL, 'c' },
1128 { "legend", required_argument, NULL, ARG_LEGEND },
1129 { "interface", required_argument, NULL, 'i' },
1130 { "protocol", required_argument, NULL, 'p' },
1131 { "cname", required_argument, NULL, ARG_CNAME },
1132 { "service", no_argument, NULL, ARG_SERVICE },
1133 { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
1134 { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
1135 { "openpgp", no_argument, NULL, ARG_OPENPGP },
1136 { "tlsa", optional_argument, NULL, ARG_TLSA },
1137 { "raw", optional_argument, NULL, ARG_RAW },
1138 { "search", required_argument, NULL, ARG_SEARCH },
1139 { "statistics", no_argument, NULL, ARG_STATISTICS, },
1140 { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
1141 {}
1142 };
1143
1144 int c, r;
1145
1146 assert(argc >= 0);
1147 assert(argv);
1148
1149 while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
1150 switch(c) {
1151
1152 case 'h':
1153 help();
1154 return 0; /* done */;
1155
1156 case ARG_VERSION:
1157 return version();
1158
1159 case '4':
1160 arg_family = AF_INET;
1161 break;
1162
1163 case '6':
1164 arg_family = AF_INET6;
1165 break;
1166
1167 case 'i': {
1168 int ifi;
1169
1170 if (parse_ifindex(optarg, &ifi) >= 0)
1171 arg_ifindex = ifi;
1172 else {
1173 ifi = if_nametoindex(optarg);
1174 if (ifi <= 0)
1175 return log_error_errno(errno, "Unknown interface %s: %m", optarg);
1176
1177 arg_ifindex = ifi;
1178 }
1179
1180 break;
1181 }
1182
1183 case 't':
1184 if (streq(optarg, "help")) {
1185 help_dns_types();
1186 return 0;
1187 }
1188
1189 r = dns_type_from_string(optarg);
1190 if (r < 0) {
1191 log_error("Failed to parse RR record type %s", optarg);
1192 return r;
1193 }
1194 arg_type = (uint16_t) r;
1195 assert((int) arg_type == r);
1196
1197 arg_mode = MODE_RESOLVE_RECORD;
1198 break;
1199
1200 case 'c':
1201 if (streq(optarg, "help")) {
1202 help_dns_classes();
1203 return 0;
1204 }
1205
1206 r = dns_class_from_string(optarg);
1207 if (r < 0) {
1208 log_error("Failed to parse RR record class %s", optarg);
1209 return r;
1210 }
1211 arg_class = (uint16_t) r;
1212 assert((int) arg_class == r);
1213
1214 break;
1215
1216 case ARG_LEGEND:
1217 r = parse_boolean(optarg);
1218 if (r < 0)
1219 return log_error_errno(r, "Failed to parse --legend= argument");
1220
1221 arg_legend = r;
1222 break;
1223
1224 case 'p':
1225 if (streq(optarg, "help")) {
1226 help_protocol_types();
1227 return 0;
1228 } else if (streq(optarg, "dns"))
1229 arg_flags |= SD_RESOLVED_DNS;
1230 else if (streq(optarg, "llmnr"))
1231 arg_flags |= SD_RESOLVED_LLMNR;
1232 else if (streq(optarg, "llmnr-ipv4"))
1233 arg_flags |= SD_RESOLVED_LLMNR_IPV4;
1234 else if (streq(optarg, "llmnr-ipv6"))
1235 arg_flags |= SD_RESOLVED_LLMNR_IPV6;
1236 else {
1237 log_error("Unknown protocol specifier: %s", optarg);
1238 return -EINVAL;
1239 }
1240
1241 break;
1242
1243 case ARG_SERVICE:
1244 arg_mode = MODE_RESOLVE_SERVICE;
1245 break;
1246
1247 case ARG_OPENPGP:
1248 arg_mode = MODE_RESOLVE_OPENPGP;
1249 break;
1250
1251 case ARG_TLSA:
1252 arg_mode = MODE_RESOLVE_TLSA;
1253 arg_service_family = service_family_from_string(optarg);
1254 if (arg_service_family < 0) {
1255 log_error("Unknown service family \"%s\".", optarg);
1256 return -EINVAL;
1257 }
1258 break;
1259
1260 case ARG_RAW:
1261 if (on_tty()) {
1262 log_error("Refusing to write binary data to tty.");
1263 return -ENOTTY;
1264 }
1265
1266 if (optarg == NULL || streq(optarg, "payload"))
1267 arg_raw = RAW_PAYLOAD;
1268 else if (streq(optarg, "packet"))
1269 arg_raw = RAW_PACKET;
1270 else {
1271 log_error("Unknown --raw specifier \"%s\".", optarg);
1272 return -EINVAL;
1273 }
1274
1275 arg_legend = false;
1276 break;
1277
1278 case ARG_CNAME:
1279 r = parse_boolean(optarg);
1280 if (r < 0)
1281 return log_error_errno(r, "Failed to parse --cname= argument.");
1282 SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0);
1283 break;
1284
1285 case ARG_SERVICE_ADDRESS:
1286 r = parse_boolean(optarg);
1287 if (r < 0)
1288 return log_error_errno(r, "Failed to parse --service-address= argument.");
1289 SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0);
1290 break;
1291
1292 case ARG_SERVICE_TXT:
1293 r = parse_boolean(optarg);
1294 if (r < 0)
1295 return log_error_errno(r, "Failed to parse --service-txt= argument.");
1296 SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
1297 break;
1298
1299 case ARG_SEARCH:
1300 r = parse_boolean(optarg);
1301 if (r < 0)
1302 return log_error_errno(r, "Failed to parse --search argument.");
1303 SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0);
1304 break;
1305
1306 case ARG_STATISTICS:
1307 arg_mode = MODE_STATISTICS;
1308 break;
1309
1310 case ARG_RESET_STATISTICS:
1311 arg_mode = MODE_RESET_STATISTICS;
1312 break;
1313
1314 case '?':
1315 return -EINVAL;
1316
1317 default:
1318 assert_not_reached("Unhandled option");
1319 }
1320
1321 if (arg_type == 0 && arg_class != 0) {
1322 log_error("--class= may only be used in conjunction with --type=.");
1323 return -EINVAL;
1324 }
1325
1326 if (arg_type != 0 && arg_mode == MODE_RESOLVE_SERVICE) {
1327 log_error("--service and --type= may not be combined.");
1328 return -EINVAL;
1329 }
1330
1331 if (arg_type != 0 && arg_class == 0)
1332 arg_class = DNS_CLASS_IN;
1333
1334 if (arg_class != 0 && arg_type == 0)
1335 arg_type = DNS_TYPE_A;
1336
1337 return 1 /* work to do */;
1338 }
1339
1340 int main(int argc, char **argv) {
1341 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1342 int r;
1343
1344 log_parse_environment();
1345 log_open();
1346
1347 r = parse_argv(argc, argv);
1348 if (r <= 0)
1349 goto finish;
1350
1351 r = sd_bus_open_system(&bus);
1352 if (r < 0) {
1353 log_error_errno(r, "sd_bus_open_system: %m");
1354 goto finish;
1355 }
1356
1357 switch (arg_mode) {
1358
1359 case MODE_RESOLVE_HOST:
1360 if (optind >= argc) {
1361 log_error("No arguments passed.");
1362 r = -EINVAL;
1363 goto finish;
1364 }
1365
1366 while (argv[optind]) {
1367 int family, ifindex, k;
1368 union in_addr_union a;
1369
1370 if (startswith(argv[optind], "dns:"))
1371 k = resolve_rfc4501(bus, argv[optind]);
1372 else {
1373 k = parse_address(argv[optind], &family, &a, &ifindex);
1374 if (k >= 0)
1375 k = resolve_address(bus, family, &a, ifindex);
1376 else
1377 k = resolve_host(bus, argv[optind]);
1378 }
1379
1380 if (r == 0)
1381 r = k;
1382
1383 optind++;
1384 }
1385 break;
1386
1387 case MODE_RESOLVE_RECORD:
1388 if (optind >= argc) {
1389 log_error("No arguments passed.");
1390 r = -EINVAL;
1391 goto finish;
1392 }
1393
1394 while (argv[optind]) {
1395 int k;
1396
1397 k = resolve_record(bus, argv[optind], arg_class, arg_type);
1398 if (r == 0)
1399 r = k;
1400
1401 optind++;
1402 }
1403 break;
1404
1405 case MODE_RESOLVE_SERVICE:
1406 if (argc < optind + 1) {
1407 log_error("Domain specification required.");
1408 r = -EINVAL;
1409 goto finish;
1410
1411 } else if (argc == optind + 1)
1412 r = resolve_service(bus, NULL, NULL, argv[optind]);
1413 else if (argc == optind + 2)
1414 r = resolve_service(bus, NULL, argv[optind], argv[optind+1]);
1415 else if (argc == optind + 3)
1416 r = resolve_service(bus, argv[optind], argv[optind+1], argv[optind+2]);
1417 else {
1418 log_error("Too many arguments.");
1419 r = -EINVAL;
1420 goto finish;
1421 }
1422
1423 break;
1424
1425 case MODE_RESOLVE_OPENPGP:
1426 if (argc < optind + 1) {
1427 log_error("E-mail address required.");
1428 r = -EINVAL;
1429 goto finish;
1430
1431 }
1432
1433 r = 0;
1434 while (optind < argc) {
1435 int k;
1436
1437 k = resolve_openpgp(bus, argv[optind++]);
1438 if (k < 0)
1439 r = k;
1440 }
1441 break;
1442
1443 case MODE_RESOLVE_TLSA:
1444 if (argc < optind + 1) {
1445 log_error("Domain name required.");
1446 r = -EINVAL;
1447 goto finish;
1448
1449 }
1450
1451 r = 0;
1452 while (optind < argc) {
1453 int k;
1454
1455 k = resolve_tlsa(bus, argv[optind++]);
1456 if (k < 0)
1457 r = k;
1458 }
1459 break;
1460
1461 case MODE_STATISTICS:
1462 if (argc > optind) {
1463 log_error("Too many arguments.");
1464 r = -EINVAL;
1465 goto finish;
1466 }
1467
1468 r = show_statistics(bus);
1469 break;
1470
1471 case MODE_RESET_STATISTICS:
1472 if (argc > optind) {
1473 log_error("Too many arguments.");
1474 r = -EINVAL;
1475 goto finish;
1476 }
1477
1478 r = reset_statistics(bus);
1479 break;
1480 }
1481
1482 finish:
1483 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1484 }