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