]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolvectl.c
tree-wide: drop 'This file is part of systemd' blurb
[thirdparty/systemd.git] / src / resolve / resolvectl.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
bdef7319 2/***
bdef7319 3 Copyright 2014 Zbigniew Jędrzejewski-Szmek
bdef7319
ZJS
4***/
5
bdef7319 6#include <getopt.h>
cf0fbc49 7#include <net/if.h>
bdef7319
ZJS
8
9#include "sd-bus.h"
be371fe0 10#include "sd-netlink.h"
3f6fd1ba
LP
11
12#include "af-list.h"
b5efdb8a 13#include "alloc-util.h"
14965b94 14#include "bus-common-errors.h"
bdef7319 15#include "bus-error.h"
3f6fd1ba 16#include "bus-util.h"
14965b94 17#include "dns-domain.h"
45ec7efb 18#include "escape.h"
4ac2ca1b 19#include "gcrypt-util.h"
be371fe0
LP
20#include "in-addr-util.h"
21#include "netlink-util.h"
22#include "pager.h"
6bedfcbb 23#include "parse-util.h"
088c1363 24#include "resolvconf-compat.h"
c2e84cab 25#include "resolvectl.h"
51323288 26#include "resolved-def.h"
3f6fd1ba 27#include "resolved-dns-packet.h"
5c828e66 28#include "string-table.h"
be371fe0 29#include "strv.h"
a150ff5e 30#include "terminal-util.h"
a7a4c60a 31#include "verbs.h"
2d4c5cbc 32
bdef7319 33static int arg_family = AF_UNSPEC;
088c1363 34int arg_ifindex = 0;
a7a4c60a 35const char *arg_ifname = NULL;
4b548ef3 36static uint16_t arg_type = 0;
2d4c5cbc 37static uint16_t arg_class = 0;
b93312f5 38static bool arg_legend = true;
51323288 39static uint64_t arg_flags = 0;
be371fe0 40static bool arg_no_pager = false;
088c1363 41bool arg_ifindex_permissive = false; /* If true, don't generate an error if the specified interface index doesn't exist */
a7a4c60a 42static const char *arg_service_family = NULL;
82d1d240 43
dab48ea6
ZJS
44typedef enum RawType {
45 RAW_NONE,
46 RAW_PAYLOAD,
47 RAW_PACKET,
48} RawType;
dab48ea6 49static RawType arg_raw = RAW_NONE;
a150ff5e 50
088c1363
LP
51ExecutionMode arg_mode = MODE_RESOLVE_HOST;
52
a7a4c60a 53char **arg_set_dns = NULL;
088c1363 54char **arg_set_domain = NULL;
a7a4c60a
YW
55static const char *arg_set_llmnr = NULL;
56static const char *arg_set_mdns = NULL;
c9299be2 57static const char *arg_set_dns_over_tls = NULL;
a7a4c60a 58static const char *arg_set_dnssec = NULL;
14965b94
LP
59static char **arg_set_nta = NULL;
60
a7a4c60a
YW
61typedef enum StatusMode {
62 STATUS_ALL,
63 STATUS_DNS,
64 STATUS_DOMAIN,
65 STATUS_LLMNR,
66 STATUS_MDNS,
d050561a 67 STATUS_PRIVATE,
a7a4c60a
YW
68 STATUS_DNSSEC,
69 STATUS_NTA,
70} StatusMode;
71
72static int parse_ifindex_with_warn(const char *s) {
73 int ifi;
74
75 assert(s);
76
77 if (parse_ifindex(s, &ifi) < 0) {
78 ifi = if_nametoindex(s);
79 if (ifi <= 0)
80 return log_error_errno(errno, "Unknown interface %s: %m", s);
81 }
82
83 return ifi;
84}
85
78c6a153 86static void print_source(uint64_t flags, usec_t rtt) {
74998408 87 char rtt_str[FORMAT_TIMESTAMP_MAX];
51323288
LP
88
89 if (!arg_legend)
90 return;
91
78c6a153 92 if (flags == 0)
51323288
LP
93 return;
94
95 fputs("\n-- Information acquired via", stdout);
96
97 if (flags != 0)
786c8e9f 98 printf(" protocol%s%s%s%s%s",
51323288
LP
99 flags & SD_RESOLVED_DNS ? " DNS" :"",
100 flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
786c8e9f 101 flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "",
44ccb3d7
YW
102 flags & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4" : "",
103 flags & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6" : "");
51323288 104
74998408
TG
105 assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100));
106
107 printf(" in %s", rtt_str);
108
51323288
LP
109 fputc('.', stdout);
110 fputc('\n', stdout);
931851e8
LP
111
112 printf("-- Data is authenticated: %s\n", yes_no(flags & SD_RESOLVED_AUTHENTICATED));
51323288 113}
bdef7319 114
79266746 115static int resolve_host(sd_bus *bus, const char *name) {
4afd3348
LP
116 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
117 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
79266746 118 const char *canonical = NULL;
78c6a153 119 char ifname[IF_NAMESIZE] = "";
bdef7319 120 unsigned c = 0;
78c6a153 121 int r;
51323288 122 uint64_t flags;
74998408 123 usec_t ts;
bdef7319
ZJS
124
125 assert(name);
126
78c6a153
LP
127 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
128 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
129
130 log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
bdef7319
ZJS
131
132 r = sd_bus_message_new_method_call(
133 bus,
134 &req,
135 "org.freedesktop.resolve1",
136 "/org/freedesktop/resolve1",
137 "org.freedesktop.resolve1.Manager",
138 "ResolveHostname");
02dd6e18
LP
139 if (r < 0)
140 return bus_log_create_error(r);
bdef7319 141
51323288 142 r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
02dd6e18
LP
143 if (r < 0)
144 return bus_log_create_error(r);
bdef7319 145
74998408
TG
146 ts = now(CLOCK_MONOTONIC);
147
4cbfd62b 148 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
45ec7efb
LP
149 if (r < 0)
150 return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(&error, r));
bdef7319 151
74998408
TG
152 ts = now(CLOCK_MONOTONIC) - ts;
153
78c6a153 154 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
02dd6e18
LP
155 if (r < 0)
156 return bus_log_parse_error(r);
bdef7319 157
78c6a153 158 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
bdef7319 159 _cleanup_free_ char *pretty = NULL;
78c6a153 160 int ifindex, family;
45ec7efb
LP
161 const void *a;
162 size_t sz;
78c6a153
LP
163
164 assert_cc(sizeof(int) == sizeof(int32_t));
bdef7319 165
78c6a153 166 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
02dd6e18
LP
167 if (r < 0)
168 return bus_log_parse_error(r);
bdef7319
ZJS
169
170 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
02dd6e18
LP
171 if (r < 0)
172 return bus_log_parse_error(r);
bdef7319 173
bdef7319 174 r = sd_bus_message_exit_container(reply);
02dd6e18
LP
175 if (r < 0)
176 return bus_log_parse_error(r);
bdef7319 177
79266746 178 if (!IN_SET(family, AF_INET, AF_INET6)) {
be636413 179 log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
bdef7319
ZJS
180 continue;
181 }
182
183 if (sz != FAMILY_ADDRESS_SIZE(family)) {
78c6a153 184 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
45ec7efb 185 return -EINVAL;
bdef7319
ZJS
186 }
187
78c6a153
LP
188 ifname[0] = 0;
189 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
190 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
bdef7319 191
145fab1e 192 r = in_addr_ifindex_to_string(family, a, ifindex, &pretty);
78c6a153
LP
193 if (r < 0)
194 return log_error_errno(r, "Failed to print address for %s: %m", name);
bdef7319 195
79266746
LP
196 printf("%*s%s %s%s%s\n",
197 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
198 pretty,
199 isempty(ifname) ? "" : "%", ifname);
bdef7319
ZJS
200
201 c++;
202 }
79266746
LP
203 if (r < 0)
204 return bus_log_parse_error(r);
205
206 r = sd_bus_message_exit_container(reply);
207 if (r < 0)
208 return bus_log_parse_error(r);
209
51323288 210 r = sd_bus_message_read(reply, "st", &canonical, &flags);
79266746
LP
211 if (r < 0)
212 return bus_log_parse_error(r);
213
ece174c5 214 if (!streq(name, canonical))
79266746
LP
215 printf("%*s%s (%s)\n",
216 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
217 canonical);
bdef7319
ZJS
218
219 if (c == 0) {
220 log_error("%s: no addresses found", name);
79266746
LP
221 return -ESRCH;
222 }
223
78c6a153 224 print_source(flags, ts);
51323288 225
79266746
LP
226 return 0;
227}
228
229static int resolve_address(sd_bus *bus, int family, const union in_addr_union *address, int ifindex) {
4afd3348
LP
230 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
231 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
79266746
LP
232 _cleanup_free_ char *pretty = NULL;
233 char ifname[IF_NAMESIZE] = "";
51323288 234 uint64_t flags;
79266746 235 unsigned c = 0;
74998408 236 usec_t ts;
79266746
LP
237 int r;
238
239 assert(bus);
240 assert(IN_SET(family, AF_INET, AF_INET6));
241 assert(address);
242
78c6a153
LP
243 if (ifindex <= 0)
244 ifindex = arg_ifindex;
245
145fab1e 246 r = in_addr_ifindex_to_string(family, address, ifindex, &pretty);
79266746
LP
247 if (r < 0)
248 return log_oom();
249
78c6a153
LP
250 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
251 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
79266746
LP
252
253 log_debug("Resolving %s%s%s.", pretty, isempty(ifname) ? "" : "%", ifname);
254
255 r = sd_bus_message_new_method_call(
256 bus,
257 &req,
258 "org.freedesktop.resolve1",
259 "/org/freedesktop/resolve1",
260 "org.freedesktop.resolve1.Manager",
261 "ResolveAddress");
262 if (r < 0)
263 return bus_log_create_error(r);
264
51323288 265 r = sd_bus_message_append(req, "ii", ifindex, family);
79266746
LP
266 if (r < 0)
267 return bus_log_create_error(r);
268
269 r = sd_bus_message_append_array(req, 'y', address, FAMILY_ADDRESS_SIZE(family));
270 if (r < 0)
271 return bus_log_create_error(r);
272
51323288 273 r = sd_bus_message_append(req, "t", arg_flags);
79266746
LP
274 if (r < 0)
275 return bus_log_create_error(r);
276
74998408
TG
277 ts = now(CLOCK_MONOTONIC);
278
4cbfd62b 279 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
79266746
LP
280 if (r < 0) {
281 log_error("%s: resolve call failed: %s", pretty, bus_error_message(&error, r));
282 return r;
283 }
284
74998408
TG
285 ts = now(CLOCK_MONOTONIC) - ts;
286
78c6a153 287 r = sd_bus_message_enter_container(reply, 'a', "(is)");
79266746
LP
288 if (r < 0)
289 return bus_log_create_error(r);
290
78c6a153
LP
291 while ((r = sd_bus_message_enter_container(reply, 'r', "is")) > 0) {
292 const char *n;
293
294 assert_cc(sizeof(int) == sizeof(int32_t));
79266746 295
78c6a153
LP
296 r = sd_bus_message_read(reply, "is", &ifindex, &n);
297 if (r < 0)
298 return r;
299
300 r = sd_bus_message_exit_container(reply);
301 if (r < 0)
302 return r;
303
304 ifname[0] = 0;
305 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
306 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
307
308 printf("%*s%*s%*s%s %s\n",
79266746 309 (int) strlen(pretty), c == 0 ? pretty : "",
78c6a153
LP
310 isempty(ifname) ? 0 : 1, c > 0 || isempty(ifname) ? "" : "%",
311 (int) strlen(ifname), c == 0 ? ifname : "",
79266746
LP
312 c == 0 ? ":" : " ",
313 n);
314
315 c++;
bdef7319 316 }
79266746
LP
317 if (r < 0)
318 return bus_log_parse_error(r);
bdef7319 319
02dd6e18
LP
320 r = sd_bus_message_exit_container(reply);
321 if (r < 0)
322 return bus_log_parse_error(r);
323
51323288
LP
324 r = sd_bus_message_read(reply, "t", &flags);
325 if (r < 0)
326 return bus_log_parse_error(r);
327
79266746
LP
328 if (c == 0) {
329 log_error("%s: no names found", pretty);
330 return -ESRCH;
331 }
332
78c6a153 333 print_source(flags, ts);
51323288 334
79266746
LP
335 return 0;
336}
337
dab48ea6
ZJS
338static int output_rr_packet(const void *d, size_t l, int ifindex) {
339 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
340 _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL;
341 int r;
342 char ifname[IF_NAMESIZE] = "";
343
51027656 344 r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX);
dab48ea6
ZJS
345 if (r < 0)
346 return log_oom();
347
348 p->refuse_compression = true;
349
350 r = dns_packet_append_blob(p, d, l, NULL);
351 if (r < 0)
352 return log_oom();
353
354 r = dns_packet_read_rr(p, &rr, NULL, NULL);
355 if (r < 0)
356 return log_error_errno(r, "Failed to parse RR: %m");
357
358 if (arg_raw == RAW_PAYLOAD) {
359 void *data;
360 ssize_t k;
361
362 k = dns_resource_record_payload(rr, &data);
363 if (k < 0)
364 return log_error_errno(k, "Cannot dump RR: %m");
365 fwrite(data, 1, k, stdout);
366 } else {
367 const char *s;
368
369 s = dns_resource_record_to_string(rr);
370 if (!s)
371 return log_oom();
372
373 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
374 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
375
376 printf("%s%s%s\n", s, isempty(ifname) ? "" : " # interface ", ifname);
377 }
378
379 return 0;
380}
381
a60f4d0b 382static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type, bool warn_missing) {
4afd3348
LP
383 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
384 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
78c6a153 385 char ifname[IF_NAMESIZE] = "";
2d4c5cbc 386 unsigned n = 0;
51323288 387 uint64_t flags;
78c6a153 388 int r;
74998408 389 usec_t ts;
41815a4a 390 bool needs_authentication = false;
2d4c5cbc
LP
391
392 assert(name);
393
78c6a153
LP
394 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
395 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
396
c1dafe4f 397 log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(ifname) ? "*" : ifname);
2d4c5cbc
LP
398
399 r = sd_bus_message_new_method_call(
400 bus,
401 &req,
402 "org.freedesktop.resolve1",
403 "/org/freedesktop/resolve1",
404 "org.freedesktop.resolve1.Manager",
405 "ResolveRecord");
406 if (r < 0)
407 return bus_log_create_error(r);
408
c1dafe4f 409 r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, class, type, arg_flags);
2d4c5cbc
LP
410 if (r < 0)
411 return bus_log_create_error(r);
412
74998408
TG
413 ts = now(CLOCK_MONOTONIC);
414
4cbfd62b 415 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
2d4c5cbc 416 if (r < 0) {
a60f4d0b
SS
417 if (warn_missing || r != -ENXIO)
418 log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
2d4c5cbc
LP
419 return r;
420 }
421
74998408
TG
422 ts = now(CLOCK_MONOTONIC) - ts;
423
78c6a153 424 r = sd_bus_message_enter_container(reply, 'a', "(iqqay)");
51323288
LP
425 if (r < 0)
426 return bus_log_parse_error(r);
427
78c6a153 428 while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
2d4c5cbc 429 uint16_t c, t;
78c6a153 430 int ifindex;
2d4c5cbc
LP
431 const void *d;
432 size_t l;
433
78c6a153
LP
434 assert_cc(sizeof(int) == sizeof(int32_t));
435
436 r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t);
2d4c5cbc
LP
437 if (r < 0)
438 return bus_log_parse_error(r);
439
440 r = sd_bus_message_read_array(reply, 'y', &d, &l);
441 if (r < 0)
442 return bus_log_parse_error(r);
443
444 r = sd_bus_message_exit_container(reply);
445 if (r < 0)
446 return bus_log_parse_error(r);
447
dab48ea6
ZJS
448 if (arg_raw == RAW_PACKET) {
449 uint64_t u64 = htole64(l);
2d4c5cbc 450
dab48ea6
ZJS
451 fwrite(&u64, sizeof(u64), 1, stdout);
452 fwrite(d, 1, l, stdout);
2e74028a 453 } else {
dab48ea6
ZJS
454 r = output_rr_packet(d, l, ifindex);
455 if (r < 0)
456 return r;
2e74028a 457 }
78c6a153 458
41815a4a
LP
459 if (dns_type_needs_authentication(t))
460 needs_authentication = true;
461
2d4c5cbc
LP
462 n++;
463 }
464 if (r < 0)
465 return bus_log_parse_error(r);
466
467 r = sd_bus_message_exit_container(reply);
468 if (r < 0)
469 return bus_log_parse_error(r);
470
51323288
LP
471 r = sd_bus_message_read(reply, "t", &flags);
472 if (r < 0)
473 return bus_log_parse_error(r);
474
2d4c5cbc 475 if (n == 0) {
a60f4d0b
SS
476 if (warn_missing)
477 log_error("%s: no records found", name);
2d4c5cbc
LP
478 return -ESRCH;
479 }
480
78c6a153 481 print_source(flags, ts);
51323288 482
41815a4a
LP
483 if ((flags & SD_RESOLVED_AUTHENTICATED) == 0 && needs_authentication) {
484 fflush(stdout);
485
486 fprintf(stderr, "\n%s"
487 "WARNING: The resources shown contain cryptographic key data which could not be\n"
488 " authenticated. It is not suitable to authenticate any communication.\n"
489 " This is usually indication that DNSSEC authentication was not enabled\n"
490 " or is not available for the selected protocol or DNS servers.%s\n",
491 ansi_highlight_red(),
492 ansi_normal());
493 }
494
2d4c5cbc
LP
495 return 0;
496}
497
c1dafe4f
LP
498static int resolve_rfc4501(sd_bus *bus, const char *name) {
499 uint16_t type = 0, class = 0;
500 const char *p, *q, *n;
501 int r;
502
503 assert(bus);
504 assert(name);
505 assert(startswith(name, "dns:"));
506
507 /* Parse RFC 4501 dns: URIs */
508
509 p = name + 4;
510
511 if (p[0] == '/') {
512 const char *e;
513
514 if (p[1] != '/')
515 goto invalid;
516
517 e = strchr(p + 2, '/');
518 if (!e)
519 goto invalid;
520
521 if (e != p + 2)
522 log_warning("DNS authority specification not supported; ignoring specified authority.");
523
524 p = e + 1;
525 }
526
527 q = strchr(p, '?');
528 if (q) {
529 n = strndupa(p, q - p);
530 q++;
531
532 for (;;) {
533 const char *f;
534
535 f = startswith_no_case(q, "class=");
536 if (f) {
537 _cleanup_free_ char *t = NULL;
538 const char *e;
539
540 if (class != 0) {
541 log_error("DNS class specified twice.");
542 return -EINVAL;
543 }
544
545 e = strchrnul(f, ';');
546 t = strndup(f, e - f);
547 if (!t)
548 return log_oom();
549
550 r = dns_class_from_string(t);
551 if (r < 0) {
552 log_error("Unknown DNS class %s.", t);
553 return -EINVAL;
554 }
555
556 class = r;
557
558 if (*e == ';') {
559 q = e + 1;
560 continue;
561 }
562
563 break;
564 }
565
566 f = startswith_no_case(q, "type=");
567 if (f) {
568 _cleanup_free_ char *t = NULL;
569 const char *e;
570
571 if (type != 0) {
572 log_error("DNS type specified twice.");
573 return -EINVAL;
574 }
575
576 e = strchrnul(f, ';');
577 t = strndup(f, e - f);
578 if (!t)
579 return log_oom();
580
581 r = dns_type_from_string(t);
582 if (r < 0) {
583 log_error("Unknown DNS type %s.", t);
584 return -EINVAL;
585 }
586
587 type = r;
588
589 if (*e == ';') {
590 q = e + 1;
591 continue;
592 }
593
594 break;
595 }
596
597 goto invalid;
598 }
599 } else
600 n = p;
601
c1dafe4f 602 if (class == 0)
4ac2ca1b
ZJS
603 class = arg_class ?: DNS_CLASS_IN;
604 if (type == 0)
605 type = arg_type ?: DNS_TYPE_A;
c1dafe4f 606
a60f4d0b 607 return resolve_record(bus, n, class, type, true);
c1dafe4f
LP
608
609invalid:
610 log_error("Invalid DNS URI: %s", name);
611 return -EINVAL;
612}
613
a7a4c60a
YW
614static int verb_query(int argc, char **argv, void *userdata) {
615 sd_bus *bus = userdata;
616 char **p;
617 int q, r = 0;
618
619 if (arg_type != 0)
620 STRV_FOREACH(p, argv + 1) {
621 q = resolve_record(bus, *p, arg_class, arg_type, true);
622 if (q < 0)
623 r = q;
624 }
625
626 else
627 STRV_FOREACH(p, argv + 1) {
628 if (startswith(*p, "dns:"))
629 q = resolve_rfc4501(bus, *p);
630 else {
631 int family, ifindex;
632 union in_addr_union a;
633
634 q = in_addr_ifindex_from_string_auto(*p, &family, &a, &ifindex);
635 if (q >= 0)
636 q = resolve_address(bus, family, &a, ifindex);
637 else
638 q = resolve_host(bus, *p);
639 }
640 if (q < 0)
641 r = q;
642 }
643
644 return r;
645}
646
45ec7efb
LP
647static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) {
648 const char *canonical_name, *canonical_type, *canonical_domain;
4afd3348
LP
649 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
650 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
45ec7efb
LP
651 char ifname[IF_NAMESIZE] = "";
652 size_t indent, sz;
653 uint64_t flags;
654 const char *p;
655 unsigned c;
656 usec_t ts;
657 int r;
658
659 assert(bus);
660 assert(domain);
661
3c6f7c34
LP
662 name = empty_to_null(name);
663 type = empty_to_null(type);
45ec7efb
LP
664
665 if (arg_ifindex > 0 && !if_indextoname(arg_ifindex, ifname))
666 return log_error_errno(errno, "Failed to resolve interface name for index %i: %m", arg_ifindex);
667
668 if (name)
669 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);
670 else if (type)
671 log_debug("Resolving service type %s of %s (family %s, interface %s).", type, domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
672 else
673 log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(ifname) ? "*" : ifname);
674
675 r = sd_bus_message_new_method_call(
676 bus,
677 &req,
678 "org.freedesktop.resolve1",
679 "/org/freedesktop/resolve1",
680 "org.freedesktop.resolve1.Manager",
681 "ResolveService");
682 if (r < 0)
683 return bus_log_create_error(r);
684
685 r = sd_bus_message_append(req, "isssit", arg_ifindex, name, type, domain, arg_family, arg_flags);
686 if (r < 0)
687 return bus_log_create_error(r);
688
689 ts = now(CLOCK_MONOTONIC);
690
4cbfd62b 691 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
45ec7efb
LP
692 if (r < 0)
693 return log_error_errno(r, "Resolve call failed: %s", bus_error_message(&error, r));
694
695 ts = now(CLOCK_MONOTONIC) - ts;
696
697 r = sd_bus_message_enter_container(reply, 'a', "(qqqsa(iiay)s)");
698 if (r < 0)
699 return bus_log_parse_error(r);
700
701 indent =
702 (name ? strlen(name) + 1 : 0) +
703 (type ? strlen(type) + 1 : 0) +
704 strlen(domain) + 2;
705
706 c = 0;
707 while ((r = sd_bus_message_enter_container(reply, 'r', "qqqsa(iiay)s")) > 0) {
708 uint16_t priority, weight, port;
709 const char *hostname, *canonical;
710
711 r = sd_bus_message_read(reply, "qqqs", &priority, &weight, &port, &hostname);
712 if (r < 0)
713 return bus_log_parse_error(r);
714
715 if (name)
716 printf("%*s%s", (int) strlen(name), c == 0 ? name : "", c == 0 ? "/" : " ");
717 if (type)
718 printf("%*s%s", (int) strlen(type), c == 0 ? type : "", c == 0 ? "/" : " ");
719
720 printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
721 (int) strlen(domain), c == 0 ? domain : "",
722 c == 0 ? ":" : " ",
723 hostname, port,
724 priority, weight);
725
726 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
727 if (r < 0)
728 return bus_log_parse_error(r);
729
730 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
731 _cleanup_free_ char *pretty = NULL;
732 int ifindex, family;
733 const void *a;
734
735 assert_cc(sizeof(int) == sizeof(int32_t));
736
737 r = sd_bus_message_read(reply, "ii", &ifindex, &family);
738 if (r < 0)
739 return bus_log_parse_error(r);
740
741 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
742 if (r < 0)
743 return bus_log_parse_error(r);
744
745 r = sd_bus_message_exit_container(reply);
746 if (r < 0)
747 return bus_log_parse_error(r);
748
749 if (!IN_SET(family, AF_INET, AF_INET6)) {
750 log_debug("%s: skipping entry with family %d (%s)", name, family, af_to_name(family) ?: "unknown");
751 continue;
752 }
753
754 if (sz != FAMILY_ADDRESS_SIZE(family)) {
755 log_error("%s: systemd-resolved returned address of invalid size %zu for family %s", name, sz, af_to_name(family) ?: "unknown");
756 return -EINVAL;
757 }
758
759 ifname[0] = 0;
760 if (ifindex > 0 && !if_indextoname(ifindex, ifname))
761 log_warning_errno(errno, "Failed to resolve interface name for index %i: %m", ifindex);
762
763 r = in_addr_to_string(family, a, &pretty);
764 if (r < 0)
765 return log_error_errno(r, "Failed to print address for %s: %m", name);
766
767 printf("%*s%s%s%s\n", (int) indent, "", pretty, isempty(ifname) ? "" : "%s", ifname);
768 }
769 if (r < 0)
770 return bus_log_parse_error(r);
771
772 r = sd_bus_message_exit_container(reply);
773 if (r < 0)
774 return bus_log_parse_error(r);
775
776 r = sd_bus_message_read(reply, "s", &canonical);
777 if (r < 0)
778 return bus_log_parse_error(r);
779
780 if (!streq(hostname, canonical))
781 printf("%*s(%s)\n", (int) indent, "", canonical);
782
783 r = sd_bus_message_exit_container(reply);
784 if (r < 0)
785 return bus_log_parse_error(r);
786
787 c++;
788 }
789 if (r < 0)
790 return bus_log_parse_error(r);
791
792 r = sd_bus_message_exit_container(reply);
793 if (r < 0)
794 return bus_log_parse_error(r);
795
796 r = sd_bus_message_enter_container(reply, 'a', "ay");
797 if (r < 0)
798 return bus_log_parse_error(r);
799
45ec7efb
LP
800 while ((r = sd_bus_message_read_array(reply, 'y', (const void**) &p, &sz)) > 0) {
801 _cleanup_free_ char *escaped = NULL;
802
803 escaped = cescape_length(p, sz);
804 if (!escaped)
805 return log_oom();
806
807 printf("%*s%s\n", (int) indent, "", escaped);
45ec7efb
LP
808 }
809 if (r < 0)
810 return bus_log_parse_error(r);
811
812 r = sd_bus_message_exit_container(reply);
813 if (r < 0)
814 return bus_log_parse_error(r);
815
816 r = sd_bus_message_read(reply, "ssst", &canonical_name, &canonical_type, &canonical_domain, &flags);
817 if (r < 0)
818 return bus_log_parse_error(r);
819
3c6f7c34
LP
820 canonical_name = empty_to_null(canonical_name);
821 canonical_type = empty_to_null(canonical_type);
45ec7efb
LP
822
823 if (!streq_ptr(name, canonical_name) ||
824 !streq_ptr(type, canonical_type) ||
825 !streq_ptr(domain, canonical_domain)) {
826
827 printf("%*s(", (int) indent, "");
828
829 if (canonical_name)
830 printf("%s/", canonical_name);
831 if (canonical_type)
832 printf("%s/", canonical_type);
833
834 printf("%s)\n", canonical_domain);
835 }
836
837 print_source(flags, ts);
838
839 return 0;
840}
841
a7a4c60a
YW
842static int verb_service(int argc, char **argv, void *userdata) {
843 sd_bus *bus = userdata;
844
845 if (argc == 2)
846 return resolve_service(bus, NULL, NULL, argv[1]);
847 else if (argc == 3)
848 return resolve_service(bus, NULL, argv[1], argv[2]);
849 else
850 return resolve_service(bus, argv[1], argv[2], argv[3]);
851}
852
4ac2ca1b
ZJS
853static int resolve_openpgp(sd_bus *bus, const char *address) {
854 const char *domain, *full;
855 int r;
856 _cleanup_free_ char *hashed = NULL;
857
858 assert(bus);
859 assert(address);
860
861 domain = strrchr(address, '@');
862 if (!domain) {
863 log_error("Address does not contain '@': \"%s\"", address);
864 return -EINVAL;
865 } else if (domain == address || domain[1] == '\0') {
866 log_error("Address starts or ends with '@': \"%s\"", address);
867 return -EINVAL;
868 }
869 domain++;
870
a60f4d0b 871 r = string_hashsum_sha256(address, domain - 1 - address, &hashed);
4ac2ca1b
ZJS
872 if (r < 0)
873 return log_error_errno(r, "Hashing failed: %m");
874
a60f4d0b
SS
875 strshorten(hashed, 56);
876
4ac2ca1b
ZJS
877 full = strjoina(hashed, "._openpgpkey.", domain);
878 log_debug("Looking up \"%s\".", full);
879
a60f4d0b
SS
880 r = resolve_record(bus, full,
881 arg_class ?: DNS_CLASS_IN,
882 arg_type ?: DNS_TYPE_OPENPGPKEY, false);
883
884 if (IN_SET(r, -ENXIO, -ESRCH)) { /* NXDOMAIN or NODATA? */
885 hashed = NULL;
886 r = string_hashsum_sha224(address, domain - 1 - address, &hashed);
887 if (r < 0)
888 return log_error_errno(r, "Hashing failed: %m");
889
890 full = strjoina(hashed, "._openpgpkey.", domain);
891 log_debug("Looking up \"%s\".", full);
892
893 return resolve_record(bus, full,
894 arg_class ?: DNS_CLASS_IN,
895 arg_type ?: DNS_TYPE_OPENPGPKEY, true);
896 }
897
898 return r;
4ac2ca1b
ZJS
899}
900
a7a4c60a
YW
901static int verb_openpgp(int argc, char **argv, void *userdata) {
902 sd_bus *bus = userdata;
903 char **p;
904 int q, r = 0;
905
906 STRV_FOREACH(p, argv + 1) {
907 q = resolve_openpgp(bus, *p);
908 if (q < 0)
909 r = q;
910 }
911
912 return r;
913}
914
ebbc70e5 915static int resolve_tlsa(sd_bus *bus, const char *family, const char *address) {
82d1d240
ZJS
916 const char *port;
917 uint16_t port_num = 443;
918 _cleanup_free_ char *full = NULL;
919 int r;
920
921 assert(bus);
922 assert(address);
923
924 port = strrchr(address, ':');
925 if (port) {
10452f7c
SS
926 r = parse_ip_port(port + 1, &port_num);
927 if (r < 0)
82d1d240
ZJS
928 return log_error_errno(r, "Invalid port \"%s\".", port + 1);
929
930 address = strndupa(address, port - address);
931 }
932
ebbc70e5 933 r = asprintf(&full, "_%u._%s.%s",
82d1d240 934 port_num,
ebbc70e5 935 family,
82d1d240
ZJS
936 address);
937 if (r < 0)
938 return log_oom();
939
940 log_debug("Looking up \"%s\".", full);
941
942 return resolve_record(bus, full,
943 arg_class ?: DNS_CLASS_IN,
a60f4d0b 944 arg_type ?: DNS_TYPE_TLSA, true);
82d1d240
ZJS
945}
946
ebbc70e5
YW
947static bool service_family_is_valid(const char *s) {
948 return STR_IN_SET(s, "tcp", "udp", "sctp");
949}
950
a7a4c60a
YW
951static int verb_tlsa(int argc, char **argv, void *userdata) {
952 sd_bus *bus = userdata;
a7a4c60a 953 char **p, **args = argv + 1;
ebbc70e5 954 const char *family = "tcp";
a7a4c60a
YW
955 int q, r = 0;
956
ebbc70e5
YW
957 if (service_family_is_valid(argv[1])) {
958 family = argv[1];
a7a4c60a 959 args++;
ebbc70e5 960 }
a7a4c60a
YW
961
962 STRV_FOREACH(p, args) {
963 q = resolve_tlsa(bus, family, *p);
964 if (q < 0)
965 r = q;
966 }
967
968 return r;
969}
970
971static int show_statistics(int argc, char **argv, void *userdata) {
a150ff5e
LP
972 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
973 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
a7a4c60a 974 sd_bus *bus = userdata;
a150ff5e
LP
975 uint64_t n_current_transactions, n_total_transactions,
976 cache_size, n_cache_hit, n_cache_miss,
977 n_dnssec_secure, n_dnssec_insecure, n_dnssec_bogus, n_dnssec_indeterminate;
593f665c 978 int r, dnssec_supported;
a150ff5e
LP
979
980 assert(bus);
981
593f665c
LP
982 r = sd_bus_get_property_trivial(bus,
983 "org.freedesktop.resolve1",
984 "/org/freedesktop/resolve1",
985 "org.freedesktop.resolve1.Manager",
986 "DNSSECSupported",
987 &error,
988 'b',
989 &dnssec_supported);
990 if (r < 0)
991 return log_error_errno(r, "Failed to get DNSSEC supported state: %s", bus_error_message(&error, r));
992
993 printf("DNSSEC supported by current servers: %s%s%s\n\n",
994 ansi_highlight(),
995 yes_no(dnssec_supported),
996 ansi_normal());
997
a150ff5e
LP
998 r = sd_bus_get_property(bus,
999 "org.freedesktop.resolve1",
1000 "/org/freedesktop/resolve1",
1001 "org.freedesktop.resolve1.Manager",
1002 "TransactionStatistics",
1003 &error,
1004 &reply,
1005 "(tt)");
1006 if (r < 0)
1007 return log_error_errno(r, "Failed to get transaction statistics: %s", bus_error_message(&error, r));
1008
1009 r = sd_bus_message_read(reply, "(tt)",
1010 &n_current_transactions,
1011 &n_total_transactions);
1012 if (r < 0)
1013 return bus_log_parse_error(r);
1014
1015 printf("%sTransactions%s\n"
1016 "Current Transactions: %" PRIu64 "\n"
1017 " Total Transactions: %" PRIu64 "\n",
1018 ansi_highlight(),
1019 ansi_normal(),
1020 n_current_transactions,
1021 n_total_transactions);
1022
1023 reply = sd_bus_message_unref(reply);
1024
1025 r = sd_bus_get_property(bus,
1026 "org.freedesktop.resolve1",
1027 "/org/freedesktop/resolve1",
1028 "org.freedesktop.resolve1.Manager",
1029 "CacheStatistics",
1030 &error,
1031 &reply,
1032 "(ttt)");
f7700834
TA
1033 if (r < 0)
1034 return log_error_errno(r, "Failed to get cache statistics: %s", bus_error_message(&error, r));
a150ff5e
LP
1035
1036 r = sd_bus_message_read(reply, "(ttt)",
1037 &cache_size,
1038 &n_cache_hit,
1039 &n_cache_miss);
1040 if (r < 0)
1041 return bus_log_parse_error(r);
1042
1043 printf("\n%sCache%s\n"
1044 " Current Cache Size: %" PRIu64 "\n"
1045 " Cache Hits: %" PRIu64 "\n"
1046 " Cache Misses: %" PRIu64 "\n",
1047 ansi_highlight(),
1048 ansi_normal(),
1049 cache_size,
1050 n_cache_hit,
1051 n_cache_miss);
1052
1053 reply = sd_bus_message_unref(reply);
1054
1055 r = sd_bus_get_property(bus,
1056 "org.freedesktop.resolve1",
1057 "/org/freedesktop/resolve1",
1058 "org.freedesktop.resolve1.Manager",
1059 "DNSSECStatistics",
1060 &error,
1061 &reply,
1062 "(tttt)");
f7700834
TA
1063 if (r < 0)
1064 return log_error_errno(r, "Failed to get DNSSEC statistics: %s", bus_error_message(&error, r));
a150ff5e
LP
1065
1066 r = sd_bus_message_read(reply, "(tttt)",
1067 &n_dnssec_secure,
1068 &n_dnssec_insecure,
1069 &n_dnssec_bogus,
1070 &n_dnssec_indeterminate);
1071 if (r < 0)
1072 return bus_log_parse_error(r);
1073
7405bb3e
LP
1074 printf("\n%sDNSSEC Verdicts%s\n"
1075 " Secure: %" PRIu64 "\n"
1076 " Insecure: %" PRIu64 "\n"
1077 " Bogus: %" PRIu64 "\n"
1078 " Indeterminate: %" PRIu64 "\n",
a150ff5e
LP
1079 ansi_highlight(),
1080 ansi_normal(),
1081 n_dnssec_secure,
1082 n_dnssec_insecure,
1083 n_dnssec_bogus,
1084 n_dnssec_indeterminate);
1085
1086 return 0;
1087}
1088
a7a4c60a 1089static int reset_statistics(int argc, char **argv, void *userdata) {
a150ff5e 1090 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
a7a4c60a 1091 sd_bus *bus = userdata;
a150ff5e
LP
1092 int r;
1093
1094 r = sd_bus_call_method(bus,
1095 "org.freedesktop.resolve1",
1096 "/org/freedesktop/resolve1",
1097 "org.freedesktop.resolve1.Manager",
1098 "ResetStatistics",
1099 &error,
1100 NULL,
1101 NULL);
1102 if (r < 0)
1103 return log_error_errno(r, "Failed to reset statistics: %s", bus_error_message(&error, r));
1104
1105 return 0;
1106}
1107
a7a4c60a 1108static int flush_caches(int argc, char **argv, void *userdata) {
ba35662f 1109 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
a7a4c60a 1110 sd_bus *bus = userdata;
ba35662f
LP
1111 int r;
1112
1113 r = sd_bus_call_method(bus,
1114 "org.freedesktop.resolve1",
1115 "/org/freedesktop/resolve1",
1116 "org.freedesktop.resolve1.Manager",
1117 "FlushCaches",
1118 &error,
1119 NULL,
1120 NULL);
1121 if (r < 0)
1122 return log_error_errno(r, "Failed to flush caches: %s", bus_error_message(&error, r));
1123
1124 return 0;
1125}
1126
a7a4c60a 1127static int reset_server_features(int argc, char **argv, void *userdata) {
d55b0463 1128 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
a7a4c60a 1129 sd_bus *bus = userdata;
d55b0463
LP
1130 int r;
1131
1132 r = sd_bus_call_method(bus,
1133 "org.freedesktop.resolve1",
1134 "/org/freedesktop/resolve1",
1135 "org.freedesktop.resolve1.Manager",
1136 "ResetServerFeatures",
1137 &error,
1138 NULL,
1139 NULL);
1140 if (r < 0)
1141 return log_error_errno(r, "Failed to reset server features: %s", bus_error_message(&error, r));
1142
1143 return 0;
1144}
1145
58f48a56
YW
1146static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, char **ret) {
1147 _cleanup_free_ char *pretty = NULL;
1148 int ifindex, family, r;
1149 const void *a;
1150 size_t sz;
1151
1152 assert(m);
1153 assert(ret);
1154
1155 r = sd_bus_message_enter_container(m, 'r', with_ifindex ? "iiay" : "iay");
1156 if (r <= 0)
1157 return r;
1158
1159 if (with_ifindex) {
1160 r = sd_bus_message_read(m, "i", &ifindex);
1161 if (r < 0)
1162 return r;
1163 }
1164
1165 r = sd_bus_message_read(m, "i", &family);
1166 if (r < 0)
1167 return r;
1168
1169 r = sd_bus_message_read_array(m, 'y', &a, &sz);
1170 if (r < 0)
1171 return r;
1172
1173 r = sd_bus_message_exit_container(m);
1174 if (r < 0)
1175 return r;
1176
1177 if (with_ifindex && ifindex != 0) {
1178 /* only show the global ones here */
1179 *ret = NULL;
1180 return 1;
1181 }
1182
1183 if (!IN_SET(family, AF_INET, AF_INET6)) {
1184 log_debug("Unexpected family, ignoring: %i", family);
1185
1186 *ret = NULL;
1187 return 1;
1188 }
1189
1190 if (sz != FAMILY_ADDRESS_SIZE(family)) {
1191 log_debug("Address size mismatch, ignoring.");
1192
1193 *ret = NULL;
1194 return 1;
1195 }
1196
1197 r = in_addr_to_string(family, a, &pretty);
1198 if (r < 0)
1199 return r;
1200
1201 *ret = TAKE_PTR(pretty);
1202
1203 return 1;
1204}
1205
be371fe0
LP
1206static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1207 char ***l = userdata;
1208 int r;
1209
1210 assert(bus);
1211 assert(member);
1212 assert(m);
1213 assert(l);
1214
1215 r = sd_bus_message_enter_container(m, 'a', "(iay)");
1216 if (r < 0)
1217 return r;
1218
1219 for (;;) {
58f48a56 1220 char *pretty = NULL;
be371fe0 1221
58f48a56 1222 r = read_dns_server_one(m, false, &pretty);
be371fe0
LP
1223 if (r < 0)
1224 return r;
1225 if (r == 0)
1226 break;
1227
58f48a56 1228 if (isempty(pretty))
be371fe0 1229 continue;
be371fe0
LP
1230
1231 r = strv_consume(l, pretty);
1232 if (r < 0)
1233 return r;
1234 }
1235
1236 r = sd_bus_message_exit_container(m);
1237 if (r < 0)
1238 return r;
1239
1240 return 0;
1241}
1242
446c6415
YW
1243static int map_link_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1244 assert(m);
1245 assert(userdata);
1246
1247 return read_dns_server_one(m, false, userdata);
1248}
1249
c513bb6e
YW
1250static int read_domain_one(sd_bus_message *m, bool with_ifindex, char **ret) {
1251 _cleanup_free_ char *str = NULL;
1252 int ifindex, route_only, r;
1253 const char *domain;
1254
1255 assert(m);
1256 assert(ret);
1257
1258 if (with_ifindex)
1259 r = sd_bus_message_read(m, "(isb)", &ifindex, &domain, &route_only);
1260 else
1261 r = sd_bus_message_read(m, "(sb)", &domain, &route_only);
1262 if (r <= 0)
1263 return r;
1264
1265 if (with_ifindex && ifindex != 0) {
1266 /* only show the global ones here */
1267 *ret = NULL;
1268 return 1;
1269 }
1270
1271 if (route_only)
1272 str = strappend("~", domain);
1273 else
1274 str = strdup(domain);
1275 if (!str)
1276 return -ENOMEM;
1277
1278 *ret = TAKE_PTR(str);
1279
1280 return 1;
1281}
1282
be371fe0
LP
1283static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1284 char ***l = userdata;
1285 int r;
1286
1287 assert(bus);
1288 assert(member);
1289 assert(m);
1290 assert(l);
1291
1292 r = sd_bus_message_enter_container(m, 'a', "(sb)");
1293 if (r < 0)
1294 return r;
1295
1296 for (;;) {
c513bb6e 1297 char *pretty = NULL;
be371fe0 1298
c513bb6e 1299 r = read_domain_one(m, false, &pretty);
be371fe0
LP
1300 if (r < 0)
1301 return r;
1302 if (r == 0)
1303 break;
1304
c513bb6e
YW
1305 if (isempty(pretty))
1306 continue;
be371fe0
LP
1307
1308 r = strv_consume(l, pretty);
1309 if (r < 0)
1310 return r;
1311 }
1312
1313 r = sd_bus_message_exit_container(m);
1314 if (r < 0)
1315 return r;
1316
1317 return 0;
1318}
1319
a7a4c60a
YW
1320static int status_print_strv_ifindex(int ifindex, const char *ifname, char **p) {
1321 char **i;
1322
1323 printf("%sLink %i (%s)%s:",
1324 ansi_highlight(), ifindex, ifname, ansi_normal());
1325
1326 STRV_FOREACH(i, p)
1327 printf(" %s", *i);
1328
1329 printf("\n");
1330
1331 return 0;
1332}
1333
1334static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode mode, bool *empty_line) {
be371fe0
LP
1335
1336 struct link_info {
1337 uint64_t scopes_mask;
f37f8a61
YW
1338 const char *llmnr;
1339 const char *mdns;
c9299be2 1340 const char *dns_over_tls;
f37f8a61 1341 const char *dnssec;
446c6415 1342 char *current_dns;
be371fe0
LP
1343 char **dns;
1344 char **domains;
1345 char **ntas;
f37f8a61 1346 bool dnssec_supported;
be371fe0
LP
1347 } link_info = {};
1348
1349 static const struct bus_properties_map property_map[] = {
446c6415
YW
1350 { "ScopesMask", "t", NULL, offsetof(struct link_info, scopes_mask) },
1351 { "DNS", "a(iay)", map_link_dns_servers, offsetof(struct link_info, dns) },
1352 { "CurrentDNSServer", "(iay)", map_link_current_dns_server, offsetof(struct link_info, current_dns) },
1353 { "Domains", "a(sb)", map_link_domains, offsetof(struct link_info, domains) },
1354 { "LLMNR", "s", NULL, offsetof(struct link_info, llmnr) },
1355 { "MulticastDNS", "s", NULL, offsetof(struct link_info, mdns) },
c9299be2 1356 { "DNSOverTLS", "s", NULL, offsetof(struct link_info, dns_over_tls) },
446c6415
YW
1357 { "DNSSEC", "s", NULL, offsetof(struct link_info, dnssec) },
1358 { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct link_info, ntas) },
1359 { "DNSSECSupported", "b", NULL, offsetof(struct link_info, dnssec_supported) },
be371fe0
LP
1360 {}
1361 };
1362
f9e0eefc 1363 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
f37f8a61 1364 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
be371fe0
LP
1365 _cleanup_free_ char *ifi = NULL, *p = NULL;
1366 char ifname[IF_NAMESIZE] = "";
1367 char **i;
1368 int r;
1369
1370 assert(bus);
1371 assert(ifindex > 0);
be371fe0
LP
1372
1373 if (!name) {
1374 if (!if_indextoname(ifindex, ifname))
1375 return log_error_errno(errno, "Failed to resolve interface name for %i: %m", ifindex);
1376
1377 name = ifname;
1378 }
1379
1380 if (asprintf(&ifi, "%i", ifindex) < 0)
1381 return log_oom();
1382
1383 r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifi, &p);
1384 if (r < 0)
1385 return log_oom();
1386
1387 r = bus_map_all_properties(bus,
1388 "org.freedesktop.resolve1",
1389 p,
1390 property_map,
a7e4861c 1391 BUS_MAP_BOOLEAN_AS_BOOL,
f9e0eefc 1392 &error,
f37f8a61 1393 &m,
be371fe0
LP
1394 &link_info);
1395 if (r < 0) {
f9e0eefc 1396 log_error_errno(r, "Failed to get link data for %i: %s", ifindex, bus_error_message(&error, r));
be371fe0
LP
1397 goto finish;
1398 }
1399
ee5324aa 1400 (void) pager_open(arg_no_pager, false);
be371fe0 1401
a7a4c60a
YW
1402 if (mode == STATUS_DNS) {
1403 r = status_print_strv_ifindex(ifindex, name, link_info.dns);
1404 goto finish;
1405 }
1406
1407 if (mode == STATUS_DOMAIN) {
1408 r = status_print_strv_ifindex(ifindex, name, link_info.domains);
1409 goto finish;
1410 }
1411
1412 if (mode == STATUS_NTA) {
1413 r = status_print_strv_ifindex(ifindex, name, link_info.ntas);
1414 goto finish;
1415 }
1416
1417 if (mode == STATUS_LLMNR) {
1418 printf("%sLink %i (%s)%s: %s\n",
1419 ansi_highlight(), ifindex, name, ansi_normal(),
1420 strna(link_info.llmnr));
1421
1422 r = 0;
1423 goto finish;
1424 }
1425
1426 if (mode == STATUS_MDNS) {
1427 printf("%sLink %i (%s)%s: %s\n",
1428 ansi_highlight(), ifindex, name, ansi_normal(),
1429 strna(link_info.mdns));
1430
1431 r = 0;
1432 goto finish;
1433 }
1434
d050561a
IT
1435 if (mode == STATUS_PRIVATE) {
1436 printf("%sLink %i (%s)%s: %s\n",
1437 ansi_highlight(), ifindex, name, ansi_normal(),
c9299be2 1438 strna(link_info.dns_over_tls));
d050561a
IT
1439
1440 r = 0;
1441 goto finish;
1442 }
1443
a7a4c60a
YW
1444 if (mode == STATUS_DNSSEC) {
1445 printf("%sLink %i (%s)%s: %s\n",
1446 ansi_highlight(), ifindex, name, ansi_normal(),
1447 strna(link_info.dnssec));
1448
1449 r = 0;
1450 goto finish;
1451 }
1452
1453 if (empty_line && *empty_line)
be371fe0
LP
1454 fputc('\n', stdout);
1455
1456 printf("%sLink %i (%s)%s\n",
1457 ansi_highlight(), ifindex, name, ansi_normal());
1458
1459 if (link_info.scopes_mask == 0)
1460 printf(" Current Scopes: none\n");
1461 else
1462 printf(" Current Scopes:%s%s%s%s%s\n",
1463 link_info.scopes_mask & SD_RESOLVED_DNS ? " DNS" : "",
1464 link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
1465 link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "",
1466 link_info.scopes_mask & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4" : "",
1467 link_info.scopes_mask & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6" : "");
1468
1469 printf(" LLMNR setting: %s\n"
1470 "MulticastDNS setting: %s\n"
c9299be2 1471 " DNSOverTLS setting: %s\n"
be371fe0 1472 " DNSSEC setting: %s\n"
c369f207 1473 " DNSSEC supported: %s\n",
be371fe0
LP
1474 strna(link_info.llmnr),
1475 strna(link_info.mdns),
c9299be2 1476 strna(link_info.dns_over_tls),
be371fe0 1477 strna(link_info.dnssec),
c369f207
YW
1478 yes_no(link_info.dnssec_supported));
1479
1480 if (link_info.current_dns)
1481 printf(" Current DNS Server: %s\n", link_info.current_dns);
be371fe0
LP
1482
1483 STRV_FOREACH(i, link_info.dns) {
7b7c1aac
ZJS
1484 printf(" %s %s\n",
1485 i == link_info.dns ? "DNS Servers:" : " ",
be371fe0
LP
1486 *i);
1487 }
1488
1489 STRV_FOREACH(i, link_info.domains) {
1490 printf(" %s %s\n",
1491 i == link_info.domains ? "DNS Domain:" : " ",
1492 *i);
1493 }
1494
1495 STRV_FOREACH(i, link_info.ntas) {
1496 printf(" %s %s\n",
1497 i == link_info.ntas ? "DNSSEC NTA:" : " ",
1498 *i);
1499 }
1500
a7a4c60a
YW
1501 if (empty_line)
1502 *empty_line = true;
be371fe0
LP
1503
1504 r = 0;
1505
1506finish:
446c6415 1507 free(link_info.current_dns);
be371fe0
LP
1508 strv_free(link_info.dns);
1509 strv_free(link_info.domains);
be371fe0
LP
1510 strv_free(link_info.ntas);
1511 return r;
1512}
1513
1514static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1515 char ***l = userdata;
1516 int r;
1517
1518 assert(bus);
1519 assert(member);
1520 assert(m);
1521 assert(l);
1522
1523 r = sd_bus_message_enter_container(m, 'a', "(iiay)");
1524 if (r < 0)
1525 return r;
1526
1527 for (;;) {
58f48a56 1528 char *pretty = NULL;
be371fe0 1529
58f48a56 1530 r = read_dns_server_one(m, true, &pretty);
be371fe0
LP
1531 if (r < 0)
1532 return r;
1533 if (r == 0)
1534 break;
1535
58f48a56 1536 if (isempty(pretty))
be371fe0
LP
1537 continue;
1538
be371fe0
LP
1539 r = strv_consume(l, pretty);
1540 if (r < 0)
1541 return r;
1542 }
1543
1544 r = sd_bus_message_exit_container(m);
1545 if (r < 0)
1546 return r;
1547
1548 return 0;
1549}
1550
446c6415
YW
1551static int map_global_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1552 assert(m);
1553 assert(userdata);
1554
1555 return read_dns_server_one(m, true, userdata);
1556}
1557
be371fe0
LP
1558static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1559 char ***l = userdata;
1560 int r;
1561
1562 assert(bus);
1563 assert(member);
1564 assert(m);
1565 assert(l);
1566
1567 r = sd_bus_message_enter_container(m, 'a', "(isb)");
1568 if (r < 0)
1569 return r;
1570
1571 for (;;) {
c513bb6e 1572 char *pretty = NULL;
be371fe0 1573
c513bb6e 1574 r = read_domain_one(m, true, &pretty);
be371fe0
LP
1575 if (r < 0)
1576 return r;
1577 if (r == 0)
1578 break;
1579
c513bb6e 1580 if (isempty(pretty))
be371fe0
LP
1581 continue;
1582
be371fe0
LP
1583 r = strv_consume(l, pretty);
1584 if (r < 0)
1585 return r;
1586 }
1587
1588 r = sd_bus_message_exit_container(m);
1589 if (r < 0)
1590 return r;
1591
1592 return 0;
1593}
1594
a7a4c60a
YW
1595static int status_print_strv_global(char **p) {
1596 char **i;
1597
1598 printf("%sGlobal%s:", ansi_highlight(), ansi_normal());
1599
1600 STRV_FOREACH(i, p)
1601 printf(" %s", *i);
1602
1603 printf("\n");
1604
1605 return 0;
1606}
1607
1608static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
be371fe0
LP
1609
1610 struct global_info {
58f48a56 1611 char *current_dns;
be371fe0 1612 char **dns;
4b320ac5 1613 char **fallback_dns;
be371fe0
LP
1614 char **domains;
1615 char **ntas;
11d6e9e9
YW
1616 const char *llmnr;
1617 const char *mdns;
c9299be2 1618 const char *dns_over_tls;
11d6e9e9
YW
1619 const char *dnssec;
1620 bool dnssec_supported;
be371fe0
LP
1621 } global_info = {};
1622
1623 static const struct bus_properties_map property_map[] = {
446c6415 1624 { "DNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, dns) },
4b320ac5 1625 { "FallbackDNS", "a(iiay)", map_global_dns_servers, offsetof(struct global_info, fallback_dns) },
446c6415
YW
1626 { "CurrentDNSServer", "(iiay)", map_global_current_dns_server, offsetof(struct global_info, current_dns) },
1627 { "Domains", "a(isb)", map_global_domains, offsetof(struct global_info, domains) },
1628 { "DNSSECNegativeTrustAnchors", "as", NULL, offsetof(struct global_info, ntas) },
1629 { "LLMNR", "s", NULL, offsetof(struct global_info, llmnr) },
1630 { "MulticastDNS", "s", NULL, offsetof(struct global_info, mdns) },
c9299be2 1631 { "DNSOverTLS", "s", NULL, offsetof(struct global_info, dns_over_tls) },
446c6415
YW
1632 { "DNSSEC", "s", NULL, offsetof(struct global_info, dnssec) },
1633 { "DNSSECSupported", "b", NULL, offsetof(struct global_info, dnssec_supported) },
be371fe0
LP
1634 {}
1635 };
1636
f9e0eefc 1637 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
f37f8a61 1638 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
be371fe0
LP
1639 char **i;
1640 int r;
1641
1642 assert(bus);
1643 assert(empty_line);
1644
1645 r = bus_map_all_properties(bus,
1646 "org.freedesktop.resolve1",
1647 "/org/freedesktop/resolve1",
1648 property_map,
a7e4861c 1649 BUS_MAP_BOOLEAN_AS_BOOL,
f9e0eefc 1650 &error,
f37f8a61 1651 &m,
be371fe0
LP
1652 &global_info);
1653 if (r < 0) {
f9e0eefc 1654 log_error_errno(r, "Failed to get global data: %s", bus_error_message(&error, r));
be371fe0
LP
1655 goto finish;
1656 }
1657
ee5324aa 1658 (void) pager_open(arg_no_pager, false);
be371fe0 1659
a7a4c60a
YW
1660 if (mode == STATUS_DNS) {
1661 r = status_print_strv_global(global_info.dns);
1662 goto finish;
1663 }
1664
1665 if (mode == STATUS_DOMAIN) {
1666 r = status_print_strv_global(global_info.domains);
1667 goto finish;
1668 }
1669
1670 if (mode == STATUS_NTA) {
1671 r = status_print_strv_global(global_info.ntas);
1672 goto finish;
1673 }
1674
1675 if (mode == STATUS_LLMNR) {
1676 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
1677 strna(global_info.llmnr));
1678
1679 r = 0;
1680 goto finish;
1681 }
1682
1683 if (mode == STATUS_MDNS) {
1684 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
1685 strna(global_info.mdns));
1686
1687 r = 0;
1688 goto finish;
1689 }
1690
d050561a
IT
1691 if (mode == STATUS_PRIVATE) {
1692 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
c9299be2 1693 strna(global_info.dns_over_tls));
d050561a
IT
1694
1695 r = 0;
1696 goto finish;
1697 }
1698
a7a4c60a
YW
1699 if (mode == STATUS_DNSSEC) {
1700 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
1701 strna(global_info.dnssec));
1702
1703 r = 0;
1704 goto finish;
1705 }
1706
be371fe0 1707 printf("%sGlobal%s\n", ansi_highlight(), ansi_normal());
11d6e9e9
YW
1708
1709 printf(" LLMNR setting: %s\n"
1710 "MulticastDNS setting: %s\n"
c9299be2 1711 " DNSOverTLS setting: %s\n"
11d6e9e9 1712 " DNSSEC setting: %s\n"
c369f207 1713 " DNSSEC supported: %s\n",
11d6e9e9
YW
1714 strna(global_info.llmnr),
1715 strna(global_info.mdns),
c9299be2 1716 strna(global_info.dns_over_tls),
11d6e9e9 1717 strna(global_info.dnssec),
c369f207
YW
1718 yes_no(global_info.dnssec_supported));
1719
1720 if (global_info.current_dns)
1721 printf(" Current DNS Server: %s\n", global_info.current_dns);
11d6e9e9 1722
be371fe0 1723 STRV_FOREACH(i, global_info.dns) {
7b7c1aac
ZJS
1724 printf(" %s %s\n",
1725 i == global_info.dns ? "DNS Servers:" : " ",
be371fe0
LP
1726 *i);
1727 }
1728
4b320ac5
YW
1729 STRV_FOREACH(i, global_info.fallback_dns) {
1730 printf("%s %s\n",
1731 i == global_info.fallback_dns ? "Fallback DNS Servers:" : " ",
1732 *i);
1733 }
1734
be371fe0
LP
1735 STRV_FOREACH(i, global_info.domains) {
1736 printf(" %s %s\n",
1737 i == global_info.domains ? "DNS Domain:" : " ",
1738 *i);
1739 }
1740
1741 strv_sort(global_info.ntas);
1742 STRV_FOREACH(i, global_info.ntas) {
1743 printf(" %s %s\n",
1744 i == global_info.ntas ? "DNSSEC NTA:" : " ",
1745 *i);
1746 }
1747
1748 *empty_line = true;
1749
1750 r = 0;
1751
1752finish:
446c6415 1753 free(global_info.current_dns);
be371fe0 1754 strv_free(global_info.dns);
4b320ac5 1755 strv_free(global_info.fallback_dns);
be371fe0
LP
1756 strv_free(global_info.domains);
1757 strv_free(global_info.ntas);
1758
1759 return r;
1760}
1761
a7a4c60a 1762static int status_all(sd_bus *bus, StatusMode mode) {
be371fe0
LP
1763 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
1764 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
1765 sd_netlink_message *i;
96ace31d 1766 bool empty_line = false;
be371fe0
LP
1767 int r;
1768
1769 assert(bus);
1770
a7a4c60a 1771 r = status_global(bus, mode, &empty_line);
be371fe0
LP
1772 if (r < 0)
1773 return r;
1774
1775 r = sd_netlink_open(&rtnl);
1776 if (r < 0)
1777 return log_error_errno(r, "Failed to connect to netlink: %m");
1778
1779 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
1780 if (r < 0)
1781 return rtnl_log_create_error(r);
1782
1783 r = sd_netlink_message_request_dump(req, true);
1784 if (r < 0)
1785 return rtnl_log_create_error(r);
1786
1787 r = sd_netlink_call(rtnl, req, 0, &reply);
1788 if (r < 0)
1789 return log_error_errno(r, "Failed to enumerate links: %m");
1790
1791 r = 0;
1792 for (i = reply; i; i = sd_netlink_message_next(i)) {
1793 const char *name;
1794 int ifindex, q;
1795 uint16_t type;
1796
1797 q = sd_netlink_message_get_type(i, &type);
1798 if (q < 0)
1799 return rtnl_log_parse_error(q);
1800
1801 if (type != RTM_NEWLINK)
1802 continue;
1803
1804 q = sd_rtnl_message_link_get_ifindex(i, &ifindex);
1805 if (q < 0)
1806 return rtnl_log_parse_error(q);
1807
1808 if (ifindex == LOOPBACK_IFINDEX)
1809 continue;
1810
1811 q = sd_netlink_message_read_string(i, IFLA_IFNAME, &name);
1812 if (q < 0)
1813 return rtnl_log_parse_error(q);
1814
a7a4c60a 1815 q = status_ifindex(bus, ifindex, name, mode, &empty_line);
be371fe0
LP
1816 if (q < 0 && r >= 0)
1817 r = q;
1818 }
1819
1820 return r;
1821}
1822
a7a4c60a
YW
1823static int verb_status(int argc, char **argv, void *userdata) {
1824 sd_bus *bus = userdata;
1825 int q, r = 0;
14965b94 1826
a7a4c60a
YW
1827 if (argc > 1) {
1828 char **ifname;
1829 bool empty_line = false;
14965b94 1830
a7a4c60a
YW
1831 STRV_FOREACH(ifname, argv + 1) {
1832 int ifindex;
14965b94 1833
a7a4c60a
YW
1834 ifindex = parse_ifindex_with_warn(*ifname);
1835 if (ifindex < 0)
1836 continue;
14965b94 1837
a7a4c60a
YW
1838 q = status_ifindex(bus, ifindex, NULL, STATUS_ALL, &empty_line);
1839 if (q < 0)
1840 r = q;
1841 }
1842 } else
1843 r = status_all(bus, STATUS_ALL);
14965b94 1844
a7a4c60a
YW
1845 return r;
1846}
14965b94 1847
a7a4c60a
YW
1848static int log_interface_is_managed(int r, int ifindex) {
1849 char ifname[IFNAMSIZ];
14965b94 1850
a7a4c60a
YW
1851 return log_error_errno(r,
1852 "The specified interface %s is managed by systemd-networkd. Operation refused.\n"
1853 "Please configure DNS settings for systemd-networkd managed interfaces directly in their .network files.",
1854 strna(if_indextoname(ifindex, ifname)));
1855}
14965b94 1856
a7a4c60a
YW
1857static int verb_dns(int argc, char **argv, void *userdata) {
1858 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1859 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
1860 sd_bus *bus = userdata;
1861 int ifindex, r;
1862 char **p;
14965b94 1863
a7a4c60a 1864 assert(bus);
14965b94 1865
a7a4c60a
YW
1866 if (argc <= 1)
1867 return status_all(bus, STATUS_DNS);
14965b94 1868
a7a4c60a
YW
1869 ifindex = parse_ifindex_with_warn(argv[1]);
1870 if (ifindex < 0)
1871 return ifindex;
1872
1873 if (ifindex == LOOPBACK_IFINDEX) {
1874 log_error("Interface can't be the loopback interface (lo). Sorry.");
1875 return -EINVAL;
14965b94
LP
1876 }
1877
a7a4c60a
YW
1878 if (argc == 2)
1879 return status_ifindex(bus, ifindex, NULL, STATUS_DNS, NULL);
14965b94 1880
a7a4c60a
YW
1881 r = sd_bus_message_new_method_call(
1882 bus,
1883 &req,
1884 "org.freedesktop.resolve1",
1885 "/org/freedesktop/resolve1",
1886 "org.freedesktop.resolve1.Manager",
1887 "SetLinkDNS");
1888 if (r < 0)
1889 return bus_log_create_error(r);
14965b94 1890
a7a4c60a
YW
1891 r = sd_bus_message_append(req, "i", ifindex);
1892 if (r < 0)
1893 return bus_log_create_error(r);
14965b94 1894
a7a4c60a
YW
1895 r = sd_bus_message_open_container(req, 'a', "(iay)");
1896 if (r < 0)
1897 return bus_log_create_error(r);
14965b94 1898
a7a4c60a
YW
1899 STRV_FOREACH(p, argv + 2) {
1900 struct in_addr_data data;
14965b94 1901
a7a4c60a
YW
1902 r = in_addr_from_string_auto(*p, &data.family, &data.address);
1903 if (r < 0)
1904 return log_error_errno(r, "Failed to parse DNS server address: %s", *p);
14965b94 1905
a7a4c60a
YW
1906 r = sd_bus_message_open_container(req, 'r', "iay");
1907 if (r < 0)
1908 return bus_log_create_error(r);
14965b94 1909
a7a4c60a
YW
1910 r = sd_bus_message_append(req, "i", data.family);
1911 if (r < 0)
1912 return bus_log_create_error(r);
14965b94 1913
a7a4c60a
YW
1914 r = sd_bus_message_append_array(req, 'y', &data.address, FAMILY_ADDRESS_SIZE(data.family));
1915 if (r < 0)
1916 return bus_log_create_error(r);
1917
1918 r = sd_bus_message_close_container(req);
1919 if (r < 0)
1920 return bus_log_create_error(r);
14965b94
LP
1921 }
1922
a7a4c60a
YW
1923 r = sd_bus_message_close_container(req);
1924 if (r < 0)
1925 return bus_log_create_error(r);
1926
1927 r = sd_bus_call(bus, req, 0, &error, NULL);
1928 if (r < 0) {
1929 if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
1930 return log_interface_is_managed(r, ifindex);
1931
1932 if (arg_ifindex_permissive &&
1933 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
1934 return 0;
1935
1936 return log_error_errno(r, "Failed to set DNS configuration: %s", bus_error_message(&error, r));
14965b94
LP
1937 }
1938
a7a4c60a
YW
1939 return 0;
1940}
1941
1942static int verb_domain(int argc, char **argv, void *userdata) {
1943 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1944 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
1945 sd_bus *bus = userdata;
1946 int ifindex, r;
1947 char **p;
1948
1949 assert(bus);
1950
1951 if (argc <= 1)
1952 return status_all(bus, STATUS_DOMAIN);
1953
1954 ifindex = parse_ifindex_with_warn(argv[1]);
1955 if (ifindex < 0)
1956 return ifindex;
1957
1958 if (ifindex == LOOPBACK_IFINDEX) {
1959 log_error("Interface can't be the loopback interface (lo). Sorry.");
1960 return -EINVAL;
14965b94
LP
1961 }
1962
a7a4c60a
YW
1963 if (argc == 2)
1964 return status_ifindex(bus, ifindex, NULL, STATUS_DOMAIN, NULL);
14965b94 1965
a7a4c60a
YW
1966 r = sd_bus_message_new_method_call(
1967 bus,
1968 &req,
1969 "org.freedesktop.resolve1",
1970 "/org/freedesktop/resolve1",
1971 "org.freedesktop.resolve1.Manager",
1972 "SetLinkDomains");
1973 if (r < 0)
1974 return bus_log_create_error(r);
14965b94 1975
a7a4c60a
YW
1976 r = sd_bus_message_append(req, "i", ifindex);
1977 if (r < 0)
1978 return bus_log_create_error(r);
14965b94 1979
a7a4c60a
YW
1980 r = sd_bus_message_open_container(req, 'a', "(sb)");
1981 if (r < 0)
1982 return bus_log_create_error(r);
1983
1984 STRV_FOREACH(p, argv + 2) {
1985 const char *n;
14965b94 1986
a7a4c60a 1987 n = **p == '~' ? *p + 1 : *p;
14965b94 1988
a7a4c60a
YW
1989 r = dns_name_is_valid(n);
1990 if (r < 0)
1991 return log_error_errno(r, "Failed to validate specified domain %s: %m", n);
1992 if (r == 0) {
1993 log_error("Domain not valid: %s", n);
1994 return -EINVAL;
14965b94 1995 }
a7a4c60a
YW
1996
1997 r = sd_bus_message_append(req, "(sb)", n, **p == '~');
1998 if (r < 0)
1999 return bus_log_create_error(r);
14965b94
LP
2000 }
2001
a7a4c60a
YW
2002 r = sd_bus_message_close_container(req);
2003 if (r < 0)
2004 return bus_log_create_error(r);
2005
2006 r = sd_bus_call(bus, req, 0, &error, NULL);
2007 if (r < 0) {
2008 if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
2009 return log_interface_is_managed(r, ifindex);
14965b94 2010
a7a4c60a
YW
2011 if (arg_ifindex_permissive &&
2012 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2013 return 0;
14965b94 2014
a7a4c60a 2015 return log_error_errno(r, "Failed to set domain configuration: %s", bus_error_message(&error, r));
14965b94 2016 }
a7a4c60a
YW
2017
2018 return 0;
14965b94
LP
2019}
2020
a7a4c60a 2021static int verb_llmnr(int argc, char **argv, void *userdata) {
14965b94 2022 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
a7a4c60a
YW
2023 sd_bus *bus = userdata;
2024 int ifindex, r;
14965b94
LP
2025
2026 assert(bus);
2027
a7a4c60a
YW
2028 if (argc <= 1)
2029 return status_all(bus, STATUS_LLMNR);
2030
2031 ifindex = parse_ifindex_with_warn(argv[1]);
2032 if (ifindex < 0)
2033 return ifindex;
2034
2035 if (ifindex == LOOPBACK_IFINDEX) {
2036 log_error("Interface can't be the loopback interface (lo). Sorry.");
2037 return -EINVAL;
2038 }
2039
2040 if (argc == 2)
2041 return status_ifindex(bus, ifindex, NULL, STATUS_LLMNR, NULL);
2042
14965b94
LP
2043 r = sd_bus_call_method(bus,
2044 "org.freedesktop.resolve1",
2045 "/org/freedesktop/resolve1",
2046 "org.freedesktop.resolve1.Manager",
a7a4c60a 2047 "SetLinkLLMNR",
14965b94
LP
2048 &error,
2049 NULL,
a7a4c60a 2050 "is", ifindex, argv[2]);
088c1363 2051 if (r < 0) {
a7a4c60a
YW
2052 if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
2053 return log_interface_is_managed(r, ifindex);
2054
088c1363
LP
2055 if (arg_ifindex_permissive &&
2056 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2057 return 0;
2058
a7a4c60a 2059 return log_error_errno(r, "Failed to set LLMNR configuration: %s", bus_error_message(&error, r));
088c1363 2060 }
14965b94
LP
2061
2062 return 0;
2063}
2064
a7a4c60a
YW
2065static int verb_mdns(int argc, char **argv, void *userdata) {
2066 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2067 sd_bus *bus = userdata;
2068 int ifindex, r;
ba82da3b 2069
a7a4c60a 2070 assert(bus);
b93312f5 2071
a7a4c60a
YW
2072 if (argc <= 1)
2073 return status_all(bus, STATUS_MDNS);
2074
2075 ifindex = parse_ifindex_with_warn(argv[1]);
2076 if (ifindex < 0)
2077 return ifindex;
2078
2079 if (ifindex == LOOPBACK_IFINDEX) {
2080 log_error("Interface can't be the loopback interface (lo). Sorry.");
2081 return -EINVAL;
2082 }
2083
2084 if (argc == 2)
2085 return status_ifindex(bus, ifindex, NULL, STATUS_MDNS, NULL);
2086
2087 r = sd_bus_call_method(bus,
2088 "org.freedesktop.resolve1",
2089 "/org/freedesktop/resolve1",
2090 "org.freedesktop.resolve1.Manager",
2091 "SetLinkMulticastDNS",
2092 &error,
2093 NULL,
2094 "is", ifindex, argv[2]);
2095 if (r < 0) {
2096 if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
2097 return log_interface_is_managed(r, ifindex);
2098
2099 if (arg_ifindex_permissive &&
2100 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2101 return 0;
2102
2103 return log_error_errno(r, "Failed to set MulticastDNS configuration: %s", bus_error_message(&error, r));
2104 }
2105
2106 return 0;
2107}
2108
c9299be2 2109static int verb_dns_over_tls(int argc, char **argv, void *userdata) {
d050561a
IT
2110 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2111 sd_bus *bus = userdata;
2112 int ifindex, r;
2113
2114 assert(bus);
2115
2116 if (argc <= 1)
2117 return status_all(bus, STATUS_PRIVATE);
2118
2119 ifindex = parse_ifindex_with_warn(argv[1]);
2120 if (ifindex < 0)
2121 return ifindex;
2122
2123 if (ifindex == LOOPBACK_IFINDEX) {
2124 log_error("Interface can't be the loopback interface (lo). Sorry.");
2125 return -EINVAL;
2126 }
2127
2128 if (argc == 2)
2129 return status_ifindex(bus, ifindex, NULL, STATUS_PRIVATE, NULL);
2130
2131 r = sd_bus_call_method(bus,
2132 "org.freedesktop.resolve1",
2133 "/org/freedesktop/resolve1",
2134 "org.freedesktop.resolve1.Manager",
c9299be2 2135 "SetLinkDNSOverTLS",
d050561a
IT
2136 &error,
2137 NULL,
2138 "is", ifindex, argv[2]);
2139 if (r < 0) {
2140 if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
2141 return log_interface_is_managed(r, ifindex);
2142
2143 if (arg_ifindex_permissive &&
2144 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2145 return 0;
2146
c9299be2 2147 return log_error_errno(r, "Failed to set DNSOverTLS configuration: %s", bus_error_message(&error, r));
d050561a
IT
2148 }
2149
2150 return 0;
2151}
2152
a7a4c60a
YW
2153static int verb_dnssec(int argc, char **argv, void *userdata) {
2154 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2155 sd_bus *bus = userdata;
2156 int ifindex, r;
2157
2158 assert(bus);
2159
2160 if (argc <= 1)
2161 return status_all(bus, STATUS_DNSSEC);
2162
2163 ifindex = parse_ifindex_with_warn(argv[1]);
2164 if (ifindex < 0)
2165 return ifindex;
2166
2167 if (ifindex == LOOPBACK_IFINDEX) {
2168 log_error("Interface can't be the loopback interface (lo). Sorry.");
2169 return -EINVAL;
2170 }
2171
2172 if (argc == 2)
2173 return status_ifindex(bus, ifindex, NULL, STATUS_DNSSEC, NULL);
2174
2175 r = sd_bus_call_method(bus,
2176 "org.freedesktop.resolve1",
2177 "/org/freedesktop/resolve1",
2178 "org.freedesktop.resolve1.Manager",
2179 "SetLinkDNSSEC",
2180 &error,
2181 NULL,
2182 "is", ifindex, argv[2]);
2183 if (r < 0) {
2184 if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
2185 return log_interface_is_managed(r, ifindex);
2186
2187 if (arg_ifindex_permissive &&
2188 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2189 return 0;
2190
2191 return log_error_errno(r, "Failed to set DNSSEC configuration: %s", bus_error_message(&error, r));
2192 }
2193
2194 return 0;
2195}
2196
2197static int verb_nta(int argc, char **argv, void *userdata) {
2198 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2199 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
2200 sd_bus *bus = userdata;
2201 int ifindex, i, r;
2202
2203 assert(bus);
2204
2205 if (argc <= 1)
2206 return status_all(bus, STATUS_NTA);
2207
2208 ifindex = parse_ifindex_with_warn(argv[1]);
2209 if (ifindex < 0)
2210 return ifindex;
2211
2212 if (ifindex == LOOPBACK_IFINDEX) {
2213 log_error("Interface can't be the loopback interface (lo). Sorry.");
2214 return -EINVAL;
2215 }
2216
2217 if (argc == 2)
2218 return status_ifindex(bus, ifindex, NULL, STATUS_NTA, NULL);
2219
2220 for (i = 2; i < argc; i++) {
2221 r = dns_name_is_valid(argv[i]);
2222 if (r < 0)
2223 return log_error_errno(r, "Failed to validate specified domain %s: %m", argv[i]);
2224 if (r == 0) {
2225 log_error("Domain not valid: %s", argv[i]);
2226 return -EINVAL;
2227 }
2228 }
2229
2230 r = sd_bus_message_new_method_call(
2231 bus,
2232 &req,
2233 "org.freedesktop.resolve1",
2234 "/org/freedesktop/resolve1",
2235 "org.freedesktop.resolve1.Manager",
2236 "SetLinkDNSSECNegativeTrustAnchors");
2237 if (r < 0)
2238 return bus_log_create_error(r);
2239
2240 r = sd_bus_message_append(req, "i", ifindex);
2241 if (r < 0)
2242 return bus_log_create_error(r);
2243
2244 r = sd_bus_message_append_strv(req, argv + 2);
2245 if (r < 0)
2246 return bus_log_create_error(r);
2247
2248 r = sd_bus_call(bus, req, 0, &error, NULL);
2249 if (r < 0) {
2250 if (sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY))
2251 return log_interface_is_managed(r, ifindex);
2252
2253 if (arg_ifindex_permissive &&
2254 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2255 return 0;
2256
2257 return log_error_errno(r, "Failed to set DNSSEC NTA configuration: %s", bus_error_message(&error, r));
2258 }
2259
2260 return 0;
2261}
2262
2263static int verb_revert_link(int argc, char **argv, void *userdata) {
2264 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2265 sd_bus *bus = userdata;
2266 int ifindex, r;
2267
2268 assert(bus);
2269
2270 ifindex = parse_ifindex_with_warn(argv[1]);
2271 if (ifindex < 0)
2272 return ifindex;
2273
2274 if (ifindex == LOOPBACK_IFINDEX) {
2275 log_error("Interface can't be the loopback interface (lo). Sorry.");
2276 return -EINVAL;
2277 }
2278
2279 r = sd_bus_call_method(bus,
2280 "org.freedesktop.resolve1",
2281 "/org/freedesktop/resolve1",
2282 "org.freedesktop.resolve1.Manager",
2283 "RevertLink",
2284 &error,
2285 NULL,
2286 "i", ifindex);
2287 if (r < 0) {
2288 if (arg_ifindex_permissive &&
2289 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2290 return 0;
2291
2292 return log_error_errno(r, "Failed to revert interface configuration: %s", bus_error_message(&error, r));
2293 }
2294
2295 return 0;
2296}
2297
2298static void help_protocol_types(void) {
2299 if (arg_legend)
2300 puts("Known protocol types:");
2301 puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6\nmdns\nmdns-ipv4\nmdns-ipv6");
2302}
2303
2304static void help_dns_types(void) {
a7a4c60a
YW
2305 if (arg_legend)
2306 puts("Known DNS RR types:");
5c828e66
LP
2307
2308 DUMP_STRING_TABLE(dns_type, int, _DNS_TYPE_MAX);
b93312f5
ZJS
2309}
2310
2311static void help_dns_classes(void) {
b93312f5 2312 if (arg_legend)
09b1fe14 2313 puts("Known DNS RR classes:");
5c828e66
LP
2314
2315 DUMP_STRING_TABLE(dns_class, int, _DNS_CLASS_MAX);
b93312f5
ZJS
2316}
2317
a7a4c60a 2318static void compat_help(void) {
1ace2438
ZJS
2319 printf("%1$s [OPTIONS...] HOSTNAME|ADDRESS...\n"
2320 "%1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n"
2321 "%1$s [OPTIONS...] --openpgp EMAIL@DOMAIN...\n"
2322 "%1$s [OPTIONS...] --statistics\n"
2323 "%1$s [OPTIONS...] --reset-statistics\n"
2324 "\n"
90b4a64d 2325 "Resolve domain names, IPv4 and IPv6 addresses, DNS records, and services.\n\n"
1ace2438
ZJS
2326 " -h --help Show this help\n"
2327 " --version Show package version\n"
be371fe0 2328 " --no-pager Do not pipe output into a pager\n"
1ace2438
ZJS
2329 " -4 Resolve IPv4 addresses\n"
2330 " -6 Resolve IPv6 addresses\n"
2331 " -i --interface=INTERFACE Look on interface\n"
2332 " -p --protocol=PROTO|help Look via protocol\n"
2333 " -t --type=TYPE|help Query RR with DNS type\n"
2334 " -c --class=CLASS|help Query RR with DNS class\n"
2335 " --service Resolve service (SRV)\n"
2336 " --service-address=BOOL Resolve address for services (default: yes)\n"
2337 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
2338 " --openpgp Query OpenPGP public key\n"
82d1d240 2339 " --tlsa Query TLS public key\n"
1ace2438
ZJS
2340 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
2341 " --search=BOOL Use search domains for single-label names\n"
2342 " (default: yes)\n"
dab48ea6 2343 " --raw[=payload|packet] Dump the answer as binary data\n"
1ace2438
ZJS
2344 " --legend=BOOL Print headers and additional info (default: yes)\n"
2345 " --statistics Show resolver statistics\n"
2346 " --reset-statistics Reset resolver statistics\n"
be371fe0 2347 " --status Show link and server status\n"
ba35662f 2348 " --flush-caches Flush all local DNS caches\n"
d55b0463
LP
2349 " --reset-server-features\n"
2350 " Forget learnt DNS server feature levels\n"
14965b94
LP
2351 " --set-dns=SERVER Set per-interface DNS server address\n"
2352 " --set-domain=DOMAIN Set per-interface search domain\n"
2353 " --set-llmnr=MODE Set per-interface LLMNR mode\n"
2354 " --set-mdns=MODE Set per-interface MulticastDNS mode\n"
c9299be2 2355 " --set-dnsovertls=MODE Set per-interface DNS-over-TLS mode\n"
14965b94
LP
2356 " --set-dnssec=MODE Set per-interface DNSSEC mode\n"
2357 " --set-nta=DOMAIN Set per-interface DNSSEC NTA\n"
2358 " --revert Revert per-interface configuration\n"
1ace2438 2359 , program_invocation_short_name);
bdef7319
ZJS
2360}
2361
a7a4c60a
YW
2362static void native_help(void) {
2363 printf("%1$s [OPTIONS...] {COMMAND} ...\n"
2364 "\n"
2365 "Send control commands to the network name resolution manager, or\n"
2366 "resolve domain names, IPv4 and IPv6 addresses, DNS records, and services.\n"
2367 "\n"
2368 " -h --help Show this help\n"
2369 " --version Show package version\n"
2370 " --no-pager Do not pipe output into a pager\n"
2371 " -4 Resolve IPv4 addresses\n"
2372 " -6 Resolve IPv6 addresses\n"
2373 " -i --interface=INTERFACE Look on interface\n"
2374 " -p --protocol=PROTO|help Look via protocol\n"
2375 " -t --type=TYPE|help Query RR with DNS type\n"
2376 " -c --class=CLASS|help Query RR with DNS class\n"
2377 " --service-address=BOOL Resolve address for services (default: yes)\n"
2378 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
2379 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
2380 " --search=BOOL Use search domains for single-label names\n"
2381 " (default: yes)\n"
2382 " --raw[=payload|packet] Dump the answer as binary data\n"
2383 " --legend=BOOL Print headers and additional info (default: yes)\n"
2384 "\n"
2385 "Commands:\n"
2386 " query HOSTNAME|ADDRESS... Resolve domain names, IPv4 and IPv6 addresses\n"
2387 " service [[NAME] TYPE] DOMAIN Resolve service (SRV)\n"
2388 " openpgp EMAIL@DOMAIN... Query OpenPGP public key\n"
2389 " tlsa DOMAIN[:PORT]... Query TLS public key\n"
2390 " status [LINK...] Show link and server status\n"
2391 " statistics Show resolver statistics\n"
2392 " reset-statistics Reset resolver statistics\n"
2393 " flush-caches Flush all local DNS caches\n"
2394 " reset-server-features Forget learnt DNS server feature levels\n"
2395 " dns [LINK [SERVER...]] Get/set per-interface DNS server address\n"
2396 " domain [LINK [DOMAIN...]] Get/set per-interface search domain\n"
2397 " llmnr [LINK [MODE]] Get/set per-interface LLMNR mode\n"
2398 " mdns [LINK [MODE]] Get/set per-interface MulticastDNS mode\n"
c9299be2 2399 " dnsovertls [LINK [MODE]] Get/set per-interface DNS-over-TLS mode\n"
a7a4c60a
YW
2400 " dnssec [LINK [MODE]] Get/set per-interface DNSSEC mode\n"
2401 " nta [LINK [DOMAIN...]] Get/set per-interface DNSSEC NTA\n"
2402 " revert LINK Revert per-interface configuration\n"
2403 , program_invocation_short_name);
2404}
2405
2406static int verb_help(int argc, char **argv, void *userdata) {
2407 native_help();
2408 return 0;
2409}
2410
2411static int compat_parse_argv(int argc, char *argv[]) {
bdef7319
ZJS
2412 enum {
2413 ARG_VERSION = 0x100,
dad29dff 2414 ARG_LEGEND,
45ec7efb
LP
2415 ARG_SERVICE,
2416 ARG_CNAME,
2417 ARG_SERVICE_ADDRESS,
2418 ARG_SERVICE_TXT,
4ac2ca1b 2419 ARG_OPENPGP,
82d1d240 2420 ARG_TLSA,
2e74028a 2421 ARG_RAW,
801ad6a6 2422 ARG_SEARCH,
a150ff5e
LP
2423 ARG_STATISTICS,
2424 ARG_RESET_STATISTICS,
be371fe0 2425 ARG_STATUS,
ba35662f 2426 ARG_FLUSH_CACHES,
d55b0463 2427 ARG_RESET_SERVER_FEATURES,
be371fe0 2428 ARG_NO_PAGER,
14965b94
LP
2429 ARG_SET_DNS,
2430 ARG_SET_DOMAIN,
2431 ARG_SET_LLMNR,
2432 ARG_SET_MDNS,
d050561a 2433 ARG_SET_PRIVATE,
14965b94
LP
2434 ARG_SET_DNSSEC,
2435 ARG_SET_NTA,
2436 ARG_REVERT_LINK,
bdef7319
ZJS
2437 };
2438
2439 static const struct option options[] = {
d55b0463
LP
2440 { "help", no_argument, NULL, 'h' },
2441 { "version", no_argument, NULL, ARG_VERSION },
2442 { "type", required_argument, NULL, 't' },
2443 { "class", required_argument, NULL, 'c' },
2444 { "legend", required_argument, NULL, ARG_LEGEND },
2445 { "interface", required_argument, NULL, 'i' },
2446 { "protocol", required_argument, NULL, 'p' },
2447 { "cname", required_argument, NULL, ARG_CNAME },
2448 { "service", no_argument, NULL, ARG_SERVICE },
2449 { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
2450 { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
2451 { "openpgp", no_argument, NULL, ARG_OPENPGP },
2452 { "tlsa", optional_argument, NULL, ARG_TLSA },
2453 { "raw", optional_argument, NULL, ARG_RAW },
2454 { "search", required_argument, NULL, ARG_SEARCH },
2455 { "statistics", no_argument, NULL, ARG_STATISTICS, },
2456 { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
2457 { "status", no_argument, NULL, ARG_STATUS },
2458 { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES },
2459 { "reset-server-features", no_argument, NULL, ARG_RESET_SERVER_FEATURES },
2460 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
14965b94
LP
2461 { "set-dns", required_argument, NULL, ARG_SET_DNS },
2462 { "set-domain", required_argument, NULL, ARG_SET_DOMAIN },
2463 { "set-llmnr", required_argument, NULL, ARG_SET_LLMNR },
2464 { "set-mdns", required_argument, NULL, ARG_SET_MDNS },
c9299be2 2465 { "set-dnsovertls", required_argument, NULL, ARG_SET_PRIVATE },
14965b94
LP
2466 { "set-dnssec", required_argument, NULL, ARG_SET_DNSSEC },
2467 { "set-nta", required_argument, NULL, ARG_SET_NTA },
2468 { "revert", no_argument, NULL, ARG_REVERT_LINK },
bdef7319
ZJS
2469 {}
2470 };
2471
2d4c5cbc 2472 int c, r;
bdef7319
ZJS
2473
2474 assert(argc >= 0);
2475 assert(argv);
2476
51323288 2477 while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
bdef7319
ZJS
2478 switch(c) {
2479
2480 case 'h':
a7a4c60a 2481 compat_help();
bdef7319
ZJS
2482 return 0; /* done */;
2483
2484 case ARG_VERSION:
3f6fd1ba 2485 return version();
bdef7319
ZJS
2486
2487 case '4':
2488 arg_family = AF_INET;
2489 break;
2490
2491 case '6':
2492 arg_family = AF_INET6;
2493 break;
2494
27d8af3e 2495 case 'i':
a7a4c60a
YW
2496 r = parse_ifindex_with_warn(optarg);
2497 if (r < 0)
2498 return r;
3fa4999b 2499
a7a4c60a
YW
2500 arg_ifname = optarg;
2501 arg_ifindex = r;
2d4c5cbc
LP
2502 break;
2503
2504 case 't':
b93312f5
ZJS
2505 if (streq(optarg, "help")) {
2506 help_dns_types();
2507 return 0;
2508 }
2509
4b548ef3
LP
2510 r = dns_type_from_string(optarg);
2511 if (r < 0) {
2d4c5cbc 2512 log_error("Failed to parse RR record type %s", optarg);
4b548ef3 2513 return r;
2d4c5cbc 2514 }
4b548ef3
LP
2515 arg_type = (uint16_t) r;
2516 assert((int) arg_type == r);
b93312f5 2517
a150ff5e 2518 arg_mode = MODE_RESOLVE_RECORD;
2d4c5cbc
LP
2519 break;
2520
2521 case 'c':
b93312f5
ZJS
2522 if (streq(optarg, "help")) {
2523 help_dns_classes();
2524 return 0;
2525 }
2526
4b548ef3 2527 r = dns_class_from_string(optarg);
2d4c5cbc
LP
2528 if (r < 0) {
2529 log_error("Failed to parse RR record class %s", optarg);
2530 return r;
bdef7319 2531 }
4b548ef3
LP
2532 arg_class = (uint16_t) r;
2533 assert((int) arg_class == r);
b93312f5
ZJS
2534
2535 break;
2536
dad29dff 2537 case ARG_LEGEND:
45ec7efb
LP
2538 r = parse_boolean(optarg);
2539 if (r < 0)
2540 return log_error_errno(r, "Failed to parse --legend= argument");
2541
2542 arg_legend = r;
bdef7319
ZJS
2543 break;
2544
51323288 2545 case 'p':
ba82da3b
ZJS
2546 if (streq(optarg, "help")) {
2547 help_protocol_types();
2548 return 0;
2549 } else if (streq(optarg, "dns"))
51323288
LP
2550 arg_flags |= SD_RESOLVED_DNS;
2551 else if (streq(optarg, "llmnr"))
2552 arg_flags |= SD_RESOLVED_LLMNR;
2553 else if (streq(optarg, "llmnr-ipv4"))
2554 arg_flags |= SD_RESOLVED_LLMNR_IPV4;
2555 else if (streq(optarg, "llmnr-ipv6"))
2556 arg_flags |= SD_RESOLVED_LLMNR_IPV6;
062aabb9
DR
2557 else if (streq(optarg, "mdns"))
2558 arg_flags |= SD_RESOLVED_MDNS;
2559 else if (streq(optarg, "mdns-ipv4"))
2560 arg_flags |= SD_RESOLVED_MDNS_IPV4;
2561 else if (streq(optarg, "mdns-ipv6"))
2562 arg_flags |= SD_RESOLVED_MDNS_IPV6;
51323288
LP
2563 else {
2564 log_error("Unknown protocol specifier: %s", optarg);
2565 return -EINVAL;
2566 }
2567
2568 break;
2569
45ec7efb 2570 case ARG_SERVICE:
a150ff5e 2571 arg_mode = MODE_RESOLVE_SERVICE;
45ec7efb
LP
2572 break;
2573
4ac2ca1b
ZJS
2574 case ARG_OPENPGP:
2575 arg_mode = MODE_RESOLVE_OPENPGP;
2576 break;
2577
82d1d240
ZJS
2578 case ARG_TLSA:
2579 arg_mode = MODE_RESOLVE_TLSA;
ebbc70e5
YW
2580 if (!optarg || service_family_is_valid(optarg))
2581 arg_service_family = optarg;
2582 else {
82d1d240
ZJS
2583 log_error("Unknown service family \"%s\".", optarg);
2584 return -EINVAL;
2585 }
2586 break;
2587
2e74028a
ZJS
2588 case ARG_RAW:
2589 if (on_tty()) {
2590 log_error("Refusing to write binary data to tty.");
2591 return -ENOTTY;
2592 }
2593
dab48ea6
ZJS
2594 if (optarg == NULL || streq(optarg, "payload"))
2595 arg_raw = RAW_PAYLOAD;
2596 else if (streq(optarg, "packet"))
2597 arg_raw = RAW_PACKET;
2598 else {
2599 log_error("Unknown --raw specifier \"%s\".", optarg);
2600 return -EINVAL;
2601 }
2602
2e74028a
ZJS
2603 arg_legend = false;
2604 break;
2605
45ec7efb
LP
2606 case ARG_CNAME:
2607 r = parse_boolean(optarg);
2608 if (r < 0)
2609 return log_error_errno(r, "Failed to parse --cname= argument.");
5883ff60 2610 SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0);
45ec7efb
LP
2611 break;
2612
2613 case ARG_SERVICE_ADDRESS:
2614 r = parse_boolean(optarg);
2615 if (r < 0)
2616 return log_error_errno(r, "Failed to parse --service-address= argument.");
5883ff60 2617 SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0);
45ec7efb
LP
2618 break;
2619
2620 case ARG_SERVICE_TXT:
2621 r = parse_boolean(optarg);
2622 if (r < 0)
2623 return log_error_errno(r, "Failed to parse --service-txt= argument.");
5883ff60 2624 SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
45ec7efb
LP
2625 break;
2626
801ad6a6
LP
2627 case ARG_SEARCH:
2628 r = parse_boolean(optarg);
2629 if (r < 0)
2630 return log_error_errno(r, "Failed to parse --search argument.");
5883ff60 2631 SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0);
801ad6a6
LP
2632 break;
2633
a150ff5e
LP
2634 case ARG_STATISTICS:
2635 arg_mode = MODE_STATISTICS;
2636 break;
2637
2638 case ARG_RESET_STATISTICS:
2639 arg_mode = MODE_RESET_STATISTICS;
2640 break;
2641
ba35662f
LP
2642 case ARG_FLUSH_CACHES:
2643 arg_mode = MODE_FLUSH_CACHES;
2644 break;
2645
d55b0463
LP
2646 case ARG_RESET_SERVER_FEATURES:
2647 arg_mode = MODE_RESET_SERVER_FEATURES;
2648 break;
2649
be371fe0
LP
2650 case ARG_STATUS:
2651 arg_mode = MODE_STATUS;
2652 break;
2653
2654 case ARG_NO_PAGER:
2655 arg_no_pager = true;
2656 break;
2657
a7a4c60a
YW
2658 case ARG_SET_DNS:
2659 r = strv_extend(&arg_set_dns, optarg);
14965b94 2660 if (r < 0)
14965b94 2661 return log_oom();
14965b94 2662
14965b94
LP
2663 arg_mode = MODE_SET_LINK;
2664 break;
14965b94 2665
a7a4c60a 2666 case ARG_SET_DOMAIN:
14965b94
LP
2667 r = strv_extend(&arg_set_domain, optarg);
2668 if (r < 0)
2669 return log_oom();
2670
2671 arg_mode = MODE_SET_LINK;
2672 break;
14965b94
LP
2673
2674 case ARG_SET_LLMNR:
a7a4c60a 2675 arg_set_llmnr = optarg;
14965b94
LP
2676 arg_mode = MODE_SET_LINK;
2677 break;
2678
2679 case ARG_SET_MDNS:
a7a4c60a 2680 arg_set_mdns = optarg;
14965b94
LP
2681 arg_mode = MODE_SET_LINK;
2682 break;
2683
d050561a 2684 case ARG_SET_PRIVATE:
c9299be2 2685 arg_set_dns_over_tls = optarg;
d050561a
IT
2686 arg_mode = MODE_SET_LINK;
2687 break;
2688
14965b94 2689 case ARG_SET_DNSSEC:
a7a4c60a 2690 arg_set_dnssec = optarg;
14965b94
LP
2691 arg_mode = MODE_SET_LINK;
2692 break;
2693
2694 case ARG_SET_NTA:
14965b94
LP
2695 r = strv_extend(&arg_set_nta, optarg);
2696 if (r < 0)
2697 return log_oom();
2698
2699 arg_mode = MODE_SET_LINK;
2700 break;
2701
2702 case ARG_REVERT_LINK:
2703 arg_mode = MODE_REVERT_LINK;
2704 break;
2705
bdef7319
ZJS
2706 case '?':
2707 return -EINVAL;
2708
2709 default:
2710 assert_not_reached("Unhandled option");
2711 }
2712
2d4c5cbc 2713 if (arg_type == 0 && arg_class != 0) {
45ec7efb
LP
2714 log_error("--class= may only be used in conjunction with --type=.");
2715 return -EINVAL;
2716 }
2717
82d1d240 2718 if (arg_type != 0 && arg_mode == MODE_RESOLVE_SERVICE) {
45ec7efb 2719 log_error("--service and --type= may not be combined.");
2d4c5cbc
LP
2720 return -EINVAL;
2721 }
2722
2723 if (arg_type != 0 && arg_class == 0)
2724 arg_class = DNS_CLASS_IN;
2725
c1dafe4f
LP
2726 if (arg_class != 0 && arg_type == 0)
2727 arg_type = DNS_TYPE_A;
2728
14965b94
LP
2729 if (IN_SET(arg_mode, MODE_SET_LINK, MODE_REVERT_LINK)) {
2730
2731 if (arg_ifindex <= 0) {
c9299be2 2732 log_error("--set-dns=, --set-domain=, --set-llmnr=, --set-mdns=, --set-dnsovertls=, --set-dnssec=, --set-nta= and --revert require --interface=.");
14965b94
LP
2733 return -EINVAL;
2734 }
2735
2736 if (arg_ifindex == LOOPBACK_IFINDEX) {
2737 log_error("Interface can't be the loopback interface (lo). Sorry.");
2738 return -EINVAL;
2739 }
2740 }
2741
bdef7319
ZJS
2742 return 1 /* work to do */;
2743}
2744
a7a4c60a
YW
2745static int native_parse_argv(int argc, char *argv[]) {
2746 enum {
2747 ARG_VERSION = 0x100,
2748 ARG_LEGEND,
2749 ARG_CNAME,
2750 ARG_SERVICE_ADDRESS,
2751 ARG_SERVICE_TXT,
2752 ARG_RAW,
2753 ARG_SEARCH,
2754 ARG_NO_PAGER,
2755 };
bdef7319 2756
a7a4c60a
YW
2757 static const struct option options[] = {
2758 { "help", no_argument, NULL, 'h' },
2759 { "version", no_argument, NULL, ARG_VERSION },
2760 { "type", required_argument, NULL, 't' },
2761 { "class", required_argument, NULL, 'c' },
2762 { "legend", required_argument, NULL, ARG_LEGEND },
2763 { "interface", required_argument, NULL, 'i' },
2764 { "protocol", required_argument, NULL, 'p' },
2765 { "cname", required_argument, NULL, ARG_CNAME },
2766 { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
2767 { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
2768 { "raw", optional_argument, NULL, ARG_RAW },
2769 { "search", required_argument, NULL, ARG_SEARCH },
2770 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
2771 {}
2772 };
bdef7319 2773
a7a4c60a 2774 int c, r;
79266746 2775
a7a4c60a
YW
2776 assert(argc >= 0);
2777 assert(argv);
bdef7319 2778
a7a4c60a
YW
2779 while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
2780 switch(c) {
45ec7efb 2781
a7a4c60a
YW
2782 case 'h':
2783 native_help();
2784 return 0; /* done */;
2785
2786 case ARG_VERSION:
2787 return version();
a150ff5e 2788
a7a4c60a
YW
2789 case '4':
2790 arg_family = AF_INET;
2791 break;
a150ff5e 2792
a7a4c60a
YW
2793 case '6':
2794 arg_family = AF_INET6;
2795 break;
2796
2797 case 'i':
2798 r = parse_ifindex_with_warn(optarg);
2799 if (r < 0)
2800 return r;
2801
2802 arg_ifindex = r;
2803 break;
2804
2805 case 't':
2806 if (streq(optarg, "help")) {
2807 help_dns_types();
2808 return 0;
2809 }
2810
2811 r = dns_type_from_string(optarg);
2812 if (r < 0) {
2813 log_error("Failed to parse RR record type %s", optarg);
2814 return r;
2815 }
2816 arg_type = (uint16_t) r;
2817 assert((int) arg_type == r);
2818
2819 break;
2820
2821 case 'c':
2822 if (streq(optarg, "help")) {
2823 help_dns_classes();
2824 return 0;
2825 }
2826
2827 r = dns_class_from_string(optarg);
2828 if (r < 0) {
2829 log_error("Failed to parse RR record class %s", optarg);
2830 return r;
2831 }
2832 arg_class = (uint16_t) r;
2833 assert((int) arg_class == r);
2834
2835 break;
2836
2837 case ARG_LEGEND:
2838 r = parse_boolean(optarg);
2839 if (r < 0)
2840 return log_error_errno(r, "Failed to parse --legend= argument");
2841
2842 arg_legend = r;
2843 break;
2844
2845 case 'p':
2846 if (streq(optarg, "help")) {
2847 help_protocol_types();
2848 return 0;
2849 } else if (streq(optarg, "dns"))
2850 arg_flags |= SD_RESOLVED_DNS;
2851 else if (streq(optarg, "llmnr"))
2852 arg_flags |= SD_RESOLVED_LLMNR;
2853 else if (streq(optarg, "llmnr-ipv4"))
2854 arg_flags |= SD_RESOLVED_LLMNR_IPV4;
2855 else if (streq(optarg, "llmnr-ipv6"))
2856 arg_flags |= SD_RESOLVED_LLMNR_IPV6;
2857 else if (streq(optarg, "mdns"))
2858 arg_flags |= SD_RESOLVED_MDNS;
2859 else if (streq(optarg, "mdns-ipv4"))
2860 arg_flags |= SD_RESOLVED_MDNS_IPV4;
2861 else if (streq(optarg, "mdns-ipv6"))
2862 arg_flags |= SD_RESOLVED_MDNS_IPV6;
c1dafe4f 2863 else {
a7a4c60a
YW
2864 log_error("Unknown protocol specifier: %s", optarg);
2865 return -EINVAL;
c1dafe4f 2866 }
a150ff5e 2867
a7a4c60a 2868 break;
a150ff5e 2869
a7a4c60a
YW
2870 case ARG_RAW:
2871 if (on_tty()) {
2872 log_error("Refusing to write binary data to tty.");
2873 return -ENOTTY;
2874 }
a150ff5e 2875
a7a4c60a
YW
2876 if (optarg == NULL || streq(optarg, "payload"))
2877 arg_raw = RAW_PAYLOAD;
2878 else if (streq(optarg, "packet"))
2879 arg_raw = RAW_PACKET;
2880 else {
2881 log_error("Unknown --raw specifier \"%s\".", optarg);
2882 return -EINVAL;
2883 }
a150ff5e 2884
a7a4c60a
YW
2885 arg_legend = false;
2886 break;
a150ff5e 2887
a7a4c60a
YW
2888 case ARG_CNAME:
2889 r = parse_boolean(optarg);
2890 if (r < 0)
2891 return log_error_errno(r, "Failed to parse --cname= argument.");
2892 SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0);
2893 break;
a150ff5e 2894
a7a4c60a
YW
2895 case ARG_SERVICE_ADDRESS:
2896 r = parse_boolean(optarg);
2897 if (r < 0)
2898 return log_error_errno(r, "Failed to parse --service-address= argument.");
2899 SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0);
2900 break;
a150ff5e 2901
a7a4c60a
YW
2902 case ARG_SERVICE_TXT:
2903 r = parse_boolean(optarg);
2904 if (r < 0)
2905 return log_error_errno(r, "Failed to parse --service-txt= argument.");
2906 SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
2907 break;
45ec7efb 2908
a7a4c60a
YW
2909 case ARG_SEARCH:
2910 r = parse_boolean(optarg);
2911 if (r < 0)
2912 return log_error_errno(r, "Failed to parse --search argument.");
2913 SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0);
2914 break;
79266746 2915
a7a4c60a
YW
2916 case ARG_NO_PAGER:
2917 arg_no_pager = true;
2918 break;
2919
2920 case '?':
2921 return -EINVAL;
4ac2ca1b 2922
a7a4c60a
YW
2923 default:
2924 assert_not_reached("Unhandled option");
4ac2ca1b
ZJS
2925 }
2926
a7a4c60a
YW
2927 if (arg_type == 0 && arg_class != 0) {
2928 log_error("--class= may only be used in conjunction with --type=.");
2929 return -EINVAL;
2930 }
4ac2ca1b 2931
a7a4c60a
YW
2932 if (arg_type != 0 && arg_class == 0)
2933 arg_class = DNS_CLASS_IN;
4ac2ca1b 2934
a7a4c60a
YW
2935 if (arg_class != 0 && arg_type == 0)
2936 arg_type = DNS_TYPE_A;
82d1d240 2937
a7a4c60a
YW
2938 return 1 /* work to do */;
2939}
82d1d240 2940
a7a4c60a
YW
2941static int native_main(int argc, char *argv[], sd_bus *bus) {
2942
2943 static const Verb verbs[] = {
2944 { "help", VERB_ANY, VERB_ANY, 0, verb_help },
2945 { "status", VERB_ANY, VERB_ANY, VERB_DEFAULT, verb_status },
2946 { "query", 2, VERB_ANY, 0, verb_query },
2947 { "service", 2, 4, 0, verb_service },
2948 { "openpgp", 2, VERB_ANY, 0, verb_openpgp },
2949 { "tlsa", 2, VERB_ANY, 0, verb_tlsa },
2950 { "statistics", VERB_ANY, 1, 0, show_statistics },
2951 { "reset-statistics", VERB_ANY, 1, 0, reset_statistics },
2952 { "flush-caches", VERB_ANY, 1, 0, flush_caches },
2953 { "reset-server-features", VERB_ANY, 1, 0, reset_server_features },
2954 { "dns", VERB_ANY, VERB_ANY, 0, verb_dns },
2955 { "domain", VERB_ANY, VERB_ANY, 0, verb_domain },
2956 { "llmnr", VERB_ANY, 3, 0, verb_llmnr },
2957 { "mdns", VERB_ANY, 3, 0, verb_mdns },
c9299be2 2958 { "dnsovertls", VERB_ANY, 3, 0, verb_dns_over_tls },
a7a4c60a
YW
2959 { "dnssec", VERB_ANY, 3, 0, verb_dnssec },
2960 { "nta", VERB_ANY, VERB_ANY, 0, verb_nta },
2961 { "revert", 2, 2, 0, verb_revert_link },
2962 {}
2963 };
82d1d240 2964
a7a4c60a
YW
2965 return dispatch_verb(argc, argv, verbs, bus);
2966}
82d1d240 2967
da6053d0 2968static int translate(const char *verb, const char *single_arg, size_t num_args, char **args, sd_bus *bus) {
a7a4c60a 2969 char **fake, **p;
da6053d0 2970 size_t num, i;
bdef7319 2971
a7a4c60a
YW
2972 assert(verb);
2973 assert(num_args == 0 || args);
a150ff5e 2974
a7a4c60a 2975 num = !!single_arg + num_args + 1;
79266746 2976
a7a4c60a
YW
2977 p = fake = newa0(char *, num + 1);
2978 *p++ = (char *) verb;
2979 if (single_arg)
2980 *p++ = (char *) single_arg;
2981 for (i = 0; i < num_args; i++)
2982 *p++ = args[i];
ba35662f 2983
a7a4c60a 2984 optind = 0;
da6053d0 2985 return native_main((int) num, fake, bus);
a7a4c60a 2986}
ba35662f 2987
a7a4c60a
YW
2988static int compat_main(int argc, char *argv[], sd_bus *bus) {
2989 int r = 0;
be371fe0 2990
a7a4c60a
YW
2991 switch (arg_mode) {
2992 case MODE_RESOLVE_HOST:
2993 case MODE_RESOLVE_RECORD:
2994 return translate("query", NULL, argc - optind, argv + optind, bus);
d55b0463 2995
a7a4c60a
YW
2996 case MODE_RESOLVE_SERVICE:
2997 return translate("service", NULL, argc - optind, argv + optind, bus);
d55b0463 2998
a7a4c60a
YW
2999 case MODE_RESOLVE_OPENPGP:
3000 return translate("openpgp", NULL, argc - optind, argv + optind, bus);
be371fe0 3001
a7a4c60a
YW
3002 case MODE_RESOLVE_TLSA:
3003 return translate("tlsa", arg_service_family, argc - optind, argv + optind, bus);
be371fe0 3004
a7a4c60a
YW
3005 case MODE_STATISTICS:
3006 return translate("statistics", NULL, 0, NULL, bus);
3007
3008 case MODE_RESET_STATISTICS:
3009 return translate("reset-statistics", NULL, 0, NULL, bus);
3010
3011 case MODE_FLUSH_CACHES:
3012 return translate("flush-caches", NULL, 0, NULL, bus);
3013
3014 case MODE_RESET_SERVER_FEATURES:
3015 return translate("reset-server-features", NULL, 0, NULL, bus);
be371fe0 3016
a7a4c60a
YW
3017 case MODE_STATUS:
3018 return translate("status", NULL, argc - optind, argv + optind, bus);
14965b94 3019
14965b94 3020 case MODE_SET_LINK:
a7a4c60a
YW
3021 if (arg_set_dns) {
3022 r = translate("dns", arg_ifname, strv_length(arg_set_dns), arg_set_dns, bus);
3023 if (r < 0)
3024 return r;
3025 }
3026
3027 if (arg_set_domain) {
3028 r = translate("domain", arg_ifname, strv_length(arg_set_domain), arg_set_domain, bus);
3029 if (r < 0)
3030 return r;
14965b94
LP
3031 }
3032
a7a4c60a
YW
3033 if (arg_set_nta) {
3034 r = translate("nta", arg_ifname, strv_length(arg_set_nta), arg_set_nta, bus);
3035 if (r < 0)
3036 return r;
3037 }
14965b94 3038
a7a4c60a
YW
3039 if (arg_set_llmnr) {
3040 r = translate("llmnr", arg_ifname, 1, (char **) &arg_set_llmnr, bus);
3041 if (r < 0)
3042 return r;
3043 }
3044
3045 if (arg_set_mdns) {
3046 r = translate("mdns", arg_ifname, 1, (char **) &arg_set_mdns, bus);
3047 if (r < 0)
3048 return r;
3049 }
3050
c9299be2
IT
3051 if (arg_set_dns_over_tls) {
3052 r = translate("dnsovertls", arg_ifname, 1, (char **) &arg_set_dns_over_tls, bus);
d050561a
IT
3053 if (r < 0)
3054 return r;
3055 }
3056
a7a4c60a
YW
3057 if (arg_set_dnssec) {
3058 r = translate("dnssec", arg_ifname, 1, (char **) &arg_set_dnssec, bus);
3059 if (r < 0)
3060 return r;
14965b94
LP
3061 }
3062
a7a4c60a
YW
3063 return r;
3064
3065 case MODE_REVERT_LINK:
3066 return translate("revert", arg_ifname, 0, NULL, bus);
088c1363
LP
3067
3068 case _MODE_INVALID:
3069 assert_not_reached("invalid mode");
bdef7319
ZJS
3070 }
3071
a7a4c60a
YW
3072 return 0;
3073}
3074
3075int main(int argc, char **argv) {
3076 sd_bus *bus = NULL;
3077 int r;
3078
3079 setlocale(LC_ALL, "");
3080 log_parse_environment();
3081 log_open();
3082
3083 if (streq(program_invocation_short_name, "resolvconf"))
3084 r = resolvconf_parse_argv(argc, argv);
3085 else if (streq(program_invocation_short_name, "systemd-resolve"))
3086 r = compat_parse_argv(argc, argv);
3087 else
3088 r = native_parse_argv(argc, argv);
3089 if (r <= 0)
3090 goto finish;
3091
3092 r = sd_bus_open_system(&bus);
3093 if (r < 0) {
3094 log_error_errno(r, "sd_bus_open_system: %m");
3095 goto finish;
3096 }
3097
3098 if (streq(program_invocation_short_name, "systemd-resolve"))
3099 r = compat_main(argc, argv, bus);
3100 else
3101 r = native_main(argc, argv, bus);
3102
79266746 3103finish:
a7a4c60a
YW
3104 /* make sure we terminate the bus connection first, and then close the
3105 * pager, see issue #3543 for the details. */
3106 sd_bus_flush_close_unref(bus);
be371fe0
LP
3107 pager_close();
3108
a7a4c60a 3109 strv_free(arg_set_dns);
14965b94 3110 strv_free(arg_set_domain);
14965b94
LP
3111 strv_free(arg_set_nta);
3112
a7a4c60a 3113 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
bdef7319 3114}