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