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