]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolve-tool.c
journal: remove template from open_journal args
[thirdparty/systemd.git] / src / resolve / resolve-tool.c
CommitLineData
bdef7319
ZJS
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
bdef7319 22#include <getopt.h>
cf0fbc49 23#include <net/if.h>
bdef7319
ZJS
24
25#include "sd-bus.h"
3f6fd1ba
LP
26
27#include "af-list.h"
b5efdb8a 28#include "alloc-util.h"
bdef7319 29#include "bus-error.h"
3f6fd1ba 30#include "bus-util.h"
45ec7efb 31#include "escape.h"
bdef7319 32#include "in-addr-util.h"
6bedfcbb 33#include "parse-util.h"
51323288 34#include "resolved-def.h"
3f6fd1ba 35#include "resolved-dns-packet.h"
a150ff5e 36#include "terminal-util.h"
2d4c5cbc 37
bdef7319
ZJS
38#define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC)
39
40static int arg_family = AF_UNSPEC;
41static int arg_ifindex = 0;
4b548ef3 42static uint16_t arg_type = 0;
2d4c5cbc 43static uint16_t arg_class = 0;
b93312f5 44static bool arg_legend = true;
51323288 45static uint64_t arg_flags = 0;
a150ff5e
LP
46
47static 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;
51323288 54
78c6a153 55static void print_source(uint64_t flags, usec_t rtt) {
74998408 56 char rtt_str[FORMAT_TIMESTAMP_MAX];
51323288
LP
57
58 if (!arg_legend)
59 return;
60
78c6a153 61 if (flags == 0)
51323288
LP
62 return;
63
64 fputs("\n-- Information acquired via", stdout);
65
66 if (flags != 0)
786c8e9f 67 printf(" protocol%s%s%s%s%s",
51323288
LP
68 flags & SD_RESOLVED_DNS ? " DNS" :"",
69 flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
786c8e9f
LP
70 flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "",
71 flags & SD_RESOLVED_MDNS_IPV4 ? "mDNS/IPv4" : "",
72 flags & SD_RESOLVED_MDNS_IPV6 ? "mDNS/IPv6" : "");
51323288 73
74998408
TG
74 assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100));
75
76 printf(" in %s", rtt_str);
77
51323288
LP
78 fputc('.', stdout);
79 fputc('\n', stdout);
931851e8
LP
80
81 printf("-- Data is authenticated: %s\n", yes_no(flags & SD_RESOLVED_AUTHENTICATED));
51323288 82}
bdef7319 83
79266746 84static int resolve_host(sd_bus *bus, const char *name) {
bdef7319 85
4afd3348
LP
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;
79266746 88 const char *canonical = NULL;
78c6a153 89 char ifname[IF_NAMESIZE] = "";
bdef7319 90 unsigned c = 0;
78c6a153 91 int r;
51323288 92 uint64_t flags;
74998408 93 usec_t ts;
bdef7319
ZJS
94
95 assert(name);
96
78c6a153
LP
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);
bdef7319
ZJS
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");
02dd6e18
LP
109 if (r < 0)
110 return bus_log_create_error(r);
bdef7319 111
51323288 112 r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
02dd6e18
LP
113 if (r < 0)
114 return bus_log_create_error(r);
bdef7319 115
74998408
TG
116 ts = now(CLOCK_MONOTONIC);
117
bdef7319 118 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
45ec7efb
LP
119 if (r < 0)
120 return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(&error, r));
bdef7319 121
74998408
TG
122 ts = now(CLOCK_MONOTONIC) - ts;
123
78c6a153 124 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
02dd6e18
LP
125 if (r < 0)
126 return bus_log_parse_error(r);
bdef7319 127
78c6a153 128 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
bdef7319 129 _cleanup_free_ char *pretty = NULL;
78c6a153 130 int ifindex, family;
45ec7efb
LP
131 const void *a;
132 size_t sz;
78c6a153
LP
133
134 assert_cc(sizeof(int) == sizeof(int32_t));
bdef7319 135
78c6a153 136 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
02dd6e18
LP
137 if (r < 0)
138 return bus_log_parse_error(r);
bdef7319
ZJS
139
140 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
02dd6e18
LP
141 if (r < 0)
142 return bus_log_parse_error(r);
bdef7319 143
bdef7319 144 r = sd_bus_message_exit_container(reply);
02dd6e18
LP
145 if (r < 0)
146 return bus_log_parse_error(r);
bdef7319 147
79266746 148 if (!IN_SET(family, AF_INET, AF_INET6)) {
be636413 149 log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
bdef7319
ZJS
150 continue;
151 }
152
153 if (sz != FAMILY_ADDRESS_SIZE(family)) {
78c6a153 154 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
45ec7efb 155 return -EINVAL;
bdef7319
ZJS
156 }
157
78c6a153
LP
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);
bdef7319 161
bdef7319 162 r = in_addr_to_string(family, a, &pretty);
78c6a153
LP
163 if (r < 0)
164 return log_error_errno(r, "Failed to print address for %s: %m", name);
bdef7319 165
79266746
LP
166 printf("%*s%s %s%s%s\n",
167 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
168 pretty,
169 isempty(ifname) ? "" : "%", ifname);
bdef7319
ZJS
170
171 c++;
172 }
79266746
LP
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
51323288 180 r = sd_bus_message_read(reply, "st", &canonical, &flags);
79266746
LP
181 if (r < 0)
182 return bus_log_parse_error(r);
183
ece174c5 184 if (!streq(name, canonical))
79266746
LP
185 printf("%*s%s (%s)\n",
186 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
187 canonical);
bdef7319
ZJS
188
189 if (c == 0) {
190 log_error("%s: no addresses found", name);
79266746
LP
191 return -ESRCH;
192 }
193
78c6a153 194 print_source(flags, ts);
51323288 195
79266746
LP
196 return 0;
197}
198
199static int resolve_address(sd_bus *bus, int family, const union in_addr_union *address, int ifindex) {
4afd3348
LP
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;
79266746
LP
202 _cleanup_free_ char *pretty = NULL;
203 char ifname[IF_NAMESIZE] = "";
51323288 204 uint64_t flags;
79266746 205 unsigned c = 0;
74998408 206 usec_t ts;
79266746
LP
207 int r;
208
209 assert(bus);
210 assert(IN_SET(family, AF_INET, AF_INET6));
211 assert(address);
212
78c6a153
LP
213 if (ifindex <= 0)
214 ifindex = arg_ifindex;
215
79266746
LP
216 r = in_addr_to_string(family, address, &pretty);
217 if (r < 0)
218 return log_oom();
219
78c6a153
LP
220 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
221 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
79266746
LP
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
51323288 235 r = sd_bus_message_append(req, "ii", ifindex, family);
79266746
LP
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
51323288 243 r = sd_bus_message_append(req, "t", arg_flags);
79266746
LP
244 if (r < 0)
245 return bus_log_create_error(r);
246
74998408
TG
247 ts = now(CLOCK_MONOTONIC);
248
79266746
LP
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
74998408
TG
255 ts = now(CLOCK_MONOTONIC) - ts;
256
78c6a153 257 r = sd_bus_message_enter_container(reply, 'a', "(is)");
79266746
LP
258 if (r < 0)
259 return bus_log_create_error(r);
260
78c6a153
LP
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));
79266746 265
78c6a153
LP
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",
79266746 279 (int) strlen(pretty), c == 0 ? pretty : "",
78c6a153
LP
280 isempty(ifname) ? 0 : 1, c > 0 || isempty(ifname) ? "" : "%",
281 (int) strlen(ifname), c == 0 ? ifname : "",
79266746
LP
282 c == 0 ? ":" : " ",
283 n);
284
285 c++;
bdef7319 286 }
79266746
LP
287 if (r < 0)
288 return bus_log_parse_error(r);
bdef7319 289
02dd6e18
LP
290 r = sd_bus_message_exit_container(reply);
291 if (r < 0)
292 return bus_log_parse_error(r);
293
51323288
LP
294 r = sd_bus_message_read(reply, "t", &flags);
295 if (r < 0)
296 return bus_log_parse_error(r);
297
79266746
LP
298 if (c == 0) {
299 log_error("%s: no names found", pretty);
300 return -ESRCH;
301 }
302
78c6a153 303 print_source(flags, ts);
51323288 304
79266746
LP
305 return 0;
306}
307
308static 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) {
6ad623a3 315 if (parse_ifindex(percent+1, &ifi) < 0) {
79266746
LP
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;
02dd6e18 330 return 0;
bdef7319
ZJS
331}
332
c1dafe4f 333static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type) {
4afd3348
LP
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;
78c6a153 336 char ifname[IF_NAMESIZE] = "";
2d4c5cbc 337 unsigned n = 0;
51323288 338 uint64_t flags;
78c6a153 339 int r;
74998408 340 usec_t ts;
2d4c5cbc
LP
341
342 assert(name);
343
78c6a153
LP
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
c1dafe4f 347 log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(ifname) ? "*" : ifname);
2d4c5cbc
LP
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
c1dafe4f 359 r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, class, type, arg_flags);
2d4c5cbc
LP
360 if (r < 0)
361 return bus_log_create_error(r);
362
74998408
TG
363 ts = now(CLOCK_MONOTONIC);
364
2d4c5cbc
LP
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
74998408
TG
371 ts = now(CLOCK_MONOTONIC) - ts;
372
78c6a153 373 r = sd_bus_message_enter_container(reply, 'a', "(iqqay)");
51323288
LP
374 if (r < 0)
375 return bus_log_parse_error(r);
376
78c6a153 377 while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
2d4c5cbc
LP
378 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
379 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
7b50eb2e 380 const char *s;
2d4c5cbc 381 uint16_t c, t;
78c6a153 382 int ifindex;
2d4c5cbc
LP
383 const void *d;
384 size_t l;
385
78c6a153
LP
386 assert_cc(sizeof(int) == sizeof(int32_t));
387
388 r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t);
2d4c5cbc
LP
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
f6a5fec6
LP
404 p->refuse_compression = true;
405
2d4c5cbc
LP
406 r = dns_packet_append_blob(p, d, l, NULL);
407 if (r < 0)
408 return log_oom();
409
d2579eec 410 r = dns_packet_read_rr(p, &rr, NULL, NULL);
40667ebe 411 if (r < 0)
502a7985 412 return log_error_errno(r, "Failed to parse RR: %m");
2d4c5cbc 413
7b50eb2e 414 s = dns_resource_record_to_string(rr);
502a7985
LP
415 if (!s)
416 return log_oom();
2d4c5cbc 417
78c6a153
LP
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);
2d4c5cbc
LP
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
51323288
LP
432 r = sd_bus_message_read(reply, "t", &flags);
433 if (r < 0)
434 return bus_log_parse_error(r);
435
2d4c5cbc
LP
436 if (n == 0) {
437 log_error("%s: no records found", name);
438 return -ESRCH;
439 }
440
78c6a153 441 print_source(flags, ts);
51323288 442
2d4c5cbc
LP
443 return 0;
444}
445
c1dafe4f
LP
446static 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
562invalid:
563 log_error("Invalid DNS URI: %s", name);
564 return -EINVAL;
565}
566
45ec7efb
LP
567static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) {
568 const char *canonical_name, *canonical_type, *canonical_domain;
4afd3348
LP
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;
45ec7efb
LP
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
a150ff5e
LP
768static 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;
593f665c 774 int r, dnssec_supported;
a150ff5e
LP
775
776 assert(bus);
777
593f665c
LP
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
a150ff5e
LP
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)");
f7700834
TA
829 if (r < 0)
830 return log_error_errno(r, "Failed to get cache statistics: %s", bus_error_message(&error, r));
a150ff5e
LP
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)");
f7700834
TA
859 if (r < 0)
860 return log_error_errno(r, "Failed to get DNSSEC statistics: %s", bus_error_message(&error, r));
a150ff5e
LP
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
7405bb3e
LP
870 printf("\n%sDNSSEC Verdicts%s\n"
871 " Secure: %" PRIu64 "\n"
872 " Insecure: %" PRIu64 "\n"
873 " Bogus: %" PRIu64 "\n"
874 " Indeterminate: %" PRIu64 "\n",
a150ff5e
LP
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
885static 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
ba82da3b
ZJS
903static void help_protocol_types(void) {
904 if (arg_legend)
905 puts("Known protocol types:");
906 puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6");
907}
908
b93312f5
ZJS
909static void help_dns_types(void) {
910 int i;
911 const char *t;
912
913 if (arg_legend)
09b1fe14 914 puts("Known DNS RR types:");
b93312f5
ZJS
915 for (i = 0; i < _DNS_TYPE_MAX; i++) {
916 t = dns_type_to_string(i);
917 if (t)
918 puts(t);
919 }
920}
921
922static void help_dns_classes(void) {
923 int i;
924 const char *t;
925
926 if (arg_legend)
09b1fe14 927 puts("Known DNS RR classes:");
b93312f5
ZJS
928 for (i = 0; i < _DNS_CLASS_MAX; i++) {
929 t = dns_class_to_string(i);
930 if (t)
931 puts(t);
932 }
933}
934
bdef7319 935static void help(void) {
45ec7efb
LP
936 printf("%s [OPTIONS...] NAME...\n"
937 "%s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n\n"
300a716d 938 "Resolve domain names, IPv4 and IPv6 addresses, DNS resource records, and services.\n\n"
ba82da3b
ZJS
939 " -h --help Show this help\n"
940 " --version Show package version\n"
941 " -4 Resolve IPv4 addresses\n"
942 " -6 Resolve IPv6 addresses\n"
943 " -i --interface=INTERFACE Look on interface\n"
944 " -p --protocol=PROTOCOL|help Look via protocol\n"
945 " -t --type=TYPE|help Query RR with DNS type\n"
946 " -c --class=CLASS|help Query RR with DNS class\n"
947 " --service Resolve service (SRV)\n"
948 " --service-address=BOOL Do [not] resolve address for services\n"
949 " --service-txt=BOOL Do [not] resolve TXT records for services\n"
950 " --cname=BOOL Do [not] follow CNAME redirects\n"
951 " --search=BOOL Do [not] use search domains\n"
952 " --legend=BOOL Do [not] print column headers and meta information\n"
953 " --statistics Show resolver statistics\n"
954 " --reset-statistics Reset resolver statistics\n"
45ec7efb 955 , program_invocation_short_name, program_invocation_short_name);
bdef7319
ZJS
956}
957
958static int parse_argv(int argc, char *argv[]) {
959 enum {
960 ARG_VERSION = 0x100,
dad29dff 961 ARG_LEGEND,
45ec7efb
LP
962 ARG_SERVICE,
963 ARG_CNAME,
964 ARG_SERVICE_ADDRESS,
965 ARG_SERVICE_TXT,
801ad6a6 966 ARG_SEARCH,
a150ff5e
LP
967 ARG_STATISTICS,
968 ARG_RESET_STATISTICS,
bdef7319
ZJS
969 };
970
971 static const struct option options[] = {
a150ff5e
LP
972 { "help", no_argument, NULL, 'h' },
973 { "version", no_argument, NULL, ARG_VERSION },
974 { "type", required_argument, NULL, 't' },
975 { "class", required_argument, NULL, 'c' },
976 { "legend", required_argument, NULL, ARG_LEGEND },
5b911843 977 { "interface", required_argument, NULL, 'i' },
a150ff5e
LP
978 { "protocol", required_argument, NULL, 'p' },
979 { "cname", required_argument, NULL, ARG_CNAME },
980 { "service", no_argument, NULL, ARG_SERVICE },
981 { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
982 { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
983 { "search", required_argument, NULL, ARG_SEARCH },
984 { "statistics", no_argument, NULL, ARG_STATISTICS, },
985 { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
bdef7319
ZJS
986 {}
987 };
988
2d4c5cbc 989 int c, r;
bdef7319
ZJS
990
991 assert(argc >= 0);
992 assert(argv);
993
51323288 994 while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
bdef7319
ZJS
995 switch(c) {
996
997 case 'h':
998 help();
999 return 0; /* done */;
1000
1001 case ARG_VERSION:
3f6fd1ba 1002 return version();
bdef7319
ZJS
1003
1004 case '4':
1005 arg_family = AF_INET;
1006 break;
1007
1008 case '6':
1009 arg_family = AF_INET6;
1010 break;
1011
3fa4999b
LP
1012 case 'i': {
1013 int ifi;
1014
6ad623a3 1015 if (parse_ifindex(optarg, &ifi) >= 0)
3fa4999b
LP
1016 arg_ifindex = ifi;
1017 else {
1018 ifi = if_nametoindex(optarg);
1019 if (ifi <= 0)
1020 return log_error_errno(errno, "Unknown interface %s: %m", optarg);
1021
1022 arg_ifindex = ifi;
1023 }
1024
2d4c5cbc 1025 break;
3fa4999b 1026 }
2d4c5cbc
LP
1027
1028 case 't':
b93312f5
ZJS
1029 if (streq(optarg, "help")) {
1030 help_dns_types();
1031 return 0;
1032 }
1033
4b548ef3
LP
1034 r = dns_type_from_string(optarg);
1035 if (r < 0) {
2d4c5cbc 1036 log_error("Failed to parse RR record type %s", optarg);
4b548ef3 1037 return r;
2d4c5cbc 1038 }
4b548ef3
LP
1039 arg_type = (uint16_t) r;
1040 assert((int) arg_type == r);
b93312f5 1041
a150ff5e 1042 arg_mode = MODE_RESOLVE_RECORD;
2d4c5cbc
LP
1043 break;
1044
1045 case 'c':
b93312f5
ZJS
1046 if (streq(optarg, "help")) {
1047 help_dns_classes();
1048 return 0;
1049 }
1050
4b548ef3 1051 r = dns_class_from_string(optarg);
2d4c5cbc
LP
1052 if (r < 0) {
1053 log_error("Failed to parse RR record class %s", optarg);
1054 return r;
bdef7319 1055 }
4b548ef3
LP
1056 arg_class = (uint16_t) r;
1057 assert((int) arg_class == r);
b93312f5
ZJS
1058
1059 break;
1060
dad29dff 1061 case ARG_LEGEND:
45ec7efb
LP
1062 r = parse_boolean(optarg);
1063 if (r < 0)
1064 return log_error_errno(r, "Failed to parse --legend= argument");
1065
1066 arg_legend = r;
bdef7319
ZJS
1067 break;
1068
51323288 1069 case 'p':
ba82da3b
ZJS
1070 if (streq(optarg, "help")) {
1071 help_protocol_types();
1072 return 0;
1073 } else if (streq(optarg, "dns"))
51323288
LP
1074 arg_flags |= SD_RESOLVED_DNS;
1075 else if (streq(optarg, "llmnr"))
1076 arg_flags |= SD_RESOLVED_LLMNR;
1077 else if (streq(optarg, "llmnr-ipv4"))
1078 arg_flags |= SD_RESOLVED_LLMNR_IPV4;
1079 else if (streq(optarg, "llmnr-ipv6"))
1080 arg_flags |= SD_RESOLVED_LLMNR_IPV6;
1081 else {
1082 log_error("Unknown protocol specifier: %s", optarg);
1083 return -EINVAL;
1084 }
1085
1086 break;
1087
45ec7efb 1088 case ARG_SERVICE:
a150ff5e 1089 arg_mode = MODE_RESOLVE_SERVICE;
45ec7efb
LP
1090 break;
1091
1092 case ARG_CNAME:
1093 r = parse_boolean(optarg);
1094 if (r < 0)
1095 return log_error_errno(r, "Failed to parse --cname= argument.");
1096 if (r == 0)
1097 arg_flags |= SD_RESOLVED_NO_CNAME;
1098 else
1099 arg_flags &= ~SD_RESOLVED_NO_CNAME;
1100 break;
1101
1102 case ARG_SERVICE_ADDRESS:
1103 r = parse_boolean(optarg);
1104 if (r < 0)
1105 return log_error_errno(r, "Failed to parse --service-address= argument.");
1106 if (r == 0)
1107 arg_flags |= SD_RESOLVED_NO_ADDRESS;
1108 else
1109 arg_flags &= ~SD_RESOLVED_NO_ADDRESS;
1110 break;
1111
1112 case ARG_SERVICE_TXT:
1113 r = parse_boolean(optarg);
1114 if (r < 0)
1115 return log_error_errno(r, "Failed to parse --service-txt= argument.");
1116 if (r == 0)
1117 arg_flags |= SD_RESOLVED_NO_TXT;
1118 else
1119 arg_flags &= ~SD_RESOLVED_NO_TXT;
1120 break;
1121
801ad6a6
LP
1122 case ARG_SEARCH:
1123 r = parse_boolean(optarg);
1124 if (r < 0)
1125 return log_error_errno(r, "Failed to parse --search argument.");
1126 if (r == 0)
1127 arg_flags |= SD_RESOLVED_NO_SEARCH;
1128 else
1129 arg_flags &= ~SD_RESOLVED_NO_SEARCH;
1130 break;
1131
a150ff5e
LP
1132 case ARG_STATISTICS:
1133 arg_mode = MODE_STATISTICS;
1134 break;
1135
1136 case ARG_RESET_STATISTICS:
1137 arg_mode = MODE_RESET_STATISTICS;
1138 break;
1139
bdef7319
ZJS
1140 case '?':
1141 return -EINVAL;
1142
1143 default:
1144 assert_not_reached("Unhandled option");
1145 }
1146
2d4c5cbc 1147 if (arg_type == 0 && arg_class != 0) {
45ec7efb
LP
1148 log_error("--class= may only be used in conjunction with --type=.");
1149 return -EINVAL;
1150 }
1151
a150ff5e 1152 if (arg_type != 0 && arg_mode != MODE_RESOLVE_RECORD) {
45ec7efb 1153 log_error("--service and --type= may not be combined.");
2d4c5cbc
LP
1154 return -EINVAL;
1155 }
1156
1157 if (arg_type != 0 && arg_class == 0)
1158 arg_class = DNS_CLASS_IN;
1159
c1dafe4f
LP
1160 if (arg_class != 0 && arg_type == 0)
1161 arg_type = DNS_TYPE_A;
1162
bdef7319
ZJS
1163 return 1 /* work to do */;
1164}
1165
bdef7319 1166int main(int argc, char **argv) {
4afd3348 1167 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
bdef7319
ZJS
1168 int r;
1169
1170 log_parse_environment();
1171 log_open();
1172
1173 r = parse_argv(argc, argv);
1174 if (r <= 0)
79266746
LP
1175 goto finish;
1176
bdef7319
ZJS
1177 r = sd_bus_open_system(&bus);
1178 if (r < 0) {
da927ba9 1179 log_error_errno(r, "sd_bus_open_system: %m");
79266746 1180 goto finish;
bdef7319
ZJS
1181 }
1182
a150ff5e 1183 switch (arg_mode) {
45ec7efb 1184
a150ff5e
LP
1185 case MODE_RESOLVE_HOST:
1186 if (optind >= argc) {
300a716d 1187 log_error("No arguments passed.");
a150ff5e
LP
1188 r = -EINVAL;
1189 goto finish;
1190 }
1191
1192 while (argv[optind]) {
1193 int family, ifindex, k;
1194 union in_addr_union a;
1195
c1dafe4f
LP
1196 if (startswith(argv[optind], "dns:"))
1197 k = resolve_rfc4501(bus, argv[optind]);
1198 else {
1199 k = parse_address(argv[optind], &family, &a, &ifindex);
1200 if (k >= 0)
1201 k = resolve_address(bus, family, &a, ifindex);
1202 else
1203 k = resolve_host(bus, argv[optind]);
1204 }
a150ff5e
LP
1205
1206 if (r == 0)
1207 r = k;
1208
1209 optind++;
1210 }
1211 break;
1212
1213 case MODE_RESOLVE_RECORD:
1214 if (optind >= argc) {
300a716d 1215 log_error("No arguments passed.");
a150ff5e
LP
1216 r = -EINVAL;
1217 goto finish;
1218 }
1219
1220 while (argv[optind]) {
1221 int k;
1222
c1dafe4f 1223 k = resolve_record(bus, argv[optind], arg_class, arg_type);
a150ff5e
LP
1224 if (r == 0)
1225 r = k;
1226
1227 optind++;
1228 }
1229 break;
1230
1231 case MODE_RESOLVE_SERVICE:
45ec7efb
LP
1232 if (argc < optind + 1) {
1233 log_error("Domain specification required.");
1234 r = -EINVAL;
1235 goto finish;
1236
1237 } else if (argc == optind + 1)
1238 r = resolve_service(bus, NULL, NULL, argv[optind]);
1239 else if (argc == optind + 2)
1240 r = resolve_service(bus, NULL, argv[optind], argv[optind+1]);
1241 else if (argc == optind + 3)
1242 r = resolve_service(bus, argv[optind], argv[optind+1], argv[optind+2]);
1243 else {
300a716d 1244 log_error("Too many arguments.");
45ec7efb
LP
1245 r = -EINVAL;
1246 goto finish;
1247 }
1248
a150ff5e 1249 break;
79266746 1250
a150ff5e
LP
1251 case MODE_STATISTICS:
1252 if (argc > optind) {
1253 log_error("Too many arguments.");
1254 r = -EINVAL;
1255 goto finish;
2d4c5cbc 1256 }
bdef7319 1257
a150ff5e
LP
1258 r = show_statistics(bus);
1259 break;
1260
1261 case MODE_RESET_STATISTICS:
1262 if (argc > optind) {
1263 log_error("Too many arguments.");
1264 r = -EINVAL;
1265 goto finish;
1266 }
79266746 1267
a150ff5e
LP
1268 r = reset_statistics(bus);
1269 break;
bdef7319
ZJS
1270 }
1271
79266746 1272finish:
bdef7319
ZJS
1273 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
1274}