1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include "sd-netlink.h"
11 #include "alloc-util.h"
13 #include "bus-common-errors.h"
14 #include "bus-error.h"
15 #include "bus-locator.h"
16 #include "bus-map-properties.h"
17 #include "bus-message-util.h"
18 #include "dns-domain.h"
19 #include "errno-list.h"
21 #include "format-table.h"
22 #include "format-util.h"
23 #include "gcrypt-util.h"
24 #include "hostname-util.h"
26 #include "main-func.h"
27 #include "missing_network.h"
28 #include "netlink-util.h"
29 #include "openssl-util.h"
31 #include "parse-argument.h"
32 #include "parse-util.h"
33 #include "pretty-print.h"
34 #include "process-util.h"
35 #include "resolvconf-compat.h"
36 #include "resolve-util.h"
37 #include "resolvectl.h"
38 #include "resolved-def.h"
39 #include "resolved-dns-packet.h"
40 #include "resolved-util.h"
41 #include "socket-netlink.h"
42 #include "sort-util.h"
43 #include "stdio-util.h"
44 #include "string-table.h"
46 #include "terminal-util.h"
49 #include "verb-log-control.h"
52 static int arg_family
= AF_UNSPEC
;
53 static int arg_ifindex
= 0;
54 static char *arg_ifname
= NULL
;
55 static uint16_t arg_type
= 0;
56 static uint16_t arg_class
= 0;
57 static bool arg_legend
= true;
58 static uint64_t arg_flags
= 0;
59 static JsonFormatFlags arg_json_format_flags
= JSON_FORMAT_OFF
;
60 static PagerFlags arg_pager_flags
= 0;
61 bool arg_ifindex_permissive
= false; /* If true, don't generate an error if the specified interface index doesn't exist */
62 static const char *arg_service_family
= NULL
;
64 typedef enum RawType
{
69 static RawType arg_raw
= RAW_NONE
;
71 ExecutionMode arg_mode
= MODE_RESOLVE_HOST
;
73 char **arg_set_dns
= NULL
;
74 char **arg_set_domain
= NULL
;
75 static const char *arg_set_llmnr
= NULL
;
76 static const char *arg_set_mdns
= NULL
;
77 static const char *arg_set_dns_over_tls
= NULL
;
78 static const char *arg_set_dnssec
= NULL
;
79 static char **arg_set_nta
= NULL
;
81 STATIC_DESTRUCTOR_REGISTER(arg_ifname
, freep
);
82 STATIC_DESTRUCTOR_REGISTER(arg_set_dns
, strv_freep
);
83 STATIC_DESTRUCTOR_REGISTER(arg_set_domain
, strv_freep
);
84 STATIC_DESTRUCTOR_REGISTER(arg_set_nta
, strv_freep
);
86 typedef enum StatusMode
{
98 typedef struct InterfaceInfo
{
103 static int interface_info_compare(const InterfaceInfo
*a
, const InterfaceInfo
*b
) {
106 r
= CMP(a
->index
, b
->index
);
110 return strcmp_ptr(a
->name
, b
->name
);
113 int ifname_mangle_full(const char *s
, bool drop_protocol_specifier
) {
114 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
115 _cleanup_strv_free_
char **found
= NULL
;
120 if (drop_protocol_specifier
) {
121 _cleanup_free_
char *buf
= NULL
;
122 int ifindex_longest_name
= -ENODEV
;
124 /* When invoked as resolvconf, drop the protocol specifier(s) at the end. */
131 r
= rtnl_resolve_interface(&rtnl
, buf
);
133 if (ifindex_longest_name
<= 0)
134 ifindex_longest_name
= r
;
136 r
= strv_extend(&found
, buf
);
141 char *dot
= strrchr(buf
, '.');
148 unsigned n
= strv_length(found
);
150 _cleanup_free_
char *joined
= NULL
;
152 joined
= strv_join(found
, ", ");
153 log_warning("Found multiple interfaces (%s) matching with '%s'. Using '%s' (ifindex=%i).",
154 strna(joined
), s
, found
[0], ifindex_longest_name
);
159 proto
= ASSERT_PTR(startswith(s
, found
[0]));
161 log_info("Dropped protocol specifier '%s' from '%s'. Using '%s' (ifindex=%i).",
162 proto
, s
, found
[0], ifindex_longest_name
);
165 r
= ifindex_longest_name
;
167 r
= rtnl_resolve_interface(&rtnl
, s
);
169 if (ERRNO_IS_DEVICE_ABSENT(r
) && arg_ifindex_permissive
) {
170 log_debug_errno(r
, "Interface '%s' not found, but -f specified, ignoring: %m", s
);
173 return log_error_errno(r
, "Failed to resolve interface \"%s\": %m", s
);
176 if (arg_ifindex
> 0 && arg_ifindex
!= r
)
177 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Specified multiple different interfaces. Refusing.");
180 return free_and_strdup_warn(&arg_ifname
, found
? found
[0] : s
); /* found */
183 static void print_source(uint64_t flags
, usec_t rtt
) {
190 printf("\n%s-- Information acquired via", ansi_grey());
192 printf(" protocol%s%s%s%s%s",
193 flags
& SD_RESOLVED_DNS
? " DNS" :"",
194 flags
& SD_RESOLVED_LLMNR_IPV4
? " LLMNR/IPv4" : "",
195 flags
& SD_RESOLVED_LLMNR_IPV6
? " LLMNR/IPv6" : "",
196 flags
& SD_RESOLVED_MDNS_IPV4
? " mDNS/IPv4" : "",
197 flags
& SD_RESOLVED_MDNS_IPV6
? " mDNS/IPv6" : "");
200 "%s-- Data is authenticated: %s; Data was acquired via local or encrypted transport: %s%s\n",
201 FORMAT_TIMESPAN(rtt
, 100),
204 yes_no(flags
& SD_RESOLVED_AUTHENTICATED
),
205 yes_no(flags
& SD_RESOLVED_CONFIDENTIAL
),
208 if ((flags
& (SD_RESOLVED_FROM_MASK
|SD_RESOLVED_SYNTHETIC
)) != 0)
209 printf("%s-- Data from:%s%s%s%s%s%s\n",
211 FLAGS_SET(flags
, SD_RESOLVED_SYNTHETIC
) ? " synthetic" : "",
212 FLAGS_SET(flags
, SD_RESOLVED_FROM_CACHE
) ? " cache" : "",
213 FLAGS_SET(flags
, SD_RESOLVED_FROM_ZONE
) ? " zone" : "",
214 FLAGS_SET(flags
, SD_RESOLVED_FROM_TRUST_ANCHOR
) ? " trust-anchor" : "",
215 FLAGS_SET(flags
, SD_RESOLVED_FROM_NETWORK
) ? " network" : "",
219 static void print_ifindex_comment(int printed_so_far
, int ifindex
) {
220 char ifname
[IF_NAMESIZE
];
226 r
= format_ifname(ifindex
, ifname
);
228 return (void) log_warning_errno(r
, "Failed to resolve interface name for index %i, ignoring: %m", ifindex
);
230 printf("%*s%s-- link: %s%s",
231 60 > printed_so_far
? 60 - printed_so_far
: 0, " ", /* Align comment to the 60th column */
232 ansi_grey(), ifname
, ansi_normal());
235 static int resolve_host_error(const char *name
, int r
, const sd_bus_error
*error
) {
236 if (sd_bus_error_has_name(error
, BUS_ERROR_DNS_NXDOMAIN
))
237 return log_error_errno(r
, "%s: %s", name
, bus_error_message(error
, r
));
239 return log_error_errno(r
, "%s: resolve call failed: %s", name
, bus_error_message(error
, r
));
242 static int resolve_host(sd_bus
*bus
, const char *name
) {
243 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
244 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
245 const char *canonical
= NULL
;
253 log_debug("Resolving %s (family %s, interface %s).", name
, af_to_name(arg_family
) ?: "*", isempty(arg_ifname
) ? "*" : arg_ifname
);
255 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveHostname");
257 return bus_log_create_error(r
);
259 r
= sd_bus_message_append(req
, "isit", arg_ifindex
, name
, arg_family
, arg_flags
);
261 return bus_log_create_error(r
);
263 ts
= now(CLOCK_MONOTONIC
);
265 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
267 return resolve_host_error(name
, r
, &error
);
269 ts
= now(CLOCK_MONOTONIC
) - ts
;
271 r
= sd_bus_message_enter_container(reply
, 'a', "(iiay)");
273 return bus_log_parse_error(r
);
275 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iiay")) > 0) {
276 _cleanup_free_
char *pretty
= NULL
;
277 int ifindex
, family
, k
;
278 union in_addr_union a
;
280 assert_cc(sizeof(int) == sizeof(int32_t));
282 r
= sd_bus_message_read(reply
, "i", &ifindex
);
284 return bus_log_parse_error(r
);
286 sd_bus_error_free(&error
);
287 r
= bus_message_read_in_addr_auto(reply
, &error
, &family
, &a
);
288 if (r
< 0 && !sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
))
289 return log_error_errno(r
, "%s: systemd-resolved returned invalid result: %s", name
, bus_error_message(&error
, r
));
291 r
= sd_bus_message_exit_container(reply
);
293 return bus_log_parse_error(r
);
295 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
)) {
296 log_debug_errno(r
, "%s: systemd-resolved returned invalid result, ignoring: %s", name
, bus_error_message(&error
, r
));
300 r
= in_addr_ifindex_to_string(family
, &a
, ifindex
, &pretty
);
302 return log_error_errno(r
, "Failed to print address for %s: %m", name
);
304 k
= printf("%*s%s %s%s%s",
305 (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? ":" : " ",
306 ansi_highlight(), pretty
, ansi_normal());
308 print_ifindex_comment(k
, ifindex
);
314 return bus_log_parse_error(r
);
316 r
= sd_bus_message_exit_container(reply
);
318 return bus_log_parse_error(r
);
320 r
= sd_bus_message_read(reply
, "st", &canonical
, &flags
);
322 return bus_log_parse_error(r
);
324 if (!streq(name
, canonical
))
325 printf("%*s%s (%s)\n",
326 (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? ":" : " ",
330 return log_error_errno(SYNTHETIC_ERRNO(ESRCH
),
331 "%s: no addresses found", name
);
333 print_source(flags
, ts
);
338 static int resolve_address(sd_bus
*bus
, int family
, const union in_addr_union
*address
, int ifindex
) {
339 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
340 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
341 _cleanup_free_
char *pretty
= NULL
;
348 assert(IN_SET(family
, AF_INET
, AF_INET6
));
352 ifindex
= arg_ifindex
;
354 r
= in_addr_ifindex_to_string(family
, address
, ifindex
, &pretty
);
358 log_debug("Resolving %s.", pretty
);
360 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveAddress");
362 return bus_log_create_error(r
);
364 r
= sd_bus_message_append(req
, "ii", ifindex
, family
);
366 return bus_log_create_error(r
);
368 r
= sd_bus_message_append_array(req
, 'y', address
, FAMILY_ADDRESS_SIZE(family
));
370 return bus_log_create_error(r
);
372 r
= sd_bus_message_append(req
, "t", arg_flags
);
374 return bus_log_create_error(r
);
376 ts
= now(CLOCK_MONOTONIC
);
378 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
380 return log_error_errno(r
, "%s: resolve call failed: %s", pretty
, bus_error_message(&error
, r
));
382 ts
= now(CLOCK_MONOTONIC
) - ts
;
384 r
= sd_bus_message_enter_container(reply
, 'a', "(is)");
386 return bus_log_create_error(r
);
388 while ((r
= sd_bus_message_enter_container(reply
, 'r', "is")) > 0) {
392 assert_cc(sizeof(int) == sizeof(int32_t));
394 r
= sd_bus_message_read(reply
, "is", &ifindex
, &n
);
398 r
= sd_bus_message_exit_container(reply
);
402 k
= printf("%*s%s %s%s%s",
403 (int) strlen(pretty
), c
== 0 ? pretty
: "",
405 ansi_highlight(), n
, ansi_normal());
407 print_ifindex_comment(k
, ifindex
);
413 return bus_log_parse_error(r
);
415 r
= sd_bus_message_exit_container(reply
);
417 return bus_log_parse_error(r
);
419 r
= sd_bus_message_read(reply
, "t", &flags
);
421 return bus_log_parse_error(r
);
424 return log_error_errno(SYNTHETIC_ERRNO(ESRCH
),
425 "%s: no names found", pretty
);
427 print_source(flags
, ts
);
432 static int output_rr_packet(const void *d
, size_t l
, int ifindex
) {
433 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
436 r
= dns_resource_record_new_from_raw(&rr
, d
, l
);
438 return log_error_errno(r
, "Failed to parse RR: %m");
440 if (arg_raw
== RAW_PAYLOAD
) {
444 k
= dns_resource_record_payload(rr
, &data
);
446 return log_error_errno(k
, "Cannot dump RR: %m");
447 fwrite(data
, 1, k
, stdout
);
452 s
= dns_resource_record_to_string(rr
);
457 print_ifindex_comment(k
, ifindex
);
464 static int idna_candidate(const char *name
, char **ret
) {
465 _cleanup_free_
char *idnafied
= NULL
;
471 r
= dns_name_apply_idna(name
, &idnafied
);
473 return log_error_errno(r
, "Failed to apply IDNA to name '%s': %m", name
);
474 if (r
> 0 && !streq(name
, idnafied
)) {
475 *ret
= TAKE_PTR(idnafied
);
483 static bool single_label_nonsynthetic(const char *name
) {
484 _cleanup_free_
char *first_label
= NULL
;
487 if (!dns_name_is_single_label(name
))
490 if (is_localhost(name
) ||
491 is_gateway_hostname(name
) ||
492 is_outbound_hostname(name
) ||
493 is_dns_stub_hostname(name
) ||
494 is_dns_proxy_stub_hostname(name
))
497 r
= resolve_system_hostname(NULL
, &first_label
);
499 log_warning_errno(r
, "Failed to determine the hostname: %m");
503 return !streq(name
, first_label
);
506 static int resolve_record(sd_bus
*bus
, const char *name
, uint16_t class, uint16_t type
, bool warn_missing
) {
507 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
508 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
509 _cleanup_free_
char *idnafied
= NULL
;
510 bool needs_authentication
= false;
518 log_debug("Resolving %s %s %s (interface %s).", name
, dns_class_to_string(class), dns_type_to_string(type
), isempty(arg_ifname
) ? "*" : arg_ifname
);
520 if (dns_name_dot_suffixed(name
) == 0 && single_label_nonsynthetic(name
))
521 log_notice("(Note that search domains are not appended when --type= is specified. "
522 "Please specify fully qualified domain names, or remove --type= switch from invocation in order to request regular hostname resolution.)");
524 r
= idna_candidate(name
, &idnafied
);
528 log_notice("(Note that IDNA translation is not applied when --type= is specified. "
529 "Please specify translated domain names — i.e. '%s' — when resolving raw records, or remove --type= switch from invocation in order to request regular hostname resolution.",
532 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveRecord");
534 return bus_log_create_error(r
);
536 r
= sd_bus_message_append(req
, "isqqt", arg_ifindex
, name
, class, type
, arg_flags
);
538 return bus_log_create_error(r
);
540 ts
= now(CLOCK_MONOTONIC
);
542 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
544 if (warn_missing
|| r
!= -ENXIO
)
545 log_error("%s: resolve call failed: %s", name
, bus_error_message(&error
, r
));
549 ts
= now(CLOCK_MONOTONIC
) - ts
;
551 r
= sd_bus_message_enter_container(reply
, 'a', "(iqqay)");
553 return bus_log_parse_error(r
);
555 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iqqay")) > 0) {
561 assert_cc(sizeof(int) == sizeof(int32_t));
563 r
= sd_bus_message_read(reply
, "iqq", &ifindex
, &c
, &t
);
565 return bus_log_parse_error(r
);
567 r
= sd_bus_message_read_array(reply
, 'y', &d
, &l
);
569 return bus_log_parse_error(r
);
571 r
= sd_bus_message_exit_container(reply
);
573 return bus_log_parse_error(r
);
575 if (arg_raw
== RAW_PACKET
) {
576 uint64_t u64
= htole64(l
);
578 fwrite(&u64
, sizeof(u64
), 1, stdout
);
579 fwrite(d
, 1, l
, stdout
);
581 r
= output_rr_packet(d
, l
, ifindex
);
586 if (dns_type_needs_authentication(t
))
587 needs_authentication
= true;
592 return bus_log_parse_error(r
);
594 r
= sd_bus_message_exit_container(reply
);
596 return bus_log_parse_error(r
);
598 r
= sd_bus_message_read(reply
, "t", &flags
);
600 return bus_log_parse_error(r
);
604 log_error("%s: no records found", name
);
608 print_source(flags
, ts
);
610 if ((flags
& SD_RESOLVED_AUTHENTICATED
) == 0 && needs_authentication
) {
613 fprintf(stderr
, "\n%s"
614 "WARNING: The resources shown contain cryptographic key data which could not be\n"
615 " authenticated. It is not suitable to authenticate any communication.\n"
616 " This is usually indication that DNSSEC authentication was not enabled\n"
617 " or is not available for the selected protocol or DNS servers.%s\n",
618 ansi_highlight_red(),
625 static int resolve_rfc4501(sd_bus
*bus
, const char *name
) {
626 uint16_t type
= 0, class = 0;
627 const char *p
, *q
, *n
;
632 assert(startswith(name
, "dns:"));
634 /* Parse RFC 4501 dns: URIs */
644 e
= strchr(p
+ 2, '/');
649 log_warning("DNS authority specification not supported; ignoring specified authority.");
656 n
= strndupa_safe(p
, q
- p
);
662 f
= startswith_no_case(q
, "class=");
664 _cleanup_free_
char *t
= NULL
;
668 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
669 "DNS class specified twice.");
671 e
= strchrnul(f
, ';');
672 t
= strndup(f
, e
- f
);
676 r
= dns_class_from_string(t
);
678 return log_error_errno(r
, "Unknown DNS class %s.", t
);
690 f
= startswith_no_case(q
, "type=");
692 _cleanup_free_
char *t
= NULL
;
696 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
697 "DNS type specified twice.");
699 e
= strchrnul(f
, ';');
700 t
= strndup(f
, e
- f
);
704 r
= dns_type_from_string(t
);
706 return log_error_errno(r
, "Unknown DNS type %s: %m", t
);
724 class = arg_class
?: DNS_CLASS_IN
;
726 type
= arg_type
?: DNS_TYPE_A
;
728 return resolve_record(bus
, n
, class, type
, true);
731 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
732 "Invalid DNS URI: %s", name
);
735 static int verb_query(int argc
, char **argv
, void *userdata
) {
736 sd_bus
*bus
= userdata
;
740 STRV_FOREACH(p
, argv
+ 1) {
741 q
= resolve_record(bus
, *p
, arg_class
, arg_type
, true);
747 STRV_FOREACH(p
, argv
+ 1) {
748 if (startswith(*p
, "dns:"))
749 q
= resolve_rfc4501(bus
, *p
);
752 union in_addr_union a
;
754 q
= in_addr_ifindex_from_string_auto(*p
, &family
, &a
, &ifindex
);
756 q
= resolve_address(bus
, family
, &a
, ifindex
);
758 q
= resolve_host(bus
, *p
);
767 static int resolve_service(sd_bus
*bus
, const char *name
, const char *type
, const char *domain
) {
768 const char *canonical_name
, *canonical_type
, *canonical_domain
;
769 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
770 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
781 name
= empty_to_null(name
);
782 type
= empty_to_null(type
);
785 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
);
787 log_debug("Resolving service type %s of %s (family %s, interface %s).", type
, domain
, af_to_name(arg_family
) ?: "*", isempty(arg_ifname
) ? "*" : arg_ifname
);
789 log_debug("Resolving service type %s (family %s, interface %s).", domain
, af_to_name(arg_family
) ?: "*", isempty(arg_ifname
) ? "*" : arg_ifname
);
791 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveService");
793 return bus_log_create_error(r
);
795 r
= sd_bus_message_append(req
, "isssit", arg_ifindex
, name
, type
, domain
, arg_family
, arg_flags
);
797 return bus_log_create_error(r
);
799 ts
= now(CLOCK_MONOTONIC
);
801 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
803 return log_error_errno(r
, "Resolve call failed: %s", bus_error_message(&error
, r
));
805 ts
= now(CLOCK_MONOTONIC
) - ts
;
807 r
= sd_bus_message_enter_container(reply
, 'a', "(qqqsa(iiay)s)");
809 return bus_log_parse_error(r
);
812 (name
? strlen(name
) + 1 : 0) +
813 (type
? strlen(type
) + 1 : 0) +
817 while ((r
= sd_bus_message_enter_container(reply
, 'r', "qqqsa(iiay)s")) > 0) {
818 uint16_t priority
, weight
, port
;
819 const char *hostname
, *canonical
;
821 r
= sd_bus_message_read(reply
, "qqqs", &priority
, &weight
, &port
, &hostname
);
823 return bus_log_parse_error(r
);
826 printf("%*s%s", (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? "/" : " ");
828 printf("%*s%s", (int) strlen(type
), c
== 0 ? type
: "", c
== 0 ? "/" : " ");
830 printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
831 (int) strlen(domain
), c
== 0 ? domain
: "",
836 r
= sd_bus_message_enter_container(reply
, 'a', "(iiay)");
838 return bus_log_parse_error(r
);
840 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iiay")) > 0) {
841 _cleanup_free_
char *pretty
= NULL
;
842 int ifindex
, family
, k
;
843 union in_addr_union a
;
845 assert_cc(sizeof(int) == sizeof(int32_t));
847 r
= sd_bus_message_read(reply
, "i", &ifindex
);
849 return bus_log_parse_error(r
);
851 sd_bus_error_free(&error
);
852 r
= bus_message_read_in_addr_auto(reply
, &error
, &family
, &a
);
853 if (r
< 0 && !sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
))
854 return log_error_errno(r
, "%s: systemd-resolved returned invalid result: %s", name
, bus_error_message(&error
, r
));
856 r
= sd_bus_message_exit_container(reply
);
858 return bus_log_parse_error(r
);
860 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
)) {
861 log_debug_errno(r
, "%s: systemd-resolved returned invalid result, ignoring: %s", name
, bus_error_message(&error
, r
));
865 r
= in_addr_ifindex_to_string(family
, &a
, ifindex
, &pretty
);
867 return log_error_errno(r
, "Failed to print address for %s: %m", name
);
869 k
= printf("%*s%s", (int) indent
, "", pretty
);
870 print_ifindex_comment(k
, ifindex
);
874 return bus_log_parse_error(r
);
876 r
= sd_bus_message_exit_container(reply
);
878 return bus_log_parse_error(r
);
880 r
= sd_bus_message_read(reply
, "s", &canonical
);
882 return bus_log_parse_error(r
);
884 if (!streq(hostname
, canonical
))
885 printf("%*s(%s)\n", (int) indent
, "", canonical
);
887 r
= sd_bus_message_exit_container(reply
);
889 return bus_log_parse_error(r
);
894 return bus_log_parse_error(r
);
896 r
= sd_bus_message_exit_container(reply
);
898 return bus_log_parse_error(r
);
900 r
= sd_bus_message_enter_container(reply
, 'a', "ay");
902 return bus_log_parse_error(r
);
904 while ((r
= sd_bus_message_read_array(reply
, 'y', (const void**) &p
, &sz
)) > 0) {
905 _cleanup_free_
char *escaped
= NULL
;
907 escaped
= cescape_length(p
, sz
);
911 printf("%*s%s\n", (int) indent
, "", escaped
);
914 return bus_log_parse_error(r
);
916 r
= sd_bus_message_exit_container(reply
);
918 return bus_log_parse_error(r
);
920 r
= sd_bus_message_read(reply
, "ssst", &canonical_name
, &canonical_type
, &canonical_domain
, &flags
);
922 return bus_log_parse_error(r
);
924 canonical_name
= empty_to_null(canonical_name
);
925 canonical_type
= empty_to_null(canonical_type
);
927 if (!streq_ptr(name
, canonical_name
) ||
928 !streq_ptr(type
, canonical_type
) ||
929 !streq_ptr(domain
, canonical_domain
)) {
931 printf("%*s(", (int) indent
, "");
934 printf("%s/", canonical_name
);
936 printf("%s/", canonical_type
);
938 printf("%s)\n", canonical_domain
);
941 print_source(flags
, ts
);
946 static int verb_service(int argc
, char **argv
, void *userdata
) {
947 sd_bus
*bus
= userdata
;
950 return resolve_service(bus
, NULL
, NULL
, argv
[1]);
952 return resolve_service(bus
, NULL
, argv
[1], argv
[2]);
954 return resolve_service(bus
, argv
[1], argv
[2], argv
[3]);
957 static int resolve_openpgp(sd_bus
*bus
, const char *address
) {
958 const char *domain
, *full
;
960 _cleanup_free_
char *hashed
= NULL
;
965 domain
= strrchr(address
, '@');
967 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
968 "Address does not contain '@': \"%s\"", address
);
969 if (domain
== address
|| domain
[1] == '\0')
970 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
971 "Address starts or ends with '@': \"%s\"", address
);
974 r
= string_hashsum_sha256(address
, domain
- 1 - address
, &hashed
);
976 return log_error_errno(r
, "Hashing failed: %m");
978 strshorten(hashed
, 56);
980 full
= strjoina(hashed
, "._openpgpkey.", domain
);
981 log_debug("Looking up \"%s\".", full
);
983 r
= resolve_record(bus
, full
,
984 arg_class
?: DNS_CLASS_IN
,
985 arg_type
?: DNS_TYPE_OPENPGPKEY
, false);
987 if (IN_SET(r
, -ENXIO
, -ESRCH
)) { /* NXDOMAIN or NODATA? */
988 hashed
= mfree(hashed
);
989 r
= string_hashsum_sha224(address
, domain
- 1 - address
, &hashed
);
991 return log_error_errno(r
, "Hashing failed: %m");
993 full
= strjoina(hashed
, "._openpgpkey.", domain
);
994 log_debug("Looking up \"%s\".", full
);
996 return resolve_record(bus
, full
,
997 arg_class
?: DNS_CLASS_IN
,
998 arg_type
?: DNS_TYPE_OPENPGPKEY
, true);
1004 static int verb_openpgp(int argc
, char **argv
, void *userdata
) {
1005 sd_bus
*bus
= userdata
;
1008 STRV_FOREACH(p
, argv
+ 1) {
1009 q
= resolve_openpgp(bus
, *p
);
1017 static int resolve_tlsa(sd_bus
*bus
, const char *family
, const char *address
) {
1019 uint16_t port_num
= 443;
1020 _cleanup_free_
char *full
= NULL
;
1026 port
= strrchr(address
, ':');
1028 r
= parse_ip_port(port
+ 1, &port_num
);
1030 return log_error_errno(r
, "Invalid port \"%s\".", port
+ 1);
1032 address
= strndupa_safe(address
, port
- address
);
1035 r
= asprintf(&full
, "_%u._%s.%s",
1042 log_debug("Looking up \"%s\".", full
);
1044 return resolve_record(bus
, full
,
1045 arg_class
?: DNS_CLASS_IN
,
1046 arg_type
?: DNS_TYPE_TLSA
, true);
1049 static bool service_family_is_valid(const char *s
) {
1050 return STR_IN_SET(s
, "tcp", "udp", "sctp");
1053 static int verb_tlsa(int argc
, char **argv
, void *userdata
) {
1054 sd_bus
*bus
= userdata
;
1055 char **args
= argv
+ 1;
1056 const char *family
= "tcp";
1059 if (service_family_is_valid(argv
[1])) {
1064 STRV_FOREACH(p
, args
) {
1065 q
= resolve_tlsa(bus
, family
, *p
);
1073 static int show_statistics(int argc
, char **argv
, void *userdata
) {
1074 _cleanup_(table_unrefp
) Table
*table
= NULL
;
1075 JsonVariant
*reply
= NULL
;
1076 _cleanup_(varlink_unrefp
) Varlink
*vl
= NULL
;
1079 r
= varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
1081 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
1083 r
= varlink_call(vl
, "io.systemd.Resolve.Monitor.DumpStatistics", NULL
, &reply
, NULL
, 0);
1085 return log_error_errno(r
, "Failed to issue DumpStatistics() varlink call: %m");
1087 if (!FLAGS_SET(arg_json_format_flags
, JSON_FORMAT_OFF
))
1088 return json_variant_dump(reply
, arg_json_format_flags
, NULL
, NULL
);
1091 JsonVariant
*transactions
;
1093 JsonVariant
*dnssec
;
1096 static const JsonDispatch statistics_dispatch_table
[] = {
1097 { "transactions", JSON_VARIANT_OBJECT
, json_dispatch_variant_noref
, offsetof(struct statistics
, transactions
), JSON_MANDATORY
},
1098 { "cache", JSON_VARIANT_OBJECT
, json_dispatch_variant_noref
, offsetof(struct statistics
, cache
), JSON_MANDATORY
},
1099 { "dnssec", JSON_VARIANT_OBJECT
, json_dispatch_variant_noref
, offsetof(struct statistics
, dnssec
), JSON_MANDATORY
},
1103 r
= json_dispatch(reply
, statistics_dispatch_table
, JSON_LOG
, &statistics
);
1107 struct transactions
{
1108 uint64_t n_current_transactions
;
1109 uint64_t n_transactions_total
;
1110 uint64_t n_timeouts_total
;
1111 uint64_t n_timeouts_served_stale_total
;
1112 uint64_t n_failure_responses_total
;
1113 uint64_t n_failure_responses_served_stale_total
;
1116 static const JsonDispatch transactions_dispatch_table
[] = {
1117 { "currentTransactions", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct transactions
, n_current_transactions
), JSON_MANDATORY
},
1118 { "totalTransactions", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct transactions
, n_transactions_total
), JSON_MANDATORY
},
1119 { "totalTimeouts", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct transactions
, n_timeouts_total
), JSON_MANDATORY
},
1120 { "totalTimeoutsServedStale", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct transactions
, n_timeouts_served_stale_total
), JSON_MANDATORY
},
1121 { "totalFailedResponses", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct transactions
, n_failure_responses_total
), JSON_MANDATORY
},
1122 { "totalFailedResponsesServedStale", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct transactions
, n_failure_responses_served_stale_total
), JSON_MANDATORY
},
1126 r
= json_dispatch(statistics
.transactions
, transactions_dispatch_table
, JSON_LOG
, &transactions
);
1131 uint64_t cache_size
;
1132 uint64_t n_cache_hit
;
1133 uint64_t n_cache_miss
;
1136 static const JsonDispatch cache_dispatch_table
[] = {
1137 { "size", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct cache
, cache_size
), JSON_MANDATORY
},
1138 { "hits", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct cache
, n_cache_hit
), JSON_MANDATORY
},
1139 { "misses", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct cache
, n_cache_miss
), JSON_MANDATORY
},
1143 r
= json_dispatch(statistics
.cache
, cache_dispatch_table
, JSON_LOG
, &cache
);
1148 uint64_t n_dnssec_secure
;
1149 uint64_t n_dnssec_insecure
;
1150 uint64_t n_dnssec_bogus
;
1151 uint64_t n_dnssec_indeterminate
;
1154 static const JsonDispatch dnssec_dispatch_table
[] = {
1155 { "secure", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct dnsssec
, n_dnssec_secure
), JSON_MANDATORY
},
1156 { "insecure", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct dnsssec
, n_dnssec_insecure
), JSON_MANDATORY
},
1157 { "bogus", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct dnsssec
, n_dnssec_bogus
), JSON_MANDATORY
},
1158 { "indeterminate", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct dnsssec
, n_dnssec_indeterminate
), JSON_MANDATORY
},
1162 r
= json_dispatch(statistics
.dnssec
, dnssec_dispatch_table
, JSON_LOG
, &dnsssec
);
1166 table
= table_new_vertical();
1170 r
= table_add_many(table
,
1171 TABLE_STRING
, "Transactions",
1172 TABLE_SET_COLOR
, ansi_highlight(),
1173 TABLE_SET_ALIGN_PERCENT
, 0,
1175 TABLE_FIELD
, "Current Transactions",
1176 TABLE_SET_ALIGN_PERCENT
, 100,
1177 TABLE_UINT64
, transactions
.n_current_transactions
,
1178 TABLE_SET_ALIGN_PERCENT
, 100,
1179 TABLE_FIELD
, "Total Transactions",
1180 TABLE_UINT64
, transactions
.n_transactions_total
,
1181 TABLE_EMPTY
, TABLE_EMPTY
,
1182 TABLE_STRING
, "Cache",
1183 TABLE_SET_COLOR
, ansi_highlight(),
1184 TABLE_SET_ALIGN_PERCENT
, 0,
1186 TABLE_FIELD
, "Current Cache Size",
1187 TABLE_SET_ALIGN_PERCENT
, 100,
1188 TABLE_UINT64
, cache
.cache_size
,
1189 TABLE_FIELD
, "Cache Hits",
1190 TABLE_UINT64
, cache
.n_cache_hit
,
1191 TABLE_FIELD
, "Cache Misses",
1192 TABLE_UINT64
, cache
.n_cache_miss
,
1193 TABLE_EMPTY
, TABLE_EMPTY
,
1194 TABLE_STRING
, "Failure Transactions",
1195 TABLE_SET_COLOR
, ansi_highlight(),
1196 TABLE_SET_ALIGN_PERCENT
, 0,
1198 TABLE_FIELD
, "Total Timeouts",
1199 TABLE_SET_ALIGN_PERCENT
, 100,
1200 TABLE_UINT64
, transactions
.n_timeouts_total
,
1201 TABLE_FIELD
, "Total Timeouts (Stale Data Served)",
1202 TABLE_UINT64
, transactions
.n_timeouts_served_stale_total
,
1203 TABLE_FIELD
, "Total Failure Responses",
1204 TABLE_UINT64
, transactions
.n_failure_responses_total
,
1205 TABLE_FIELD
, "Total Failure Responses (Stale Data Served)",
1206 TABLE_UINT64
, transactions
.n_failure_responses_served_stale_total
,
1207 TABLE_EMPTY
, TABLE_EMPTY
,
1208 TABLE_STRING
, "DNSSEC Verdicts",
1209 TABLE_SET_COLOR
, ansi_highlight(),
1210 TABLE_SET_ALIGN_PERCENT
, 0,
1212 TABLE_FIELD
, "Secure",
1213 TABLE_SET_ALIGN_PERCENT
, 100,
1214 TABLE_UINT64
, dnsssec
.n_dnssec_secure
,
1215 TABLE_FIELD
, "Insecure",
1216 TABLE_UINT64
, dnsssec
.n_dnssec_insecure
,
1217 TABLE_FIELD
, "Bogus",
1218 TABLE_UINT64
, dnsssec
.n_dnssec_bogus
,
1219 TABLE_FIELD
, "Indeterminate",
1220 TABLE_UINT64
, dnsssec
.n_dnssec_indeterminate
1223 return table_log_add_error(r
);
1225 r
= table_print(table
, NULL
);
1227 return table_log_print_error(r
);
1232 static int reset_statistics(int argc
, char **argv
, void *userdata
) {
1233 JsonVariant
*reply
= NULL
;
1234 _cleanup_(varlink_unrefp
) Varlink
*vl
= NULL
;
1237 r
= varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
1239 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
1241 r
= varlink_call(vl
, "io.systemd.Resolve.Monitor.ResetStatistics", NULL
, &reply
, NULL
, 0);
1243 return log_error_errno(r
, "Failed to issue ResetStatistics() varlink call: %m");
1245 if (!FLAGS_SET(arg_json_format_flags
, JSON_FORMAT_OFF
))
1246 return json_variant_dump(reply
, arg_json_format_flags
, NULL
, NULL
);
1251 static int flush_caches(int argc
, char **argv
, void *userdata
) {
1252 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1253 sd_bus
*bus
= userdata
;
1256 r
= bus_call_method(bus
, bus_resolve_mgr
, "FlushCaches", &error
, NULL
, NULL
);
1258 return log_error_errno(r
, "Failed to flush caches: %s", bus_error_message(&error
, r
));
1263 static int reset_server_features(int argc
, char **argv
, void *userdata
) {
1264 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1265 sd_bus
*bus
= userdata
;
1268 r
= bus_call_method(bus
, bus_resolve_mgr
, "ResetServerFeatures", &error
, NULL
, NULL
);
1270 return log_error_errno(r
, "Failed to reset server features: %s", bus_error_message(&error
, r
));
1275 static int read_dns_server_one(
1277 bool with_ifindex
, /* read "ifindex" reply that also carries an interface index */
1278 bool extended
, /* read "extended" reply, i.e. with port number and server name */
1279 bool only_global
, /* suppress entries with an (non-loopback) ifindex set (i.e. which are specific to some interface) */
1282 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1283 _cleanup_free_
char *pretty
= NULL
;
1284 union in_addr_union a
;
1285 const char *name
= NULL
;
1286 int32_t ifindex
= 0;
1293 r
= sd_bus_message_enter_container(
1296 with_ifindex
? (extended
? "iiayqs" : "iiay") :
1297 (extended
? "iayqs" : "iay"));
1302 r
= sd_bus_message_read(m
, "i", &ifindex
);
1307 k
= bus_message_read_in_addr_auto(m
, &error
, &family
, &a
);
1308 if (k
< 0 && !sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
))
1312 r
= sd_bus_message_read(m
, "q", &port
);
1316 r
= sd_bus_message_read(m
, "s", &name
);
1321 r
= sd_bus_message_exit_container(m
);
1326 log_debug("Invalid DNS server, ignoring: %s", bus_error_message(&error
, k
));
1331 if (only_global
&& ifindex
> 0 && ifindex
!= LOOPBACK_IFINDEX
) {
1332 /* This one has an (non-loopback) ifindex set, and we were told to suppress those. Hence do so. */
1337 r
= in_addr_port_ifindex_name_to_string(family
, &a
, port
, ifindex
, name
, &pretty
);
1341 *ret
= TAKE_PTR(pretty
);
1345 static int map_link_dns_servers_internal(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
, bool extended
) {
1346 char ***l
= ASSERT_PTR(userdata
);
1353 r
= sd_bus_message_enter_container(m
, 'a', extended
? "(iayqs)" : "(iay)");
1358 _cleanup_free_
char *pretty
= NULL
;
1360 r
= read_dns_server_one(m
, /* with_ifindex= */ false, extended
, /* only_global= */ false, &pretty
);
1366 if (isempty(pretty
))
1369 r
= strv_consume(l
, TAKE_PTR(pretty
));
1374 r
= sd_bus_message_exit_container(m
);
1381 static int map_link_dns_servers(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1382 return map_link_dns_servers_internal(bus
, member
, m
, error
, userdata
, false);
1385 static int map_link_dns_servers_ex(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1386 return map_link_dns_servers_internal(bus
, member
, m
, error
, userdata
, true);
1389 static int map_link_current_dns_server(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1393 return read_dns_server_one(m
, /* with_ifindex= */ false, /* extended= */ false, /* only_global= */ false, userdata
);
1396 static int map_link_current_dns_server_ex(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1400 return read_dns_server_one(m
, /* with_ifindex= */ false, /* extended= */ true, /* only_global= */ false, userdata
);
1403 static int read_domain_one(sd_bus_message
*m
, bool with_ifindex
, char **ret
) {
1404 _cleanup_free_
char *str
= NULL
;
1405 int ifindex
, route_only
, r
;
1412 r
= sd_bus_message_read(m
, "(isb)", &ifindex
, &domain
, &route_only
);
1414 r
= sd_bus_message_read(m
, "(sb)", &domain
, &route_only
);
1418 if (with_ifindex
&& ifindex
!= 0) {
1419 /* only show the global ones here */
1425 str
= strjoin("~", domain
);
1427 str
= strdup(domain
);
1431 *ret
= TAKE_PTR(str
);
1436 static int map_link_domains(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1437 char ***l
= ASSERT_PTR(userdata
);
1444 r
= sd_bus_message_enter_container(m
, 'a', "(sb)");
1449 _cleanup_free_
char *pretty
= NULL
;
1451 r
= read_domain_one(m
, false, &pretty
);
1457 if (isempty(pretty
))
1460 r
= strv_consume(l
, TAKE_PTR(pretty
));
1465 r
= sd_bus_message_exit_container(m
);
1472 static int status_print_strv_ifindex(int ifindex
, const char *ifname
, char **p
) {
1473 const unsigned indent
= strlen("Global: "); /* Use the same indentation everywhere to make things nice */
1477 printf("%s%nLink %i (%s)%n%s:", ansi_highlight(), &pos1
, ifindex
, ifname
, &pos2
, ansi_normal());
1479 printf("%s%nGlobal%n%s:", ansi_highlight(), &pos1
, &pos2
, ansi_normal());
1481 size_t cols
= columns(), position
= pos2
- pos1
+ 2;
1483 STRV_FOREACH(i
, p
) {
1484 size_t our_len
= utf8_console_width(*i
); /* This returns -1 on invalid utf-8 (which shouldn't happen).
1485 * If that happens, we'll just print one item per line. */
1487 if (position
<= indent
|| size_add(size_add(position
, 1), our_len
) < cols
) {
1489 position
= size_add(size_add(position
, 1), our_len
);
1491 printf("\n%*s%s", (int) indent
, "", *i
);
1492 position
= size_add(our_len
, indent
);
1501 static int status_print_strv_global(char **p
) {
1502 return status_print_strv_ifindex(0, NULL
, p
);
1505 typedef struct LinkInfo
{
1506 uint64_t scopes_mask
;
1509 const char *dns_over_tls
;
1512 char *current_dns_ex
;
1517 bool dnssec_supported
;
1521 typedef struct GlobalInfo
{
1523 char *current_dns_ex
;
1526 char **fallback_dns
;
1527 char **fallback_dns_ex
;
1532 const char *dns_over_tls
;
1534 const char *resolv_conf_mode
;
1535 bool dnssec_supported
;
1538 static void link_info_clear(LinkInfo
*p
) {
1539 free(p
->current_dns
);
1540 free(p
->current_dns_ex
);
1542 strv_free(p
->dns_ex
);
1543 strv_free(p
->domains
);
1547 static void global_info_clear(GlobalInfo
*p
) {
1548 free(p
->current_dns
);
1549 free(p
->current_dns_ex
);
1551 strv_free(p
->dns_ex
);
1552 strv_free(p
->fallback_dns
);
1553 strv_free(p
->fallback_dns_ex
);
1554 strv_free(p
->domains
);
1558 static int dump_list(Table
*table
, const char *field
, char * const *l
) {
1561 if (strv_isempty(l
))
1564 r
= table_add_many(table
,
1566 TABLE_STRV_WRAPPED
, l
);
1568 return table_log_add_error(r
);
1573 static int strv_extend_extended_bool(char ***strv
, const char *name
, const char *value
) {
1577 r
= parse_boolean(value
);
1579 return strv_extendf(strv
, "%s%s", plus_minus(r
), name
);
1582 return strv_extendf(strv
, "%s=%s", name
, value
?: "???");
1585 static char** link_protocol_status(const LinkInfo
*info
) {
1586 _cleanup_strv_free_
char **s
= NULL
;
1588 if (strv_extendf(&s
, "%sDefaultRoute", plus_minus(info
->default_route
)) < 0)
1591 if (strv_extend_extended_bool(&s
, "LLMNR", info
->llmnr
) < 0)
1594 if (strv_extend_extended_bool(&s
, "mDNS", info
->mdns
) < 0)
1597 if (strv_extend_extended_bool(&s
, "DNSOverTLS", info
->dns_over_tls
) < 0)
1600 if (strv_extendf(&s
, "DNSSEC=%s/%s",
1601 info
->dnssec
?: "???",
1602 info
->dnssec_supported
? "supported" : "unsupported") < 0)
1608 static char** global_protocol_status(const GlobalInfo
*info
) {
1609 _cleanup_strv_free_
char **s
= NULL
;
1611 if (strv_extend_extended_bool(&s
, "LLMNR", info
->llmnr
) < 0)
1614 if (strv_extend_extended_bool(&s
, "mDNS", info
->mdns
) < 0)
1617 if (strv_extend_extended_bool(&s
, "DNSOverTLS", info
->dns_over_tls
) < 0)
1620 if (strv_extendf(&s
, "DNSSEC=%s/%s",
1621 info
->dnssec
?: "???",
1622 info
->dnssec_supported
? "supported" : "unsupported") < 0)
1628 static int status_ifindex(sd_bus
*bus
, int ifindex
, const char *name
, StatusMode mode
, bool *empty_line
) {
1629 static const struct bus_properties_map property_map
[] = {
1630 { "ScopesMask", "t", NULL
, offsetof(LinkInfo
, scopes_mask
) },
1631 { "DNS", "a(iay)", map_link_dns_servers
, offsetof(LinkInfo
, dns
) },
1632 { "DNSEx", "a(iayqs)", map_link_dns_servers_ex
, offsetof(LinkInfo
, dns_ex
) },
1633 { "CurrentDNSServer", "(iay)", map_link_current_dns_server
, offsetof(LinkInfo
, current_dns
) },
1634 { "CurrentDNSServerEx", "(iayqs)", map_link_current_dns_server_ex
, offsetof(LinkInfo
, current_dns_ex
) },
1635 { "Domains", "a(sb)", map_link_domains
, offsetof(LinkInfo
, domains
) },
1636 { "DefaultRoute", "b", NULL
, offsetof(LinkInfo
, default_route
) },
1637 { "LLMNR", "s", NULL
, offsetof(LinkInfo
, llmnr
) },
1638 { "MulticastDNS", "s", NULL
, offsetof(LinkInfo
, mdns
) },
1639 { "DNSOverTLS", "s", NULL
, offsetof(LinkInfo
, dns_over_tls
) },
1640 { "DNSSEC", "s", NULL
, offsetof(LinkInfo
, dnssec
) },
1641 { "DNSSECNegativeTrustAnchors", "as", bus_map_strv_sort
, offsetof(LinkInfo
, ntas
) },
1642 { "DNSSECSupported", "b", NULL
, offsetof(LinkInfo
, dnssec_supported
) },
1645 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1646 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
1647 _cleanup_(link_info_clear
) LinkInfo link_info
= {};
1648 _cleanup_(table_unrefp
) Table
*table
= NULL
;
1649 _cleanup_free_
char *p
= NULL
;
1650 char ifi
[DECIMAL_STR_MAX(int)], ifname
[IF_NAMESIZE
];
1654 assert(ifindex
> 0);
1657 r
= format_ifname(ifindex
, ifname
);
1659 return log_error_errno(r
, "Failed to resolve interface name for %i: %m", ifindex
);
1664 xsprintf(ifi
, "%i", ifindex
);
1665 r
= sd_bus_path_encode("/org/freedesktop/resolve1/link", ifi
, &p
);
1669 r
= bus_map_all_properties(bus
,
1670 "org.freedesktop.resolve1",
1673 BUS_MAP_BOOLEAN_AS_BOOL
,
1678 return log_error_errno(r
, "Failed to get link data for %i: %s", ifindex
, bus_error_message(&error
, r
));
1680 pager_open(arg_pager_flags
);
1682 if (mode
== STATUS_DNS
)
1683 return status_print_strv_ifindex(ifindex
, name
, link_info
.dns_ex
?: link_info
.dns
);
1685 if (mode
== STATUS_DOMAIN
)
1686 return status_print_strv_ifindex(ifindex
, name
, link_info
.domains
);
1688 if (mode
== STATUS_NTA
)
1689 return status_print_strv_ifindex(ifindex
, name
, link_info
.ntas
);
1691 if (mode
== STATUS_DEFAULT_ROUTE
) {
1692 printf("%sLink %i (%s)%s: %s\n",
1693 ansi_highlight(), ifindex
, name
, ansi_normal(),
1694 yes_no(link_info
.default_route
));
1699 if (mode
== STATUS_LLMNR
) {
1700 printf("%sLink %i (%s)%s: %s\n",
1701 ansi_highlight(), ifindex
, name
, ansi_normal(),
1702 strna(link_info
.llmnr
));
1707 if (mode
== STATUS_MDNS
) {
1708 printf("%sLink %i (%s)%s: %s\n",
1709 ansi_highlight(), ifindex
, name
, ansi_normal(),
1710 strna(link_info
.mdns
));
1715 if (mode
== STATUS_PRIVATE
) {
1716 printf("%sLink %i (%s)%s: %s\n",
1717 ansi_highlight(), ifindex
, name
, ansi_normal(),
1718 strna(link_info
.dns_over_tls
));
1723 if (mode
== STATUS_DNSSEC
) {
1724 printf("%sLink %i (%s)%s: %s\n",
1725 ansi_highlight(), ifindex
, name
, ansi_normal(),
1726 strna(link_info
.dnssec
));
1731 if (empty_line
&& *empty_line
)
1732 fputc('\n', stdout
);
1734 printf("%sLink %i (%s)%s\n",
1735 ansi_highlight(), ifindex
, name
, ansi_normal());
1737 table
= table_new_vertical();
1741 r
= table_add_many(table
,
1742 TABLE_FIELD
, "Current Scopes",
1743 TABLE_SET_MINIMUM_WIDTH
, 19);
1745 return table_log_add_error(r
);
1747 if (link_info
.scopes_mask
== 0)
1748 r
= table_add_cell(table
, NULL
, TABLE_STRING
, "none");
1750 _cleanup_free_
char *buf
= NULL
;
1753 if (asprintf(&buf
, "%s%s%s%s%s",
1754 link_info
.scopes_mask
& SD_RESOLVED_DNS
? "DNS " : "",
1755 link_info
.scopes_mask
& SD_RESOLVED_LLMNR_IPV4
? "LLMNR/IPv4 " : "",
1756 link_info
.scopes_mask
& SD_RESOLVED_LLMNR_IPV6
? "LLMNR/IPv6 " : "",
1757 link_info
.scopes_mask
& SD_RESOLVED_MDNS_IPV4
? "mDNS/IPv4 " : "",
1758 link_info
.scopes_mask
& SD_RESOLVED_MDNS_IPV6
? "mDNS/IPv6 " : "") < 0)
1763 buf
[len
- 1] = '\0';
1765 r
= table_add_cell(table
, NULL
, TABLE_STRING
, buf
);
1768 return table_log_add_error(r
);
1770 _cleanup_strv_free_
char **pstatus
= link_protocol_status(&link_info
);
1774 r
= table_add_many(table
,
1775 TABLE_FIELD
, "Protocols",
1776 TABLE_STRV_WRAPPED
, pstatus
);
1778 return table_log_add_error(r
);
1780 if (link_info
.current_dns
) {
1781 r
= table_add_many(table
,
1782 TABLE_FIELD
, "Current DNS Server",
1783 TABLE_STRING
, link_info
.current_dns_ex
?: link_info
.current_dns
);
1785 return table_log_add_error(r
);
1788 r
= dump_list(table
, "DNS Servers", link_info
.dns_ex
?: link_info
.dns
);
1792 r
= dump_list(table
, "DNS Domain", link_info
.domains
);
1796 r
= table_print(table
, NULL
);
1798 return table_log_print_error(r
);
1806 static int map_global_dns_servers_internal(
1810 sd_bus_error
*error
,
1814 char ***l
= ASSERT_PTR(userdata
);
1821 r
= sd_bus_message_enter_container(m
, 'a', extended
? "(iiayqs)" : "(iiay)");
1826 _cleanup_free_
char *pretty
= NULL
;
1828 r
= read_dns_server_one(m
, /* with_ifindex= */ true, extended
, /* only_global= */ true, &pretty
);
1834 if (isempty(pretty
))
1837 r
= strv_consume(l
, TAKE_PTR(pretty
));
1842 r
= sd_bus_message_exit_container(m
);
1849 static int map_global_dns_servers(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1850 return map_global_dns_servers_internal(bus
, member
, m
, error
, userdata
, /* extended= */ false);
1853 static int map_global_dns_servers_ex(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1854 return map_global_dns_servers_internal(bus
, member
, m
, error
, userdata
, /* extended= */ true);
1857 static int map_global_current_dns_server(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1858 return read_dns_server_one(m
, /* with_ifindex= */ true, /* extended= */ false, /* only_global= */ true, userdata
);
1861 static int map_global_current_dns_server_ex(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1862 return read_dns_server_one(m
, /* with_ifindex= */ true, /* extended= */ true, /* only_global= */ true, userdata
);
1865 static int map_global_domains(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1866 char ***l
= ASSERT_PTR(userdata
);
1873 r
= sd_bus_message_enter_container(m
, 'a', "(isb)");
1878 _cleanup_free_
char *pretty
= NULL
;
1880 r
= read_domain_one(m
, true, &pretty
);
1886 if (isempty(pretty
))
1889 r
= strv_consume(l
, TAKE_PTR(pretty
));
1894 r
= sd_bus_message_exit_container(m
);
1903 static int status_global(sd_bus
*bus
, StatusMode mode
, bool *empty_line
) {
1904 static const struct bus_properties_map property_map
[] = {
1905 { "DNS", "a(iiay)", map_global_dns_servers
, offsetof(GlobalInfo
, dns
) },
1906 { "DNSEx", "a(iiayqs)", map_global_dns_servers_ex
, offsetof(GlobalInfo
, dns_ex
) },
1907 { "FallbackDNS", "a(iiay)", map_global_dns_servers
, offsetof(GlobalInfo
, fallback_dns
) },
1908 { "FallbackDNSEx", "a(iiayqs)", map_global_dns_servers_ex
, offsetof(GlobalInfo
, fallback_dns_ex
) },
1909 { "CurrentDNSServer", "(iiay)", map_global_current_dns_server
, offsetof(GlobalInfo
, current_dns
) },
1910 { "CurrentDNSServerEx", "(iiayqs)", map_global_current_dns_server_ex
, offsetof(GlobalInfo
, current_dns_ex
) },
1911 { "Domains", "a(isb)", map_global_domains
, offsetof(GlobalInfo
, domains
) },
1912 { "DNSSECNegativeTrustAnchors", "as", bus_map_strv_sort
, offsetof(GlobalInfo
, ntas
) },
1913 { "LLMNR", "s", NULL
, offsetof(GlobalInfo
, llmnr
) },
1914 { "MulticastDNS", "s", NULL
, offsetof(GlobalInfo
, mdns
) },
1915 { "DNSOverTLS", "s", NULL
, offsetof(GlobalInfo
, dns_over_tls
) },
1916 { "DNSSEC", "s", NULL
, offsetof(GlobalInfo
, dnssec
) },
1917 { "DNSSECSupported", "b", NULL
, offsetof(GlobalInfo
, dnssec_supported
) },
1918 { "ResolvConfMode", "s", NULL
, offsetof(GlobalInfo
, resolv_conf_mode
) },
1921 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1922 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
1923 _cleanup_(global_info_clear
) GlobalInfo global_info
= {};
1924 _cleanup_(table_unrefp
) Table
*table
= NULL
;
1930 r
= bus_map_all_properties(bus
,
1931 "org.freedesktop.resolve1",
1932 "/org/freedesktop/resolve1",
1934 BUS_MAP_BOOLEAN_AS_BOOL
,
1939 return log_error_errno(r
, "Failed to get global data: %s", bus_error_message(&error
, r
));
1941 pager_open(arg_pager_flags
);
1943 if (mode
== STATUS_DNS
)
1944 return status_print_strv_global(global_info
.dns_ex
?: global_info
.dns
);
1946 if (mode
== STATUS_DOMAIN
)
1947 return status_print_strv_global(global_info
.domains
);
1949 if (mode
== STATUS_NTA
)
1950 return status_print_strv_global(global_info
.ntas
);
1952 if (mode
== STATUS_LLMNR
) {
1953 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
1954 strna(global_info
.llmnr
));
1959 if (mode
== STATUS_MDNS
) {
1960 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
1961 strna(global_info
.mdns
));
1966 if (mode
== STATUS_PRIVATE
) {
1967 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
1968 strna(global_info
.dns_over_tls
));
1973 if (mode
== STATUS_DNSSEC
) {
1974 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
1975 strna(global_info
.dnssec
));
1980 printf("%sGlobal%s\n", ansi_highlight(), ansi_normal());
1982 table
= table_new_vertical();
1986 _cleanup_strv_free_
char **pstatus
= global_protocol_status(&global_info
);
1990 r
= table_add_many(table
,
1991 TABLE_FIELD
, "Protocols",
1992 TABLE_SET_MINIMUM_WIDTH
, 19,
1993 TABLE_STRV_WRAPPED
, pstatus
);
1995 return table_log_add_error(r
);
1997 if (global_info
.resolv_conf_mode
) {
1998 r
= table_add_many(table
,
1999 TABLE_FIELD
, "resolv.conf mode",
2000 TABLE_STRING
, global_info
.resolv_conf_mode
);
2002 return table_log_add_error(r
);
2005 if (global_info
.current_dns
) {
2006 r
= table_add_many(table
,
2007 TABLE_FIELD
, "Current DNS Server",
2008 TABLE_STRING
, global_info
.current_dns_ex
?: global_info
.current_dns
);
2010 return table_log_add_error(r
);
2013 r
= dump_list(table
, "DNS Servers", global_info
.dns_ex
?: global_info
.dns
);
2017 r
= dump_list(table
, "Fallback DNS Servers", global_info
.fallback_dns_ex
?: global_info
.fallback_dns
);
2021 r
= dump_list(table
, "DNS Domain", global_info
.domains
);
2025 r
= table_print(table
, NULL
);
2027 return table_log_print_error(r
);
2034 static int status_all(sd_bus
*bus
, StatusMode mode
) {
2035 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
2036 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
2037 bool empty_line
= false;
2042 r
= status_global(bus
, mode
, &empty_line
);
2046 r
= sd_netlink_open(&rtnl
);
2048 return log_error_errno(r
, "Failed to connect to netlink: %m");
2050 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
2052 return rtnl_log_create_error(r
);
2054 r
= sd_netlink_message_set_request_dump(req
, true);
2056 return rtnl_log_create_error(r
);
2058 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
2060 return log_error_errno(r
, "Failed to enumerate links: %m");
2062 _cleanup_free_ InterfaceInfo
*infos
= NULL
;
2065 for (sd_netlink_message
*i
= reply
; i
; i
= sd_netlink_message_next(i
)) {
2070 r
= sd_netlink_message_get_type(i
, &type
);
2072 return rtnl_log_parse_error(r
);
2074 if (type
!= RTM_NEWLINK
)
2077 r
= sd_rtnl_message_link_get_ifindex(i
, &ifindex
);
2079 return rtnl_log_parse_error(r
);
2081 if (ifindex
== LOOPBACK_IFINDEX
)
2084 r
= sd_netlink_message_read_string(i
, IFLA_IFNAME
, &name
);
2086 return rtnl_log_parse_error(r
);
2088 if (!GREEDY_REALLOC(infos
, n_infos
+ 1))
2091 infos
[n_infos
++] = (InterfaceInfo
) { ifindex
, name
};
2094 typesafe_qsort(infos
, n_infos
, interface_info_compare
);
2097 for (size_t i
= 0; i
< n_infos
; i
++) {
2098 int q
= status_ifindex(bus
, infos
[i
].index
, infos
[i
].name
, mode
, &empty_line
);
2099 if (q
< 0 && r
>= 0)
2106 static int verb_status(int argc
, char **argv
, void *userdata
) {
2107 sd_bus
*bus
= userdata
;
2108 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
2112 bool empty_line
= false;
2114 STRV_FOREACH(ifname
, argv
+ 1) {
2117 ifindex
= rtnl_resolve_interface(&rtnl
, *ifname
);
2119 log_warning_errno(ifindex
, "Failed to resolve interface \"%s\", ignoring: %m", *ifname
);
2123 q
= status_ifindex(bus
, ifindex
, NULL
, STATUS_ALL
, &empty_line
);
2128 r
= status_all(bus
, STATUS_ALL
);
2133 static int call_dns(sd_bus
*bus
, char **dns
, const BusLocator
*locator
, sd_bus_error
*error
, bool extended
) {
2134 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
;
2137 r
= bus_message_new_method_call(bus
, &req
, locator
, extended
? "SetLinkDNSEx" : "SetLinkDNS");
2139 return bus_log_create_error(r
);
2141 r
= sd_bus_message_append(req
, "i", arg_ifindex
);
2143 return bus_log_create_error(r
);
2145 r
= sd_bus_message_open_container(req
, 'a', extended
? "(iayqs)" : "(iay)");
2147 return bus_log_create_error(r
);
2149 /* If only argument is the empty string, then call SetLinkDNS() with an
2150 * empty list, which will clear the list of domains for an interface. */
2151 if (!strv_equal(dns
, STRV_MAKE("")))
2152 STRV_FOREACH(p
, dns
) {
2153 _cleanup_free_
char *name
= NULL
;
2154 struct in_addr_data data
;
2158 r
= in_addr_port_ifindex_name_from_string_auto(*p
, &data
.family
, &data
.address
, &port
, &ifindex
, &name
);
2160 return log_error_errno(r
, "Failed to parse DNS server address: %s", *p
);
2162 if (ifindex
!= 0 && ifindex
!= arg_ifindex
)
2163 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid ifindex: %i", ifindex
);
2165 r
= sd_bus_message_open_container(req
, 'r', extended
? "iayqs" : "iay");
2167 return bus_log_create_error(r
);
2169 r
= sd_bus_message_append(req
, "i", data
.family
);
2171 return bus_log_create_error(r
);
2173 r
= sd_bus_message_append_array(req
, 'y', &data
.address
, FAMILY_ADDRESS_SIZE(data
.family
));
2175 return bus_log_create_error(r
);
2178 r
= sd_bus_message_append(req
, "q", port
);
2180 return bus_log_create_error(r
);
2182 r
= sd_bus_message_append(req
, "s", name
);
2184 return bus_log_create_error(r
);
2187 r
= sd_bus_message_close_container(req
);
2189 return bus_log_create_error(r
);
2192 r
= sd_bus_message_close_container(req
);
2194 return bus_log_create_error(r
);
2196 r
= sd_bus_call(bus
, req
, 0, error
, NULL
);
2197 if (r
< 0 && extended
&& sd_bus_error_has_name(error
, SD_BUS_ERROR_UNKNOWN_METHOD
)) {
2198 sd_bus_error_free(error
);
2199 return call_dns(bus
, dns
, locator
, error
, false);
2204 static int verb_dns(int argc
, char **argv
, void *userdata
) {
2205 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2206 sd_bus
*bus
= ASSERT_PTR(userdata
);
2210 r
= ifname_mangle(argv
[1]);
2215 if (arg_ifindex
<= 0)
2216 return status_all(bus
, STATUS_DNS
);
2219 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_DNS
, NULL
);
2221 r
= call_dns(bus
, argv
+ 2, bus_resolve_mgr
, &error
, true);
2222 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2223 sd_bus_error_free(&error
);
2225 r
= call_dns(bus
, argv
+ 2, bus_network_mgr
, &error
, true);
2228 if (arg_ifindex_permissive
&&
2229 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2232 return log_error_errno(r
, "Failed to set DNS configuration: %s", bus_error_message(&error
, r
));
2238 static int call_domain(sd_bus
*bus
, char **domain
, const BusLocator
*locator
, sd_bus_error
*error
) {
2239 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
;
2242 r
= bus_message_new_method_call(bus
, &req
, locator
, "SetLinkDomains");
2244 return bus_log_create_error(r
);
2246 r
= sd_bus_message_append(req
, "i", arg_ifindex
);
2248 return bus_log_create_error(r
);
2250 r
= sd_bus_message_open_container(req
, 'a', "(sb)");
2252 return bus_log_create_error(r
);
2254 /* If only argument is the empty string, then call SetLinkDomains() with an
2255 * empty list, which will clear the list of domains for an interface. */
2256 if (!strv_equal(domain
, STRV_MAKE("")))
2257 STRV_FOREACH(p
, domain
) {
2260 n
= **p
== '~' ? *p
+ 1 : *p
;
2262 r
= dns_name_is_valid(n
);
2264 return log_error_errno(r
, "Failed to validate specified domain %s: %m", n
);
2266 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2267 "Domain not valid: %s",
2270 r
= sd_bus_message_append(req
, "(sb)", n
, **p
== '~');
2272 return bus_log_create_error(r
);
2275 r
= sd_bus_message_close_container(req
);
2277 return bus_log_create_error(r
);
2279 return sd_bus_call(bus
, req
, 0, error
, NULL
);
2282 static int verb_domain(int argc
, char **argv
, void *userdata
) {
2283 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2284 sd_bus
*bus
= ASSERT_PTR(userdata
);
2288 r
= ifname_mangle(argv
[1]);
2293 if (arg_ifindex
<= 0)
2294 return status_all(bus
, STATUS_DOMAIN
);
2297 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_DOMAIN
, NULL
);
2299 r
= call_domain(bus
, argv
+ 2, bus_resolve_mgr
, &error
);
2300 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2301 sd_bus_error_free(&error
);
2303 r
= call_domain(bus
, argv
+ 2, bus_network_mgr
, &error
);
2306 if (arg_ifindex_permissive
&&
2307 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2310 return log_error_errno(r
, "Failed to set domain configuration: %s", bus_error_message(&error
, r
));
2316 static int verb_default_route(int argc
, char **argv
, void *userdata
) {
2317 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2318 sd_bus
*bus
= ASSERT_PTR(userdata
);
2322 r
= ifname_mangle(argv
[1]);
2327 if (arg_ifindex
<= 0)
2328 return status_all(bus
, STATUS_DEFAULT_ROUTE
);
2331 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_DEFAULT_ROUTE
, NULL
);
2333 b
= parse_boolean(argv
[2]);
2335 return log_error_errno(b
, "Failed to parse boolean argument: %s", argv
[2]);
2337 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkDefaultRoute", &error
, NULL
, "ib", arg_ifindex
, b
);
2338 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2339 sd_bus_error_free(&error
);
2341 r
= bus_call_method(bus
, bus_network_mgr
, "SetLinkDefaultRoute", &error
, NULL
, "ib", arg_ifindex
, b
);
2344 if (arg_ifindex_permissive
&&
2345 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2348 return log_error_errno(r
, "Failed to set default route configuration: %s", bus_error_message(&error
, r
));
2354 static int verb_llmnr(int argc
, char **argv
, void *userdata
) {
2355 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2356 _cleanup_free_
char *global_llmnr_support_str
= NULL
;
2357 ResolveSupport global_llmnr_support
, llmnr_support
;
2358 sd_bus
*bus
= ASSERT_PTR(userdata
);
2362 r
= ifname_mangle(argv
[1]);
2367 if (arg_ifindex
<= 0)
2368 return status_all(bus
, STATUS_LLMNR
);
2371 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_LLMNR
, NULL
);
2373 llmnr_support
= resolve_support_from_string(argv
[2]);
2374 if (llmnr_support
< 0)
2375 return log_error_errno(llmnr_support
, "Invalid LLMNR setting: %s", argv
[2]);
2377 r
= bus_get_property_string(bus
, bus_resolve_mgr
, "LLMNR", &error
, &global_llmnr_support_str
);
2379 return log_error_errno(r
, "Failed to get the global LLMNR support state: %s", bus_error_message(&error
, r
));
2381 global_llmnr_support
= resolve_support_from_string(global_llmnr_support_str
);
2382 if (global_llmnr_support
< 0)
2383 return log_error_errno(global_llmnr_support
, "Received invalid global LLMNR setting: %s", global_llmnr_support_str
);
2385 if (global_llmnr_support
< llmnr_support
)
2386 log_warning("Setting LLMNR support level \"%s\" for \"%s\", but the global support level is \"%s\".",
2387 argv
[2], arg_ifname
, global_llmnr_support_str
);
2389 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkLLMNR", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2390 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2391 sd_bus_error_free(&error
);
2393 r
= bus_call_method(bus
, bus_network_mgr
, "SetLinkLLMNR", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2396 if (arg_ifindex_permissive
&&
2397 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2400 return log_error_errno(r
, "Failed to set LLMNR configuration: %s", bus_error_message(&error
, r
));
2406 static int verb_mdns(int argc
, char **argv
, void *userdata
) {
2407 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2408 _cleanup_free_
char *global_mdns_support_str
= NULL
;
2409 ResolveSupport global_mdns_support
, mdns_support
;
2410 sd_bus
*bus
= ASSERT_PTR(userdata
);
2414 r
= ifname_mangle(argv
[1]);
2419 if (arg_ifindex
<= 0)
2420 return status_all(bus
, STATUS_MDNS
);
2423 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_MDNS
, NULL
);
2425 mdns_support
= resolve_support_from_string(argv
[2]);
2426 if (mdns_support
< 0)
2427 return log_error_errno(mdns_support
, "Invalid mDNS setting: %s", argv
[2]);
2429 r
= bus_get_property_string(bus
, bus_resolve_mgr
, "MulticastDNS", &error
, &global_mdns_support_str
);
2431 return log_error_errno(r
, "Failed to get the global mDNS support state: %s", bus_error_message(&error
, r
));
2433 global_mdns_support
= resolve_support_from_string(global_mdns_support_str
);
2434 if (global_mdns_support
< 0)
2435 return log_error_errno(global_mdns_support
, "Received invalid global mDNS setting: %s", global_mdns_support_str
);
2437 if (global_mdns_support
< mdns_support
)
2438 log_warning("Setting mDNS support level \"%s\" for \"%s\", but the global support level is \"%s\".",
2439 argv
[2], arg_ifname
, global_mdns_support_str
);
2441 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkMulticastDNS", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2442 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2443 sd_bus_error_free(&error
);
2445 r
= bus_call_method(
2448 "SetLinkMulticastDNS",
2451 "is", arg_ifindex
, argv
[2]);
2454 if (arg_ifindex_permissive
&&
2455 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2458 return log_error_errno(r
, "Failed to set MulticastDNS configuration: %s", bus_error_message(&error
, r
));
2464 static int verb_dns_over_tls(int argc
, char **argv
, void *userdata
) {
2465 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2466 sd_bus
*bus
= ASSERT_PTR(userdata
);
2470 r
= ifname_mangle(argv
[1]);
2475 if (arg_ifindex
<= 0)
2476 return status_all(bus
, STATUS_PRIVATE
);
2479 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_PRIVATE
, NULL
);
2481 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkDNSOverTLS", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2482 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2483 sd_bus_error_free(&error
);
2485 r
= bus_call_method(
2488 "SetLinkDNSOverTLS",
2491 "is", arg_ifindex
, argv
[2]);
2494 if (arg_ifindex_permissive
&&
2495 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2498 return log_error_errno(r
, "Failed to set DNSOverTLS configuration: %s", bus_error_message(&error
, r
));
2504 static int verb_dnssec(int argc
, char **argv
, void *userdata
) {
2505 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2506 sd_bus
*bus
= ASSERT_PTR(userdata
);
2510 r
= ifname_mangle(argv
[1]);
2515 if (arg_ifindex
<= 0)
2516 return status_all(bus
, STATUS_DNSSEC
);
2519 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_DNSSEC
, NULL
);
2521 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkDNSSEC", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2522 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2523 sd_bus_error_free(&error
);
2525 r
= bus_call_method(bus
, bus_network_mgr
, "SetLinkDNSSEC", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2528 if (arg_ifindex_permissive
&&
2529 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2532 return log_error_errno(r
, "Failed to set DNSSEC configuration: %s", bus_error_message(&error
, r
));
2538 static int call_nta(sd_bus
*bus
, char **nta
, const BusLocator
*locator
, sd_bus_error
*error
) {
2539 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
;
2542 r
= bus_message_new_method_call(bus
, &req
, locator
, "SetLinkDNSSECNegativeTrustAnchors");
2544 return bus_log_create_error(r
);
2546 r
= sd_bus_message_append(req
, "i", arg_ifindex
);
2548 return bus_log_create_error(r
);
2550 r
= sd_bus_message_append_strv(req
, nta
);
2552 return bus_log_create_error(r
);
2554 return sd_bus_call(bus
, req
, 0, error
, NULL
);
2557 static int verb_nta(int argc
, char **argv
, void *userdata
) {
2558 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2559 sd_bus
*bus
= ASSERT_PTR(userdata
);
2564 r
= ifname_mangle(argv
[1]);
2569 if (arg_ifindex
<= 0)
2570 return status_all(bus
, STATUS_NTA
);
2573 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_NTA
, NULL
);
2575 /* If only argument is the empty string, then call SetLinkDNSSECNegativeTrustAnchors()
2576 * with an empty list, which will clear the list of domains for an interface. */
2577 clear
= strv_equal(argv
+ 2, STRV_MAKE(""));
2580 STRV_FOREACH(p
, argv
+ 2) {
2581 r
= dns_name_is_valid(*p
);
2583 return log_error_errno(r
, "Failed to validate specified domain %s: %m", *p
);
2585 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2586 "Domain not valid: %s",
2590 r
= call_nta(bus
, clear
? NULL
: argv
+ 2, bus_resolve_mgr
, &error
);
2591 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2592 sd_bus_error_free(&error
);
2594 r
= call_nta(bus
, clear
? NULL
: argv
+ 2, bus_network_mgr
, &error
);
2597 if (arg_ifindex_permissive
&&
2598 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2601 return log_error_errno(r
, "Failed to set DNSSEC NTA configuration: %s", bus_error_message(&error
, r
));
2607 static int verb_revert_link(int argc
, char **argv
, void *userdata
) {
2608 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2609 sd_bus
*bus
= ASSERT_PTR(userdata
);
2613 r
= ifname_mangle(argv
[1]);
2618 if (arg_ifindex
<= 0)
2619 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Interface argument required.");
2621 r
= bus_call_method(bus
, bus_resolve_mgr
, "RevertLink", &error
, NULL
, "i", arg_ifindex
);
2622 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2623 sd_bus_error_free(&error
);
2625 r
= bus_call_method(bus
, bus_network_mgr
, "RevertLinkDNS", &error
, NULL
, "i", arg_ifindex
);
2628 if (arg_ifindex_permissive
&&
2629 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2632 return log_error_errno(r
, "Failed to revert interface configuration: %s", bus_error_message(&error
, r
));
2638 static int verb_log_level(int argc
, char *argv
[], void *userdata
) {
2639 sd_bus
*bus
= ASSERT_PTR(userdata
);
2641 assert(IN_SET(argc
, 1, 2));
2643 return verb_log_control_common(bus
, "org.freedesktop.resolve1", argv
[0], argc
== 2 ? argv
[1] : NULL
);
2646 static int print_question(char prefix
, const char *color
, JsonVariant
*question
) {
2647 JsonVariant
*q
= NULL
;
2652 JSON_VARIANT_ARRAY_FOREACH(q
, question
) {
2653 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
2654 char buf
[DNS_RESOURCE_KEY_STRING_MAX
];
2656 r
= dns_resource_key_from_json(q
, &key
);
2658 log_warning_errno(r
, "Received monitor message with invalid question key, ignoring: %m");
2662 printf("%s%s %c%s: %s\n",
2664 special_glyph(SPECIAL_GLYPH_ARROW_RIGHT
),
2667 dns_resource_key_to_string(key
, buf
, sizeof(buf
)));
2673 static int print_answer(JsonVariant
*answer
) {
2677 JSON_VARIANT_ARRAY_FOREACH(a
, answer
) {
2678 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
2679 _cleanup_free_
void *d
= NULL
;
2684 jraw
= json_variant_by_key(a
, "raw");
2686 log_warning("Received monitor answer lacking valid raw data, ignoring.");
2690 r
= json_variant_unbase64(jraw
, &d
, &l
);
2692 log_warning_errno(r
, "Failed to undo base64 encoding of monitor answer raw data, ignoring.");
2696 r
= dns_resource_record_new_from_raw(&rr
, d
, l
);
2698 log_warning_errno(r
, "Failed to parse monitor answer RR, ignoring: %m");
2702 s
= dns_resource_record_to_string(rr
);
2706 printf("%s%s A%s: %s\n",
2707 ansi_highlight_yellow(),
2708 special_glyph(SPECIAL_GLYPH_ARROW_LEFT
),
2716 static void monitor_query_dump(JsonVariant
*v
) {
2717 _cleanup_(json_variant_unrefp
) JsonVariant
*question
= NULL
, *answer
= NULL
, *collected_questions
= NULL
;
2718 int rcode
= -1, error
= 0;
2719 const char *state
= NULL
;
2723 JsonDispatch dispatch_table
[] = {
2724 { "question", JSON_VARIANT_ARRAY
, json_dispatch_variant
, PTR_TO_SIZE(&question
), JSON_MANDATORY
},
2725 { "answer", JSON_VARIANT_ARRAY
, json_dispatch_variant
, PTR_TO_SIZE(&answer
), 0 },
2726 { "collectedQuestions", JSON_VARIANT_ARRAY
, json_dispatch_variant
, PTR_TO_SIZE(&collected_questions
), 0 },
2727 { "state", JSON_VARIANT_STRING
, json_dispatch_const_string
, PTR_TO_SIZE(&state
), JSON_MANDATORY
},
2728 { "rcode", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_int
, PTR_TO_SIZE(&rcode
), 0 },
2729 { "errno", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_int
, PTR_TO_SIZE(&error
), 0 },
2733 if (json_dispatch(v
, dispatch_table
, JSON_LOG
|JSON_ALLOW_EXTENSIONS
, NULL
) < 0)
2736 /* First show the current question */
2737 print_question('Q', ansi_highlight_cyan(), question
);
2739 /* And then show the questions that led to this one in case this was a CNAME chain */
2740 print_question('C', ansi_highlight_grey(), collected_questions
);
2742 printf("%s%s S%s: %s\n",
2743 streq_ptr(state
, "success") ? ansi_highlight_green() : ansi_highlight_red(),
2744 special_glyph(SPECIAL_GLYPH_ARROW_LEFT
),
2746 strna(streq_ptr(state
, "errno") ? errno_to_name(error
) :
2747 streq_ptr(state
, "rcode-failure") ? dns_rcode_to_string(rcode
) :
2750 print_answer(answer
);
2753 static int monitor_reply(
2755 JsonVariant
*parameters
,
2756 const char *error_id
,
2757 VarlinkReplyFlags flags
,
2765 disconnect
= streq(error_id
, VARLINK_ERROR_DISCONNECTED
);
2767 log_info("Disconnected.");
2769 log_error("Varlink error: %s", error_id
);
2771 (void) sd_event_exit(ASSERT_PTR(varlink_get_event(link
)), disconnect
? EXIT_SUCCESS
: EXIT_FAILURE
);
2775 if (json_variant_by_key(parameters
, "ready")) {
2776 /* The first message coming in will just indicate that we are now subscribed. We let our
2777 * caller know if they asked for it. Once the caller sees this they should know that we are
2778 * not going to miss any queries anymore. */
2779 (void) sd_notify(/* unset_environment=false */ false, "READY=1");
2783 if (arg_json_format_flags
& JSON_FORMAT_OFF
) {
2784 monitor_query_dump(parameters
);
2787 json_variant_dump(parameters
, arg_json_format_flags
, NULL
, NULL
);
2794 static int verb_monitor(int argc
, char *argv
[], void *userdata
) {
2795 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
2796 _cleanup_(varlink_unrefp
) Varlink
*vl
= NULL
;
2799 r
= sd_event_default(&event
);
2801 return log_error_errno(r
, "Failed to get event loop: %m");
2803 r
= sd_event_set_signal_exit(event
, true);
2805 return log_error_errno(r
, "Failed to enable exit on SIGINT/SIGTERM: %m");
2807 r
= varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
2809 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
2811 r
= varlink_set_relative_timeout(vl
, USEC_INFINITY
); /* We want the monitor to run basically forever */
2813 return log_error_errno(r
, "Failed to set varlink time-out: %m");
2815 r
= varlink_attach_event(vl
, event
, SD_EVENT_PRIORITY_NORMAL
);
2817 return log_error_errno(r
, "Failed to attach varlink connection to event loop: %m");
2819 r
= varlink_bind_reply(vl
, monitor_reply
);
2821 return log_error_errno(r
, "Failed to bind reply callback to varlink connection: %m");
2823 r
= varlink_observe(vl
, "io.systemd.Resolve.Monitor.SubscribeQueryResults", NULL
);
2825 return log_error_errno(r
, "Failed to issue SubscribeQueryResults() varlink call: %m");
2827 r
= sd_event_loop(event
);
2829 return log_error_errno(r
, "Failed to run event loop: %m");
2831 r
= sd_event_get_exit_code(event
, &c
);
2833 return log_error_errno(r
, "Failed to get exit code: %m");
2838 static int dump_cache_item(JsonVariant
*item
) {
2847 static const JsonDispatch dispatch_table
[] = {
2848 { "key", JSON_VARIANT_OBJECT
, json_dispatch_variant_noref
, offsetof(struct item_info
, key
), JSON_MANDATORY
},
2849 { "rrs", JSON_VARIANT_ARRAY
, json_dispatch_variant_noref
, offsetof(struct item_info
, rrs
), 0 },
2850 { "type", JSON_VARIANT_STRING
, json_dispatch_const_string
, offsetof(struct item_info
, type
), 0 },
2851 { "until", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct item_info
, until
), 0 },
2855 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*k
= NULL
;
2858 r
= json_dispatch(item
, dispatch_table
, JSON_LOG
|JSON_ALLOW_EXTENSIONS
, &item_info
);
2862 r
= dns_resource_key_from_json(item_info
.key
, &k
);
2864 return log_error_errno(r
, "Failed to turn JSON data to resource key: %m");
2867 printf("%s %s%s%s\n", DNS_RESOURCE_KEY_TO_STRING(k
), ansi_highlight_red(), item_info
.type
, ansi_normal());
2871 JSON_VARIANT_ARRAY_FOREACH(i
, item_info
.rrs
) {
2872 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
2873 _cleanup_free_
void *data
= NULL
;
2877 raw
= json_variant_by_key(i
, "raw");
2879 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
), "raw field missing from RR JSON data.");
2881 r
= json_variant_unbase64(raw
, &data
, &size
);
2883 return log_error_errno(r
, "Unable to decode raw RR JSON data: %m");
2885 r
= dns_resource_record_new_from_raw(&rr
, data
, size
);
2887 return log_error_errno(r
, "Failed to parse DNS data: %m");
2889 printf("%s\n", dns_resource_record_to_string(rr
));
2897 static int dump_cache_scope(JsonVariant
*scope
) {
2900 const char *protocol
;
2906 .family
= AF_UNSPEC
,
2911 static const JsonDispatch dispatch_table
[] = {
2912 { "protocol", JSON_VARIANT_STRING
, json_dispatch_const_string
, offsetof(struct scope_info
, protocol
), JSON_MANDATORY
},
2913 { "family", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_int
, offsetof(struct scope_info
, family
), 0 },
2914 { "ifindex", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_int
, offsetof(struct scope_info
, ifindex
), 0 },
2915 { "ifname", JSON_VARIANT_STRING
, json_dispatch_const_string
, offsetof(struct scope_info
, ifname
), 0 },
2916 { "cache", JSON_VARIANT_ARRAY
, json_dispatch_variant_noref
, offsetof(struct scope_info
, cache
), JSON_MANDATORY
},
2920 r
= json_dispatch(scope
, dispatch_table
, JSON_LOG
|JSON_ALLOW_EXTENSIONS
, &scope_info
);
2924 printf("%sScope protocol=%s", ansi_underline(), scope_info
.protocol
);
2926 if (scope_info
.family
!= AF_UNSPEC
)
2927 printf(" family=%s", af_to_name(scope_info
.family
));
2929 if (scope_info
.ifindex
> 0)
2930 printf(" ifindex=%i", scope_info
.ifindex
);
2931 if (scope_info
.ifname
)
2932 printf(" ifname=%s", scope_info
.ifname
);
2934 printf("%s\n", ansi_normal());
2936 JSON_VARIANT_ARRAY_FOREACH(i
, scope_info
.cache
) {
2937 r
= dump_cache_item(i
);
2945 printf("%sNo entries.%s\n\n", ansi_grey(), ansi_normal());
2952 static int verb_show_cache(int argc
, char *argv
[], void *userdata
) {
2953 JsonVariant
*reply
= NULL
, *d
= NULL
;
2954 _cleanup_(varlink_unrefp
) Varlink
*vl
= NULL
;
2957 r
= varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
2959 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
2961 r
= varlink_call(vl
, "io.systemd.Resolve.Monitor.DumpCache", NULL
, &reply
, NULL
, 0);
2963 return log_error_errno(r
, "Failed to issue DumpCache() varlink call: %m");
2965 d
= json_variant_by_key(reply
, "dump");
2967 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
2968 "DumpCache() response is missing 'dump' key.");
2970 if (!json_variant_is_array(d
))
2971 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
2972 "DumpCache() response 'dump' field not an array");
2974 if (FLAGS_SET(arg_json_format_flags
, JSON_FORMAT_OFF
)) {
2977 JSON_VARIANT_ARRAY_FOREACH(i
, d
) {
2978 r
= dump_cache_scope(i
);
2986 return json_variant_dump(d
, arg_json_format_flags
, NULL
, NULL
);
2989 static int dump_server_state(JsonVariant
*server
) {
2990 _cleanup_(table_unrefp
) Table
*table
= NULL
;
2993 struct server_state
{
2994 const char *server_name
;
2998 const char *verified_feature_level
;
2999 const char *possible_feature_level
;
3000 const char *dnssec_mode
;
3001 bool dnssec_supported
;
3002 size_t received_udp_fragment_max
;
3003 uint64_t n_failed_udp
;
3004 uint64_t n_failed_tcp
;
3005 bool packet_truncated
;
3006 bool packet_bad_opt
;
3007 bool packet_rrsig_missing
;
3008 bool packet_invalid
;
3016 static const JsonDispatch dispatch_table
[] = {
3017 { "Server", JSON_VARIANT_STRING
, json_dispatch_const_string
, offsetof(struct server_state
, server_name
), JSON_MANDATORY
},
3018 { "Type", JSON_VARIANT_STRING
, json_dispatch_const_string
, offsetof(struct server_state
, type
), JSON_MANDATORY
},
3019 { "Interface", JSON_VARIANT_STRING
, json_dispatch_const_string
, offsetof(struct server_state
, ifname
), 0 },
3020 { "InterfaceIndex", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_int
, offsetof(struct server_state
, ifindex
), 0 },
3021 { "VerifiedFeatureLevel", JSON_VARIANT_STRING
, json_dispatch_const_string
, offsetof(struct server_state
, verified_feature_level
), 0 },
3022 { "PossibleFeatureLevel", JSON_VARIANT_STRING
, json_dispatch_const_string
, offsetof(struct server_state
, possible_feature_level
), 0 },
3023 { "DNSSECMode", JSON_VARIANT_STRING
, json_dispatch_const_string
, offsetof(struct server_state
, dnssec_mode
), JSON_MANDATORY
},
3024 { "DNSSECSupported", JSON_VARIANT_BOOLEAN
, json_dispatch_boolean
, offsetof(struct server_state
, dnssec_supported
), JSON_MANDATORY
},
3025 { "ReceivedUDPFragmentMax", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct server_state
, received_udp_fragment_max
), JSON_MANDATORY
},
3026 { "FailedUDPAttempts", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct server_state
, n_failed_udp
), JSON_MANDATORY
},
3027 { "FailedTCPAttempts", _JSON_VARIANT_TYPE_INVALID
, json_dispatch_uint64
, offsetof(struct server_state
, n_failed_tcp
), JSON_MANDATORY
},
3028 { "PacketTruncated", JSON_VARIANT_BOOLEAN
, json_dispatch_boolean
, offsetof(struct server_state
, packet_truncated
), JSON_MANDATORY
},
3029 { "PacketBadOpt", JSON_VARIANT_BOOLEAN
, json_dispatch_boolean
, offsetof(struct server_state
, packet_bad_opt
), JSON_MANDATORY
},
3030 { "PacketRRSIGMissing", JSON_VARIANT_BOOLEAN
, json_dispatch_boolean
, offsetof(struct server_state
, packet_rrsig_missing
), JSON_MANDATORY
},
3031 { "PacketInvalid", JSON_VARIANT_BOOLEAN
, json_dispatch_boolean
, offsetof(struct server_state
, packet_invalid
), JSON_MANDATORY
},
3032 { "PacketDoOff", JSON_VARIANT_BOOLEAN
, json_dispatch_boolean
, offsetof(struct server_state
, packet_do_off
), JSON_MANDATORY
},
3036 r
= json_dispatch(server
, dispatch_table
, JSON_LOG
|JSON_ALLOW_EXTENSIONS
, &server_state
);
3040 table
= table_new_vertical();
3044 assert_se(cell
= table_get_cell(table
, 0, 0));
3045 (void) table_set_ellipsize_percent(table
, cell
, 100);
3046 (void) table_set_align_percent(table
, cell
, 0);
3048 r
= table_add_cell_stringf(table
, NULL
, "Server: %s", server_state
.server_name
);
3050 return table_log_add_error(r
);
3052 r
= table_add_many(table
,
3054 TABLE_FIELD
, "Type",
3055 TABLE_SET_ALIGN_PERCENT
, 100,
3056 TABLE_STRING
, server_state
.type
);
3058 return table_log_add_error(r
);
3060 if (server_state
.ifname
) {
3061 r
= table_add_many(table
,
3062 TABLE_FIELD
, "Interface",
3063 TABLE_STRING
, server_state
.ifname
);
3065 return table_log_add_error(r
);
3068 if (server_state
.ifindex
>= 0) {
3069 r
= table_add_many(table
,
3070 TABLE_FIELD
, "Interface Index",
3071 TABLE_INT
, server_state
.ifindex
);
3073 return table_log_add_error(r
);
3076 if (server_state
.verified_feature_level
) {
3077 r
= table_add_many(table
,
3078 TABLE_FIELD
, "Verified feature level",
3079 TABLE_STRING
, server_state
.verified_feature_level
);
3081 return table_log_add_error(r
);
3084 if (server_state
.possible_feature_level
) {
3085 r
= table_add_many(table
,
3086 TABLE_FIELD
, "Possible feature level",
3087 TABLE_STRING
, server_state
.possible_feature_level
);
3089 return table_log_add_error(r
);
3092 r
= table_add_many(table
,
3093 TABLE_FIELD
, "DNSSEC Mode",
3094 TABLE_STRING
, server_state
.dnssec_mode
,
3095 TABLE_FIELD
, "DNSSEC Supported",
3096 TABLE_STRING
, yes_no(server_state
.dnssec_supported
),
3097 TABLE_FIELD
, "Maximum UDP fragment size received",
3098 TABLE_UINT64
, server_state
.received_udp_fragment_max
,
3099 TABLE_FIELD
, "Failed UDP attempts",
3100 TABLE_UINT64
, server_state
.n_failed_udp
,
3101 TABLE_FIELD
, "Failed TCP attempts",
3102 TABLE_UINT64
, server_state
.n_failed_tcp
,
3103 TABLE_FIELD
, "Seen truncated packet",
3104 TABLE_STRING
, yes_no(server_state
.packet_truncated
),
3105 TABLE_FIELD
, "Seen OPT RR getting lost",
3106 TABLE_STRING
, yes_no(server_state
.packet_bad_opt
),
3107 TABLE_FIELD
, "Seen RRSIG RR missing",
3108 TABLE_STRING
, yes_no(server_state
.packet_rrsig_missing
),
3109 TABLE_FIELD
, "Seen invalid packet",
3110 TABLE_STRING
, yes_no(server_state
.packet_invalid
),
3111 TABLE_FIELD
, "Server dropped DO flag",
3112 TABLE_STRING
, yes_no(server_state
.packet_do_off
),
3113 TABLE_SET_ALIGN_PERCENT
, 0,
3114 TABLE_EMPTY
, TABLE_EMPTY
);
3117 return table_log_add_error(r
);
3119 r
= table_print(table
, NULL
);
3121 return table_log_print_error(r
);
3126 static int verb_show_server_state(int argc
, char *argv
[], void *userdata
) {
3127 JsonVariant
*reply
= NULL
, *d
= NULL
;
3128 _cleanup_(varlink_unrefp
) Varlink
*vl
= NULL
;
3131 r
= varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
3133 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
3135 r
= varlink_call(vl
, "io.systemd.Resolve.Monitor.DumpServerState", NULL
, &reply
, NULL
, 0);
3137 return log_error_errno(r
, "Failed to issue DumpServerState() varlink call: %m");
3139 d
= json_variant_by_key(reply
, "dump");
3141 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
3142 "DumpCache() response is missing 'dump' key.");
3144 if (!json_variant_is_array(d
))
3145 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
3146 "DumpCache() response 'dump' field not an array");
3148 if (FLAGS_SET(arg_json_format_flags
, JSON_FORMAT_OFF
)) {
3151 JSON_VARIANT_ARRAY_FOREACH(i
, d
) {
3152 r
= dump_server_state(i
);
3160 return json_variant_dump(d
, arg_json_format_flags
, NULL
, NULL
);
3163 static void help_protocol_types(void) {
3165 puts("Known protocol types:");
3175 static void help_dns_types(void) {
3177 puts("Known DNS RR types:");
3179 DUMP_STRING_TABLE(dns_type
, int, _DNS_TYPE_MAX
);
3182 static void help_dns_classes(void) {
3184 puts("Known DNS RR classes:");
3186 DUMP_STRING_TABLE(dns_class
, int, _DNS_CLASS_MAX
);
3189 static int compat_help(void) {
3190 _cleanup_free_
char *link
= NULL
;
3193 r
= terminal_urlify_man("resolvectl", "1", &link
);
3197 printf("%1$s [OPTIONS...] HOSTNAME|ADDRESS...\n"
3198 "%1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n"
3199 "%1$s [OPTIONS...] --openpgp EMAIL@DOMAIN...\n"
3200 "%1$s [OPTIONS...] --statistics\n"
3201 "%1$s [OPTIONS...] --reset-statistics\n"
3203 "%2$sResolve domain names, IPv4 and IPv6 addresses, DNS records, and services.%3$s\n\n"
3204 " -h --help Show this help\n"
3205 " --version Show package version\n"
3206 " --no-pager Do not pipe output into a pager\n"
3207 " -4 Resolve IPv4 addresses\n"
3208 " -6 Resolve IPv6 addresses\n"
3209 " -i --interface=INTERFACE Look on interface\n"
3210 " -p --protocol=PROTO|help Look via protocol\n"
3211 " -t --type=TYPE|help Query RR with DNS type\n"
3212 " -c --class=CLASS|help Query RR with DNS class\n"
3213 " --service Resolve service (SRV)\n"
3214 " --service-address=BOOL Resolve address for services (default: yes)\n"
3215 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
3216 " --openpgp Query OpenPGP public key\n"
3217 " --tlsa Query TLS public key\n"
3218 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
3219 " --search=BOOL Use search domains for single-label names\n"
3221 " --raw[=payload|packet] Dump the answer as binary data\n"
3222 " --legend=BOOL Print headers and additional info (default: yes)\n"
3223 " --statistics Show resolver statistics\n"
3224 " --reset-statistics Reset resolver statistics\n"
3225 " --status Show link and server status\n"
3226 " --flush-caches Flush all local DNS caches\n"
3227 " --reset-server-features\n"
3228 " Forget learnt DNS server feature levels\n"
3229 " --set-dns=SERVER Set per-interface DNS server address\n"
3230 " --set-domain=DOMAIN Set per-interface search domain\n"
3231 " --set-llmnr=MODE Set per-interface LLMNR mode\n"
3232 " --set-mdns=MODE Set per-interface MulticastDNS mode\n"
3233 " --set-dnsovertls=MODE Set per-interface DNS-over-TLS mode\n"
3234 " --set-dnssec=MODE Set per-interface DNSSEC mode\n"
3235 " --set-nta=DOMAIN Set per-interface DNSSEC NTA\n"
3236 " --revert Revert per-interface configuration\n"
3237 "\nSee the %4$s for details.\n",
3238 program_invocation_short_name
,
3246 static int native_help(void) {
3247 _cleanup_free_
char *link
= NULL
;
3250 r
= terminal_urlify_man("resolvectl", "1", &link
);
3254 printf("%s [OPTIONS...] COMMAND ...\n"
3256 "%sSend control commands to the network name resolution manager, or%s\n"
3257 "%sresolve domain names, IPv4 and IPv6 addresses, DNS records, and services.%s\n"
3259 " query HOSTNAME|ADDRESS... Resolve domain names, IPv4 and IPv6 addresses\n"
3260 " service [[NAME] TYPE] DOMAIN Resolve service (SRV)\n"
3261 " openpgp EMAIL@DOMAIN... Query OpenPGP public key\n"
3262 " tlsa DOMAIN[:PORT]... Query TLS public key\n"
3263 " status [LINK...] Show link and server status\n"
3264 " statistics Show resolver statistics\n"
3265 " reset-statistics Reset resolver statistics\n"
3266 " flush-caches Flush all local DNS caches\n"
3267 " reset-server-features Forget learnt DNS server feature levels\n"
3268 " monitor Monitor DNS queries\n"
3269 " show-cache Show cache contents\n"
3270 " show-server-state Show servers state\n"
3271 " dns [LINK [SERVER...]] Get/set per-interface DNS server address\n"
3272 " domain [LINK [DOMAIN...]] Get/set per-interface search domain\n"
3273 " default-route [LINK [BOOL]] Get/set per-interface default route flag\n"
3274 " llmnr [LINK [MODE]] Get/set per-interface LLMNR mode\n"
3275 " mdns [LINK [MODE]] Get/set per-interface MulticastDNS mode\n"
3276 " dnsovertls [LINK [MODE]] Get/set per-interface DNS-over-TLS mode\n"
3277 " dnssec [LINK [MODE]] Get/set per-interface DNSSEC mode\n"
3278 " nta [LINK [DOMAIN...]] Get/set per-interface DNSSEC NTA\n"
3279 " revert LINK Revert per-interface configuration\n"
3280 " log-level [LEVEL] Get/set logging threshold for systemd-resolved\n"
3282 " -h --help Show this help\n"
3283 " --version Show package version\n"
3284 " --no-pager Do not pipe output into a pager\n"
3285 " -4 Resolve IPv4 addresses\n"
3286 " -6 Resolve IPv6 addresses\n"
3287 " -i --interface=INTERFACE Look on interface\n"
3288 " -p --protocol=PROTO|help Look via protocol\n"
3289 " -t --type=TYPE|help Query RR with DNS type\n"
3290 " -c --class=CLASS|help Query RR with DNS class\n"
3291 " --service-address=BOOL Resolve address for services (default: yes)\n"
3292 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
3293 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
3294 " --validate=BOOL Allow DNSSEC validation (default: yes)\n"
3295 " --synthesize=BOOL Allow synthetic response (default: yes)\n"
3296 " --cache=BOOL Allow response from cache (default: yes)\n"
3297 " --stale-data=BOOL Allow response from cache with stale data (default: yes)\n"
3298 " --zone=BOOL Allow response from locally registered mDNS/LLMNR\n"
3299 " records (default: yes)\n"
3300 " --trust-anchor=BOOL Allow response from local trust anchor (default:\n"
3302 " --network=BOOL Allow response from network (default: yes)\n"
3303 " --search=BOOL Use search domains for single-label names (default:\n"
3305 " --raw[=payload|packet] Dump the answer as binary data\n"
3306 " --legend=BOOL Print headers and additional info (default: yes)\n"
3307 " --json=MODE Output as JSON\n"
3308 " -j Same as --json=pretty on tty, --json=short\n"
3310 "\nSee the %s for details.\n",
3311 program_invocation_short_name
,
3321 static int verb_help(int argc
, char **argv
, void *userdata
) {
3322 return native_help();
3325 static int compat_parse_argv(int argc
, char *argv
[]) {
3327 ARG_VERSION
= 0x100,
3331 ARG_SERVICE_ADDRESS
,
3338 ARG_RESET_STATISTICS
,
3341 ARG_RESET_SERVER_FEATURES
,
3353 static const struct option options
[] = {
3354 { "help", no_argument
, NULL
, 'h' },
3355 { "version", no_argument
, NULL
, ARG_VERSION
},
3356 { "type", required_argument
, NULL
, 't' },
3357 { "class", required_argument
, NULL
, 'c' },
3358 { "legend", required_argument
, NULL
, ARG_LEGEND
},
3359 { "interface", required_argument
, NULL
, 'i' },
3360 { "protocol", required_argument
, NULL
, 'p' },
3361 { "cname", required_argument
, NULL
, ARG_CNAME
},
3362 { "service", no_argument
, NULL
, ARG_SERVICE
},
3363 { "service-address", required_argument
, NULL
, ARG_SERVICE_ADDRESS
},
3364 { "service-txt", required_argument
, NULL
, ARG_SERVICE_TXT
},
3365 { "openpgp", no_argument
, NULL
, ARG_OPENPGP
},
3366 { "tlsa", optional_argument
, NULL
, ARG_TLSA
},
3367 { "raw", optional_argument
, NULL
, ARG_RAW
},
3368 { "search", required_argument
, NULL
, ARG_SEARCH
},
3369 { "statistics", no_argument
, NULL
, ARG_STATISTICS
, },
3370 { "reset-statistics", no_argument
, NULL
, ARG_RESET_STATISTICS
},
3371 { "status", no_argument
, NULL
, ARG_STATUS
},
3372 { "flush-caches", no_argument
, NULL
, ARG_FLUSH_CACHES
},
3373 { "reset-server-features", no_argument
, NULL
, ARG_RESET_SERVER_FEATURES
},
3374 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
3375 { "set-dns", required_argument
, NULL
, ARG_SET_DNS
},
3376 { "set-domain", required_argument
, NULL
, ARG_SET_DOMAIN
},
3377 { "set-llmnr", required_argument
, NULL
, ARG_SET_LLMNR
},
3378 { "set-mdns", required_argument
, NULL
, ARG_SET_MDNS
},
3379 { "set-dnsovertls", required_argument
, NULL
, ARG_SET_PRIVATE
},
3380 { "set-dnssec", required_argument
, NULL
, ARG_SET_DNSSEC
},
3381 { "set-nta", required_argument
, NULL
, ARG_SET_NTA
},
3382 { "revert", no_argument
, NULL
, ARG_REVERT_LINK
},
3391 while ((c
= getopt_long(argc
, argv
, "h46i:t:c:p:", options
, NULL
)) >= 0)
3395 return compat_help();
3401 arg_family
= AF_INET
;
3405 arg_family
= AF_INET6
;
3409 r
= ifname_mangle(optarg
);
3415 if (streq(optarg
, "help")) {
3420 r
= dns_type_from_string(optarg
);
3422 return log_error_errno(r
, "Failed to parse RR record type %s: %m", optarg
);
3424 arg_type
= (uint16_t) r
;
3425 assert((int) arg_type
== r
);
3427 arg_mode
= MODE_RESOLVE_RECORD
;
3431 if (streq(optarg
, "help")) {
3436 r
= dns_class_from_string(optarg
);
3438 return log_error_errno(r
, "Failed to parse RR record class %s: %m", optarg
);
3440 arg_class
= (uint16_t) r
;
3441 assert((int) arg_class
== r
);
3446 r
= parse_boolean_argument("--legend=", optarg
, &arg_legend
);
3452 if (streq(optarg
, "help")) {
3453 help_protocol_types();
3455 } else if (streq(optarg
, "dns"))
3456 arg_flags
|= SD_RESOLVED_DNS
;
3457 else if (streq(optarg
, "llmnr"))
3458 arg_flags
|= SD_RESOLVED_LLMNR
;
3459 else if (streq(optarg
, "llmnr-ipv4"))
3460 arg_flags
|= SD_RESOLVED_LLMNR_IPV4
;
3461 else if (streq(optarg
, "llmnr-ipv6"))
3462 arg_flags
|= SD_RESOLVED_LLMNR_IPV6
;
3463 else if (streq(optarg
, "mdns"))
3464 arg_flags
|= SD_RESOLVED_MDNS
;
3465 else if (streq(optarg
, "mdns-ipv4"))
3466 arg_flags
|= SD_RESOLVED_MDNS_IPV4
;
3467 else if (streq(optarg
, "mdns-ipv6"))
3468 arg_flags
|= SD_RESOLVED_MDNS_IPV6
;
3470 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
3471 "Unknown protocol specifier: %s", optarg
);
3476 arg_mode
= MODE_RESOLVE_SERVICE
;
3480 arg_mode
= MODE_RESOLVE_OPENPGP
;
3484 arg_mode
= MODE_RESOLVE_TLSA
;
3485 if (!optarg
|| service_family_is_valid(optarg
))
3486 arg_service_family
= optarg
;
3488 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
3489 "Unknown service family \"%s\".", optarg
);
3494 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY
),
3495 "Refusing to write binary data to tty.");
3497 if (optarg
== NULL
|| streq(optarg
, "payload"))
3498 arg_raw
= RAW_PAYLOAD
;
3499 else if (streq(optarg
, "packet"))
3500 arg_raw
= RAW_PACKET
;
3502 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
3503 "Unknown --raw specifier \"%s\".",
3510 r
= parse_boolean_argument("--cname=", optarg
, NULL
);
3513 SET_FLAG(arg_flags
, SD_RESOLVED_NO_CNAME
, r
== 0);
3516 case ARG_SERVICE_ADDRESS
:
3517 r
= parse_boolean_argument("--service-address=", optarg
, NULL
);
3520 SET_FLAG(arg_flags
, SD_RESOLVED_NO_ADDRESS
, r
== 0);
3523 case ARG_SERVICE_TXT
:
3524 r
= parse_boolean_argument("--service-txt=", optarg
, NULL
);
3527 SET_FLAG(arg_flags
, SD_RESOLVED_NO_TXT
, r
== 0);
3531 r
= parse_boolean_argument("--search=", optarg
, NULL
);
3534 SET_FLAG(arg_flags
, SD_RESOLVED_NO_SEARCH
, r
== 0);
3537 case ARG_STATISTICS
:
3538 arg_mode
= MODE_STATISTICS
;
3541 case ARG_RESET_STATISTICS
:
3542 arg_mode
= MODE_RESET_STATISTICS
;
3545 case ARG_FLUSH_CACHES
:
3546 arg_mode
= MODE_FLUSH_CACHES
;
3549 case ARG_RESET_SERVER_FEATURES
:
3550 arg_mode
= MODE_RESET_SERVER_FEATURES
;
3554 arg_mode
= MODE_STATUS
;
3558 arg_pager_flags
|= PAGER_DISABLE
;
3562 r
= strv_extend(&arg_set_dns
, optarg
);
3566 arg_mode
= MODE_SET_LINK
;
3569 case ARG_SET_DOMAIN
:
3570 r
= strv_extend(&arg_set_domain
, optarg
);
3574 arg_mode
= MODE_SET_LINK
;
3578 arg_set_llmnr
= optarg
;
3579 arg_mode
= MODE_SET_LINK
;
3583 arg_set_mdns
= optarg
;
3584 arg_mode
= MODE_SET_LINK
;
3587 case ARG_SET_PRIVATE
:
3588 arg_set_dns_over_tls
= optarg
;
3589 arg_mode
= MODE_SET_LINK
;
3592 case ARG_SET_DNSSEC
:
3593 arg_set_dnssec
= optarg
;
3594 arg_mode
= MODE_SET_LINK
;
3598 r
= strv_extend(&arg_set_nta
, optarg
);
3602 arg_mode
= MODE_SET_LINK
;
3605 case ARG_REVERT_LINK
:
3606 arg_mode
= MODE_REVERT_LINK
;
3613 assert_not_reached();
3616 if (arg_type
== 0 && arg_class
!= 0)
3617 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
3618 "--class= may only be used in conjunction with --type=.");
3620 if (arg_type
!= 0 && arg_mode
== MODE_RESOLVE_SERVICE
)
3621 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
3622 "--service and --type= may not be combined.");
3624 if (arg_type
!= 0 && arg_class
== 0)
3625 arg_class
= DNS_CLASS_IN
;
3627 if (arg_class
!= 0 && arg_type
== 0)
3628 arg_type
= DNS_TYPE_A
;
3630 if (IN_SET(arg_mode
, MODE_SET_LINK
, MODE_REVERT_LINK
)) {
3632 if (arg_ifindex
<= 0)
3633 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
3634 "--set-dns=, --set-domain=, --set-llmnr=, --set-mdns=, --set-dnsovertls=, --set-dnssec=, --set-nta= and --revert require --interface=.");
3637 return 1 /* work to do */;
3640 static int native_parse_argv(int argc
, char *argv
[]) {
3642 ARG_VERSION
= 0x100,
3651 ARG_SERVICE_ADDRESS
,
3660 static const struct option options
[] = {
3661 { "help", no_argument
, NULL
, 'h' },
3662 { "version", no_argument
, NULL
, ARG_VERSION
},
3663 { "type", required_argument
, NULL
, 't' },
3664 { "class", required_argument
, NULL
, 'c' },
3665 { "legend", required_argument
, NULL
, ARG_LEGEND
},
3666 { "interface", required_argument
, NULL
, 'i' },
3667 { "protocol", required_argument
, NULL
, 'p' },
3668 { "cname", required_argument
, NULL
, ARG_CNAME
},
3669 { "validate", required_argument
, NULL
, ARG_VALIDATE
},
3670 { "synthesize", required_argument
, NULL
, ARG_SYNTHESIZE
},
3671 { "cache", required_argument
, NULL
, ARG_CACHE
},
3672 { "zone", required_argument
, NULL
, ARG_ZONE
},
3673 { "trust-anchor", required_argument
, NULL
, ARG_TRUST_ANCHOR
},
3674 { "network", required_argument
, NULL
, ARG_NETWORK
},
3675 { "service-address", required_argument
, NULL
, ARG_SERVICE_ADDRESS
},
3676 { "service-txt", required_argument
, NULL
, ARG_SERVICE_TXT
},
3677 { "raw", optional_argument
, NULL
, ARG_RAW
},
3678 { "search", required_argument
, NULL
, ARG_SEARCH
},
3679 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
3680 { "json", required_argument
, NULL
, ARG_JSON
},
3681 { "stale-data", required_argument
, NULL
, ARG_STALE_DATA
},
3690 while ((c
= getopt_long(argc
, argv
, "h46i:t:c:p:j", options
, NULL
)) >= 0)
3694 return native_help();
3700 arg_family
= AF_INET
;
3704 arg_family
= AF_INET6
;
3708 r
= ifname_mangle(optarg
);
3714 if (streq(optarg
, "help")) {
3719 r
= dns_type_from_string(optarg
);
3721 return log_error_errno(r
, "Failed to parse RR record type %s: %m", optarg
);
3723 arg_type
= (uint16_t) r
;
3724 assert((int) arg_type
== r
);
3729 if (streq(optarg
, "help")) {
3734 r
= dns_class_from_string(optarg
);
3736 return log_error_errno(r
, "Failed to parse RR record class %s: %m", optarg
);
3738 arg_class
= (uint16_t) r
;
3739 assert((int) arg_class
== r
);
3744 r
= parse_boolean_argument("--legend=", optarg
, &arg_legend
);
3750 if (streq(optarg
, "help")) {
3751 help_protocol_types();
3753 } else if (streq(optarg
, "dns"))
3754 arg_flags
|= SD_RESOLVED_DNS
;
3755 else if (streq(optarg
, "llmnr"))
3756 arg_flags
|= SD_RESOLVED_LLMNR
;
3757 else if (streq(optarg
, "llmnr-ipv4"))
3758 arg_flags
|= SD_RESOLVED_LLMNR_IPV4
;
3759 else if (streq(optarg
, "llmnr-ipv6"))
3760 arg_flags
|= SD_RESOLVED_LLMNR_IPV6
;
3761 else if (streq(optarg
, "mdns"))
3762 arg_flags
|= SD_RESOLVED_MDNS
;
3763 else if (streq(optarg
, "mdns-ipv4"))
3764 arg_flags
|= SD_RESOLVED_MDNS_IPV4
;
3765 else if (streq(optarg
, "mdns-ipv6"))
3766 arg_flags
|= SD_RESOLVED_MDNS_IPV6
;
3768 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
3769 "Unknown protocol specifier: %s",
3776 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY
),
3777 "Refusing to write binary data to tty.");
3779 if (optarg
== NULL
|| streq(optarg
, "payload"))
3780 arg_raw
= RAW_PAYLOAD
;
3781 else if (streq(optarg
, "packet"))
3782 arg_raw
= RAW_PACKET
;
3784 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
3785 "Unknown --raw specifier \"%s\".",
3792 r
= parse_boolean_argument("--cname=", optarg
, NULL
);
3795 SET_FLAG(arg_flags
, SD_RESOLVED_NO_CNAME
, r
== 0);
3799 r
= parse_boolean_argument("--validate=", optarg
, NULL
);
3802 SET_FLAG(arg_flags
, SD_RESOLVED_NO_VALIDATE
, r
== 0);
3805 case ARG_SYNTHESIZE
:
3806 r
= parse_boolean_argument("--synthesize=", optarg
, NULL
);
3809 SET_FLAG(arg_flags
, SD_RESOLVED_NO_SYNTHESIZE
, r
== 0);
3813 r
= parse_boolean_argument("--cache=", optarg
, NULL
);
3816 SET_FLAG(arg_flags
, SD_RESOLVED_NO_CACHE
, r
== 0);
3819 case ARG_STALE_DATA
:
3820 r
= parse_boolean_argument("--stale-data=", optarg
, NULL
);
3823 SET_FLAG(arg_flags
, SD_RESOLVED_NO_STALE
, r
== 0);
3827 r
= parse_boolean_argument("--zone=", optarg
, NULL
);
3830 SET_FLAG(arg_flags
, SD_RESOLVED_NO_ZONE
, r
== 0);
3833 case ARG_TRUST_ANCHOR
:
3834 r
= parse_boolean_argument("--trust-anchor=", optarg
, NULL
);
3837 SET_FLAG(arg_flags
, SD_RESOLVED_NO_TRUST_ANCHOR
, r
== 0);
3841 r
= parse_boolean_argument("--network=", optarg
, NULL
);
3844 SET_FLAG(arg_flags
, SD_RESOLVED_NO_NETWORK
, r
== 0);
3847 case ARG_SERVICE_ADDRESS
:
3848 r
= parse_boolean_argument("--service-address=", optarg
, NULL
);
3851 SET_FLAG(arg_flags
, SD_RESOLVED_NO_ADDRESS
, r
== 0);
3854 case ARG_SERVICE_TXT
:
3855 r
= parse_boolean_argument("--service-txt=", optarg
, NULL
);
3858 SET_FLAG(arg_flags
, SD_RESOLVED_NO_TXT
, r
== 0);
3862 r
= parse_boolean_argument("--search=", optarg
, NULL
);
3865 SET_FLAG(arg_flags
, SD_RESOLVED_NO_SEARCH
, r
== 0);
3869 arg_pager_flags
|= PAGER_DISABLE
;
3873 r
= parse_json_argument(optarg
, &arg_json_format_flags
);
3880 arg_json_format_flags
= JSON_FORMAT_PRETTY_AUTO
|JSON_FORMAT_COLOR_AUTO
;
3887 assert_not_reached();
3890 if (arg_type
== 0 && arg_class
!= 0)
3891 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
3892 "--class= may only be used in conjunction with --type=.");
3894 if (arg_type
!= 0 && arg_class
== 0)
3895 arg_class
= DNS_CLASS_IN
;
3897 if (arg_class
!= 0 && arg_type
== 0)
3898 arg_type
= DNS_TYPE_A
;
3900 return 1 /* work to do */;
3903 static int native_main(int argc
, char *argv
[], sd_bus
*bus
) {
3905 static const Verb verbs
[] = {
3906 { "help", VERB_ANY
, VERB_ANY
, 0, verb_help
},
3907 { "status", VERB_ANY
, VERB_ANY
, VERB_DEFAULT
, verb_status
},
3908 { "query", 2, VERB_ANY
, 0, verb_query
},
3909 { "service", 2, 4, 0, verb_service
},
3910 { "openpgp", 2, VERB_ANY
, 0, verb_openpgp
},
3911 { "tlsa", 2, VERB_ANY
, 0, verb_tlsa
},
3912 { "statistics", VERB_ANY
, 1, 0, show_statistics
},
3913 { "reset-statistics", VERB_ANY
, 1, 0, reset_statistics
},
3914 { "flush-caches", VERB_ANY
, 1, 0, flush_caches
},
3915 { "reset-server-features", VERB_ANY
, 1, 0, reset_server_features
},
3916 { "dns", VERB_ANY
, VERB_ANY
, 0, verb_dns
},
3917 { "domain", VERB_ANY
, VERB_ANY
, 0, verb_domain
},
3918 { "default-route", VERB_ANY
, 3, 0, verb_default_route
},
3919 { "llmnr", VERB_ANY
, 3, 0, verb_llmnr
},
3920 { "mdns", VERB_ANY
, 3, 0, verb_mdns
},
3921 { "dnsovertls", VERB_ANY
, 3, 0, verb_dns_over_tls
},
3922 { "dnssec", VERB_ANY
, 3, 0, verb_dnssec
},
3923 { "nta", VERB_ANY
, VERB_ANY
, 0, verb_nta
},
3924 { "revert", VERB_ANY
, 2, 0, verb_revert_link
},
3925 { "log-level", VERB_ANY
, 2, 0, verb_log_level
},
3926 { "monitor", VERB_ANY
, 1, 0, verb_monitor
},
3927 { "show-cache", VERB_ANY
, 1, 0, verb_show_cache
},
3928 { "show-server-state", VERB_ANY
, 1, 0, verb_show_server_state
},
3932 return dispatch_verb(argc
, argv
, verbs
, bus
);
3935 static int translate(const char *verb
, const char *single_arg
, size_t num_args
, char **args
, sd_bus
*bus
) {
3940 assert(num_args
== 0 || args
);
3942 num
= !!single_arg
+ num_args
+ 1;
3944 p
= fake
= newa0(char *, num
+ 1);
3945 *p
++ = (char *) verb
;
3947 *p
++ = (char *) single_arg
;
3948 for (size_t i
= 0; i
< num_args
; i
++)
3952 return native_main((int) num
, fake
, bus
);
3955 static int compat_main(int argc
, char *argv
[], sd_bus
*bus
) {
3959 case MODE_RESOLVE_HOST
:
3960 case MODE_RESOLVE_RECORD
:
3961 return translate("query", NULL
, argc
- optind
, argv
+ optind
, bus
);
3963 case MODE_RESOLVE_SERVICE
:
3964 return translate("service", NULL
, argc
- optind
, argv
+ optind
, bus
);
3966 case MODE_RESOLVE_OPENPGP
:
3967 return translate("openpgp", NULL
, argc
- optind
, argv
+ optind
, bus
);
3969 case MODE_RESOLVE_TLSA
:
3970 return translate("tlsa", arg_service_family
, argc
- optind
, argv
+ optind
, bus
);
3972 case MODE_STATISTICS
:
3973 return translate("statistics", NULL
, 0, NULL
, bus
);
3975 case MODE_RESET_STATISTICS
:
3976 return translate("reset-statistics", NULL
, 0, NULL
, bus
);
3978 case MODE_FLUSH_CACHES
:
3979 return translate("flush-caches", NULL
, 0, NULL
, bus
);
3981 case MODE_RESET_SERVER_FEATURES
:
3982 return translate("reset-server-features", NULL
, 0, NULL
, bus
);
3985 return translate("status", NULL
, argc
- optind
, argv
+ optind
, bus
);
3991 r
= translate("dns", arg_ifname
, strv_length(arg_set_dns
), arg_set_dns
, bus
);
3996 if (arg_set_domain
) {
3997 r
= translate("domain", arg_ifname
, strv_length(arg_set_domain
), arg_set_domain
, bus
);
4003 r
= translate("nta", arg_ifname
, strv_length(arg_set_nta
), arg_set_nta
, bus
);
4008 if (arg_set_llmnr
) {
4009 r
= translate("llmnr", arg_ifname
, 1, (char **) &arg_set_llmnr
, bus
);
4015 r
= translate("mdns", arg_ifname
, 1, (char **) &arg_set_mdns
, bus
);
4020 if (arg_set_dns_over_tls
) {
4021 r
= translate("dnsovertls", arg_ifname
, 1, (char **) &arg_set_dns_over_tls
, bus
);
4026 if (arg_set_dnssec
) {
4027 r
= translate("dnssec", arg_ifname
, 1, (char **) &arg_set_dnssec
, bus
);
4034 case MODE_REVERT_LINK
:
4037 return translate("revert", arg_ifname
, 0, NULL
, bus
);
4040 assert_not_reached();
4046 static int run(int argc
, char **argv
) {
4047 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
4048 bool compat
= false;
4051 setlocale(LC_ALL
, "");
4054 if (invoked_as(argv
, "resolvconf")) {
4056 r
= resolvconf_parse_argv(argc
, argv
);
4057 } else if (invoked_as(argv
, "systemd-resolve")) {
4059 r
= compat_parse_argv(argc
, argv
);
4061 r
= native_parse_argv(argc
, argv
);
4065 r
= sd_bus_open_system(&bus
);
4067 return log_error_errno(r
, "sd_bus_open_system: %m");
4070 return compat_main(argc
, argv
, bus
);
4072 return native_main(argc
, argv
, bus
);
4075 DEFINE_MAIN_FUNCTION(run
);