]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolve-tool.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / resolve / resolve-tool.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
bdef7319
ZJS
2/***
3 This file is part of systemd.
4
5 Copyright 2014 Zbigniew Jędrzejewski-Szmek
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
bdef7319 21#include <getopt.h>
cf0fbc49 22#include <net/if.h>
bdef7319
ZJS
23
24#include "sd-bus.h"
be371fe0 25#include "sd-netlink.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"
4ac2ca1b 32#include "gcrypt-util.h"
be371fe0
LP
33#include "in-addr-util.h"
34#include "netlink-util.h"
35#include "pager.h"
6bedfcbb 36#include "parse-util.h"
51323288 37#include "resolved-def.h"
3f6fd1ba 38#include "resolved-dns-packet.h"
be371fe0 39#include "strv.h"
a150ff5e 40#include "terminal-util.h"
2d4c5cbc 41
74a3ed74 42#define DNS_CALL_TIMEOUT_USEC (90*USEC_PER_SEC)
bdef7319
ZJS
43
44static int arg_family = AF_UNSPEC;
45static int arg_ifindex = 0;
4b548ef3 46static uint16_t arg_type = 0;
2d4c5cbc 47static uint16_t arg_class = 0;
b93312f5 48static bool arg_legend = true;
51323288 49static uint64_t arg_flags = 0;
be371fe0 50static bool arg_no_pager = false;
dab48ea6 51
82d1d240
ZJS
52typedef enum ServiceFamily {
53 SERVICE_FAMILY_TCP,
54 SERVICE_FAMILY_UDP,
55 SERVICE_FAMILY_SCTP,
56 _SERVICE_FAMILY_INVALID = -1,
57} ServiceFamily;
58static ServiceFamily arg_service_family = SERVICE_FAMILY_TCP;
59
dab48ea6
ZJS
60typedef enum RawType {
61 RAW_NONE,
62 RAW_PAYLOAD,
63 RAW_PACKET,
64} RawType;
dab48ea6 65static RawType arg_raw = RAW_NONE;
a150ff5e
LP
66
67static enum {
68 MODE_RESOLVE_HOST,
69 MODE_RESOLVE_RECORD,
70 MODE_RESOLVE_SERVICE,
4ac2ca1b 71 MODE_RESOLVE_OPENPGP,
82d1d240 72 MODE_RESOLVE_TLSA,
a150ff5e
LP
73 MODE_STATISTICS,
74 MODE_RESET_STATISTICS,
ba35662f 75 MODE_FLUSH_CACHES,
d55b0463 76 MODE_RESET_SERVER_FEATURES,
be371fe0 77 MODE_STATUS,
a150ff5e 78} arg_mode = MODE_RESOLVE_HOST;
51323288 79
82d1d240
ZJS
80static ServiceFamily service_family_from_string(const char *s) {
81 if (s == NULL || streq(s, "tcp"))
82 return SERVICE_FAMILY_TCP;
83 if (streq(s, "udp"))
84 return SERVICE_FAMILY_UDP;
85 if (streq(s, "sctp"))
86 return SERVICE_FAMILY_SCTP;
87 return _SERVICE_FAMILY_INVALID;
88}
89
90static const char* service_family_to_string(ServiceFamily service) {
91 switch(service) {
92 case SERVICE_FAMILY_TCP:
93 return "_tcp";
94 case SERVICE_FAMILY_UDP:
95 return "_udp";
96 case SERVICE_FAMILY_SCTP:
97 return "_sctp";
98 default:
99 assert_not_reached("invalid service");
100 }
101}
102
78c6a153 103static void print_source(uint64_t flags, usec_t rtt) {
74998408 104 char rtt_str[FORMAT_TIMESTAMP_MAX];
51323288
LP
105
106 if (!arg_legend)
107 return;
108
78c6a153 109 if (flags == 0)
51323288
LP
110 return;
111
112 fputs("\n-- Information acquired via", stdout);
113
114 if (flags != 0)
786c8e9f 115 printf(" protocol%s%s%s%s%s",
51323288
LP
116 flags & SD_RESOLVED_DNS ? " DNS" :"",
117 flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
786c8e9f 118 flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "",
44ccb3d7
YW
119 flags & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4" : "",
120 flags & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6" : "");
51323288 121
74998408
TG
122 assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100));
123
124 printf(" in %s", rtt_str);
125
51323288
LP
126 fputc('.', stdout);
127 fputc('\n', stdout);
931851e8
LP
128
129 printf("-- Data is authenticated: %s\n", yes_no(flags & SD_RESOLVED_AUTHENTICATED));
51323288 130}
bdef7319 131
79266746 132static int resolve_host(sd_bus *bus, const char *name) {
bdef7319 133
4afd3348
LP
134 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
135 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
79266746 136 const char *canonical = NULL;
78c6a153 137 char ifname[IF_NAMESIZE] = "";
bdef7319 138 unsigned c = 0;
78c6a153 139 int r;
51323288 140 uint64_t flags;
74998408 141 usec_t ts;
bdef7319
ZJS
142
143 assert(name);
144
78c6a153
LP
145 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
146 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
147
148 log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
bdef7319
ZJS
149
150 r = sd_bus_message_new_method_call(
151 bus,
152 &req,
153 "org.freedesktop.resolve1",
154 "/org/freedesktop/resolve1",
155 "org.freedesktop.resolve1.Manager",
156 "ResolveHostname");
02dd6e18
LP
157 if (r < 0)
158 return bus_log_create_error(r);
bdef7319 159
51323288 160 r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
02dd6e18
LP
161 if (r < 0)
162 return bus_log_create_error(r);
bdef7319 163
74998408
TG
164 ts = now(CLOCK_MONOTONIC);
165
bdef7319 166 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
45ec7efb
LP
167 if (r < 0)
168 return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(&error, r));
bdef7319 169
74998408
TG
170 ts = now(CLOCK_MONOTONIC) - ts;
171
78c6a153 172 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
02dd6e18
LP
173 if (r < 0)
174 return bus_log_parse_error(r);
bdef7319 175
78c6a153 176 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
bdef7319 177 _cleanup_free_ char *pretty = NULL;
78c6a153 178 int ifindex, family;
45ec7efb
LP
179 const void *a;
180 size_t sz;
78c6a153
LP
181
182 assert_cc(sizeof(int) == sizeof(int32_t));
bdef7319 183
78c6a153 184 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
02dd6e18
LP
185 if (r < 0)
186 return bus_log_parse_error(r);
bdef7319
ZJS
187
188 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
02dd6e18
LP
189 if (r < 0)
190 return bus_log_parse_error(r);
bdef7319 191
bdef7319 192 r = sd_bus_message_exit_container(reply);
02dd6e18
LP
193 if (r < 0)
194 return bus_log_parse_error(r);
bdef7319 195
79266746 196 if (!IN_SET(family, AF_INET, AF_INET6)) {
be636413 197 log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
bdef7319
ZJS
198 continue;
199 }
200
201 if (sz != FAMILY_ADDRESS_SIZE(family)) {
78c6a153 202 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
45ec7efb 203 return -EINVAL;
bdef7319
ZJS
204 }
205
78c6a153
LP
206 ifname[0] = 0;
207 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
208 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
bdef7319 209
145fab1e 210 r = in_addr_ifindex_to_string(family, a, ifindex, &pretty);
78c6a153
LP
211 if (r < 0)
212 return log_error_errno(r, "Failed to print address for %s: %m", name);
bdef7319 213
79266746
LP
214 printf("%*s%s %s%s%s\n",
215 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
216 pretty,
217 isempty(ifname) ? "" : "%", ifname);
bdef7319
ZJS
218
219 c++;
220 }
79266746
LP
221 if (r < 0)
222 return bus_log_parse_error(r);
223
224 r = sd_bus_message_exit_container(reply);
225 if (r < 0)
226 return bus_log_parse_error(r);
227
51323288 228 r = sd_bus_message_read(reply, "st", &canonical, &flags);
79266746
LP
229 if (r < 0)
230 return bus_log_parse_error(r);
231
ece174c5 232 if (!streq(name, canonical))
79266746
LP
233 printf("%*s%s (%s)\n",
234 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
235 canonical);
bdef7319
ZJS
236
237 if (c == 0) {
238 log_error("%s: no addresses found", name);
79266746
LP
239 return -ESRCH;
240 }
241
78c6a153 242 print_source(flags, ts);
51323288 243
79266746
LP
244 return 0;
245}
246
247static int resolve_address(sd_bus *bus, int family, const union in_addr_union *address, int ifindex) {
4afd3348
LP
248 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
249 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
79266746
LP
250 _cleanup_free_ char *pretty = NULL;
251 char ifname[IF_NAMESIZE] = "";
51323288 252 uint64_t flags;
79266746 253 unsigned c = 0;
74998408 254 usec_t ts;
79266746
LP
255 int r;
256
257 assert(bus);
258 assert(IN_SET(family, AF_INET, AF_INET6));
259 assert(address);
260
78c6a153
LP
261 if (ifindex <= 0)
262 ifindex = arg_ifindex;
263
145fab1e 264 r = in_addr_ifindex_to_string(family, address, ifindex, &pretty);
79266746
LP
265 if (r < 0)
266 return log_oom();
267
78c6a153
LP
268 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
269 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
79266746
LP
270
271 log_debug("Resolving %s%s%s.", pretty, isempty(ifname) ? "" : "%", ifname);
272
273 r = sd_bus_message_new_method_call(
274 bus,
275 &req,
276 "org.freedesktop.resolve1",
277 "/org/freedesktop/resolve1",
278 "org.freedesktop.resolve1.Manager",
279 "ResolveAddress");
280 if (r < 0)
281 return bus_log_create_error(r);
282
51323288 283 r = sd_bus_message_append(req, "ii", ifindex, family);
79266746
LP
284 if (r < 0)
285 return bus_log_create_error(r);
286
287 r = sd_bus_message_append_array(req, 'y', address, FAMILY_ADDRESS_SIZE(family));
288 if (r < 0)
289 return bus_log_create_error(r);
290
51323288 291 r = sd_bus_message_append(req, "t", arg_flags);
79266746
LP
292 if (r < 0)
293 return bus_log_create_error(r);
294
74998408
TG
295 ts = now(CLOCK_MONOTONIC);
296
79266746
LP
297 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
298 if (r < 0) {
299 log_error("%s: resolve call failed: %s", pretty, bus_error_message(&error, r));
300 return r;
301 }
302
74998408
TG
303 ts = now(CLOCK_MONOTONIC) - ts;
304
78c6a153 305 r = sd_bus_message_enter_container(reply, 'a', "(is)");
79266746
LP
306 if (r < 0)
307 return bus_log_create_error(r);
308
78c6a153
LP
309 while ((r = sd_bus_message_enter_container(reply, 'r', "is")) > 0) {
310 const char *n;
311
312 assert_cc(sizeof(int) == sizeof(int32_t));
79266746 313
78c6a153
LP
314 r = sd_bus_message_read(reply, "is", &ifindex, &n);
315 if (r < 0)
316 return r;
317
318 r = sd_bus_message_exit_container(reply);
319 if (r < 0)
320 return r;
321
322 ifname[0] = 0;
323 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
324 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
325
326 printf("%*s%*s%*s%s %s\n",
79266746 327 (int) strlen(pretty), c == 0 ? pretty : "",
78c6a153
LP
328 isempty(ifname) ? 0 : 1, c > 0 || isempty(ifname) ? "" : "%",
329 (int) strlen(ifname), c == 0 ? ifname : "",
79266746
LP
330 c == 0 ? ":" : " ",
331 n);
332
333 c++;
bdef7319 334 }
79266746
LP
335 if (r < 0)
336 return bus_log_parse_error(r);
bdef7319 337
02dd6e18
LP
338 r = sd_bus_message_exit_container(reply);
339 if (r < 0)
340 return bus_log_parse_error(r);
341
51323288
LP
342 r = sd_bus_message_read(reply, "t", &flags);
343 if (r < 0)
344 return bus_log_parse_error(r);
345
79266746
LP
346 if (c == 0) {
347 log_error("%s: no names found", pretty);
348 return -ESRCH;
349 }
350
78c6a153 351 print_source(flags, ts);
51323288 352
79266746
LP
353 return 0;
354}
355
dab48ea6
ZJS
356static int output_rr_packet(const void *d, size_t l, int ifindex) {
357 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
358 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
359 int r;
360 char ifname[IF_NAMESIZE] = "";
361
51027656 362 r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX);
dab48ea6
ZJS
363 if (r < 0)
364 return log_oom();
365
366 p->refuse_compression = true;
367
368 r = dns_packet_append_blob(p, d, l, NULL);
369 if (r < 0)
370 return log_oom();
371
372 r = dns_packet_read_rr(p, &rr, NULL, NULL);
373 if (r < 0)
374 return log_error_errno(r, "Failed to parse RR: %m");
375
376 if (arg_raw == RAW_PAYLOAD) {
377 void *data;
378 ssize_t k;
379
380 k = dns_resource_record_payload(rr, &data);
381 if (k < 0)
382 return log_error_errno(k, "Cannot dump RR: %m");
383 fwrite(data, 1, k, stdout);
384 } else {
385 const char *s;
386
387 s = dns_resource_record_to_string(rr);
388 if (!s)
389 return log_oom();
390
391 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
392 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
393
394 printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
395 }
396
397 return 0;
398}
399
a60f4d0b 400static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type, bool warn_missing) {
4afd3348
LP
401 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
402 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
78c6a153 403 char ifname[IF_NAMESIZE] = "";
2d4c5cbc 404 unsigned n = 0;
51323288 405 uint64_t flags;
78c6a153 406 int r;
74998408 407 usec_t ts;
41815a4a 408 bool needs_authentication = false;
2d4c5cbc
LP
409
410 assert(name);
411
78c6a153
LP
412 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
413 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
414
c1dafe4f 415 log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(ifname) ? "*" : ifname);
2d4c5cbc
LP
416
417 r = sd_bus_message_new_method_call(
418 bus,
419 &req,
420 "org.freedesktop.resolve1",
421 "/org/freedesktop/resolve1",
422 "org.freedesktop.resolve1.Manager",
423 "ResolveRecord");
424 if (r < 0)
425 return bus_log_create_error(r);
426
c1dafe4f 427 r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, class, type, arg_flags);
2d4c5cbc
LP
428 if (r < 0)
429 return bus_log_create_error(r);
430
74998408
TG
431 ts = now(CLOCK_MONOTONIC);
432
2d4c5cbc
LP
433 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
434 if (r < 0) {
a60f4d0b
SS
435 if (warn_missing || r != -ENXIO)
436 log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
2d4c5cbc
LP
437 return r;
438 }
439
74998408
TG
440 ts = now(CLOCK_MONOTONIC) - ts;
441
78c6a153 442 r = sd_bus_message_enter_container(reply, 'a', "(iqqay)");
51323288
LP
443 if (r < 0)
444 return bus_log_parse_error(r);
445
78c6a153 446 while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
2d4c5cbc 447 uint16_t c, t;
78c6a153 448 int ifindex;
2d4c5cbc
LP
449 const void *d;
450 size_t l;
451
78c6a153
LP
452 assert_cc(sizeof(int) == sizeof(int32_t));
453
454 r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t);
2d4c5cbc
LP
455 if (r < 0)
456 return bus_log_parse_error(r);
457
458 r = sd_bus_message_read_array(reply, 'y', &d, &l);
459 if (r < 0)
460 return bus_log_parse_error(r);
461
462 r = sd_bus_message_exit_container(reply);
463 if (r < 0)
464 return bus_log_parse_error(r);
465
dab48ea6
ZJS
466 if (arg_raw == RAW_PACKET) {
467 uint64_t u64 = htole64(l);
2d4c5cbc 468
dab48ea6
ZJS
469 fwrite(&u64, sizeof(u64), 1, stdout);
470 fwrite(d, 1, l, stdout);
2e74028a 471 } else {
dab48ea6
ZJS
472 r = output_rr_packet(d, l, ifindex);
473 if (r < 0)
474 return r;
2e74028a 475 }
78c6a153 476
41815a4a
LP
477 if (dns_type_needs_authentication(t))
478 needs_authentication = true;
479
2d4c5cbc
LP
480 n++;
481 }
482 if (r < 0)
483 return bus_log_parse_error(r);
484
485 r = sd_bus_message_exit_container(reply);
486 if (r < 0)
487 return bus_log_parse_error(r);
488
51323288
LP
489 r = sd_bus_message_read(reply, "t", &flags);
490 if (r < 0)
491 return bus_log_parse_error(r);
492
2d4c5cbc 493 if (n == 0) {
a60f4d0b
SS
494 if (warn_missing)
495 log_error("%s: no records found", name);
2d4c5cbc
LP
496 return -ESRCH;
497 }
498
78c6a153 499 print_source(flags, ts);
51323288 500
41815a4a
LP
501 if ((flags & SD_RESOLVED_AUTHENTICATED) == 0 && needs_authentication) {
502 fflush(stdout);
503
504 fprintf(stderr, "\n%s"
505 "WARNING: The resources shown contain cryptographic key data which could not be\n"
506 " authenticated. It is not suitable to authenticate any communication.\n"
507 " This is usually indication that DNSSEC authentication was not enabled\n"
508 " or is not available for the selected protocol or DNS servers.%s\n",
509 ansi_highlight_red(),
510 ansi_normal());
511 }
512
2d4c5cbc
LP
513 return 0;
514}
515
c1dafe4f
LP
516static int resolve_rfc4501(sd_bus *bus, const char *name) {
517 uint16_t type = 0, class = 0;
518 const char *p, *q, *n;
519 int r;
520
521 assert(bus);
522 assert(name);
523 assert(startswith(name, "dns:"));
524
525 /* Parse RFC 4501 dns: URIs */
526
527 p = name + 4;
528
529 if (p[0] == '/') {
530 const char *e;
531
532 if (p[1] != '/')
533 goto invalid;
534
535 e = strchr(p + 2, '/');
536 if (!e)
537 goto invalid;
538
539 if (e != p + 2)
540 log_warning("DNS authority specification not supported; ignoring specified authority.");
541
542 p = e + 1;
543 }
544
545 q = strchr(p, '?');
546 if (q) {
547 n = strndupa(p, q - p);
548 q++;
549
550 for (;;) {
551 const char *f;
552
553 f = startswith_no_case(q, "class=");
554 if (f) {
555 _cleanup_free_ char *t = NULL;
556 const char *e;
557
558 if (class != 0) {
559 log_error("DNS class specified twice.");
560 return -EINVAL;
561 }
562
563 e = strchrnul(f, ';');
564 t = strndup(f, e - f);
565 if (!t)
566 return log_oom();
567
568 r = dns_class_from_string(t);
569 if (r < 0) {
570 log_error("Unknown DNS class %s.", t);
571 return -EINVAL;
572 }
573
574 class = r;
575
576 if (*e == ';') {
577 q = e + 1;
578 continue;
579 }
580
581 break;
582 }
583
584 f = startswith_no_case(q, "type=");
585 if (f) {
586 _cleanup_free_ char *t = NULL;
587 const char *e;
588
589 if (type != 0) {
590 log_error("DNS type specified twice.");
591 return -EINVAL;
592 }
593
594 e = strchrnul(f, ';');
595 t = strndup(f, e - f);
596 if (!t)
597 return log_oom();
598
599 r = dns_type_from_string(t);
600 if (r < 0) {
601 log_error("Unknown DNS type %s.", t);
602 return -EINVAL;
603 }
604
605 type = r;
606
607 if (*e == ';') {
608 q = e + 1;
609 continue;
610 }
611
612 break;
613 }
614
615 goto invalid;
616 }
617 } else
618 n = p;
619
c1dafe4f 620 if (class == 0)
4ac2ca1b
ZJS
621 class = arg_class ?: DNS_CLASS_IN;
622 if (type == 0)
623 type = arg_type ?: DNS_TYPE_A;
c1dafe4f 624
a60f4d0b 625 return resolve_record(bus, n, class, type, true);
c1dafe4f
LP
626
627invalid:
628 log_error("Invalid DNS URI: %s", name);
629 return -EINVAL;
630}
631
45ec7efb
LP
632static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) {
633 const char *canonical_name, *canonical_type, *canonical_domain;
4afd3348
LP
634 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
635 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
45ec7efb
LP
636 char ifname[IF_NAMESIZE] = "";
637 size_t indent, sz;
638 uint64_t flags;
639 const char *p;
640 unsigned c;
641 usec_t ts;
642 int r;
643
644 assert(bus);
645 assert(domain);
646
3c6f7c34
LP
647 name = empty_to_null(name);
648 type = empty_to_null(type);
45ec7efb
LP
649
650 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
651 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
652
653 if (name)
654 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);
655 else if (type)
656 log_debug("Resolving service type %s of %s (family %s, interface %s).", type, domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
657 else
658 log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
659
660 r = sd_bus_message_new_method_call(
661 bus,
662 &req,
663 "org.freedesktop.resolve1",
664 "/org/freedesktop/resolve1",
665 "org.freedesktop.resolve1.Manager",
666 "ResolveService");
667 if (r < 0)
668 return bus_log_create_error(r);
669
670 r = sd_bus_message_append(req, "isssit", arg_ifindex, name, type, domain, arg_family, arg_flags);
671 if (r < 0)
672 return bus_log_create_error(r);
673
674 ts = now(CLOCK_MONOTONIC);
675
676 r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
677 if (r < 0)
678 return log_error_errno(r, "Resolve call failed: %s", bus_error_message(&error, r));
679
680 ts = now(CLOCK_MONOTONIC) - ts;
681
682 r = sd_bus_message_enter_container(reply, 'a', "(qqqsa(iiay)s)");
683 if (r < 0)
684 return bus_log_parse_error(r);
685
686 indent =
687 (name ? strlen(name) + 1 : 0) +
688 (type ? strlen(type) + 1 : 0) +
689 strlen(domain) + 2;
690
691 c = 0;
692 while ((r = sd_bus_message_enter_container(reply, 'r', "qqqsa(iiay)s")) > 0) {
693 uint16_t priority, weight, port;
694 const char *hostname, *canonical;
695
696 r = sd_bus_message_read(reply, "qqqs", &priority, &weight, &port, &hostname);
697 if (r < 0)
698 return bus_log_parse_error(r);
699
700 if (name)
701 printf("%*s%s", (int) strlen(name), c == 0 ? name : "", c == 0 ? "/" : " ");
702 if (type)
703 printf("%*s%s", (int) strlen(type), c == 0 ? type : "", c == 0 ? "/" : " ");
704
705 printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
706 (int) strlen(domain), c == 0 ? domain : "",
707 c == 0 ? ":" : " ",
708 hostname, port,
709 priority, weight);
710
711 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
712 if (r < 0)
713 return bus_log_parse_error(r);
714
715 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
716 _cleanup_free_ char *pretty = NULL;
717 int ifindex, family;
718 const void *a;
719
720 assert_cc(sizeof(int) == sizeof(int32_t));
721
722 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
723 if (r < 0)
724 return bus_log_parse_error(r);
725
726 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
727 if (r < 0)
728 return bus_log_parse_error(r);
729
730 r = sd_bus_message_exit_container(reply);
731 if (r < 0)
732 return bus_log_parse_error(r);
733
734 if (!IN_SET(family, AF_INET, AF_INET6)) {
735 log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
736 continue;
737 }
738
739 if (sz != FAMILY_ADDRESS_SIZE(family)) {
740 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
741 return -EINVAL;
742 }
743
744 ifname[0] = 0;
745 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
746 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
747
748 r = in_addr_to_string(family, a, &pretty);
749 if (r < 0)
750 return log_error_errno(r, "Failed to print address for %s: %m", name);
751
752 printf("%*s%s%s%s\n", (int) indent, "", pretty, isempty(ifname) ? "" : "%s", ifname);
753 }
754 if (r < 0)
755 return bus_log_parse_error(r);
756
757 r = sd_bus_message_exit_container(reply);
758 if (r < 0)
759 return bus_log_parse_error(r);
760
761 r = sd_bus_message_read(reply, "s", &canonical);
762 if (r < 0)
763 return bus_log_parse_error(r);
764
765 if (!streq(hostname, canonical))
766 printf("%*s(%s)\n", (int) indent, "", canonical);
767
768 r = sd_bus_message_exit_container(reply);
769 if (r < 0)
770 return bus_log_parse_error(r);
771
772 c++;
773 }
774 if (r < 0)
775 return bus_log_parse_error(r);
776
777 r = sd_bus_message_exit_container(reply);
778 if (r < 0)
779 return bus_log_parse_error(r);
780
781 r = sd_bus_message_enter_container(reply, 'a', "ay");
782 if (r < 0)
783 return bus_log_parse_error(r);
784
45ec7efb
LP
785 while ((r = sd_bus_message_read_array(reply, 'y', (const void**) &p, &sz)) > 0) {
786 _cleanup_free_ char *escaped = NULL;
787
788 escaped = cescape_length(p, sz);
789 if (!escaped)
790 return log_oom();
791
792 printf("%*s%s\n", (int) indent, "", escaped);
45ec7efb
LP
793 }
794 if (r < 0)
795 return bus_log_parse_error(r);
796
797 r = sd_bus_message_exit_container(reply);
798 if (r < 0)
799 return bus_log_parse_error(r);
800
801 r = sd_bus_message_read(reply, "ssst", &canonical_name, &canonical_type, &canonical_domain, &flags);
802 if (r < 0)
803 return bus_log_parse_error(r);
804
3c6f7c34
LP
805 canonical_name = empty_to_null(canonical_name);
806 canonical_type = empty_to_null(canonical_type);
45ec7efb
LP
807
808 if (!streq_ptr(name, canonical_name) ||
809 !streq_ptr(type, canonical_type) ||
810 !streq_ptr(domain, canonical_domain)) {
811
812 printf("%*s(", (int) indent, "");
813
814 if (canonical_name)
815 printf("%s/", canonical_name);
816 if (canonical_type)
817 printf("%s/", canonical_type);
818
819 printf("%s)\n", canonical_domain);
820 }
821
822 print_source(flags, ts);
823
824 return 0;
825}
826
4ac2ca1b
ZJS
827static int resolve_openpgp(sd_bus *bus, const char *address) {
828 const char *domain, *full;
829 int r;
830 _cleanup_free_ char *hashed = NULL;
831
832 assert(bus);
833 assert(address);
834
835 domain = strrchr(address, '@');
836 if (!domain) {
837 log_error("Address does not contain '@': \"%s\"", address);
838 return -EINVAL;
839 } else if (domain == address || domain[1] == '\0') {
840 log_error("Address starts or ends with '@': \"%s\"", address);
841 return -EINVAL;
842 }
843 domain++;
844
a60f4d0b 845 r = string_hashsum_sha256(address, domain - 1 - address, &hashed);
4ac2ca1b
ZJS
846 if (r < 0)
847 return log_error_errno(r, "Hashing failed: %m");
848
a60f4d0b
SS
849 strshorten(hashed, 56);
850
4ac2ca1b
ZJS
851 full = strjoina(hashed, "._openpgpkey.", domain);
852 log_debug("Looking up \"%s\".", full);
853
a60f4d0b
SS
854 r = resolve_record(bus, full,
855 arg_class ?: DNS_CLASS_IN,
856 arg_type ?: DNS_TYPE_OPENPGPKEY, false);
857
858 if (IN_SET(r, -ENXIO, -ESRCH)) { /* NXDOMAIN or NODATA? */
859 hashed = NULL;
860 r = string_hashsum_sha224(address, domain - 1 - address, &hashed);
861 if (r < 0)
862 return log_error_errno(r, "Hashing failed: %m");
863
864 full = strjoina(hashed, "._openpgpkey.", domain);
865 log_debug("Looking up \"%s\".", full);
866
867 return resolve_record(bus, full,
868 arg_class ?: DNS_CLASS_IN,
869 arg_type ?: DNS_TYPE_OPENPGPKEY, true);
870 }
871
872 return r;
4ac2ca1b
ZJS
873}
874
82d1d240
ZJS
875static int resolve_tlsa(sd_bus *bus, const char *address) {
876 const char *port;
877 uint16_t port_num = 443;
878 _cleanup_free_ char *full = NULL;
879 int r;
880
881 assert(bus);
882 assert(address);
883
884 port = strrchr(address, ':');
885 if (port) {
10452f7c
SS
886 r = parse_ip_port(port + 1, &port_num);
887 if (r < 0)
82d1d240
ZJS
888 return log_error_errno(r, "Invalid port \"%s\".", port + 1);
889
890 address = strndupa(address, port - address);
891 }
892
893 r = asprintf(&full, "_%u.%s.%s",
894 port_num,
895 service_family_to_string(arg_service_family),
896 address);
897 if (r < 0)
898 return log_oom();
899
900 log_debug("Looking up \"%s\".", full);
901
902 return resolve_record(bus, full,
903 arg_class ?: DNS_CLASS_IN,
a60f4d0b 904 arg_type ?: DNS_TYPE_TLSA, true);
82d1d240
ZJS
905}
906
a150ff5e
LP
907static int show_statistics(sd_bus *bus) {
908 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
909 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
910 uint64_t n_current_transactions, n_total_transactions,
911 cache_size, n_cache_hit, n_cache_miss,
912 n_dnssec_secure, n_dnssec_insecure, n_dnssec_bogus, n_dnssec_indeterminate;
593f665c 913 int r, dnssec_supported;
a150ff5e
LP
914
915 assert(bus);
916
593f665c
LP
917 r = sd_bus_get_property_trivial(bus,
918 "org.freedesktop.resolve1",
919 "/org/freedesktop/resolve1",
920 "org.freedesktop.resolve1.Manager",
921 "DNSSECSupported",
922 &error,
923 'b',
924 &dnssec_supported);
925 if (r < 0)
926 return log_error_errno(r, "Failed to get DNSSEC supported state: %s", bus_error_message(&error, r));
927
928 printf("DNSSEC supported by current servers: %s%s%s\n\n",
929 ansi_highlight(),
930 yes_no(dnssec_supported),
931 ansi_normal());
932
a150ff5e
LP
933 r = sd_bus_get_property(bus,
934 "org.freedesktop.resolve1",
935 "/org/freedesktop/resolve1",
936 "org.freedesktop.resolve1.Manager",
937 "TransactionStatistics",
938 &error,
939 &reply,
940 "(tt)");
941 if (r < 0)
942 return log_error_errno(r, "Failed to get transaction statistics: %s", bus_error_message(&error, r));
943
944 r = sd_bus_message_read(reply, "(tt)",
945 &n_current_transactions,
946 &n_total_transactions);
947 if (r < 0)
948 return bus_log_parse_error(r);
949
950 printf("%sTransactions%s\n"
951 "Current Transactions: %" PRIu64 "\n"
952 " Total Transactions: %" PRIu64 "\n",
953 ansi_highlight(),
954 ansi_normal(),
955 n_current_transactions,
956 n_total_transactions);
957
958 reply = sd_bus_message_unref(reply);
959
960 r = sd_bus_get_property(bus,
961 "org.freedesktop.resolve1",
962 "/org/freedesktop/resolve1",
963 "org.freedesktop.resolve1.Manager",
964 "CacheStatistics",
965 &error,
966 &reply,
967 "(ttt)");
f7700834
TA
968 if (r < 0)
969 return log_error_errno(r, "Failed to get cache statistics: %s", bus_error_message(&error, r));
a150ff5e
LP
970
971 r = sd_bus_message_read(reply, "(ttt)",
972 &cache_size,
973 &n_cache_hit,
974 &n_cache_miss);
975 if (r < 0)
976 return bus_log_parse_error(r);
977
978 printf("\n%sCache%s\n"
979 " Current Cache Size: %" PRIu64 "\n"
980 " Cache Hits: %" PRIu64 "\n"
981 " Cache Misses: %" PRIu64 "\n",
982 ansi_highlight(),
983 ansi_normal(),
984 cache_size,
985 n_cache_hit,
986 n_cache_miss);
987
988 reply = sd_bus_message_unref(reply);
989
990 r = sd_bus_get_property(bus,
991 "org.freedesktop.resolve1",
992 "/org/freedesktop/resolve1",
993 "org.freedesktop.resolve1.Manager",
994 "DNSSECStatistics",
995 &error,
996 &reply,
997 "(tttt)");
f7700834
TA
998 if (r < 0)
999 return log_error_errno(r, "Failed to get DNSSEC statistics: %s", bus_error_message(&error, r));
a150ff5e
LP
1000
1001 r = sd_bus_message_read(reply, "(tttt)",
1002 &n_dnssec_secure,
1003 &n_dnssec_insecure,
1004 &n_dnssec_bogus,
1005 &n_dnssec_indeterminate);
1006 if (r < 0)
1007 return bus_log_parse_error(r);
1008
7405bb3e
LP
1009 printf("\n%sDNSSEC Verdicts%s\n"
1010 " Secure: %" PRIu64 "\n"
1011 " Insecure: %" PRIu64 "\n"
1012 " Bogus: %" PRIu64 "\n"
1013 " Indeterminate: %" PRIu64 "\n",
a150ff5e
LP
1014 ansi_highlight(),
1015 ansi_normal(),
1016 n_dnssec_secure,
1017 n_dnssec_insecure,
1018 n_dnssec_bogus,
1019 n_dnssec_indeterminate);
1020
1021 return 0;
1022}
1023
1024static int reset_statistics(sd_bus *bus) {
1025 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1026 int r;
1027
1028 r = sd_bus_call_method(bus,
1029 "org.freedesktop.resolve1",
1030 "/org/freedesktop/resolve1",
1031 "org.freedesktop.resolve1.Manager",
1032 "ResetStatistics",
1033 &error,
1034 NULL,
1035 NULL);
1036 if (r < 0)
1037 return log_error_errno(r, "Failed to reset statistics: %s", bus_error_message(&error, r));
1038
1039 return 0;
1040}
1041
ba35662f
LP
1042static int flush_caches(sd_bus *bus) {
1043 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1044 int r;
1045
1046 r = sd_bus_call_method(bus,
1047 "org.freedesktop.resolve1",
1048 "/org/freedesktop/resolve1",
1049 "org.freedesktop.resolve1.Manager",
1050 "FlushCaches",
1051 &error,
1052 NULL,
1053 NULL);
1054 if (r < 0)
1055 return log_error_errno(r, "Failed to flush caches: %s", bus_error_message(&error, r));
1056
1057 return 0;
1058}
1059
d55b0463
LP
1060static int reset_server_features(sd_bus *bus) {
1061 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1062 int r;
1063
1064 r = sd_bus_call_method(bus,
1065 "org.freedesktop.resolve1",
1066 "/org/freedesktop/resolve1",
1067 "org.freedesktop.resolve1.Manager",
1068 "ResetServerFeatures",
1069 &error,
1070 NULL,
1071 NULL);
1072 if (r < 0)
1073 return log_error_errno(r, "Failed to reset server features: %s", bus_error_message(&error, r));
1074
1075 return 0;
1076}
1077
be371fe0
LP
1078static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1079 char ***l = userdata;
1080 int r;
1081
1082 assert(bus);
1083 assert(member);
1084 assert(m);
1085 assert(l);
1086
1087 r = sd_bus_message_enter_container(m, 'a', "(iay)");
1088 if (r < 0)
1089 return r;
1090
1091 for (;;) {
1092 const void *a;
1093 char *pretty;
1094 int family;
1095 size_t sz;
1096
1097 r = sd_bus_message_enter_container(m, 'r', "iay");
1098 if (r < 0)
1099 return r;
1100 if (r == 0)
1101 break;
1102
1103 r = sd_bus_message_read(m, "i", &family);
1104 if (r < 0)
1105 return r;
1106
1107 r = sd_bus_message_read_array(m, 'y', &a, &sz);
1108 if (r < 0)
1109 return r;
1110
1111 r = sd_bus_message_exit_container(m);
1112 if (r < 0)
1113 return r;
1114
1115 if (!IN_SET(family, AF_INET, AF_INET6)) {
1116 log_debug("Unexpected family, ignoring.");
1117 continue;
1118 }
1119
1120 if (sz != FAMILY_ADDRESS_SIZE(family)) {
1121 log_debug("Address size mismatch, ignoring.");
1122 continue;
1123 }
1124
1125 r = in_addr_to_string(family, a, &pretty);
1126 if (r < 0)
1127 return r;
1128
1129 r = strv_consume(l, pretty);
1130 if (r < 0)
1131 return r;
1132 }
1133
1134 r = sd_bus_message_exit_container(m);
1135 if (r < 0)
1136 return r;
1137
1138 return 0;
1139}
1140
1141static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1142 char ***l = userdata;
1143 int r;
1144
1145 assert(bus);
1146 assert(member);
1147 assert(m);
1148 assert(l);
1149
1150 r = sd_bus_message_enter_container(m, 'a', "(sb)");
1151 if (r < 0)
1152 return r;
1153
1154 for (;;) {
1155 const char *domain;
1156 int route_only;
1157 char *pretty;
1158
1159 r = sd_bus_message_read(m, "(sb)", &domain, &route_only);
1160 if (r < 0)
1161 return r;
1162 if (r == 0)
1163 break;
1164
1165 if (route_only)
1166 pretty = strappend("~", domain);
1167 else
1168 pretty = strdup(domain);
1169 if (!pretty)
1170 return -ENOMEM;
1171
1172 r = strv_consume(l, pretty);
1173 if (r < 0)
1174 return r;
1175 }
1176
1177 r = sd_bus_message_exit_container(m);
1178 if (r < 0)
1179 return r;
1180
1181 return 0;
1182}
1183
1184static int status_ifindex(sd_bus *bus, int ifindex, const char *name, bool *empty_line) {
1185
1186 struct link_info {
1187 uint64_t scopes_mask;
1188 char *llmnr;
1189 char *mdns;
1190 char *dnssec;
1191 char **dns;
1192 char **domains;
1193 char **ntas;
1194 int dnssec_supported;
1195 } link_info = {};
1196
1197 static const struct bus_properties_map property_map[] = {
1198 { "ScopesMask", "t", NULL, offsetof(struct link_info, scopes_mask) },
1199 { "DNS", "a(iay)", map_link_dns_servers, offsetof(struct link_info, dns) },
1200 { "Domains", "a(sb)", map_link_domains, offsetof(struct link_info, domains) },
1201 { "LLMNR", "s", NULL, offsetof(struct link_info, llmnr) },
1202 { "MulticastDNS", "s", NULL, offsetof(struct link_info, mdns) },
1203 { "DNSSEC", "s", NULL, offsetof(struct link_info, dnssec) },
1204 { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct link_info, ntas) },
1205 { "DNSSECSupported", "b", NULL, offsetof(struct link_info, dnssec_supported) },
1206 {}
1207 };
1208
f9e0eefc 1209 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
be371fe0
LP
1210 _cleanup_free_ char *ifi = NULL, *p = NULL;
1211 char ifname[IF_NAMESIZE] = "";
1212 char **i;
1213 int r;
1214
1215 assert(bus);
1216 assert(ifindex > 0);
1217 assert(empty_line);
1218
1219 if (!name) {
1220 if (!if_indextoname(ifindex, ifname))
1221 return log_error_errno(errno, "Failed to resolve interface name for %i: %m", ifindex);
1222
1223 name = ifname;
1224 }
1225
1226 if (asprintf(&ifi, "%i", ifindex) < 0)
1227 return log_oom();
1228
1229 r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifi, &p);
1230 if (r < 0)
1231 return log_oom();
1232
1233 r = bus_map_all_properties(bus,
1234 "org.freedesktop.resolve1",
1235 p,
1236 property_map,
f9e0eefc 1237 &error,
be371fe0
LP
1238 &link_info);
1239 if (r < 0) {
f9e0eefc 1240 log_error_errno(r, "Failed to get link data for %i: %s", ifindex, bus_error_message(&error, r));
be371fe0
LP
1241 goto finish;
1242 }
1243
1244 pager_open(arg_no_pager, false);
1245
1246 if (*empty_line)
1247 fputc('\n', stdout);
1248
1249 printf("%sLink %i (%s)%s\n",
1250 ansi_highlight(), ifindex, name, ansi_normal());
1251
1252 if (link_info.scopes_mask == 0)
1253 printf(" Current Scopes: none\n");
1254 else
1255 printf(" Current Scopes:%s%s%s%s%s\n",
1256 link_info.scopes_mask & SD_RESOLVED_DNS ? " DNS" : "",
1257 link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
1258 link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "",
1259 link_info.scopes_mask & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4" : "",
1260 link_info.scopes_mask & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6" : "");
1261
1262 printf(" LLMNR setting: %s\n"
1263 "MulticastDNS setting: %s\n"
1264 " DNSSEC setting: %s\n"
1265 " DNSSEC supported: %s\n",
1266 strna(link_info.llmnr),
1267 strna(link_info.mdns),
1268 strna(link_info.dnssec),
1269 yes_no(link_info.dnssec_supported));
1270
1271 STRV_FOREACH(i, link_info.dns) {
7b7c1aac
ZJS
1272 printf(" %s %s\n",
1273 i == link_info.dns ? "DNS Servers:" : " ",
be371fe0
LP
1274 *i);
1275 }
1276
1277 STRV_FOREACH(i, link_info.domains) {
1278 printf(" %s %s\n",
1279 i == link_info.domains ? "DNS Domain:" : " ",
1280 *i);
1281 }
1282
1283 STRV_FOREACH(i, link_info.ntas) {
1284 printf(" %s %s\n",
1285 i == link_info.ntas ? "DNSSEC NTA:" : " ",
1286 *i);
1287 }
1288
1289 *empty_line = true;
1290
1291 r = 0;
1292
1293finish:
1294 strv_free(link_info.dns);
1295 strv_free(link_info.domains);
1296 free(link_info.llmnr);
1297 free(link_info.mdns);
1298 free(link_info.dnssec);
1299 strv_free(link_info.ntas);
1300 return r;
1301}
1302
1303static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1304 char ***l = userdata;
1305 int r;
1306
1307 assert(bus);
1308 assert(member);
1309 assert(m);
1310 assert(l);
1311
1312 r = sd_bus_message_enter_container(m, 'a', "(iiay)");
1313 if (r < 0)
1314 return r;
1315
1316 for (;;) {
1317 const void *a;
1318 char *pretty;
1319 int family, ifindex;
1320 size_t sz;
1321
1322 r = sd_bus_message_enter_container(m, 'r', "iiay");
1323 if (r < 0)
1324 return r;
1325 if (r == 0)
1326 break;
1327
1328 r = sd_bus_message_read(m, "ii", &ifindex, &family);
1329 if (r < 0)
1330 return r;
1331
1332 r = sd_bus_message_read_array(m, 'y', &a, &sz);
1333 if (r < 0)
1334 return r;
1335
1336 r = sd_bus_message_exit_container(m);
1337 if (r < 0)
1338 return r;
1339
1340 if (ifindex != 0) /* only show the global ones here */
1341 continue;
1342
1343 if (!IN_SET(family, AF_INET, AF_INET6)) {
1344 log_debug("Unexpected family, ignoring.");
1345 continue;
1346 }
1347
1348 if (sz != FAMILY_ADDRESS_SIZE(family)) {
1349 log_debug("Address size mismatch, ignoring.");
1350 continue;
1351 }
1352
1353 r = in_addr_to_string(family, a, &pretty);
1354 if (r < 0)
1355 return r;
1356
1357 r = strv_consume(l, pretty);
1358 if (r < 0)
1359 return r;
1360 }
1361
1362 r = sd_bus_message_exit_container(m);
1363 if (r < 0)
1364 return r;
1365
1366 return 0;
1367}
1368
1369static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1370 char ***l = userdata;
1371 int r;
1372
1373 assert(bus);
1374 assert(member);
1375 assert(m);
1376 assert(l);
1377
1378 r = sd_bus_message_enter_container(m, 'a', "(isb)");
1379 if (r < 0)
1380 return r;
1381
1382 for (;;) {
1383 const char *domain;
1384 int route_only, ifindex;
1385 char *pretty;
1386
1387 r = sd_bus_message_read(m, "(isb)", &ifindex, &domain, &route_only);
1388 if (r < 0)
1389 return r;
1390 if (r == 0)
1391 break;
1392
1393 if (ifindex != 0) /* only show the global ones here */
1394 continue;
1395
1396 if (route_only)
1397 pretty = strappend("~", domain);
1398 else
1399 pretty = strdup(domain);
1400 if (!pretty)
1401 return -ENOMEM;
1402
1403 r = strv_consume(l, pretty);
1404 if (r < 0)
1405 return r;
1406 }
1407
1408 r = sd_bus_message_exit_container(m);
1409 if (r < 0)
1410 return r;
1411
1412 return 0;
1413}
1414
1415static int status_global(sd_bus *bus, bool *empty_line) {
1416
1417 struct global_info {
1418 char **dns;
1419 char **domains;
1420 char **ntas;
1421 } global_info = {};
1422
1423 static const struct bus_properties_map property_map[] = {
1424 { "DNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, dns) },
1425 { "Domains", "a(isb)", map_global_domains, offsetof(struct global_info, domains) },
1426 { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct global_info, ntas) },
1427 {}
1428 };
1429
f9e0eefc 1430 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
be371fe0
LP
1431 char **i;
1432 int r;
1433
1434 assert(bus);
1435 assert(empty_line);
1436
1437 r = bus_map_all_properties(bus,
1438 "org.freedesktop.resolve1",
1439 "/org/freedesktop/resolve1",
1440 property_map,
f9e0eefc 1441 &error,
be371fe0
LP
1442 &global_info);
1443 if (r < 0) {
f9e0eefc 1444 log_error_errno(r, "Failed to get global data: %s", bus_error_message(&error, r));
be371fe0
LP
1445 goto finish;
1446 }
1447
1448 if (strv_isempty(global_info.dns) && strv_isempty(global_info.domains) && strv_isempty(global_info.ntas)) {
1449 r = 0;
1450 goto finish;
1451 }
1452
1453 pager_open(arg_no_pager, false);
1454
1455 printf("%sGlobal%s\n", ansi_highlight(), ansi_normal());
1456 STRV_FOREACH(i, global_info.dns) {
7b7c1aac
ZJS
1457 printf(" %s %s\n",
1458 i == global_info.dns ? "DNS Servers:" : " ",
be371fe0
LP
1459 *i);
1460 }
1461
1462 STRV_FOREACH(i, global_info.domains) {
1463 printf(" %s %s\n",
1464 i == global_info.domains ? "DNS Domain:" : " ",
1465 *i);
1466 }
1467
1468 strv_sort(global_info.ntas);
1469 STRV_FOREACH(i, global_info.ntas) {
1470 printf(" %s %s\n",
1471 i == global_info.ntas ? "DNSSEC NTA:" : " ",
1472 *i);
1473 }
1474
1475 *empty_line = true;
1476
1477 r = 0;
1478
1479finish:
1480 strv_free(global_info.dns);
1481 strv_free(global_info.domains);
1482 strv_free(global_info.ntas);
1483
1484 return r;
1485}
1486
1487static int status_all(sd_bus *bus) {
1488 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
1489 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
1490 sd_netlink_message *i;
96ace31d 1491 bool empty_line = false;
be371fe0
LP
1492 int r;
1493
1494 assert(bus);
1495
1496 r = status_global(bus, &empty_line);
1497 if (r < 0)
1498 return r;
1499
1500 r = sd_netlink_open(&rtnl);
1501 if (r < 0)
1502 return log_error_errno(r, "Failed to connect to netlink: %m");
1503
1504 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
1505 if (r < 0)
1506 return rtnl_log_create_error(r);
1507
1508 r = sd_netlink_message_request_dump(req, true);
1509 if (r < 0)
1510 return rtnl_log_create_error(r);
1511
1512 r = sd_netlink_call(rtnl, req, 0, &reply);
1513 if (r < 0)
1514 return log_error_errno(r, "Failed to enumerate links: %m");
1515
1516 r = 0;
1517 for (i = reply; i; i = sd_netlink_message_next(i)) {
1518 const char *name;
1519 int ifindex, q;
1520 uint16_t type;
1521
1522 q = sd_netlink_message_get_type(i, &type);
1523 if (q < 0)
1524 return rtnl_log_parse_error(q);
1525
1526 if (type != RTM_NEWLINK)
1527 continue;
1528
1529 q = sd_rtnl_message_link_get_ifindex(i, &ifindex);
1530 if (q < 0)
1531 return rtnl_log_parse_error(q);
1532
1533 if (ifindex == LOOPBACK_IFINDEX)
1534 continue;
1535
1536 q = sd_netlink_message_read_string(i, IFLA_IFNAME, &name);
1537 if (q < 0)
1538 return rtnl_log_parse_error(q);
1539
1540 q = status_ifindex(bus, ifindex, name, &empty_line);
1541 if (q < 0 && r >= 0)
1542 r = q;
1543 }
1544
1545 return r;
1546}
1547
ba82da3b
ZJS
1548static void help_protocol_types(void) {
1549 if (arg_legend)
1550 puts("Known protocol types:");
062aabb9 1551 puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6\nmdns\nmnds-ipv4\nmdns-ipv6");
ba82da3b
ZJS
1552}
1553
b93312f5 1554static void help_dns_types(void) {
b93312f5 1555 const char *t;
be371fe0 1556 int i;
b93312f5
ZJS
1557
1558 if (arg_legend)
09b1fe14 1559 puts("Known DNS RR types:");
b93312f5
ZJS
1560 for (i = 0; i < _DNS_TYPE_MAX; i++) {
1561 t = dns_type_to_string(i);
1562 if (t)
1563 puts(t);
1564 }
1565}
1566
1567static void help_dns_classes(void) {
b93312f5 1568 const char *t;
be371fe0 1569 int i;
b93312f5
ZJS
1570
1571 if (arg_legend)
09b1fe14 1572 puts("Known DNS RR classes:");
b93312f5
ZJS
1573 for (i = 0; i < _DNS_CLASS_MAX; i++) {
1574 t = dns_class_to_string(i);
1575 if (t)
1576 puts(t);
1577 }
1578}
1579
bdef7319 1580static void help(void) {
1ace2438
ZJS
1581 printf("%1$s [OPTIONS...] HOSTNAME|ADDRESS...\n"
1582 "%1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n"
1583 "%1$s [OPTIONS...] --openpgp EMAIL@DOMAIN...\n"
1584 "%1$s [OPTIONS...] --statistics\n"
1585 "%1$s [OPTIONS...] --reset-statistics\n"
1586 "\n"
90b4a64d 1587 "Resolve domain names, IPv4 and IPv6 addresses, DNS records, and services.\n\n"
1ace2438
ZJS
1588 " -h --help Show this help\n"
1589 " --version Show package version\n"
be371fe0 1590 " --no-pager Do not pipe output into a pager\n"
1ace2438
ZJS
1591 " -4 Resolve IPv4 addresses\n"
1592 " -6 Resolve IPv6 addresses\n"
1593 " -i --interface=INTERFACE Look on interface\n"
1594 " -p --protocol=PROTO|help Look via protocol\n"
1595 " -t --type=TYPE|help Query RR with DNS type\n"
1596 " -c --class=CLASS|help Query RR with DNS class\n"
1597 " --service Resolve service (SRV)\n"
1598 " --service-address=BOOL Resolve address for services (default: yes)\n"
1599 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
1600 " --openpgp Query OpenPGP public key\n"
82d1d240 1601 " --tlsa Query TLS public key\n"
1ace2438
ZJS
1602 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
1603 " --search=BOOL Use search domains for single-label names\n"
1604 " (default: yes)\n"
dab48ea6 1605 " --raw[=payload|packet] Dump the answer as binary data\n"
1ace2438
ZJS
1606 " --legend=BOOL Print headers and additional info (default: yes)\n"
1607 " --statistics Show resolver statistics\n"
1608 " --reset-statistics Reset resolver statistics\n"
be371fe0 1609 " --status Show link and server status\n"
ba35662f 1610 " --flush-caches Flush all local DNS caches\n"
d55b0463
LP
1611 " --reset-server-features\n"
1612 " Forget learnt DNS server feature levels\n"
1ace2438 1613 , program_invocation_short_name);
bdef7319
ZJS
1614}
1615
1616static int parse_argv(int argc, char *argv[]) {
1617 enum {
1618 ARG_VERSION = 0x100,
dad29dff 1619 ARG_LEGEND,
45ec7efb
LP
1620 ARG_SERVICE,
1621 ARG_CNAME,
1622 ARG_SERVICE_ADDRESS,
1623 ARG_SERVICE_TXT,
4ac2ca1b 1624 ARG_OPENPGP,
82d1d240 1625 ARG_TLSA,
2e74028a 1626 ARG_RAW,
801ad6a6 1627 ARG_SEARCH,
a150ff5e
LP
1628 ARG_STATISTICS,
1629 ARG_RESET_STATISTICS,
be371fe0 1630 ARG_STATUS,
ba35662f 1631 ARG_FLUSH_CACHES,
d55b0463 1632 ARG_RESET_SERVER_FEATURES,
be371fe0 1633 ARG_NO_PAGER,
bdef7319
ZJS
1634 };
1635
1636 static const struct option options[] = {
d55b0463
LP
1637 { "help", no_argument, NULL, 'h' },
1638 { "version", no_argument, NULL, ARG_VERSION },
1639 { "type", required_argument, NULL, 't' },
1640 { "class", required_argument, NULL, 'c' },
1641 { "legend", required_argument, NULL, ARG_LEGEND },
1642 { "interface", required_argument, NULL, 'i' },
1643 { "protocol", required_argument, NULL, 'p' },
1644 { "cname", required_argument, NULL, ARG_CNAME },
1645 { "service", no_argument, NULL, ARG_SERVICE },
1646 { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
1647 { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
1648 { "openpgp", no_argument, NULL, ARG_OPENPGP },
1649 { "tlsa", optional_argument, NULL, ARG_TLSA },
1650 { "raw", optional_argument, NULL, ARG_RAW },
1651 { "search", required_argument, NULL, ARG_SEARCH },
1652 { "statistics", no_argument, NULL, ARG_STATISTICS, },
1653 { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
1654 { "status", no_argument, NULL, ARG_STATUS },
1655 { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES },
1656 { "reset-server-features", no_argument, NULL, ARG_RESET_SERVER_FEATURES },
1657 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
bdef7319
ZJS
1658 {}
1659 };
1660
2d4c5cbc 1661 int c, r;
bdef7319
ZJS
1662
1663 assert(argc >= 0);
1664 assert(argv);
1665
51323288 1666 while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
bdef7319
ZJS
1667 switch(c) {
1668
1669 case 'h':
1670 help();
1671 return 0; /* done */;
1672
1673 case ARG_VERSION:
3f6fd1ba 1674 return version();
bdef7319
ZJS
1675
1676 case '4':
1677 arg_family = AF_INET;
1678 break;
1679
1680 case '6':
1681 arg_family = AF_INET6;
1682 break;
1683
3fa4999b
LP
1684 case 'i': {
1685 int ifi;
1686
6ad623a3 1687 if (parse_ifindex(optarg, &ifi) >= 0)
3fa4999b
LP
1688 arg_ifindex = ifi;
1689 else {
1690 ifi = if_nametoindex(optarg);
1691 if (ifi <= 0)
1692 return log_error_errno(errno, "Unknown interface %s: %m", optarg);
1693
1694 arg_ifindex = ifi;
1695 }
1696
2d4c5cbc 1697 break;
3fa4999b 1698 }
2d4c5cbc
LP
1699
1700 case 't':
b93312f5
ZJS
1701 if (streq(optarg, "help")) {
1702 help_dns_types();
1703 return 0;
1704 }
1705
4b548ef3
LP
1706 r = dns_type_from_string(optarg);
1707 if (r < 0) {
2d4c5cbc 1708 log_error("Failed to parse RR record type %s", optarg);
4b548ef3 1709 return r;
2d4c5cbc 1710 }
4b548ef3
LP
1711 arg_type = (uint16_t) r;
1712 assert((int) arg_type == r);
b93312f5 1713
a150ff5e 1714 arg_mode = MODE_RESOLVE_RECORD;
2d4c5cbc
LP
1715 break;
1716
1717 case 'c':
b93312f5
ZJS
1718 if (streq(optarg, "help")) {
1719 help_dns_classes();
1720 return 0;
1721 }
1722
4b548ef3 1723 r = dns_class_from_string(optarg);
2d4c5cbc
LP
1724 if (r < 0) {
1725 log_error("Failed to parse RR record class %s", optarg);
1726 return r;
bdef7319 1727 }
4b548ef3
LP
1728 arg_class = (uint16_t) r;
1729 assert((int) arg_class == r);
b93312f5
ZJS
1730
1731 break;
1732
dad29dff 1733 case ARG_LEGEND:
45ec7efb
LP
1734 r = parse_boolean(optarg);
1735 if (r < 0)
1736 return log_error_errno(r, "Failed to parse --legend= argument");
1737
1738 arg_legend = r;
bdef7319
ZJS
1739 break;
1740
51323288 1741 case 'p':
ba82da3b
ZJS
1742 if (streq(optarg, "help")) {
1743 help_protocol_types();
1744 return 0;
1745 } else if (streq(optarg, "dns"))
51323288
LP
1746 arg_flags |= SD_RESOLVED_DNS;
1747 else if (streq(optarg, "llmnr"))
1748 arg_flags |= SD_RESOLVED_LLMNR;
1749 else if (streq(optarg, "llmnr-ipv4"))
1750 arg_flags |= SD_RESOLVED_LLMNR_IPV4;
1751 else if (streq(optarg, "llmnr-ipv6"))
1752 arg_flags |= SD_RESOLVED_LLMNR_IPV6;
062aabb9
DR
1753 else if (streq(optarg, "mdns"))
1754 arg_flags |= SD_RESOLVED_MDNS;
1755 else if (streq(optarg, "mdns-ipv4"))
1756 arg_flags |= SD_RESOLVED_MDNS_IPV4;
1757 else if (streq(optarg, "mdns-ipv6"))
1758 arg_flags |= SD_RESOLVED_MDNS_IPV6;
51323288
LP
1759 else {
1760 log_error("Unknown protocol specifier: %s", optarg);
1761 return -EINVAL;
1762 }
1763
1764 break;
1765
45ec7efb 1766 case ARG_SERVICE:
a150ff5e 1767 arg_mode = MODE_RESOLVE_SERVICE;
45ec7efb
LP
1768 break;
1769
4ac2ca1b
ZJS
1770 case ARG_OPENPGP:
1771 arg_mode = MODE_RESOLVE_OPENPGP;
1772 break;
1773
82d1d240
ZJS
1774 case ARG_TLSA:
1775 arg_mode = MODE_RESOLVE_TLSA;
1776 arg_service_family = service_family_from_string(optarg);
1777 if (arg_service_family < 0) {
1778 log_error("Unknown service family \"%s\".", optarg);
1779 return -EINVAL;
1780 }
1781 break;
1782
2e74028a
ZJS
1783 case ARG_RAW:
1784 if (on_tty()) {
1785 log_error("Refusing to write binary data to tty.");
1786 return -ENOTTY;
1787 }
1788
dab48ea6
ZJS
1789 if (optarg == NULL || streq(optarg, "payload"))
1790 arg_raw = RAW_PAYLOAD;
1791 else if (streq(optarg, "packet"))
1792 arg_raw = RAW_PACKET;
1793 else {
1794 log_error("Unknown --raw specifier \"%s\".", optarg);
1795 return -EINVAL;
1796 }
1797
2e74028a
ZJS
1798 arg_legend = false;
1799 break;
1800
45ec7efb
LP
1801 case ARG_CNAME:
1802 r = parse_boolean(optarg);
1803 if (r < 0)
1804 return log_error_errno(r, "Failed to parse --cname= argument.");
5883ff60 1805 SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0);
45ec7efb
LP
1806 break;
1807
1808 case ARG_SERVICE_ADDRESS:
1809 r = parse_boolean(optarg);
1810 if (r < 0)
1811 return log_error_errno(r, "Failed to parse --service-address= argument.");
5883ff60 1812 SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0);
45ec7efb
LP
1813 break;
1814
1815 case ARG_SERVICE_TXT:
1816 r = parse_boolean(optarg);
1817 if (r < 0)
1818 return log_error_errno(r, "Failed to parse --service-txt= argument.");
5883ff60 1819 SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
45ec7efb
LP
1820 break;
1821
801ad6a6
LP
1822 case ARG_SEARCH:
1823 r = parse_boolean(optarg);
1824 if (r < 0)
1825 return log_error_errno(r, "Failed to parse --search argument.");
5883ff60 1826 SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0);
801ad6a6
LP
1827 break;
1828
a150ff5e
LP
1829 case ARG_STATISTICS:
1830 arg_mode = MODE_STATISTICS;
1831 break;
1832
1833 case ARG_RESET_STATISTICS:
1834 arg_mode = MODE_RESET_STATISTICS;
1835 break;
1836
ba35662f
LP
1837 case ARG_FLUSH_CACHES:
1838 arg_mode = MODE_FLUSH_CACHES;
1839 break;
1840
d55b0463
LP
1841 case ARG_RESET_SERVER_FEATURES:
1842 arg_mode = MODE_RESET_SERVER_FEATURES;
1843 break;
1844
be371fe0
LP
1845 case ARG_STATUS:
1846 arg_mode = MODE_STATUS;
1847 break;
1848
1849 case ARG_NO_PAGER:
1850 arg_no_pager = true;
1851 break;
1852
bdef7319
ZJS
1853 case '?':
1854 return -EINVAL;
1855
1856 default:
1857 assert_not_reached("Unhandled option");
1858 }
1859
2d4c5cbc 1860 if (arg_type == 0 && arg_class != 0) {
45ec7efb
LP
1861 log_error("--class= may only be used in conjunction with --type=.");
1862 return -EINVAL;
1863 }
1864
82d1d240 1865 if (arg_type != 0 && arg_mode == MODE_RESOLVE_SERVICE) {
45ec7efb 1866 log_error("--service and --type= may not be combined.");
2d4c5cbc
LP
1867 return -EINVAL;
1868 }
1869
1870 if (arg_type != 0 && arg_class == 0)
1871 arg_class = DNS_CLASS_IN;
1872
c1dafe4f
LP
1873 if (arg_class != 0 && arg_type == 0)
1874 arg_type = DNS_TYPE_A;
1875
bdef7319
ZJS
1876 return 1 /* work to do */;
1877}
1878
bdef7319 1879int main(int argc, char **argv) {
4afd3348 1880 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
bdef7319
ZJS
1881 int r;
1882
1883 log_parse_environment();
1884 log_open();
1885
1886 r = parse_argv(argc, argv);
1887 if (r <= 0)
79266746
LP
1888 goto finish;
1889
bdef7319
ZJS
1890 r = sd_bus_open_system(&bus);
1891 if (r < 0) {
da927ba9 1892 log_error_errno(r, "sd_bus_open_system: %m");
79266746 1893 goto finish;
bdef7319
ZJS
1894 }
1895
a150ff5e 1896 switch (arg_mode) {
45ec7efb 1897
a150ff5e
LP
1898 case MODE_RESOLVE_HOST:
1899 if (optind >= argc) {
300a716d 1900 log_error("No arguments passed.");
a150ff5e
LP
1901 r = -EINVAL;
1902 goto finish;
1903 }
1904
1905 while (argv[optind]) {
1906 int family, ifindex, k;
1907 union in_addr_union a;
1908
c1dafe4f
LP
1909 if (startswith(argv[optind], "dns:"))
1910 k = resolve_rfc4501(bus, argv[optind]);
1911 else {
145fab1e 1912 k = in_addr_ifindex_from_string_auto(argv[optind], &family, &a, &ifindex);
c1dafe4f
LP
1913 if (k >= 0)
1914 k = resolve_address(bus, family, &a, ifindex);
1915 else
1916 k = resolve_host(bus, argv[optind]);
1917 }
a150ff5e
LP
1918
1919 if (r == 0)
1920 r = k;
1921
1922 optind++;
1923 }
1924 break;
1925
1926 case MODE_RESOLVE_RECORD:
1927 if (optind >= argc) {
300a716d 1928 log_error("No arguments passed.");
a150ff5e
LP
1929 r = -EINVAL;
1930 goto finish;
1931 }
1932
1933 while (argv[optind]) {
1934 int k;
1935
a60f4d0b 1936 k = resolve_record(bus, argv[optind], arg_class, arg_type, true);
a150ff5e
LP
1937 if (r == 0)
1938 r = k;
1939
1940 optind++;
1941 }
1942 break;
1943
1944 case MODE_RESOLVE_SERVICE:
45ec7efb
LP
1945 if (argc < optind + 1) {
1946 log_error("Domain specification required.");
1947 r = -EINVAL;
1948 goto finish;
1949
1950 } else if (argc == optind + 1)
1951 r = resolve_service(bus, NULL, NULL, argv[optind]);
1952 else if (argc == optind + 2)
1953 r = resolve_service(bus, NULL, argv[optind], argv[optind+1]);
1954 else if (argc == optind + 3)
1955 r = resolve_service(bus, argv[optind], argv[optind+1], argv[optind+2]);
1956 else {
300a716d 1957 log_error("Too many arguments.");
45ec7efb
LP
1958 r = -EINVAL;
1959 goto finish;
1960 }
1961
a150ff5e 1962 break;
79266746 1963
4ac2ca1b
ZJS
1964 case MODE_RESOLVE_OPENPGP:
1965 if (argc < optind + 1) {
1966 log_error("E-mail address required.");
1967 r = -EINVAL;
1968 goto finish;
1969
1970 }
1971
1972 r = 0;
1973 while (optind < argc) {
1974 int k;
1975
1976 k = resolve_openpgp(bus, argv[optind++]);
1977 if (k < 0)
1978 r = k;
1979 }
1980 break;
1981
82d1d240
ZJS
1982 case MODE_RESOLVE_TLSA:
1983 if (argc < optind + 1) {
1984 log_error("Domain name required.");
1985 r = -EINVAL;
1986 goto finish;
1987
1988 }
1989
1990 r = 0;
1991 while (optind < argc) {
1992 int k;
1993
1994 k = resolve_tlsa(bus, argv[optind++]);
1995 if (k < 0)
1996 r = k;
1997 }
1998 break;
1999
a150ff5e
LP
2000 case MODE_STATISTICS:
2001 if (argc > optind) {
2002 log_error("Too many arguments.");
2003 r = -EINVAL;
2004 goto finish;
2d4c5cbc 2005 }
bdef7319 2006
a150ff5e
LP
2007 r = show_statistics(bus);
2008 break;
2009
2010 case MODE_RESET_STATISTICS:
2011 if (argc > optind) {
2012 log_error("Too many arguments.");
2013 r = -EINVAL;
2014 goto finish;
2015 }
79266746 2016
a150ff5e
LP
2017 r = reset_statistics(bus);
2018 break;
ba35662f
LP
2019
2020 case MODE_FLUSH_CACHES:
2021 if (argc > optind) {
2022 log_error("Too many arguments.");
2023 r = -EINVAL;
2024 goto finish;
2025 }
2026
2027 r = flush_caches(bus);
2028 break;
be371fe0 2029
d55b0463
LP
2030 case MODE_RESET_SERVER_FEATURES:
2031 if (argc > optind) {
2032 log_error("Too many arguments.");
2033 r = -EINVAL;
2034 goto finish;
2035 }
2036
2037 r = reset_server_features(bus);
2038 break;
2039
be371fe0
LP
2040 case MODE_STATUS:
2041
2042 if (argc > optind) {
2043 char **ifname;
2044 bool empty_line = false;
2045
2046 r = 0;
2047 STRV_FOREACH(ifname, argv + optind) {
2048 int ifindex, q;
2049
2050 q = parse_ifindex(argv[optind], &ifindex);
2051 if (q < 0) {
2052 ifindex = if_nametoindex(argv[optind]);
2053 if (ifindex <= 0) {
2054 log_error_errno(errno, "Failed to resolve interface name: %s", argv[optind]);
2055 continue;
2056 }
2057 }
2058
2059 q = status_ifindex(bus, ifindex, NULL, &empty_line);
2060 if (q < 0 && r >= 0)
2061 r = q;
2062 }
2063 } else
2064 r = status_all(bus);
2065
2066 break;
bdef7319
ZJS
2067 }
2068
79266746 2069finish:
be371fe0
LP
2070 pager_close();
2071
bdef7319
ZJS
2072 return r == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
2073}