1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
11 #include "sd-netlink.h"
12 #include "sd-varlink.h"
15 #include "alloc-util.h"
16 #include "argv-util.h"
18 #include "bus-common-errors.h"
19 #include "bus-error.h"
20 #include "bus-locator.h"
21 #include "bus-map-properties.h"
22 #include "bus-message-util.h"
24 #include "dns-domain.h"
25 #include "dns-packet.h"
27 #include "errno-list.h"
28 #include "errno-util.h"
30 #include "format-ifname.h"
31 #include "format-table.h"
32 #include "hostname-util.h"
33 #include "json-util.h"
34 #include "main-func.h"
35 #include "missing-network.h"
36 #include "netlink-util.h"
37 #include "openssl-util.h"
39 #include "parse-argument.h"
40 #include "parse-util.h"
41 #include "polkit-agent.h"
42 #include "pretty-print.h"
43 #include "resolvconf-compat.h"
44 #include "resolve-util.h"
45 #include "resolvectl.h"
46 #include "resolved-def.h"
47 #include "resolved-util.h"
49 #include "socket-netlink.h"
50 #include "sort-util.h"
51 #include "stdio-util.h"
52 #include "string-table.h"
53 #include "string-util.h"
55 #include "terminal-util.h"
56 #include "time-util.h"
58 #include "varlink-util.h"
59 #include "verb-log-control.h"
62 static int arg_family
= AF_UNSPEC
;
63 static int arg_ifindex
= 0;
64 static char *arg_ifname
= NULL
;
65 static uint16_t arg_type
= 0;
66 static uint16_t arg_class
= 0;
67 static bool arg_legend
= true;
68 static uint64_t arg_flags
= 0;
69 static sd_json_format_flags_t arg_json_format_flags
= SD_JSON_FORMAT_OFF
;
70 static PagerFlags arg_pager_flags
= 0;
71 bool arg_ifindex_permissive
= false; /* If true, don't generate an error if the specified interface index doesn't exist */
72 static const char *arg_service_family
= NULL
;
73 static bool arg_ask_password
= true;
75 typedef enum RawType
{
80 static RawType arg_raw
= RAW_NONE
;
82 /* Used by compat interfaces: systemd-resolve and resolvconf. */
83 ExecutionMode arg_mode
= MODE_RESOLVE_HOST
;
84 char **arg_set_dns
= NULL
;
85 char **arg_set_domain
= NULL
;
86 bool arg_disable_default_route
= false;
87 static const char *arg_set_llmnr
= NULL
;
88 static const char *arg_set_mdns
= NULL
;
89 static const char *arg_set_dns_over_tls
= NULL
;
90 static const char *arg_set_dnssec
= NULL
;
91 static char **arg_set_nta
= NULL
;
93 STATIC_DESTRUCTOR_REGISTER(arg_ifname
, freep
);
94 STATIC_DESTRUCTOR_REGISTER(arg_set_dns
, strv_freep
);
95 STATIC_DESTRUCTOR_REGISTER(arg_set_domain
, strv_freep
);
96 STATIC_DESTRUCTOR_REGISTER(arg_set_nta
, strv_freep
);
98 typedef enum StatusMode
{
102 STATUS_DEFAULT_ROUTE
,
109 _STATUS_INVALID
= -EINVAL
,
112 static const char* const status_mode_json_field_table
[_STATUS_MAX
] = {
114 [STATUS_DNS
] = "servers",
115 [STATUS_DOMAIN
] = "searchDomains",
116 [STATUS_DEFAULT_ROUTE
] = "defaultRoute",
117 [STATUS_LLMNR
] = "llmnr",
118 [STATUS_MDNS
] = "mDNS",
119 [STATUS_DNS_OVER_TLS
] = "dnsOverTLS",
120 [STATUS_DNSSEC
] = "dnssec",
121 [STATUS_NTA
] = "negativeTrustAnchors",
124 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(status_mode_json_field
, StatusMode
);
126 typedef struct InterfaceInfo
{
131 static int acquire_bus(sd_bus
**ret
) {
132 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
137 r
= sd_bus_open_system(&bus
);
139 return log_error_errno(r
, "sd_bus_open_system: %m");
141 (void) sd_bus_set_allow_interactive_authorization(bus
, arg_ask_password
);
143 *ret
= TAKE_PTR(bus
);
147 static int interface_info_compare(const InterfaceInfo
*a
, const InterfaceInfo
*b
) {
150 r
= CMP(a
->index
, b
->index
);
154 return strcmp_ptr(a
->name
, b
->name
);
157 int ifname_mangle_full(const char *s
, bool drop_protocol_specifier
) {
158 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
159 _cleanup_strv_free_
char **found
= NULL
;
164 if (drop_protocol_specifier
) {
165 _cleanup_free_
char *buf
= NULL
;
166 int ifindex_longest_name
= -ENODEV
;
168 /* When invoked as resolvconf, drop the protocol specifier(s) at the end. */
175 r
= rtnl_resolve_interface(&rtnl
, buf
);
177 if (ifindex_longest_name
<= 0)
178 ifindex_longest_name
= r
;
180 r
= strv_extend(&found
, buf
);
185 char *dot
= strrchr(buf
, '.');
192 unsigned n
= strv_length(found
);
194 _cleanup_free_
char *joined
= NULL
;
196 joined
= strv_join(found
, ", ");
197 log_warning("Found multiple interfaces (%s) matching with '%s'. Using '%s' (ifindex=%i).",
198 strna(joined
), s
, found
[0], ifindex_longest_name
);
203 proto
= ASSERT_PTR(startswith(s
, found
[0]));
205 log_info("Dropped protocol specifier '%s' from '%s'. Using '%s' (ifindex=%i).",
206 proto
, s
, found
[0], ifindex_longest_name
);
209 r
= ifindex_longest_name
;
211 r
= rtnl_resolve_interface(&rtnl
, s
);
213 if (ERRNO_IS_DEVICE_ABSENT(r
) && arg_ifindex_permissive
) {
214 log_debug_errno(r
, "Interface '%s' not found, but -f specified, ignoring: %m", s
);
217 return log_error_errno(r
, "Failed to resolve interface \"%s\": %m", s
);
220 if (arg_ifindex
> 0 && arg_ifindex
!= r
)
221 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Specified multiple different interfaces. Refusing.");
224 return free_and_strdup_warn(&arg_ifname
, found
? found
[0] : s
); /* found */
227 static void print_source(uint64_t flags
, usec_t rtt
) {
231 if (sd_json_format_enabled(arg_json_format_flags
))
237 printf("\n%s-- Information acquired via", ansi_grey());
239 printf(" protocol%s%s%s%s%s",
240 flags
& SD_RESOLVED_DNS
? " DNS" :"",
241 flags
& SD_RESOLVED_LLMNR_IPV4
? " LLMNR/IPv4" : "",
242 flags
& SD_RESOLVED_LLMNR_IPV6
? " LLMNR/IPv6" : "",
243 flags
& SD_RESOLVED_MDNS_IPV4
? " mDNS/IPv4" : "",
244 flags
& SD_RESOLVED_MDNS_IPV6
? " mDNS/IPv6" : "");
247 "%s-- Data is authenticated: %s; Data was acquired via local or encrypted transport: %s%s\n",
248 FORMAT_TIMESPAN(rtt
, 100),
251 yes_no(flags
& SD_RESOLVED_AUTHENTICATED
),
252 yes_no(flags
& SD_RESOLVED_CONFIDENTIAL
),
255 if ((flags
& (SD_RESOLVED_FROM_MASK
|SD_RESOLVED_SYNTHETIC
)) != 0)
256 printf("%s-- Data from:%s%s%s%s%s%s%s\n",
258 FLAGS_SET(flags
, SD_RESOLVED_SYNTHETIC
) ? " synthetic" : "",
259 FLAGS_SET(flags
, SD_RESOLVED_FROM_CACHE
) ? " cache" : "",
260 FLAGS_SET(flags
, SD_RESOLVED_FROM_ZONE
) ? " zone" : "",
261 FLAGS_SET(flags
, SD_RESOLVED_FROM_TRUST_ANCHOR
) ? " trust-anchor" : "",
262 FLAGS_SET(flags
, SD_RESOLVED_FROM_NETWORK
) ? " network" : "",
263 FLAGS_SET(flags
, SD_RESOLVED_FROM_HOOK
) ? " hook" : "",
267 static void print_ifindex_comment(int printed_so_far
, int ifindex
) {
268 char ifname
[IF_NAMESIZE
];
274 r
= format_ifname(ifindex
, ifname
);
276 return (void) log_warning_errno(r
, "Failed to resolve interface name for index %i, ignoring: %m", ifindex
);
278 printf("%*s%s-- link: %s%s",
279 60 > printed_so_far
? 60 - printed_so_far
: 0, " ", /* Align comment to the 60th column */
280 ansi_grey(), ifname
, ansi_normal());
283 static int resolve_host_error(const char *name
, int r
, const sd_bus_error
*error
) {
284 if (sd_bus_error_has_name(error
, BUS_ERROR_DNS_NXDOMAIN
))
285 return log_error_errno(r
, "%s: %s", name
, bus_error_message(error
, r
));
287 return log_error_errno(r
, "%s: resolve call failed: %s", name
, bus_error_message(error
, r
));
290 static int resolve_host(sd_bus
*bus
, const char *name
) {
291 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
292 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
293 const char *canonical
= NULL
;
301 if (sd_json_format_enabled(arg_json_format_flags
))
302 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Use --json=pretty with --type=A or --type=AAAA to acquire address record information in JSON format.");
304 log_debug("Resolving %s (family %s, interface %s).", name
, af_to_name(arg_family
) ?: "*", isempty(arg_ifname
) ? "*" : arg_ifname
);
306 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveHostname");
308 return bus_log_create_error(r
);
310 r
= sd_bus_message_append(req
, "isit", arg_ifindex
, name
, arg_family
, arg_flags
);
312 return bus_log_create_error(r
);
314 ts
= now(CLOCK_MONOTONIC
);
316 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
318 return resolve_host_error(name
, r
, &error
);
320 ts
= now(CLOCK_MONOTONIC
) - ts
;
322 r
= sd_bus_message_enter_container(reply
, 'a', "(iiay)");
324 return bus_log_parse_error(r
);
326 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iiay")) > 0) {
327 _cleanup_free_
char *pretty
= NULL
;
328 int ifindex
, family
, k
;
329 union in_addr_union a
;
331 assert_cc(sizeof(int) == sizeof(int32_t));
333 r
= sd_bus_message_read(reply
, "i", &ifindex
);
335 return bus_log_parse_error(r
);
337 sd_bus_error_free(&error
);
338 r
= bus_message_read_in_addr_auto(reply
, &error
, &family
, &a
);
339 if (r
< 0 && !sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
))
340 return log_error_errno(r
, "%s: systemd-resolved returned invalid result: %s", name
, bus_error_message(&error
, r
));
342 r
= sd_bus_message_exit_container(reply
);
344 return bus_log_parse_error(r
);
346 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
)) {
347 log_debug_errno(r
, "%s: systemd-resolved returned invalid result, ignoring: %s", name
, bus_error_message(&error
, r
));
351 r
= in_addr_ifindex_to_string(family
, &a
, ifindex
, &pretty
);
353 return log_error_errno(r
, "Failed to print address for %s: %m", name
);
355 k
= printf("%*s%s %s%s%s",
356 (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? ":" : " ",
357 ansi_highlight(), pretty
, ansi_normal());
359 print_ifindex_comment(k
, ifindex
);
365 return bus_log_parse_error(r
);
367 r
= sd_bus_message_exit_container(reply
);
369 return bus_log_parse_error(r
);
371 r
= sd_bus_message_read(reply
, "st", &canonical
, &flags
);
373 return bus_log_parse_error(r
);
375 if (!streq(name
, canonical
))
376 printf("%*s%s (%s)\n",
377 (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? ":" : " ",
381 return log_error_errno(SYNTHETIC_ERRNO(ESRCH
),
382 "%s: no addresses found", name
);
384 print_source(flags
, ts
);
389 static int resolve_address(sd_bus
*bus
, int family
, const union in_addr_union
*address
, int ifindex
) {
390 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
391 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
392 _cleanup_free_
char *pretty
= NULL
;
399 assert(IN_SET(family
, AF_INET
, AF_INET6
));
402 if (sd_json_format_enabled(arg_json_format_flags
))
403 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
406 ifindex
= arg_ifindex
;
408 r
= in_addr_ifindex_to_string(family
, address
, ifindex
, &pretty
);
412 log_debug("Resolving %s.", pretty
);
414 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveAddress");
416 return bus_log_create_error(r
);
418 r
= sd_bus_message_append(req
, "ii", ifindex
, family
);
420 return bus_log_create_error(r
);
422 r
= sd_bus_message_append_array(req
, 'y', address
, FAMILY_ADDRESS_SIZE(family
));
424 return bus_log_create_error(r
);
426 r
= sd_bus_message_append(req
, "t", arg_flags
);
428 return bus_log_create_error(r
);
430 ts
= now(CLOCK_MONOTONIC
);
432 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
434 return log_error_errno(r
, "%s: resolve call failed: %s", pretty
, bus_error_message(&error
, r
));
436 ts
= now(CLOCK_MONOTONIC
) - ts
;
438 r
= sd_bus_message_enter_container(reply
, 'a', "(is)");
440 return bus_log_create_error(r
);
442 while ((r
= sd_bus_message_enter_container(reply
, 'r', "is")) > 0) {
446 assert_cc(sizeof(int) == sizeof(int32_t));
448 r
= sd_bus_message_read(reply
, "is", &ifindex
, &n
);
452 r
= sd_bus_message_exit_container(reply
);
456 k
= printf("%*s%s %s%s%s",
457 (int) strlen(pretty
), c
== 0 ? pretty
: "",
459 ansi_highlight(), n
, ansi_normal());
461 print_ifindex_comment(k
, ifindex
);
467 return bus_log_parse_error(r
);
469 r
= sd_bus_message_exit_container(reply
);
471 return bus_log_parse_error(r
);
473 r
= sd_bus_message_read(reply
, "t", &flags
);
475 return bus_log_parse_error(r
);
478 return log_error_errno(SYNTHETIC_ERRNO(ESRCH
),
479 "%s: no names found", pretty
);
481 print_source(flags
, ts
);
486 static int output_rr_packet(const void *d
, size_t l
, int ifindex
) {
487 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
492 r
= dns_resource_record_new_from_raw(&rr
, d
, l
);
494 return log_error_errno(r
, "Failed to parse RR: %m");
496 if (sd_json_format_enabled(arg_json_format_flags
)) {
497 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*j
= NULL
;
498 r
= dns_resource_record_to_json(rr
, &j
);
500 return log_error_errno(r
, "Failed to convert RR to JSON: %m");
503 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "JSON formatting for records of type %s (%u) not available.", dns_type_to_string(rr
->key
->type
), rr
->key
->type
);
505 r
= sd_json_variant_dump(j
, arg_json_format_flags
, NULL
, NULL
);
509 } else if (arg_raw
== RAW_PAYLOAD
) {
513 k
= dns_resource_record_payload(rr
, &data
);
515 return log_error_errno(k
, "Dumping of binary payload not available for RRs of this type: %s", dns_type_to_string(rr
->key
->type
));
517 return log_error_errno(k
, "Cannot dump RR: %m");
518 fwrite(data
, 1, k
, stdout
);
523 s
= dns_resource_record_to_string(rr
);
528 print_ifindex_comment(k
, ifindex
);
535 static int idna_candidate(const char *name
, char **ret
) {
536 _cleanup_free_
char *idnafied
= NULL
;
542 r
= dns_name_apply_idna(name
, &idnafied
);
544 return log_error_errno(r
, "Failed to apply IDNA to name '%s': %m", name
);
545 if (r
> 0 && !streq(name
, idnafied
)) {
546 *ret
= TAKE_PTR(idnafied
);
554 static bool single_label_nonsynthetic(const char *name
) {
555 _cleanup_free_
char *first_label
= NULL
;
558 if (!dns_name_is_single_label(name
))
561 if (is_localhost(name
) ||
562 is_gateway_hostname(name
) ||
563 is_outbound_hostname(name
) ||
564 is_dns_stub_hostname(name
) ||
565 is_dns_proxy_stub_hostname(name
))
568 r
= resolve_system_hostname(NULL
, &first_label
);
570 log_warning_errno(r
, "Failed to determine the hostname: %m");
574 return !streq(name
, first_label
);
577 static int resolve_record(sd_bus
*bus
, const char *name
, uint16_t class, uint16_t type
, bool warn_missing
) {
578 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
579 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
580 _cleanup_free_
char *idnafied
= NULL
;
581 bool needs_authentication
= false;
589 log_debug("Resolving %s %s %s (interface %s).", name
, dns_class_to_string(class), dns_type_to_string(type
), isempty(arg_ifname
) ? "*" : arg_ifname
);
591 if (dns_name_dot_suffixed(name
) == 0 && single_label_nonsynthetic(name
))
592 log_notice("(Note that search domains are not appended when --type= is specified. "
593 "Please specify fully qualified domain names, or remove --type= switch from invocation in order to request regular hostname resolution.)");
595 r
= idna_candidate(name
, &idnafied
);
599 log_notice("(Note that IDNA translation is not applied when --type= is specified. "
600 "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.",
603 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveRecord");
605 return bus_log_create_error(r
);
607 r
= sd_bus_message_append(req
, "isqqt", arg_ifindex
, name
, class, type
, arg_flags
);
609 return bus_log_create_error(r
);
611 ts
= now(CLOCK_MONOTONIC
);
613 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
615 if (warn_missing
|| r
!= -ENXIO
)
616 log_error("%s: resolve call failed: %s", name
, bus_error_message(&error
, r
));
620 ts
= now(CLOCK_MONOTONIC
) - ts
;
622 r
= sd_bus_message_enter_container(reply
, 'a', "(iqqay)");
624 return bus_log_parse_error(r
);
626 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iqqay")) > 0) {
632 assert_cc(sizeof(int) == sizeof(int32_t));
634 r
= sd_bus_message_read(reply
, "iqq", &ifindex
, &c
, &t
);
636 return bus_log_parse_error(r
);
638 r
= sd_bus_message_read_array(reply
, 'y', &d
, &l
);
640 return bus_log_parse_error(r
);
642 r
= sd_bus_message_exit_container(reply
);
644 return bus_log_parse_error(r
);
646 if (arg_raw
== RAW_PACKET
) {
647 uint64_t u64
= htole64(l
);
649 fwrite(&u64
, sizeof(u64
), 1, stdout
);
650 fwrite(d
, 1, l
, stdout
);
652 r
= output_rr_packet(d
, l
, ifindex
);
657 if (dns_type_needs_authentication(t
))
658 needs_authentication
= true;
663 return bus_log_parse_error(r
);
665 r
= sd_bus_message_exit_container(reply
);
667 return bus_log_parse_error(r
);
669 r
= sd_bus_message_read(reply
, "t", &flags
);
671 return bus_log_parse_error(r
);
675 log_error("%s: no records found", name
);
679 print_source(flags
, ts
);
681 if ((flags
& SD_RESOLVED_AUTHENTICATED
) == 0 && needs_authentication
) {
684 fprintf(stderr
, "\n%s"
685 "WARNING: The resources shown contain cryptographic key data which could not be\n"
686 " authenticated. It is not suitable to authenticate any communication.\n"
687 " This is usually indication that DNSSEC authentication was not enabled\n"
688 " or is not available for the selected protocol or DNS servers.%s\n",
689 ansi_highlight_red(),
696 static int resolve_rfc4501(sd_bus
*bus
, const char *name
) {
697 uint16_t type
= 0, class = 0;
698 const char *p
, *q
, *n
;
703 assert(startswith(name
, "dns:"));
705 /* Parse RFC 4501 dns: URIs */
715 e
= strchr(p
+ 2, '/');
720 log_warning("DNS authority specification not supported; ignoring specified authority.");
727 n
= strndupa_safe(p
, q
- p
);
733 f
= startswith_no_case(q
, "class=");
735 _cleanup_free_
char *t
= NULL
;
739 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
740 "DNS class specified twice.");
742 e
= strchrnul(f
, ';');
743 t
= strndup(f
, e
- f
);
747 r
= dns_class_from_string(t
);
749 return log_error_errno(r
, "Unknown DNS class %s.", t
);
761 f
= startswith_no_case(q
, "type=");
763 _cleanup_free_
char *t
= NULL
;
767 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
768 "DNS type specified twice.");
770 e
= strchrnul(f
, ';');
771 t
= strndup(f
, e
- f
);
775 r
= dns_type_from_string(t
);
777 return log_error_errno(r
, "Unknown DNS type %s: %m", t
);
795 class = arg_class
?: DNS_CLASS_IN
;
797 type
= arg_type
?: DNS_TYPE_A
;
799 return resolve_record(bus
, n
, class, type
, true);
802 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
803 "Invalid DNS URI: %s", name
);
806 static int verb_query(int argc
, char **argv
, void *userdata
) {
807 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
810 r
= acquire_bus(&bus
);
815 STRV_FOREACH(p
, strv_skip(argv
, 1))
816 RET_GATHER(ret
, resolve_record(bus
, *p
, arg_class
, arg_type
, true));
819 STRV_FOREACH(p
, strv_skip(argv
, 1)) {
820 if (startswith(*p
, "dns:"))
821 RET_GATHER(ret
, resolve_rfc4501(bus
, *p
));
824 union in_addr_union a
;
826 r
= in_addr_ifindex_from_string_auto(*p
, &family
, &a
, &ifindex
);
828 RET_GATHER(ret
, resolve_address(bus
, family
, &a
, ifindex
));
830 RET_GATHER(ret
, resolve_host(bus
, *p
));
837 static int resolve_service(sd_bus
*bus
, const char *name
, const char *type
, const char *domain
) {
838 const char *canonical_name
, *canonical_type
, *canonical_domain
;
839 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
840 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
851 name
= empty_to_null(name
);
852 type
= empty_to_null(type
);
855 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
);
857 log_debug("Resolving service type %s of %s (family %s, interface %s).", type
, domain
, af_to_name(arg_family
) ?: "*", isempty(arg_ifname
) ? "*" : arg_ifname
);
859 log_debug("Resolving service type %s (family %s, interface %s).", domain
, af_to_name(arg_family
) ?: "*", isempty(arg_ifname
) ? "*" : arg_ifname
);
861 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveService");
863 return bus_log_create_error(r
);
865 r
= sd_bus_message_append(req
, "isssit", arg_ifindex
, name
, type
, domain
, arg_family
, arg_flags
);
867 return bus_log_create_error(r
);
869 ts
= now(CLOCK_MONOTONIC
);
871 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
873 return log_error_errno(r
, "Resolve call failed: %s", bus_error_message(&error
, r
));
875 ts
= now(CLOCK_MONOTONIC
) - ts
;
877 r
= sd_bus_message_enter_container(reply
, 'a', "(qqqsa(iiay)s)");
879 return bus_log_parse_error(r
);
882 (name
? strlen(name
) + 1 : 0) +
883 (type
? strlen(type
) + 1 : 0) +
887 while ((r
= sd_bus_message_enter_container(reply
, 'r', "qqqsa(iiay)s")) > 0) {
888 uint16_t priority
, weight
, port
;
889 const char *hostname
, *canonical
;
891 r
= sd_bus_message_read(reply
, "qqqs", &priority
, &weight
, &port
, &hostname
);
893 return bus_log_parse_error(r
);
896 printf("%*s%s", (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? "/" : " ");
898 printf("%*s%s", (int) strlen(type
), c
== 0 ? type
: "", c
== 0 ? "/" : " ");
900 printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
901 (int) strlen(domain
), c
== 0 ? domain
: "",
906 r
= sd_bus_message_enter_container(reply
, 'a', "(iiay)");
908 return bus_log_parse_error(r
);
910 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iiay")) > 0) {
911 _cleanup_free_
char *pretty
= NULL
;
912 int ifindex
, family
, k
;
913 union in_addr_union a
;
915 assert_cc(sizeof(int) == sizeof(int32_t));
917 r
= sd_bus_message_read(reply
, "i", &ifindex
);
919 return bus_log_parse_error(r
);
921 sd_bus_error_free(&error
);
922 r
= bus_message_read_in_addr_auto(reply
, &error
, &family
, &a
);
923 if (r
< 0 && !sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
))
924 return log_error_errno(r
, "%s: systemd-resolved returned invalid result: %s", name
, bus_error_message(&error
, r
));
926 r
= sd_bus_message_exit_container(reply
);
928 return bus_log_parse_error(r
);
930 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
)) {
931 log_debug_errno(r
, "%s: systemd-resolved returned invalid result, ignoring: %s", name
, bus_error_message(&error
, r
));
935 r
= in_addr_ifindex_to_string(family
, &a
, ifindex
, &pretty
);
937 return log_error_errno(r
, "Failed to print address for %s: %m", name
);
939 k
= printf("%*s%s", (int) indent
, "", pretty
);
940 print_ifindex_comment(k
, ifindex
);
944 return bus_log_parse_error(r
);
946 r
= sd_bus_message_exit_container(reply
);
948 return bus_log_parse_error(r
);
950 r
= sd_bus_message_read(reply
, "s", &canonical
);
952 return bus_log_parse_error(r
);
954 if (!streq(hostname
, canonical
))
955 printf("%*s(%s)\n", (int) indent
, "", canonical
);
957 r
= sd_bus_message_exit_container(reply
);
959 return bus_log_parse_error(r
);
964 return bus_log_parse_error(r
);
966 r
= sd_bus_message_exit_container(reply
);
968 return bus_log_parse_error(r
);
970 r
= sd_bus_message_enter_container(reply
, 'a', "ay");
972 return bus_log_parse_error(r
);
974 while ((r
= sd_bus_message_read_array(reply
, 'y', (const void**) &p
, &sz
)) > 0) {
975 _cleanup_free_
char *escaped
= NULL
;
977 escaped
= cescape_length(p
, sz
);
981 printf("%*s%s\n", (int) indent
, "", escaped
);
984 return bus_log_parse_error(r
);
986 r
= sd_bus_message_exit_container(reply
);
988 return bus_log_parse_error(r
);
990 r
= sd_bus_message_read(reply
, "ssst", &canonical_name
, &canonical_type
, &canonical_domain
, &flags
);
992 return bus_log_parse_error(r
);
994 canonical_name
= empty_to_null(canonical_name
);
995 canonical_type
= empty_to_null(canonical_type
);
997 if (!streq_ptr(name
, canonical_name
) ||
998 !streq_ptr(type
, canonical_type
) ||
999 !streq_ptr(domain
, canonical_domain
)) {
1001 printf("%*s(", (int) indent
, "");
1004 printf("%s/", canonical_name
);
1006 printf("%s/", canonical_type
);
1008 printf("%s)\n", canonical_domain
);
1011 print_source(flags
, ts
);
1016 static int verb_service(int argc
, char **argv
, void *userdata
) {
1017 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1020 r
= acquire_bus(&bus
);
1024 if (sd_json_format_enabled(arg_json_format_flags
))
1025 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
1028 return resolve_service(bus
, NULL
, NULL
, argv
[1]);
1030 return resolve_service(bus
, NULL
, argv
[1], argv
[2]);
1032 return resolve_service(bus
, argv
[1], argv
[2], argv
[3]);
1036 static int resolve_openpgp(sd_bus
*bus
, const char *address
) {
1042 const char *domain
= strrchr(address
, '@');
1044 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1045 "Address does not contain '@': \"%s\"", address
);
1046 if (domain
== address
|| domain
[1] == '\0')
1047 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1048 "Address starts or ends with '@': \"%s\"", address
);
1051 _cleanup_free_
char *hashed
= NULL
;
1052 r
= string_hashsum_sha256(address
, domain
- 1 - address
, &hashed
);
1054 return log_error_errno(r
, "Hashing failed: %m");
1056 strshorten(hashed
, 56);
1058 _cleanup_free_
char *suffix
= NULL
;
1059 r
= dns_name_concat("_openpgpkey", domain
, /* flags= */ 0, &suffix
);
1061 return log_error_errno(r
, "Failed to join DNS suffix: %m");
1063 _cleanup_free_
char *full
= NULL
;
1064 r
= dns_name_concat(hashed
, suffix
, /* flags= */ 0, &full
);
1066 return log_error_errno(r
, "Failed to join OPENPGPKEY name: %m");
1067 log_debug("Looking up \"%s\".", full
);
1072 arg_class
?: DNS_CLASS_IN
,
1073 arg_type
?: DNS_TYPE_OPENPGPKEY
,
1074 /* warn_missing= */ false);
1075 if (!IN_SET(r
, -ENXIO
, -ESRCH
)) /* Not NXDOMAIN or NODATA? Then fail immediately. */
1078 hashed
= mfree(hashed
);
1079 r
= string_hashsum_sha224(address
, domain
- 1 - address
, &hashed
);
1081 return log_error_errno(r
, "Hashing failed: %m");
1084 r
= dns_name_concat(hashed
, suffix
, /* flags= */ 0, &full
);
1086 return log_error_errno(r
, "Failed to join OPENPGPKEY name: %m");
1087 log_debug("Looking up \"%s\".", full
);
1089 return resolve_record(
1092 arg_class
?: DNS_CLASS_IN
,
1093 arg_type
?: DNS_TYPE_OPENPGPKEY
,
1094 /* warn_missing= */ true);
1098 static int verb_openpgp(int argc
, char **argv
, void *userdata
) {
1100 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1103 r
= acquire_bus(&bus
);
1107 if (sd_json_format_enabled(arg_json_format_flags
))
1108 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
1110 STRV_FOREACH(p
, strv_skip(argv
, 1))
1111 RET_GATHER(ret
, resolve_openpgp(bus
, *p
));
1115 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "OpenSSL support is disabled, cannot query Open PGP keys.");
1119 static int resolve_tlsa(sd_bus
*bus
, const char *family
, const char *address
) {
1121 uint16_t port_num
= 443;
1122 _cleanup_free_
char *full
= NULL
;
1128 port
= strrchr(address
, ':');
1130 r
= parse_ip_port(port
+ 1, &port_num
);
1132 return log_error_errno(r
, "Invalid port \"%s\".", port
+ 1);
1134 address
= strndupa_safe(address
, port
- address
);
1137 r
= asprintf(&full
, "_%u._%s.%s",
1144 log_debug("Looking up \"%s\".", full
);
1146 return resolve_record(bus
, full
,
1147 arg_class
?: DNS_CLASS_IN
,
1148 arg_type
?: DNS_TYPE_TLSA
, true);
1151 static bool service_family_is_valid(const char *s
) {
1152 return STR_IN_SET(s
, "tcp", "udp", "sctp");
1155 static int verb_tlsa(int argc
, char **argv
, void *userdata
) {
1156 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1157 const char *family
= "tcp";
1163 r
= acquire_bus(&bus
);
1167 if (sd_json_format_enabled(arg_json_format_flags
))
1168 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
1170 if (service_family_is_valid(argv
[1])) {
1172 args
= strv_skip(argv
, 2);
1174 args
= strv_skip(argv
, 1);
1176 STRV_FOREACH(p
, args
)
1177 RET_GATHER(ret
, resolve_tlsa(bus
, family
, *p
));
1182 static int show_statistics(int argc
, char **argv
, void *userdata
) {
1183 _cleanup_(table_unrefp
) Table
*table
= NULL
;
1184 sd_json_variant
*reply
= NULL
;
1185 _cleanup_(sd_varlink_unrefp
) sd_varlink
*vl
= NULL
;
1188 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
1190 r
= sd_varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
1192 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
1194 r
= varlink_callbo_and_log(
1196 "io.systemd.Resolve.Monitor.DumpStatistics",
1198 SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password
));
1202 if (sd_json_format_enabled(arg_json_format_flags
))
1203 return sd_json_variant_dump(reply
, arg_json_format_flags
, NULL
, NULL
);
1206 sd_json_variant
*transactions
;
1207 sd_json_variant
*cache
;
1208 sd_json_variant
*dnssec
;
1211 static const sd_json_dispatch_field statistics_dispatch_table
[] = {
1212 { "transactions", SD_JSON_VARIANT_OBJECT
, sd_json_dispatch_variant_noref
, offsetof(struct statistics
, transactions
), SD_JSON_MANDATORY
},
1213 { "cache", SD_JSON_VARIANT_OBJECT
, sd_json_dispatch_variant_noref
, offsetof(struct statistics
, cache
), SD_JSON_MANDATORY
},
1214 { "dnssec", SD_JSON_VARIANT_OBJECT
, sd_json_dispatch_variant_noref
, offsetof(struct statistics
, dnssec
), SD_JSON_MANDATORY
},
1218 r
= sd_json_dispatch(reply
, statistics_dispatch_table
, SD_JSON_LOG
, &statistics
);
1222 struct transactions
{
1223 uint64_t n_current_transactions
;
1224 uint64_t n_transactions_total
;
1225 uint64_t n_timeouts_total
;
1226 uint64_t n_timeouts_served_stale_total
;
1227 uint64_t n_failure_responses_total
;
1228 uint64_t n_failure_responses_served_stale_total
;
1231 static const sd_json_dispatch_field transactions_dispatch_table
[] = {
1232 { "currentTransactions", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct transactions
, n_current_transactions
), SD_JSON_MANDATORY
},
1233 { "totalTransactions", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct transactions
, n_transactions_total
), SD_JSON_MANDATORY
},
1234 { "totalTimeouts", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct transactions
, n_timeouts_total
), SD_JSON_MANDATORY
},
1235 { "totalTimeoutsServedStale", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct transactions
, n_timeouts_served_stale_total
), SD_JSON_MANDATORY
},
1236 { "totalFailedResponses", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct transactions
, n_failure_responses_total
), SD_JSON_MANDATORY
},
1237 { "totalFailedResponsesServedStale", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct transactions
, n_failure_responses_served_stale_total
), SD_JSON_MANDATORY
},
1241 r
= sd_json_dispatch(statistics
.transactions
, transactions_dispatch_table
, SD_JSON_LOG
, &transactions
);
1246 uint64_t cache_size
;
1247 uint64_t n_cache_hit
;
1248 uint64_t n_cache_miss
;
1251 static const sd_json_dispatch_field cache_dispatch_table
[] = {
1252 { "size", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct cache
, cache_size
), SD_JSON_MANDATORY
},
1253 { "hits", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct cache
, n_cache_hit
), SD_JSON_MANDATORY
},
1254 { "misses", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct cache
, n_cache_miss
), SD_JSON_MANDATORY
},
1258 r
= sd_json_dispatch(statistics
.cache
, cache_dispatch_table
, SD_JSON_LOG
, &cache
);
1263 uint64_t n_dnssec_secure
;
1264 uint64_t n_dnssec_insecure
;
1265 uint64_t n_dnssec_bogus
;
1266 uint64_t n_dnssec_indeterminate
;
1269 static const sd_json_dispatch_field dnssec_dispatch_table
[] = {
1270 { "secure", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct dnsssec
, n_dnssec_secure
), SD_JSON_MANDATORY
},
1271 { "insecure", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct dnsssec
, n_dnssec_insecure
), SD_JSON_MANDATORY
},
1272 { "bogus", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct dnsssec
, n_dnssec_bogus
), SD_JSON_MANDATORY
},
1273 { "indeterminate", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct dnsssec
, n_dnssec_indeterminate
), SD_JSON_MANDATORY
},
1277 r
= sd_json_dispatch(statistics
.dnssec
, dnssec_dispatch_table
, SD_JSON_LOG
, &dnsssec
);
1281 table
= table_new_vertical();
1285 r
= table_add_many(table
,
1286 TABLE_STRING
, "Transactions",
1287 TABLE_SET_COLOR
, ansi_highlight(),
1288 TABLE_SET_ALIGN_PERCENT
, 0,
1290 TABLE_FIELD
, "Current Transactions",
1291 TABLE_SET_ALIGN_PERCENT
, 100,
1292 TABLE_UINT64
, transactions
.n_current_transactions
,
1293 TABLE_SET_ALIGN_PERCENT
, 100,
1294 TABLE_FIELD
, "Total Transactions",
1295 TABLE_UINT64
, transactions
.n_transactions_total
,
1296 TABLE_EMPTY
, TABLE_EMPTY
,
1297 TABLE_STRING
, "Cache",
1298 TABLE_SET_COLOR
, ansi_highlight(),
1299 TABLE_SET_ALIGN_PERCENT
, 0,
1301 TABLE_FIELD
, "Current Cache Size",
1302 TABLE_SET_ALIGN_PERCENT
, 100,
1303 TABLE_UINT64
, cache
.cache_size
,
1304 TABLE_FIELD
, "Cache Hits",
1305 TABLE_UINT64
, cache
.n_cache_hit
,
1306 TABLE_FIELD
, "Cache Misses",
1307 TABLE_UINT64
, cache
.n_cache_miss
,
1308 TABLE_EMPTY
, TABLE_EMPTY
,
1309 TABLE_STRING
, "Failure Transactions",
1310 TABLE_SET_COLOR
, ansi_highlight(),
1311 TABLE_SET_ALIGN_PERCENT
, 0,
1313 TABLE_FIELD
, "Total Timeouts",
1314 TABLE_SET_ALIGN_PERCENT
, 100,
1315 TABLE_UINT64
, transactions
.n_timeouts_total
,
1316 TABLE_FIELD
, "Total Timeouts (Stale Data Served)",
1317 TABLE_UINT64
, transactions
.n_timeouts_served_stale_total
,
1318 TABLE_FIELD
, "Total Failure Responses",
1319 TABLE_UINT64
, transactions
.n_failure_responses_total
,
1320 TABLE_FIELD
, "Total Failure Responses (Stale Data Served)",
1321 TABLE_UINT64
, transactions
.n_failure_responses_served_stale_total
,
1322 TABLE_EMPTY
, TABLE_EMPTY
,
1323 TABLE_STRING
, "DNSSEC Verdicts",
1324 TABLE_SET_COLOR
, ansi_highlight(),
1325 TABLE_SET_ALIGN_PERCENT
, 0,
1327 TABLE_FIELD
, "Secure",
1328 TABLE_SET_ALIGN_PERCENT
, 100,
1329 TABLE_UINT64
, dnsssec
.n_dnssec_secure
,
1330 TABLE_FIELD
, "Insecure",
1331 TABLE_UINT64
, dnsssec
.n_dnssec_insecure
,
1332 TABLE_FIELD
, "Bogus",
1333 TABLE_UINT64
, dnsssec
.n_dnssec_bogus
,
1334 TABLE_FIELD
, "Indeterminate",
1335 TABLE_UINT64
, dnsssec
.n_dnssec_indeterminate
1338 return table_log_add_error(r
);
1340 r
= table_print(table
, NULL
);
1342 return table_log_print_error(r
);
1347 static int reset_statistics(int argc
, char **argv
, void *userdata
) {
1348 sd_json_variant
*reply
= NULL
;
1349 _cleanup_(sd_varlink_unrefp
) sd_varlink
*vl
= NULL
;
1352 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
1354 r
= sd_varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
1356 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
1358 r
= varlink_callbo_and_log(
1360 "io.systemd.Resolve.Monitor.ResetStatistics",
1362 SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password
));
1366 if (sd_json_format_enabled(arg_json_format_flags
))
1367 return sd_json_variant_dump(reply
, arg_json_format_flags
, NULL
, NULL
);
1372 static int flush_caches(int argc
, char **argv
, void *userdata
) {
1373 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1374 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1377 r
= acquire_bus(&bus
);
1381 r
= bus_call_method(bus
, bus_resolve_mgr
, "FlushCaches", &error
, NULL
, NULL
);
1383 return log_error_errno(r
, "Failed to flush caches: %s", bus_error_message(&error
, r
));
1388 static int reset_server_features(int argc
, char **argv
, void *userdata
) {
1389 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1390 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1393 r
= acquire_bus(&bus
);
1397 r
= bus_call_method(bus
, bus_resolve_mgr
, "ResetServerFeatures", &error
, NULL
, NULL
);
1399 return log_error_errno(r
, "Failed to reset server features: %s", bus_error_message(&error
, r
));
1405 READ_DNS_WITH_IFINDEX
= 1 << 0, /* read "ifindex" reply that also carries an interface index */
1406 READ_DNS_EXTENDED
= 1 << 1, /* read "extended" reply, i.e. with port number and server name */
1407 READ_DNS_ONLY_GLOBAL
= 1 << 2, /* suppress entries with an (non-loopback) ifindex set (i.e. which are specific to some interface) */
1410 static const char *dns_server_property_signature(ReadDNSFlag flags
) {
1411 switch (flags
& (READ_DNS_WITH_IFINDEX
|READ_DNS_EXTENDED
)) {
1416 case READ_DNS_WITH_IFINDEX
:
1419 case READ_DNS_EXTENDED
:
1422 case READ_DNS_WITH_IFINDEX
|READ_DNS_EXTENDED
:
1426 assert_not_reached();
1430 static int read_dns_server_one(sd_bus_message
*m
, ReadDNSFlag flags
, char **ret
) {
1431 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1432 _cleanup_free_
char *pretty
= NULL
;
1433 union in_addr_union a
;
1434 const char *name
= NULL
;
1435 int32_t ifindex
= 0;
1442 r
= sd_bus_message_enter_container(
1445 dns_server_property_signature(flags
));
1449 if (FLAGS_SET(flags
, READ_DNS_WITH_IFINDEX
)) {
1450 r
= sd_bus_message_read(m
, "i", &ifindex
);
1455 r
= bus_message_read_in_addr_auto(m
, &error
, &family
, &a
);
1457 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
)) {
1458 /* CurrentDNSServer provides AF_UNSPEC when no current server assigned. */
1459 log_debug("Invalid DNS server, ignoring: %s", bus_error_message(&error
, r
));
1462 r
= sd_bus_message_skip(m
, NULL
);
1463 if (r
== -ENXIO
) /* End of the container */
1469 r
= sd_bus_message_exit_container(m
);
1480 if (FLAGS_SET(flags
, READ_DNS_EXTENDED
)) {
1481 r
= sd_bus_message_read(m
, "qs", &port
, &name
);
1486 r
= sd_bus_message_exit_container(m
);
1490 if (FLAGS_SET(flags
, READ_DNS_ONLY_GLOBAL
) && ifindex
> 0 && ifindex
!= LOOPBACK_IFINDEX
) {
1491 /* This one has an (non-loopback) ifindex set, and we were told to suppress those. Hence do so. */
1496 r
= in_addr_port_ifindex_name_to_string(family
, &a
, port
, ifindex
, name
, &pretty
);
1500 *ret
= TAKE_PTR(pretty
);
1504 static int map_dns_servers_internal(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, ReadDNSFlag flags
, sd_bus_error
*error
, void *userdata
) {
1505 char ***l
= ASSERT_PTR(userdata
);
1512 const char *sig
= strjoina("(", dns_server_property_signature(flags
), ")");
1514 r
= sd_bus_message_enter_container(m
, 'a', sig
);
1519 _cleanup_free_
char *pretty
= NULL
;
1521 r
= read_dns_server_one(m
, flags
, &pretty
);
1527 if (isempty(pretty
))
1530 r
= strv_consume(l
, TAKE_PTR(pretty
));
1535 r
= sd_bus_message_exit_container(m
);
1542 static int map_link_dns_servers(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1543 return map_dns_servers_internal(bus
, member
, m
, /* flags = */ 0, error
, userdata
);
1546 static int map_link_dns_servers_ex(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1547 return map_dns_servers_internal(bus
, member
, m
, READ_DNS_EXTENDED
, error
, userdata
);
1550 static int map_link_current_dns_server(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1554 return read_dns_server_one(m
, /* flags = */ 0, userdata
);
1557 static int map_link_current_dns_server_ex(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1561 return read_dns_server_one(m
, READ_DNS_EXTENDED
, userdata
);
1564 static int read_domain_one(sd_bus_message
*m
, bool with_ifindex
, char **ret
) {
1565 _cleanup_free_
char *str
= NULL
;
1566 int ifindex
, route_only
, r
;
1573 r
= sd_bus_message_read(m
, "(isb)", &ifindex
, &domain
, &route_only
);
1575 r
= sd_bus_message_read(m
, "(sb)", &domain
, &route_only
);
1579 if (with_ifindex
&& ifindex
!= 0) {
1580 /* only show the global ones here */
1586 str
= strjoin("~", domain
);
1588 str
= strdup(domain
);
1592 *ret
= TAKE_PTR(str
);
1596 static int map_domains_internal(
1601 sd_bus_error
*error
,
1604 char ***l
= ASSERT_PTR(userdata
);
1611 r
= sd_bus_message_enter_container(m
, 'a', with_ifindex
? "(isb)" : "(sb)");
1616 _cleanup_free_
char *pretty
= NULL
;
1618 r
= read_domain_one(m
, with_ifindex
, &pretty
);
1624 if (isempty(pretty
))
1627 r
= strv_consume(l
, TAKE_PTR(pretty
));
1632 r
= sd_bus_message_exit_container(m
);
1639 static int map_link_domains(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1640 return map_domains_internal(bus
, member
, m
, /* with_ifindex= */ false, error
, userdata
);
1643 static int status_print_strv_full(int ifindex
, const char *ifname
, const char *delegate_id
, char **p
) {
1644 const unsigned indent
= strlen("Global: "); /* Use the same indentation everywhere to make things nice */
1648 printf("%s%nLink %i (%s)%n%s:", ansi_highlight(), &pos1
, ifindex
, ifname
, &pos2
, ansi_normal());
1649 else if (delegate_id
)
1650 printf("%s%nDelegate %s%n%s:", ansi_highlight(), &pos1
, delegate_id
, &pos2
, ansi_normal());
1652 printf("%s%nGlobal%n%s:", ansi_highlight(), &pos1
, &pos2
, ansi_normal());
1654 size_t cols
= columns(), position
= pos2
- pos1
+ 2;
1656 STRV_FOREACH(i
, p
) {
1657 size_t our_len
= utf8_console_width(*i
); /* This returns -1 on invalid utf-8 (which shouldn't happen).
1658 * If that happens, we'll just print one item per line. */
1660 if (position
<= indent
|| size_add(size_add(position
, 1), our_len
) < cols
) {
1662 position
= size_add(size_add(position
, 1), our_len
);
1664 printf("\n%*s%s", (int) indent
, "", *i
);
1665 position
= size_add(our_len
, indent
);
1674 static int status_print_strv_ifindex(int ifindex
, const char *ifname
, char **p
) {
1675 return status_print_strv_full(ifindex
, ifname
, NULL
, p
);
1678 static int status_print_strv_delegate(const char *delegate_id
, char **p
) {
1679 return status_print_strv_full(0, NULL
, delegate_id
, p
);
1682 static int status_print_strv_global(char **p
) {
1683 return status_print_strv_full(0, NULL
, NULL
, p
);
1686 typedef struct LinkInfo
{
1687 uint64_t scopes_mask
;
1690 const char *dns_over_tls
;
1693 char *current_dns_ex
;
1698 bool dnssec_supported
;
1702 typedef struct GlobalInfo
{
1704 char *current_dns_ex
;
1707 char **fallback_dns
;
1708 char **fallback_dns_ex
;
1713 const char *dns_over_tls
;
1715 const char *resolv_conf_mode
;
1716 bool dnssec_supported
;
1719 static void link_info_done(LinkInfo
*p
) {
1722 free(p
->current_dns
);
1723 free(p
->current_dns_ex
);
1725 strv_free(p
->dns_ex
);
1726 strv_free(p
->domains
);
1730 static void global_info_done(GlobalInfo
*p
) {
1733 free(p
->current_dns
);
1734 free(p
->current_dns_ex
);
1736 strv_free(p
->dns_ex
);
1737 strv_free(p
->fallback_dns
);
1738 strv_free(p
->fallback_dns_ex
);
1739 strv_free(p
->domains
);
1743 static int dump_list(Table
*table
, const char *field
, char * const *l
) {
1746 if (strv_isempty(l
))
1749 r
= table_add_many(table
,
1751 TABLE_STRV_WRAPPED
, l
);
1753 return table_log_add_error(r
);
1758 static int strv_extend_extended_bool(char ***strv
, const char *name
, const char *value
) {
1762 r
= parse_boolean(value
);
1764 return strv_extendf(strv
, "%s%s", plus_minus(r
), name
);
1767 return strv_extendf(strv
, "%s=%s", name
, value
?: "???");
1770 static char** link_protocol_status(const LinkInfo
*info
) {
1771 _cleanup_strv_free_
char **s
= NULL
;
1773 if (strv_extendf(&s
, "%sDefaultRoute", plus_minus(info
->default_route
)) < 0)
1776 if (strv_extend_extended_bool(&s
, "LLMNR", info
->llmnr
) < 0)
1779 if (strv_extend_extended_bool(&s
, "mDNS", info
->mdns
) < 0)
1782 if (strv_extend_extended_bool(&s
, "DNSOverTLS", info
->dns_over_tls
) < 0)
1785 if (strv_extendf(&s
, "DNSSEC=%s/%s",
1786 info
->dnssec
?: "???",
1787 info
->dnssec_supported
? "supported" : "unsupported") < 0)
1793 static char** global_protocol_status(const GlobalInfo
*info
) {
1794 _cleanup_strv_free_
char **s
= NULL
;
1796 if (strv_extend_extended_bool(&s
, "LLMNR", info
->llmnr
) < 0)
1799 if (strv_extend_extended_bool(&s
, "mDNS", info
->mdns
) < 0)
1802 if (strv_extend_extended_bool(&s
, "DNSOverTLS", info
->dns_over_tls
) < 0)
1805 if (strv_extendf(&s
, "DNSSEC=%s/%s",
1806 info
->dnssec
?: "???",
1807 info
->dnssec_supported
? "supported" : "unsupported") < 0)
1813 static int status_json_filter_fields(sd_json_variant
**configuration
, StatusMode mode
) {
1814 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*v
= NULL
;
1819 assert(configuration
);
1821 field
= status_mode_json_field_to_string(mode
);
1823 /* Nothing to filter for this mode. */
1826 JSON_VARIANT_ARRAY_FOREACH(w
, *configuration
) {
1827 /* Always include identifier fields like ifname or delegate, and include the requested
1828 * field even if it is empty in the configuration. */
1829 r
= sd_json_variant_append_arraybo(
1831 JSON_BUILD_PAIR_VARIANT_NON_NULL("ifname", sd_json_variant_by_key(w
, "ifname")),
1832 JSON_BUILD_PAIR_VARIANT_NON_NULL("ifindex", sd_json_variant_by_key(w
, "ifindex")),
1833 JSON_BUILD_PAIR_VARIANT_NON_NULL("delegate", sd_json_variant_by_key(w
, "delegate")),
1834 SD_JSON_BUILD_PAIR_VARIANT(field
, sd_json_variant_by_key(w
, field
)));
1839 JSON_VARIANT_REPLACE(*configuration
, TAKE_PTR(v
));
1843 static int status_json_filter_links(sd_json_variant
**configuration
, char **links
) {
1844 _cleanup_set_free_ Set
*links_by_index
= NULL
;
1845 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*v
= NULL
;
1849 assert(configuration
);
1852 STRV_FOREACH(ifname
, links
) {
1853 int ifindex
= rtnl_resolve_interface_or_warn(/* rtnl= */ NULL
, *ifname
);
1857 r
= set_ensure_put(&links_by_index
, NULL
, INT_TO_PTR(ifindex
));
1862 JSON_VARIANT_ARRAY_FOREACH(w
, *configuration
) {
1863 int ifindex
= sd_json_variant_unsigned(sd_json_variant_by_key(w
, "ifindex"));
1865 if (links_by_index
) {
1867 /* Possibly invalid, but most likely unset because this is global
1868 * or delegate configuration. */
1871 if (!set_contains(links_by_index
, INT_TO_PTR(ifindex
)))
1874 } else if (ifindex
== LOOPBACK_IFINDEX
)
1875 /* By default, exclude the loopback interface. */
1878 r
= sd_json_variant_append_array(&v
, w
);
1883 JSON_VARIANT_REPLACE(*configuration
, TAKE_PTR(v
));
1887 static int varlink_dump_dns_configuration(sd_json_variant
**ret
) {
1888 _cleanup_(sd_varlink_unrefp
) sd_varlink
*vl
= NULL
;
1889 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*reply
= NULL
;
1895 r
= sd_varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve");
1897 return log_error_errno(r
, "Failed to connect to service /run/systemd/resolve/io.systemd.Resolve: %m");
1899 r
= varlink_call_and_log(vl
, "io.systemd.Resolve.DumpDNSConfiguration", /* parameters= */ NULL
, &reply
);
1903 v
= sd_json_variant_by_key(reply
, "configuration");
1905 if (!sd_json_variant_is_array(v
))
1906 return log_error_errno(SYNTHETIC_ERRNO(ENODATA
), "DumpDNSConfiguration() response missing 'configuration' key.");
1909 *ret
= sd_json_variant_ref(v
);
1913 static int status_json(StatusMode mode
, char **links
) {
1914 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*configuration
= NULL
;
1917 r
= varlink_dump_dns_configuration(&configuration
);
1921 r
= status_json_filter_links(&configuration
, links
);
1923 return log_error_errno(r
, "Failed to filter configuration JSON links: %m");
1925 r
= status_json_filter_fields(&configuration
, mode
);
1927 return log_error_errno(r
, "Failed to filter configuration JSON fields: %m");
1929 return sd_json_variant_dump(configuration
, arg_json_format_flags
, /* f= */ NULL
, /* prefix= */ NULL
);
1932 static int status_ifindex(sd_bus
*bus
, int ifindex
, const char *name
, StatusMode mode
, bool *empty_line
) {
1933 static const struct bus_properties_map property_map
[] = {
1934 { "ScopesMask", "t", NULL
, offsetof(LinkInfo
, scopes_mask
) },
1935 { "DNS", "a(iay)", map_link_dns_servers
, offsetof(LinkInfo
, dns
) },
1936 { "DNSEx", "a(iayqs)", map_link_dns_servers_ex
, offsetof(LinkInfo
, dns_ex
) },
1937 { "CurrentDNSServer", "(iay)", map_link_current_dns_server
, offsetof(LinkInfo
, current_dns
) },
1938 { "CurrentDNSServerEx", "(iayqs)", map_link_current_dns_server_ex
, offsetof(LinkInfo
, current_dns_ex
) },
1939 { "Domains", "a(sb)", map_link_domains
, offsetof(LinkInfo
, domains
) },
1940 { "DefaultRoute", "b", NULL
, offsetof(LinkInfo
, default_route
) },
1941 { "LLMNR", "s", NULL
, offsetof(LinkInfo
, llmnr
) },
1942 { "MulticastDNS", "s", NULL
, offsetof(LinkInfo
, mdns
) },
1943 { "DNSOverTLS", "s", NULL
, offsetof(LinkInfo
, dns_over_tls
) },
1944 { "DNSSEC", "s", NULL
, offsetof(LinkInfo
, dnssec
) },
1945 { "DNSSECNegativeTrustAnchors", "as", bus_map_strv_sort
, offsetof(LinkInfo
, ntas
) },
1946 { "DNSSECSupported", "b", NULL
, offsetof(LinkInfo
, dnssec_supported
) },
1949 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1950 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
1951 _cleanup_(link_info_done
) LinkInfo link_info
= {};
1952 _cleanup_(table_unrefp
) Table
*table
= NULL
;
1953 _cleanup_free_
char *p
= NULL
;
1954 char ifi
[DECIMAL_STR_MAX(int)], ifname
[IF_NAMESIZE
];
1958 assert(ifindex
> 0);
1961 r
= format_ifname(ifindex
, ifname
);
1963 return log_error_errno(r
, "Failed to resolve interface name for %i: %m", ifindex
);
1968 if (sd_json_format_enabled(arg_json_format_flags
))
1969 return status_json(mode
, STRV_MAKE(name
));
1971 xsprintf(ifi
, "%i", ifindex
);
1972 r
= sd_bus_path_encode("/org/freedesktop/resolve1/link", ifi
, &p
);
1976 r
= bus_map_all_properties(bus
,
1977 "org.freedesktop.resolve1",
1980 BUS_MAP_BOOLEAN_AS_BOOL
,
1985 return log_error_errno(r
, "Failed to get link data for %i: %s", ifindex
, bus_error_message(&error
, r
));
1987 pager_open(arg_pager_flags
);
1992 return status_print_strv_ifindex(ifindex
, name
, link_info
.dns_ex
?: link_info
.dns
);
1995 return status_print_strv_ifindex(ifindex
, name
, link_info
.domains
);
1998 return status_print_strv_ifindex(ifindex
, name
, link_info
.ntas
);
2000 case STATUS_DEFAULT_ROUTE
:
2001 printf("%sLink %i (%s)%s: %s\n",
2002 ansi_highlight(), ifindex
, name
, ansi_normal(),
2003 yes_no(link_info
.default_route
));
2008 printf("%sLink %i (%s)%s: %s\n",
2009 ansi_highlight(), ifindex
, name
, ansi_normal(),
2010 strna(link_info
.llmnr
));
2015 printf("%sLink %i (%s)%s: %s\n",
2016 ansi_highlight(), ifindex
, name
, ansi_normal(),
2017 strna(link_info
.mdns
));
2021 case STATUS_DNS_OVER_TLS
:
2022 printf("%sLink %i (%s)%s: %s\n",
2023 ansi_highlight(), ifindex
, name
, ansi_normal(),
2024 strna(link_info
.dns_over_tls
));
2029 printf("%sLink %i (%s)%s: %s\n",
2030 ansi_highlight(), ifindex
, name
, ansi_normal(),
2031 strna(link_info
.dnssec
));
2042 if (empty_line
&& *empty_line
)
2043 fputc('\n', stdout
);
2045 printf("%sLink %i (%s)%s\n",
2046 ansi_highlight(), ifindex
, name
, ansi_normal());
2048 table
= table_new_vertical();
2052 r
= table_add_many(table
,
2053 TABLE_FIELD
, "Current Scopes",
2054 TABLE_SET_MINIMUM_WIDTH
, 19);
2056 return table_log_add_error(r
);
2058 if (link_info
.scopes_mask
== 0)
2059 r
= table_add_cell(table
, NULL
, TABLE_STRING
, "none");
2061 _cleanup_free_
char *buf
= NULL
;
2064 if (asprintf(&buf
, "%s%s%s%s%s",
2065 link_info
.scopes_mask
& SD_RESOLVED_DNS
? "DNS " : "",
2066 link_info
.scopes_mask
& SD_RESOLVED_LLMNR_IPV4
? "LLMNR/IPv4 " : "",
2067 link_info
.scopes_mask
& SD_RESOLVED_LLMNR_IPV6
? "LLMNR/IPv6 " : "",
2068 link_info
.scopes_mask
& SD_RESOLVED_MDNS_IPV4
? "mDNS/IPv4 " : "",
2069 link_info
.scopes_mask
& SD_RESOLVED_MDNS_IPV6
? "mDNS/IPv6 " : "") < 0)
2074 buf
[len
- 1] = '\0';
2076 r
= table_add_cell(table
, NULL
, TABLE_STRING
, buf
);
2079 return table_log_add_error(r
);
2081 _cleanup_strv_free_
char **pstatus
= link_protocol_status(&link_info
);
2085 r
= table_add_many(table
,
2086 TABLE_FIELD
, "Protocols",
2087 TABLE_STRV_WRAPPED
, pstatus
);
2089 return table_log_add_error(r
);
2091 if (link_info
.current_dns
) {
2092 r
= table_add_many(table
,
2093 TABLE_FIELD
, "Current DNS Server",
2094 TABLE_STRING
, link_info
.current_dns_ex
?: link_info
.current_dns
);
2096 return table_log_add_error(r
);
2099 r
= dump_list(table
, "DNS Servers", link_info
.dns_ex
?: link_info
.dns
);
2103 r
= dump_list(table
, "DNS Domain", link_info
.domains
);
2107 r
= table_add_many(table
,
2108 TABLE_FIELD
, "Default Route",
2109 TABLE_BOOLEAN
, link_info
.default_route
);
2111 return table_log_add_error(r
);
2113 r
= table_print(table
, NULL
);
2115 return table_log_print_error(r
);
2123 static int map_global_dns_servers_internal(
2127 sd_bus_error
*error
,
2129 ReadDNSFlag flags
) {
2131 char ***l
= ASSERT_PTR(userdata
);
2138 r
= sd_bus_message_enter_container(m
, 'a', FLAGS_SET(flags
, READ_DNS_EXTENDED
) ? "(iiayqs)" : "(iiay)");
2143 _cleanup_free_
char *pretty
= NULL
;
2145 r
= read_dns_server_one(m
, flags
, &pretty
);
2151 if (isempty(pretty
))
2154 r
= strv_consume(l
, TAKE_PTR(pretty
));
2159 r
= sd_bus_message_exit_container(m
);
2166 static int map_global_dns_servers(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2167 return map_global_dns_servers_internal(bus
, member
, m
, error
, userdata
, READ_DNS_WITH_IFINDEX
| READ_DNS_ONLY_GLOBAL
);
2170 static int map_global_dns_servers_ex(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2171 return map_global_dns_servers_internal(bus
, member
, m
, error
, userdata
, READ_DNS_WITH_IFINDEX
| READ_DNS_ONLY_GLOBAL
| READ_DNS_EXTENDED
);
2174 static int map_global_current_dns_server(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2175 return read_dns_server_one(m
, READ_DNS_WITH_IFINDEX
| READ_DNS_ONLY_GLOBAL
, userdata
);
2178 static int map_global_current_dns_server_ex(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2179 return read_dns_server_one(m
, READ_DNS_WITH_IFINDEX
| READ_DNS_ONLY_GLOBAL
| READ_DNS_EXTENDED
, userdata
);
2182 static int map_global_domains(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2183 return map_domains_internal(bus
, member
, m
, /* with_ifindex= */ true, error
, userdata
);
2186 static int status_global(sd_bus
*bus
, StatusMode mode
, bool *empty_line
) {
2187 static const struct bus_properties_map property_map
[] = {
2188 { "DNS", "a(iiay)", map_global_dns_servers
, offsetof(GlobalInfo
, dns
) },
2189 { "DNSEx", "a(iiayqs)", map_global_dns_servers_ex
, offsetof(GlobalInfo
, dns_ex
) },
2190 { "FallbackDNS", "a(iiay)", map_global_dns_servers
, offsetof(GlobalInfo
, fallback_dns
) },
2191 { "FallbackDNSEx", "a(iiayqs)", map_global_dns_servers_ex
, offsetof(GlobalInfo
, fallback_dns_ex
) },
2192 { "CurrentDNSServer", "(iiay)", map_global_current_dns_server
, offsetof(GlobalInfo
, current_dns
) },
2193 { "CurrentDNSServerEx", "(iiayqs)", map_global_current_dns_server_ex
, offsetof(GlobalInfo
, current_dns_ex
) },
2194 { "Domains", "a(isb)", map_global_domains
, offsetof(GlobalInfo
, domains
) },
2195 { "DNSSECNegativeTrustAnchors", "as", bus_map_strv_sort
, offsetof(GlobalInfo
, ntas
) },
2196 { "LLMNR", "s", NULL
, offsetof(GlobalInfo
, llmnr
) },
2197 { "MulticastDNS", "s", NULL
, offsetof(GlobalInfo
, mdns
) },
2198 { "DNSOverTLS", "s", NULL
, offsetof(GlobalInfo
, dns_over_tls
) },
2199 { "DNSSEC", "s", NULL
, offsetof(GlobalInfo
, dnssec
) },
2200 { "DNSSECSupported", "b", NULL
, offsetof(GlobalInfo
, dnssec_supported
) },
2201 { "ResolvConfMode", "s", NULL
, offsetof(GlobalInfo
, resolv_conf_mode
) },
2204 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2205 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
2206 _cleanup_(global_info_done
) GlobalInfo global_info
= {};
2207 _cleanup_(table_unrefp
) Table
*table
= NULL
;
2213 r
= bus_map_all_properties(bus
,
2214 "org.freedesktop.resolve1",
2215 "/org/freedesktop/resolve1",
2217 BUS_MAP_BOOLEAN_AS_BOOL
,
2222 return log_error_errno(r
, "Failed to get global data: %s", bus_error_message(&error
, r
));
2224 pager_open(arg_pager_flags
);
2229 return status_print_strv_global(global_info
.dns_ex
?: global_info
.dns
);
2232 return status_print_strv_global(global_info
.domains
);
2235 return status_print_strv_global(global_info
.ntas
);
2238 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
2239 strna(global_info
.llmnr
));
2244 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
2245 strna(global_info
.mdns
));
2249 case STATUS_DNS_OVER_TLS
:
2250 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
2251 strna(global_info
.dns_over_tls
));
2256 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
2257 strna(global_info
.dnssec
));
2268 printf("%sGlobal%s\n", ansi_highlight(), ansi_normal());
2270 table
= table_new_vertical();
2274 _cleanup_strv_free_
char **pstatus
= global_protocol_status(&global_info
);
2278 r
= table_add_many(table
,
2279 TABLE_FIELD
, "Protocols",
2280 TABLE_SET_MINIMUM_WIDTH
, 19,
2281 TABLE_STRV_WRAPPED
, pstatus
);
2283 return table_log_add_error(r
);
2285 if (global_info
.resolv_conf_mode
) {
2286 r
= table_add_many(table
,
2287 TABLE_FIELD
, "resolv.conf mode",
2288 TABLE_STRING
, global_info
.resolv_conf_mode
);
2290 return table_log_add_error(r
);
2293 if (global_info
.current_dns
) {
2294 r
= table_add_many(table
,
2295 TABLE_FIELD
, "Current DNS Server",
2296 TABLE_STRING
, global_info
.current_dns_ex
?: global_info
.current_dns
);
2298 return table_log_add_error(r
);
2301 r
= dump_list(table
, "DNS Servers", global_info
.dns_ex
?: global_info
.dns
);
2305 r
= dump_list(table
, "Fallback DNS Servers", global_info
.fallback_dns_ex
?: global_info
.fallback_dns
);
2309 r
= dump_list(table
, "DNS Domain", global_info
.domains
);
2313 r
= table_print(table
, NULL
);
2315 return table_log_print_error(r
);
2322 static int status_links(sd_bus
*bus
, StatusMode mode
, bool *empty_line
) {
2323 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
2324 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
2329 r
= sd_netlink_open(&rtnl
);
2331 return log_error_errno(r
, "Failed to connect to netlink: %m");
2333 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
2335 return rtnl_log_create_error(r
);
2337 r
= sd_netlink_message_set_request_dump(req
, true);
2339 return rtnl_log_create_error(r
);
2341 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
2343 return log_error_errno(r
, "Failed to enumerate links: %m");
2345 _cleanup_free_ InterfaceInfo
*infos
= NULL
;
2348 for (sd_netlink_message
*i
= reply
; i
; i
= sd_netlink_message_next(i
)) {
2353 r
= sd_netlink_message_get_type(i
, &type
);
2355 return rtnl_log_parse_error(r
);
2357 if (type
!= RTM_NEWLINK
)
2360 r
= sd_rtnl_message_link_get_ifindex(i
, &ifindex
);
2362 return rtnl_log_parse_error(r
);
2364 if (ifindex
== LOOPBACK_IFINDEX
)
2367 r
= sd_netlink_message_read_string(i
, IFLA_IFNAME
, &name
);
2369 return rtnl_log_parse_error(r
);
2371 if (!GREEDY_REALLOC(infos
, n_infos
+ 1))
2374 infos
[n_infos
++] = (InterfaceInfo
) { ifindex
, name
};
2377 typesafe_qsort(infos
, n_infos
, interface_info_compare
);
2379 FOREACH_ARRAY(info
, infos
, n_infos
)
2380 RET_GATHER(ret
, status_ifindex(bus
, info
->index
, info
->name
, mode
, empty_line
));
2385 typedef struct DelegateInfo
{
2392 static void delegate_info_done(DelegateInfo
*p
) {
2395 free(p
->current_dns
);
2397 strv_free(p
->domains
);
2400 static int map_delegate_dns_servers(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2401 return map_dns_servers_internal(bus
, member
, m
, READ_DNS_WITH_IFINDEX
|READ_DNS_EXTENDED
, error
, userdata
);
2404 static int map_delegate_current_dns_server(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2405 return read_dns_server_one(m
, READ_DNS_WITH_IFINDEX
|READ_DNS_EXTENDED
, userdata
);
2408 static int map_delegate_domains(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2409 return map_domains_internal(bus
, member
, m
, /* with_ifindex= */ false, error
, userdata
);
2412 static int status_delegate_one(sd_bus
*bus
, const char *id
, StatusMode mode
, bool *empty_line
) {
2414 static const struct bus_properties_map property_map
[] = {
2415 { "DNS", "a(iiayqs)", map_delegate_dns_servers
, offsetof(DelegateInfo
, dns
) },
2416 { "CurrentDNSServer", "(iiayqs)", map_delegate_current_dns_server
, offsetof(DelegateInfo
, current_dns
) },
2417 { "Domains", "a(sb)", map_delegate_domains
, offsetof(DelegateInfo
, domains
) },
2418 { "DefaultRoute", "b", NULL
, offsetof(DelegateInfo
, default_route
) },
2422 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2423 _cleanup_(delegate_info_done
) DelegateInfo delegate_info
= {};
2424 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
2425 _cleanup_free_
char *p
= NULL
;
2431 r
= sd_bus_path_encode("/org/freedesktop/resolve1/dns_delegate", id
, &p
);
2435 r
= bus_map_all_properties(
2437 "org.freedesktop.resolve1",
2440 BUS_MAP_BOOLEAN_AS_BOOL
,
2445 return log_error_errno(r
, "Failed to get delegate data for %s: %s", id
, bus_error_message(&error
, r
));
2447 pager_open(arg_pager_flags
);
2452 return status_print_strv_delegate(id
, delegate_info
.dns
);
2455 return status_print_strv_delegate(id
, delegate_info
.domains
);
2457 case STATUS_DEFAULT_ROUTE
:
2458 printf("%sDelegate %s%s: %s\n",
2459 ansi_highlight(), id
, ansi_normal(),
2460 yes_no(delegate_info
.default_route
));
2471 if (empty_line
&& *empty_line
)
2472 fputc('\n', stdout
);
2474 printf("%sDelegate %s%s\n",
2475 ansi_highlight(), id
, ansi_normal());
2477 _cleanup_(table_unrefp
) Table
*table
= table_new_vertical();
2481 if (delegate_info
.current_dns
) {
2482 r
= table_add_many(table
,
2483 TABLE_FIELD
, "Current DNS Server",
2484 TABLE_STRING
, delegate_info
.current_dns
);
2486 return table_log_add_error(r
);
2489 r
= dump_list(table
, "DNS Servers", delegate_info
.dns
);
2493 r
= dump_list(table
, "DNS Domain", delegate_info
.domains
);
2497 r
= table_add_many(table
,
2498 TABLE_FIELD
, "Default Route",
2499 TABLE_SET_MINIMUM_WIDTH
, 19,
2500 TABLE_BOOLEAN
, delegate_info
.default_route
);
2502 return table_log_add_error(r
);
2504 r
= table_print(table
, NULL
);
2506 return table_log_print_error(r
);
2514 static int status_delegates(sd_bus
*bus
, StatusMode mode
, bool *empty_line
) {
2515 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2516 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2521 r
= bus_call_method(bus
, bus_resolve_mgr
, "ListDelegates", &error
, &reply
, NULL
);
2523 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
)) {
2524 log_debug("Delegates not supported, skipping.");
2527 return log_error_errno(r
, "Failed to list delegates: %s", bus_error_message(&error
, r
));
2530 r
= sd_bus_message_enter_container(reply
, 'a', "(so)");
2532 return bus_log_parse_error(r
);
2534 _cleanup_strv_free_
char **l
= NULL
;
2538 r
= sd_bus_message_read(reply
, "(so)", &id
, NULL
);
2540 return bus_log_parse_error(r
);
2544 if (strv_extend(&l
, id
) < 0)
2548 r
= sd_bus_message_exit_container(reply
);
2550 return bus_log_parse_error(r
);
2555 RET_GATHER(ret
, status_delegate_one(bus
, *i
, mode
, empty_line
));
2560 static int status_all(sd_bus
*bus
, StatusMode mode
) {
2561 bool empty_line
= false;
2566 if (sd_json_format_enabled(arg_json_format_flags
))
2567 return status_json(mode
, /* links= */ NULL
);
2569 r
= status_global(bus
, mode
, &empty_line
);
2573 r
= status_links(bus
, mode
, &empty_line
);
2577 r
= status_delegates(bus
, mode
, &empty_line
);
2584 static int verb_status(int argc
, char **argv
, void *userdata
) {
2585 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2586 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
2587 bool empty_line
= false;
2590 if (sd_json_format_enabled(arg_json_format_flags
))
2591 return status_json(STATUS_ALL
, argc
> 1 ? strv_skip(argv
, 1) : NULL
);
2593 r
= acquire_bus(&bus
);
2598 return status_all(bus
, STATUS_ALL
);
2600 STRV_FOREACH(ifname
, strv_skip(argv
, 1)) {
2603 ifindex
= rtnl_resolve_interface(&rtnl
, *ifname
);
2605 log_warning_errno(ifindex
, "Failed to resolve interface \"%s\", ignoring: %m", *ifname
);
2609 RET_GATHER(ret
, status_ifindex(bus
, ifindex
, NULL
, STATUS_ALL
, &empty_line
));
2615 static int call_dns(sd_bus
*bus
, char **dns
, const BusLocator
*locator
, sd_bus_error
*error
, bool extended
) {
2616 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
;
2619 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2621 r
= bus_message_new_method_call(bus
, &req
, locator
, extended
? "SetLinkDNSEx" : "SetLinkDNS");
2623 return bus_log_create_error(r
);
2625 r
= sd_bus_message_append(req
, "i", arg_ifindex
);
2627 return bus_log_create_error(r
);
2629 r
= sd_bus_message_open_container(req
, 'a', extended
? "(iayqs)" : "(iay)");
2631 return bus_log_create_error(r
);
2633 /* If only argument is the empty string, then call SetLinkDNS() with an
2634 * empty list, which will clear the list of domains for an interface. */
2635 if (!strv_equal(dns
, STRV_MAKE("")))
2636 STRV_FOREACH(p
, dns
) {
2637 _cleanup_free_
char *name
= NULL
;
2638 struct in_addr_data data
;
2642 r
= in_addr_port_ifindex_name_from_string_auto(*p
, &data
.family
, &data
.address
, &port
, &ifindex
, &name
);
2644 return log_error_errno(r
, "Failed to parse DNS server address: %s", *p
);
2646 if (ifindex
!= 0 && ifindex
!= arg_ifindex
)
2647 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid ifindex: %i", ifindex
);
2649 r
= sd_bus_message_open_container(req
, 'r', extended
? "iayqs" : "iay");
2651 return bus_log_create_error(r
);
2653 r
= sd_bus_message_append(req
, "i", data
.family
);
2655 return bus_log_create_error(r
);
2657 r
= sd_bus_message_append_array(req
, 'y', &data
.address
, FAMILY_ADDRESS_SIZE(data
.family
));
2659 return bus_log_create_error(r
);
2662 r
= sd_bus_message_append(req
, "q", port
);
2664 return bus_log_create_error(r
);
2666 r
= sd_bus_message_append(req
, "s", name
);
2668 return bus_log_create_error(r
);
2671 r
= sd_bus_message_close_container(req
);
2673 return bus_log_create_error(r
);
2676 r
= sd_bus_message_close_container(req
);
2678 return bus_log_create_error(r
);
2680 r
= sd_bus_call(bus
, req
, 0, error
, NULL
);
2681 if (r
< 0 && extended
&& sd_bus_error_has_name(error
, SD_BUS_ERROR_UNKNOWN_METHOD
)) {
2682 sd_bus_error_free(error
);
2683 return call_dns(bus
, dns
, locator
, error
, false);
2688 static int verb_dns(int argc
, char **argv
, void *userdata
) {
2689 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2690 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2693 r
= acquire_bus(&bus
);
2698 r
= ifname_mangle(argv
[1]);
2703 if (arg_ifindex
<= 0)
2704 return status_all(bus
, STATUS_DNS
);
2707 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_DNS
, NULL
);
2709 char **args
= strv_skip(argv
, 2);
2710 r
= call_dns(bus
, args
, bus_resolve_mgr
, &error
, true);
2711 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2712 sd_bus_error_free(&error
);
2714 r
= call_dns(bus
, args
, bus_network_mgr
, &error
, true);
2717 if (arg_ifindex_permissive
&&
2718 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2721 return log_error_errno(r
, "Failed to set DNS configuration: %s", bus_error_message(&error
, r
));
2727 static int call_domain(sd_bus
*bus
, char **domain
, const BusLocator
*locator
, sd_bus_error
*error
) {
2728 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
;
2731 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2733 r
= bus_message_new_method_call(bus
, &req
, locator
, "SetLinkDomains");
2735 return bus_log_create_error(r
);
2737 r
= sd_bus_message_append(req
, "i", arg_ifindex
);
2739 return bus_log_create_error(r
);
2741 r
= sd_bus_message_open_container(req
, 'a', "(sb)");
2743 return bus_log_create_error(r
);
2745 /* If only argument is the empty string, then call SetLinkDomains() with an
2746 * empty list, which will clear the list of domains for an interface. */
2747 if (!strv_equal(domain
, STRV_MAKE("")))
2748 STRV_FOREACH(p
, domain
) {
2751 n
= **p
== '~' ? *p
+ 1 : *p
;
2753 r
= dns_name_is_valid(n
);
2755 return log_error_errno(r
, "Failed to validate specified domain %s: %m", n
);
2757 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2758 "Domain not valid: %s",
2761 r
= sd_bus_message_append(req
, "(sb)", n
, **p
== '~');
2763 return bus_log_create_error(r
);
2766 r
= sd_bus_message_close_container(req
);
2768 return bus_log_create_error(r
);
2770 return sd_bus_call(bus
, req
, 0, error
, NULL
);
2773 static int verb_domain(int argc
, char **argv
, void *userdata
) {
2774 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2775 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2778 r
= acquire_bus(&bus
);
2783 r
= ifname_mangle(argv
[1]);
2788 if (arg_ifindex
<= 0)
2789 return status_all(bus
, STATUS_DOMAIN
);
2792 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_DOMAIN
, NULL
);
2794 char **args
= strv_skip(argv
, 2);
2795 r
= call_domain(bus
, args
, bus_resolve_mgr
, &error
);
2796 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2797 sd_bus_error_free(&error
);
2799 r
= call_domain(bus
, args
, bus_network_mgr
, &error
);
2802 if (arg_ifindex_permissive
&&
2803 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2806 return log_error_errno(r
, "Failed to set domain configuration: %s", bus_error_message(&error
, r
));
2812 static int verb_default_route(int argc
, char **argv
, void *userdata
) {
2813 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2814 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2817 r
= acquire_bus(&bus
);
2822 r
= ifname_mangle(argv
[1]);
2827 if (arg_ifindex
<= 0)
2828 return status_all(bus
, STATUS_DEFAULT_ROUTE
);
2831 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_DEFAULT_ROUTE
, NULL
);
2833 b
= parse_boolean(argv
[2]);
2835 return log_error_errno(b
, "Failed to parse boolean argument: %s", argv
[2]);
2837 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2839 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkDefaultRoute", &error
, NULL
, "ib", arg_ifindex
, b
);
2840 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2841 sd_bus_error_free(&error
);
2843 r
= bus_call_method(bus
, bus_network_mgr
, "SetLinkDefaultRoute", &error
, NULL
, "ib", arg_ifindex
, b
);
2846 if (arg_ifindex_permissive
&&
2847 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2850 return log_error_errno(r
, "Failed to set default route configuration: %s", bus_error_message(&error
, r
));
2856 static int verb_llmnr(int argc
, char **argv
, void *userdata
) {
2857 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2858 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2859 _cleanup_free_
char *global_llmnr_support_str
= NULL
;
2860 ResolveSupport global_llmnr_support
, llmnr_support
;
2863 r
= acquire_bus(&bus
);
2868 r
= ifname_mangle(argv
[1]);
2873 if (arg_ifindex
<= 0)
2874 return status_all(bus
, STATUS_LLMNR
);
2877 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_LLMNR
, NULL
);
2879 llmnr_support
= resolve_support_from_string(argv
[2]);
2880 if (llmnr_support
< 0)
2881 return log_error_errno(llmnr_support
, "Invalid LLMNR setting: %s", argv
[2]);
2883 r
= bus_get_property_string(bus
, bus_resolve_mgr
, "LLMNR", &error
, &global_llmnr_support_str
);
2885 return log_error_errno(r
, "Failed to get the global LLMNR support state: %s", bus_error_message(&error
, r
));
2887 global_llmnr_support
= resolve_support_from_string(global_llmnr_support_str
);
2888 if (global_llmnr_support
< 0)
2889 return log_error_errno(global_llmnr_support
, "Received invalid global LLMNR setting: %s", global_llmnr_support_str
);
2891 if (global_llmnr_support
< llmnr_support
)
2892 log_warning("Setting LLMNR support level \"%s\" for \"%s\", but the global support level is \"%s\".",
2893 argv
[2], arg_ifname
, global_llmnr_support_str
);
2895 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2897 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkLLMNR", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2898 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2899 sd_bus_error_free(&error
);
2901 r
= bus_call_method(bus
, bus_network_mgr
, "SetLinkLLMNR", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2904 if (arg_ifindex_permissive
&&
2905 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2908 return log_error_errno(r
, "Failed to set LLMNR configuration: %s", bus_error_message(&error
, r
));
2914 static int verb_mdns(int argc
, char **argv
, void *userdata
) {
2915 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2916 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2917 _cleanup_free_
char *global_mdns_support_str
= NULL
;
2918 ResolveSupport global_mdns_support
, mdns_support
;
2921 r
= acquire_bus(&bus
);
2926 r
= ifname_mangle(argv
[1]);
2931 if (arg_ifindex
<= 0)
2932 return status_all(bus
, STATUS_MDNS
);
2935 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_MDNS
, NULL
);
2937 mdns_support
= resolve_support_from_string(argv
[2]);
2938 if (mdns_support
< 0)
2939 return log_error_errno(mdns_support
, "Invalid mDNS setting: %s", argv
[2]);
2941 r
= bus_get_property_string(bus
, bus_resolve_mgr
, "MulticastDNS", &error
, &global_mdns_support_str
);
2943 return log_error_errno(r
, "Failed to get the global mDNS support state: %s", bus_error_message(&error
, r
));
2945 global_mdns_support
= resolve_support_from_string(global_mdns_support_str
);
2946 if (global_mdns_support
< 0)
2947 return log_error_errno(global_mdns_support
, "Received invalid global mDNS setting: %s", global_mdns_support_str
);
2949 if (global_mdns_support
< mdns_support
)
2950 log_warning("Setting mDNS support level \"%s\" for \"%s\", but the global support level is \"%s\".",
2951 argv
[2], arg_ifname
, global_mdns_support_str
);
2953 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2955 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkMulticastDNS", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2956 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2957 sd_bus_error_free(&error
);
2959 r
= bus_call_method(
2962 "SetLinkMulticastDNS",
2965 "is", arg_ifindex
, argv
[2]);
2968 if (arg_ifindex_permissive
&&
2969 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2972 return log_error_errno(r
, "Failed to set MulticastDNS configuration: %s", bus_error_message(&error
, r
));
2978 static int verb_dns_over_tls(int argc
, char **argv
, void *userdata
) {
2979 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2980 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2983 r
= acquire_bus(&bus
);
2988 r
= ifname_mangle(argv
[1]);
2993 if (arg_ifindex
<= 0)
2994 return status_all(bus
, STATUS_DNS_OVER_TLS
);
2997 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_DNS_OVER_TLS
, NULL
);
2999 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
3001 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkDNSOverTLS", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
3002 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
3003 sd_bus_error_free(&error
);
3005 r
= bus_call_method(
3008 "SetLinkDNSOverTLS",
3011 "is", arg_ifindex
, argv
[2]);
3014 if (arg_ifindex_permissive
&&
3015 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
3018 return log_error_errno(r
, "Failed to set DNSOverTLS configuration: %s", bus_error_message(&error
, r
));
3024 static int verb_dnssec(int argc
, char **argv
, void *userdata
) {
3025 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
3026 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
3029 r
= acquire_bus(&bus
);
3034 r
= ifname_mangle(argv
[1]);
3039 if (arg_ifindex
<= 0)
3040 return status_all(bus
, STATUS_DNSSEC
);
3043 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_DNSSEC
, NULL
);
3045 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
3047 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkDNSSEC", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
3048 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
3049 sd_bus_error_free(&error
);
3051 r
= bus_call_method(bus
, bus_network_mgr
, "SetLinkDNSSEC", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
3054 if (arg_ifindex_permissive
&&
3055 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
3058 return log_error_errno(r
, "Failed to set DNSSEC configuration: %s", bus_error_message(&error
, r
));
3064 static int call_nta(sd_bus
*bus
, char **nta
, const BusLocator
*locator
, sd_bus_error
*error
) {
3065 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
;
3068 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
3070 r
= bus_message_new_method_call(bus
, &req
, locator
, "SetLinkDNSSECNegativeTrustAnchors");
3072 return bus_log_create_error(r
);
3074 r
= sd_bus_message_append(req
, "i", arg_ifindex
);
3076 return bus_log_create_error(r
);
3078 r
= sd_bus_message_append_strv(req
, nta
);
3080 return bus_log_create_error(r
);
3082 return sd_bus_call(bus
, req
, 0, error
, NULL
);
3085 static int verb_nta(int argc
, char **argv
, void *userdata
) {
3086 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
3087 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
3092 r
= acquire_bus(&bus
);
3097 r
= ifname_mangle(argv
[1]);
3102 if (arg_ifindex
<= 0)
3103 return status_all(bus
, STATUS_NTA
);
3106 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_NTA
, NULL
);
3108 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
3110 /* If only argument is the empty string, then call SetLinkDNSSECNegativeTrustAnchors()
3111 * with an empty list, which will clear the list of domains for an interface. */
3112 args
= strv_skip(argv
, 2);
3113 clear
= strv_equal(args
, STRV_MAKE(""));
3116 STRV_FOREACH(p
, args
) {
3117 r
= dns_name_is_valid(*p
);
3119 return log_error_errno(r
, "Failed to validate specified domain %s: %m", *p
);
3121 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
3122 "Domain not valid: %s",
3126 r
= call_nta(bus
, clear
? NULL
: args
, bus_resolve_mgr
, &error
);
3127 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
3128 sd_bus_error_free(&error
);
3130 r
= call_nta(bus
, clear
? NULL
: args
, bus_network_mgr
, &error
);
3133 if (arg_ifindex_permissive
&&
3134 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
3137 return log_error_errno(r
, "Failed to set DNSSEC NTA configuration: %s", bus_error_message(&error
, r
));
3143 static int verb_revert_link(int argc
, char **argv
, void *userdata
) {
3144 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
3145 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
3148 r
= acquire_bus(&bus
);
3153 r
= ifname_mangle(argv
[1]);
3158 if (arg_ifindex
<= 0)
3159 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Interface argument required.");
3161 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
3163 r
= bus_call_method(bus
, bus_resolve_mgr
, "RevertLink", &error
, NULL
, "i", arg_ifindex
);
3164 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
3165 sd_bus_error_free(&error
);
3167 r
= bus_call_method(bus
, bus_network_mgr
, "RevertLinkDNS", &error
, NULL
, "i", arg_ifindex
);
3170 if (arg_ifindex_permissive
&&
3171 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
3174 return log_error_errno(r
, "Failed to revert interface configuration: %s", bus_error_message(&error
, r
));
3180 static int verb_log_level(int argc
, char *argv
[], void *userdata
) {
3181 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
3184 r
= acquire_bus(&bus
);
3188 assert(IN_SET(argc
, 1, 2));
3190 return verb_log_control_common(bus
, "org.freedesktop.resolve1", argv
[0], argc
== 2 ? argv
[1] : NULL
);
3193 static int print_question(char prefix
, const char *color
, sd_json_variant
*question
) {
3194 sd_json_variant
*q
= NULL
;
3199 JSON_VARIANT_ARRAY_FOREACH(q
, question
) {
3200 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
3201 char buf
[DNS_RESOURCE_KEY_STRING_MAX
];
3203 r
= dns_resource_key_from_json(q
, &key
);
3205 log_warning_errno(r
, "Received monitor message with invalid question key, ignoring: %m");
3209 printf("%s%s %c%s: %s\n",
3211 glyph(GLYPH_ARROW_RIGHT
),
3214 dns_resource_key_to_string(key
, buf
, sizeof(buf
)));
3220 static int print_answer(sd_json_variant
*answer
) {
3224 JSON_VARIANT_ARRAY_FOREACH(a
, answer
) {
3225 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
3226 _cleanup_free_
void *d
= NULL
;
3227 sd_json_variant
*jraw
;
3231 jraw
= sd_json_variant_by_key(a
, "raw");
3233 log_warning("Received monitor answer lacking valid raw data, ignoring.");
3237 r
= sd_json_variant_unbase64(jraw
, &d
, &l
);
3239 log_warning_errno(r
, "Failed to undo base64 encoding of monitor answer raw data, ignoring.");
3243 r
= dns_resource_record_new_from_raw(&rr
, d
, l
);
3245 log_warning_errno(r
, "Failed to parse monitor answer RR, ignoring: %m");
3249 s
= dns_resource_record_to_string(rr
);
3253 printf("%s%s A%s: %s\n",
3254 ansi_highlight_yellow(),
3255 glyph(GLYPH_ARROW_LEFT
),
3263 typedef struct MonitorQueryParams
{
3264 sd_json_variant
*question
;
3265 sd_json_variant
*answer
;
3266 sd_json_variant
*collected_questions
;
3272 const char *ede_msg
;
3273 } MonitorQueryParams
;
3275 static void monitor_query_params_done(MonitorQueryParams
*p
) {
3278 sd_json_variant_unref(p
->question
);
3279 sd_json_variant_unref(p
->answer
);
3280 sd_json_variant_unref(p
->collected_questions
);
3283 static void monitor_query_dump(sd_json_variant
*v
) {
3284 static const sd_json_dispatch_field dispatch_table
[] = {
3285 { "question", SD_JSON_VARIANT_ARRAY
, sd_json_dispatch_variant
, offsetof(MonitorQueryParams
, question
), SD_JSON_MANDATORY
},
3286 { "answer", SD_JSON_VARIANT_ARRAY
, sd_json_dispatch_variant
, offsetof(MonitorQueryParams
, answer
), 0 },
3287 { "collectedQuestions", SD_JSON_VARIANT_ARRAY
, sd_json_dispatch_variant
, offsetof(MonitorQueryParams
, collected_questions
), 0 },
3288 { "state", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(MonitorQueryParams
, state
), SD_JSON_MANDATORY
},
3289 { "result", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(MonitorQueryParams
, result
), 0 },
3290 { "rcode", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_int
, offsetof(MonitorQueryParams
, rcode
), 0 },
3291 { "errno", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_int
, offsetof(MonitorQueryParams
, error
), 0 },
3292 { "extendedDNSErrorCode", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_int
, offsetof(MonitorQueryParams
, ede_code
), 0 },
3293 { "extendedDNSErrorMessage", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(MonitorQueryParams
, ede_msg
), 0 },
3297 _cleanup_(monitor_query_params_done
) MonitorQueryParams p
= {
3304 if (sd_json_dispatch(v
, dispatch_table
, SD_JSON_LOG
|SD_JSON_ALLOW_EXTENSIONS
, &p
) < 0)
3307 /* First show the current question */
3308 print_question('Q', ansi_highlight_cyan(), p
.question
);
3310 /* And then show the questions that led to this one in case this was a CNAME chain */
3311 print_question('C', ansi_highlight_grey(), p
.collected_questions
);
3313 printf("%s%s S%s: %s",
3314 streq_ptr(p
.state
, "success") ? ansi_highlight_green() : ansi_highlight_red(),
3315 glyph(GLYPH_ARROW_LEFT
),
3317 streq_ptr(p
.state
, "errno") ? ERRNO_NAME(p
.error
) :
3318 streq_ptr(p
.state
, "rcode-failure") ? strna(dns_rcode_to_string(p
.rcode
)) :
3321 if (!isempty(p
.result
))
3322 printf(": %s", p
.result
);
3324 if (p
.ede_code
>= 0)
3326 FORMAT_DNS_EDE_RCODE(p
.ede_code
),
3327 !isempty(p
.ede_msg
) ? ": " : "",
3328 strempty(p
.ede_msg
));
3332 print_answer(p
.answer
);
3335 static int monitor_reply(
3337 sd_json_variant
*parameters
,
3338 const char *error_id
,
3339 sd_varlink_reply_flags_t flags
,
3347 disconnect
= streq(error_id
, SD_VARLINK_ERROR_DISCONNECTED
);
3349 log_info("Disconnected.");
3351 log_error("Varlink error: %s", error_id
);
3353 (void) sd_event_exit(ASSERT_PTR(sd_varlink_get_event(link
)), disconnect
? EXIT_SUCCESS
: EXIT_FAILURE
);
3357 if (sd_json_variant_by_key(parameters
, "ready")) {
3358 /* The first message coming in will just indicate that we are now subscribed. We let our
3359 * caller know if they asked for it. Once the caller sees this they should know that we are
3360 * not going to miss any queries anymore. */
3361 (void) sd_notify(/* unset_environment=false */ false, "READY=1");
3365 if (!sd_json_format_enabled(arg_json_format_flags
)) {
3366 monitor_query_dump(parameters
);
3369 sd_json_variant_dump(parameters
, arg_json_format_flags
, NULL
, NULL
);
3376 static int verb_monitor(int argc
, char *argv
[], void *userdata
) {
3377 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
3378 _cleanup_(sd_varlink_unrefp
) sd_varlink
*vl
= NULL
;
3381 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
3383 r
= sd_event_default(&event
);
3385 return log_error_errno(r
, "Failed to get event loop: %m");
3387 r
= sd_event_set_signal_exit(event
, true);
3389 return log_error_errno(r
, "Failed to enable exit on SIGINT/SIGTERM: %m");
3391 r
= sd_varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
3393 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
3395 r
= sd_varlink_set_relative_timeout(vl
, USEC_INFINITY
); /* We want the monitor to run basically forever */
3397 return log_error_errno(r
, "Failed to set varlink timeout: %m");
3399 r
= sd_varlink_attach_event(vl
, event
, SD_EVENT_PRIORITY_NORMAL
);
3401 return log_error_errno(r
, "Failed to attach varlink connection to event loop: %m");
3403 r
= sd_varlink_bind_reply(vl
, monitor_reply
);
3405 return log_error_errno(r
, "Failed to bind reply callback to varlink connection: %m");
3407 r
= sd_varlink_observebo(
3409 "io.systemd.Resolve.Monitor.SubscribeQueryResults",
3410 SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password
));
3412 return log_error_errno(r
, "Failed to issue SubscribeQueryResults() varlink call: %m");
3414 r
= sd_event_loop(event
);
3416 return log_error_errno(r
, "Failed to run event loop: %m");
3418 r
= sd_event_get_exit_code(event
, &c
);
3420 return log_error_errno(r
, "Failed to get exit code: %m");
3425 static int dump_cache_item(sd_json_variant
*item
) {
3428 sd_json_variant
*key
;
3429 sd_json_variant
*rrs
;
3434 static const sd_json_dispatch_field dispatch_table
[] = {
3435 { "key", SD_JSON_VARIANT_OBJECT
, sd_json_dispatch_variant_noref
, offsetof(struct item_info
, key
), SD_JSON_MANDATORY
},
3436 { "rrs", SD_JSON_VARIANT_ARRAY
, sd_json_dispatch_variant_noref
, offsetof(struct item_info
, rrs
), 0 },
3437 { "type", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct item_info
, type
), 0 },
3438 { "until", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct item_info
, until
), 0 },
3442 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*k
= NULL
;
3445 r
= sd_json_dispatch(item
, dispatch_table
, SD_JSON_LOG
|SD_JSON_ALLOW_EXTENSIONS
, &item_info
);
3449 r
= dns_resource_key_from_json(item_info
.key
, &k
);
3451 return log_error_errno(r
, "Failed to turn JSON data to resource key: %m");
3454 printf("%s %s%s%s\n", DNS_RESOURCE_KEY_TO_STRING(k
), ansi_highlight_red(), item_info
.type
, ansi_normal());
3458 JSON_VARIANT_ARRAY_FOREACH(i
, item_info
.rrs
) {
3459 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
3460 _cleanup_free_
void *data
= NULL
;
3461 sd_json_variant
*raw
;
3464 raw
= sd_json_variant_by_key(i
, "raw");
3466 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
), "raw field missing from RR JSON data.");
3468 r
= sd_json_variant_unbase64(raw
, &data
, &size
);
3470 return log_error_errno(r
, "Unable to decode raw RR JSON data: %m");
3472 r
= dns_resource_record_new_from_raw(&rr
, data
, size
);
3474 return log_error_errno(r
, "Failed to parse DNS data: %m");
3476 printf("%s\n", dns_resource_record_to_string(rr
));
3484 static int dump_cache_scope(sd_json_variant
*scope
) {
3487 const char *protocol
;
3491 sd_json_variant
*cache
;
3492 const char *dnssec_mode
;
3493 const char *dns_over_tls_mode
;
3495 .family
= AF_UNSPEC
,
3500 static const sd_json_dispatch_field dispatch_table
[] = {
3501 { "protocol", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct scope_info
, protocol
), SD_JSON_MANDATORY
},
3502 { "family", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_int
, offsetof(struct scope_info
, family
), 0 },
3503 { "ifindex", _SD_JSON_VARIANT_TYPE_INVALID
, json_dispatch_ifindex
, offsetof(struct scope_info
, ifindex
), SD_JSON_RELAX
},
3504 { "ifname", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct scope_info
, ifname
), 0 },
3505 { "cache", SD_JSON_VARIANT_ARRAY
, sd_json_dispatch_variant_noref
, offsetof(struct scope_info
, cache
), SD_JSON_MANDATORY
},
3506 { "dnssec", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct scope_info
, dnssec_mode
), 0 },
3507 { "dnsOverTLS", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct scope_info
, dns_over_tls_mode
), 0 },
3511 r
= sd_json_dispatch(scope
, dispatch_table
, SD_JSON_LOG
|SD_JSON_ALLOW_EXTENSIONS
, &scope_info
);
3515 printf("%sScope protocol=%s", ansi_underline(), scope_info
.protocol
);
3517 if (scope_info
.family
!= AF_UNSPEC
)
3518 printf(" family=%s", af_to_name(scope_info
.family
));
3520 if (scope_info
.ifindex
> 0)
3521 printf(" ifindex=%i", scope_info
.ifindex
);
3522 if (scope_info
.ifname
)
3523 printf(" ifname=%s", scope_info
.ifname
);
3525 if (dns_protocol_from_string(scope_info
.protocol
) == DNS_PROTOCOL_DNS
) {
3526 if (scope_info
.dnssec_mode
)
3527 printf(" DNSSEC=%s", scope_info
.dnssec_mode
);
3528 if (scope_info
.dns_over_tls_mode
)
3529 printf(" DNSOverTLS=%s", scope_info
.dns_over_tls_mode
);
3532 printf("%s\n", ansi_normal());
3534 JSON_VARIANT_ARRAY_FOREACH(i
, scope_info
.cache
) {
3535 r
= dump_cache_item(i
);
3543 printf("%sNo entries.%s\n\n", ansi_grey(), ansi_normal());
3550 static int verb_show_cache(int argc
, char *argv
[], void *userdata
) {
3551 sd_json_variant
*reply
= NULL
, *d
= NULL
;
3552 _cleanup_(sd_varlink_unrefp
) sd_varlink
*vl
= NULL
;
3555 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
3557 r
= sd_varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
3559 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
3561 r
= varlink_callbo_and_log(
3563 "io.systemd.Resolve.Monitor.DumpCache",
3565 SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password
));
3569 d
= sd_json_variant_by_key(reply
, "dump");
3571 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
3572 "DumpCache() response is missing 'dump' key.");
3574 if (!sd_json_variant_is_array(d
))
3575 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
3576 "DumpCache() response 'dump' field not an array");
3578 if (!sd_json_format_enabled(arg_json_format_flags
)) {
3581 JSON_VARIANT_ARRAY_FOREACH(i
, d
) {
3582 r
= dump_cache_scope(i
);
3590 return sd_json_variant_dump(d
, arg_json_format_flags
, NULL
, NULL
);
3593 static int dump_server_state(sd_json_variant
*server
) {
3594 _cleanup_(table_unrefp
) Table
*table
= NULL
;
3597 struct server_state
{
3598 const char *server_name
;
3602 const char *verified_feature_level
;
3603 const char *possible_feature_level
;
3604 const char *dnssec_mode
;
3605 bool dnssec_supported
;
3606 size_t received_udp_fragment_max
;
3607 uint64_t n_failed_udp
;
3608 uint64_t n_failed_tcp
;
3609 bool packet_truncated
;
3610 bool packet_bad_opt
;
3611 bool packet_rrsig_missing
;
3612 bool packet_invalid
;
3620 static const sd_json_dispatch_field dispatch_table
[] = {
3621 { "Server", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct server_state
, server_name
), SD_JSON_MANDATORY
},
3622 { "Type", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct server_state
, type
), SD_JSON_MANDATORY
},
3623 { "Interface", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct server_state
, ifname
), 0 },
3624 { "InterfaceIndex", _SD_JSON_VARIANT_TYPE_INVALID
, json_dispatch_ifindex
, offsetof(struct server_state
, ifindex
), SD_JSON_RELAX
},
3625 { "VerifiedFeatureLevel", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct server_state
, verified_feature_level
), 0 },
3626 { "PossibleFeatureLevel", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct server_state
, possible_feature_level
), 0 },
3627 { "DNSSECMode", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct server_state
, dnssec_mode
), SD_JSON_MANDATORY
},
3628 { "DNSSECSupported", SD_JSON_VARIANT_BOOLEAN
, sd_json_dispatch_stdbool
, offsetof(struct server_state
, dnssec_supported
), SD_JSON_MANDATORY
},
3629 { "ReceivedUDPFragmentMax", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct server_state
, received_udp_fragment_max
), SD_JSON_MANDATORY
},
3630 { "FailedUDPAttempts", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct server_state
, n_failed_udp
), SD_JSON_MANDATORY
},
3631 { "FailedTCPAttempts", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct server_state
, n_failed_tcp
), SD_JSON_MANDATORY
},
3632 { "PacketTruncated", SD_JSON_VARIANT_BOOLEAN
, sd_json_dispatch_stdbool
, offsetof(struct server_state
, packet_truncated
), SD_JSON_MANDATORY
},
3633 { "PacketBadOpt", SD_JSON_VARIANT_BOOLEAN
, sd_json_dispatch_stdbool
, offsetof(struct server_state
, packet_bad_opt
), SD_JSON_MANDATORY
},
3634 { "PacketRRSIGMissing", SD_JSON_VARIANT_BOOLEAN
, sd_json_dispatch_stdbool
, offsetof(struct server_state
, packet_rrsig_missing
), SD_JSON_MANDATORY
},
3635 { "PacketInvalid", SD_JSON_VARIANT_BOOLEAN
, sd_json_dispatch_stdbool
, offsetof(struct server_state
, packet_invalid
), SD_JSON_MANDATORY
},
3636 { "PacketDoOff", SD_JSON_VARIANT_BOOLEAN
, sd_json_dispatch_stdbool
, offsetof(struct server_state
, packet_do_off
), SD_JSON_MANDATORY
},
3640 r
= sd_json_dispatch(server
, dispatch_table
, SD_JSON_LOG
|SD_JSON_ALLOW_EXTENSIONS
, &server_state
);
3644 table
= table_new_vertical();
3648 assert_se(cell
= table_get_cell(table
, 0, 0));
3649 (void) table_set_ellipsize_percent(table
, cell
, 100);
3650 (void) table_set_align_percent(table
, cell
, 0);
3652 r
= table_add_cell_stringf(table
, NULL
, "Server: %s", server_state
.server_name
);
3654 return table_log_add_error(r
);
3656 r
= table_add_many(table
,
3658 TABLE_FIELD
, "Type",
3659 TABLE_SET_ALIGN_PERCENT
, 100,
3660 TABLE_STRING
, server_state
.type
);
3662 return table_log_add_error(r
);
3664 if (server_state
.ifname
) {
3665 r
= table_add_many(table
,
3666 TABLE_FIELD
, "Interface",
3667 TABLE_STRING
, server_state
.ifname
);
3669 return table_log_add_error(r
);
3672 if (server_state
.ifindex
>= 0) {
3673 r
= table_add_many(table
,
3674 TABLE_FIELD
, "Interface Index",
3675 TABLE_INT
, server_state
.ifindex
);
3677 return table_log_add_error(r
);
3680 if (server_state
.verified_feature_level
) {
3681 r
= table_add_many(table
,
3682 TABLE_FIELD
, "Verified feature level",
3683 TABLE_STRING
, server_state
.verified_feature_level
);
3685 return table_log_add_error(r
);
3688 if (server_state
.possible_feature_level
) {
3689 r
= table_add_many(table
,
3690 TABLE_FIELD
, "Possible feature level",
3691 TABLE_STRING
, server_state
.possible_feature_level
);
3693 return table_log_add_error(r
);
3696 r
= table_add_many(table
,
3697 TABLE_FIELD
, "DNSSEC Mode",
3698 TABLE_STRING
, server_state
.dnssec_mode
,
3699 TABLE_FIELD
, "DNSSEC Supported",
3700 TABLE_STRING
, yes_no(server_state
.dnssec_supported
),
3701 TABLE_FIELD
, "Maximum UDP fragment size received",
3702 TABLE_UINT64
, server_state
.received_udp_fragment_max
,
3703 TABLE_FIELD
, "Failed UDP attempts",
3704 TABLE_UINT64
, server_state
.n_failed_udp
,
3705 TABLE_FIELD
, "Failed TCP attempts",
3706 TABLE_UINT64
, server_state
.n_failed_tcp
,
3707 TABLE_FIELD
, "Seen truncated packet",
3708 TABLE_STRING
, yes_no(server_state
.packet_truncated
),
3709 TABLE_FIELD
, "Seen OPT RR getting lost",
3710 TABLE_STRING
, yes_no(server_state
.packet_bad_opt
),
3711 TABLE_FIELD
, "Seen RRSIG RR missing",
3712 TABLE_STRING
, yes_no(server_state
.packet_rrsig_missing
),
3713 TABLE_FIELD
, "Seen invalid packet",
3714 TABLE_STRING
, yes_no(server_state
.packet_invalid
),
3715 TABLE_FIELD
, "Server dropped DO flag",
3716 TABLE_STRING
, yes_no(server_state
.packet_do_off
),
3717 TABLE_SET_ALIGN_PERCENT
, 0,
3718 TABLE_EMPTY
, TABLE_EMPTY
);
3721 return table_log_add_error(r
);
3723 r
= table_print(table
, NULL
);
3725 return table_log_print_error(r
);
3730 static int verb_show_server_state(int argc
, char *argv
[], void *userdata
) {
3731 sd_json_variant
*reply
= NULL
, *d
= NULL
;
3732 _cleanup_(sd_varlink_unrefp
) sd_varlink
*vl
= NULL
;
3735 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
3737 r
= sd_varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
3739 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
3741 r
= varlink_callbo_and_log(
3743 "io.systemd.Resolve.Monitor.DumpServerState",
3745 SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password
));
3749 d
= sd_json_variant_by_key(reply
, "dump");
3751 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
3752 "DumpCache() response is missing 'dump' key.");
3754 if (!sd_json_variant_is_array(d
))
3755 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
3756 "DumpCache() response 'dump' field not an array");
3758 if (!sd_json_format_enabled(arg_json_format_flags
)) {
3761 JSON_VARIANT_ARRAY_FOREACH(i
, d
) {
3762 r
= dump_server_state(i
);
3770 return sd_json_variant_dump(d
, arg_json_format_flags
, NULL
, NULL
);
3773 static void help_protocol_types(void) {
3775 puts("Known protocol types:");
3785 static void help_dns_types(void) {
3787 puts("Known DNS RR types:");
3789 DUMP_STRING_TABLE(dns_type
, int, _DNS_TYPE_MAX
);
3792 static void help_dns_classes(void) {
3794 puts("Known DNS RR classes:");
3796 DUMP_STRING_TABLE(dns_class
, int, _DNS_CLASS_MAX
);
3799 static int compat_help(void) {
3800 _cleanup_free_
char *link
= NULL
;
3803 r
= terminal_urlify_man("resolvectl", "1", &link
);
3807 pager_open(arg_pager_flags
);
3809 printf("%1$s [OPTIONS...] HOSTNAME|ADDRESS...\n"
3810 "%1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n"
3811 "%1$s [OPTIONS...] --openpgp EMAIL@DOMAIN...\n"
3812 "%1$s [OPTIONS...] --statistics\n"
3813 "%1$s [OPTIONS...] --reset-statistics\n"
3815 "%2$sResolve domain names, IPv4 and IPv6 addresses, DNS records, and services.%3$s\n\n"
3816 " -h --help Show this help\n"
3817 " --version Show package version\n"
3818 " --no-pager Do not pipe output into a pager\n"
3819 " -4 Resolve IPv4 addresses\n"
3820 " -6 Resolve IPv6 addresses\n"
3821 " -i --interface=INTERFACE Look on interface\n"
3822 " -p --protocol=PROTO|help Look via protocol\n"
3823 " -t --type=TYPE|help Query RR with DNS type\n"
3824 " -c --class=CLASS|help Query RR with DNS class\n"
3825 " --service Resolve service (SRV)\n"
3826 " --service-address=BOOL Resolve address for services (default: yes)\n"
3827 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
3828 " --openpgp Query OpenPGP public key\n"
3829 " --tlsa Query TLS public key\n"
3830 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
3831 " --search=BOOL Use search domains for single-label names\n"
3833 " --raw[=payload|packet] Dump the answer as binary data\n"
3834 " --legend=BOOL Print headers and additional info (default: yes)\n"
3835 " --statistics Show resolver statistics\n"
3836 " --reset-statistics Reset resolver statistics\n"
3837 " --status Show link and server status\n"
3838 " --flush-caches Flush all local DNS caches\n"
3839 " --reset-server-features\n"
3840 " Forget learnt DNS server feature levels\n"
3841 " --set-dns=SERVER Set per-interface DNS server address\n"
3842 " --set-domain=DOMAIN Set per-interface search domain\n"
3843 " --set-llmnr=MODE Set per-interface LLMNR mode\n"
3844 " --set-mdns=MODE Set per-interface MulticastDNS mode\n"
3845 " --set-dnsovertls=MODE Set per-interface DNS-over-TLS mode\n"
3846 " --set-dnssec=MODE Set per-interface DNSSEC mode\n"
3847 " --set-nta=DOMAIN Set per-interface DNSSEC NTA\n"
3848 " --revert Revert per-interface configuration\n"
3849 "\nSee the %4$s for details.\n",
3850 program_invocation_short_name
,
3858 static int native_help(void) {
3859 _cleanup_free_
char *link
= NULL
;
3862 r
= terminal_urlify_man("resolvectl", "1", &link
);
3866 pager_open(arg_pager_flags
);
3868 printf("%1$s [OPTIONS...] COMMAND ...\n"
3870 "%5$sSend control commands to the network name resolution manager, or%6$s\n"
3871 "%5$sresolve domain names, IPv4 and IPv6 addresses, DNS records, and services.%6$s\n"
3872 "\n%3$sCommands:%4$s\n"
3873 " query HOSTNAME|ADDRESS... Resolve domain names, IPv4 and IPv6 addresses\n"
3874 " service [[NAME] TYPE] DOMAIN Resolve service (SRV)\n"
3875 " openpgp EMAIL@DOMAIN... Query OpenPGP public key\n"
3876 " tlsa DOMAIN[:PORT]... Query TLS public key\n"
3877 " status [LINK...] Show link and server status\n"
3878 " statistics Show resolver statistics\n"
3879 " reset-statistics Reset resolver statistics\n"
3880 " flush-caches Flush all local DNS caches\n"
3881 " reset-server-features Forget learnt DNS server feature levels\n"
3882 " monitor Monitor DNS queries\n"
3883 " show-cache Show cache contents\n"
3884 " show-server-state Show servers state\n"
3885 " dns [LINK [SERVER...]] Get/set per-interface DNS server address\n"
3886 " domain [LINK [DOMAIN...]] Get/set per-interface search domain\n"
3887 " default-route [LINK [BOOL]] Get/set per-interface default route flag\n"
3888 " llmnr [LINK [MODE]] Get/set per-interface LLMNR mode\n"
3889 " mdns [LINK [MODE]] Get/set per-interface MulticastDNS mode\n"
3890 " dnsovertls [LINK [MODE]] Get/set per-interface DNS-over-TLS mode\n"
3891 " dnssec [LINK [MODE]] Get/set per-interface DNSSEC mode\n"
3892 " nta [LINK [DOMAIN...]] Get/set per-interface DNSSEC NTA\n"
3893 " revert LINK Revert per-interface configuration\n"
3894 " log-level [LEVEL] Get/set logging threshold for systemd-resolved\n"
3895 "\n%3$sOptions:%4$s\n"
3896 " -h --help Show this help\n"
3897 " --version Show package version\n"
3898 " --no-pager Do not pipe output into a pager\n"
3899 " --no-ask-password Do not prompt for password\n"
3900 " -4 Resolve IPv4 addresses\n"
3901 " -6 Resolve IPv6 addresses\n"
3902 " -i --interface=INTERFACE Look on interface\n"
3903 " -p --protocol=PROTO|help Look via protocol\n"
3904 " -t --type=TYPE|help Query RR with DNS type\n"
3905 " -c --class=CLASS|help Query RR with DNS class\n"
3906 " --service-address=BOOL Resolve address for services (default: yes)\n"
3907 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
3908 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
3909 " --validate=BOOL Allow DNSSEC validation (default: yes)\n"
3910 " --synthesize=BOOL Allow synthetic response (default: yes)\n"
3911 " --cache=BOOL Allow response from cache (default: yes)\n"
3912 " --stale-data=BOOL Allow response from cache with stale data (default: yes)\n"
3913 " --relax-single-label=BOOL Allow single label lookups to go upstream (default: no)\n"
3914 " --zone=BOOL Allow response from locally registered mDNS/LLMNR\n"
3915 " records (default: yes)\n"
3916 " --trust-anchor=BOOL Allow response from local trust anchor (default:\n"
3918 " --network=BOOL Allow response from network (default: yes)\n"
3919 " --search=BOOL Use search domains for single-label names (default:\n"
3921 " --raw[=payload|packet] Dump the answer as binary data\n"
3922 " --legend=BOOL Print headers and additional info (default: yes)\n"
3923 " --json=MODE Output as JSON\n"
3924 " -j Same as --json=pretty on tty, --json=short\n"
3926 "\nSee the %2$s for details.\n",
3927 program_invocation_short_name
,
3937 static int verb_help(int argc
, char **argv
, void *userdata
) {
3938 return native_help();
3941 static int compat_parse_argv(int argc
, char *argv
[]) {
3943 ARG_VERSION
= 0x100,
3947 ARG_SERVICE_ADDRESS
,
3954 ARG_RESET_STATISTICS
,
3957 ARG_RESET_SERVER_FEATURES
,
3963 ARG_SET_DNS_OVER_TLS
,
3969 static const struct option options
[] = {
3970 { "help", no_argument
, NULL
, 'h' },
3971 { "version", no_argument
, NULL
, ARG_VERSION
},
3972 { "type", required_argument
, NULL
, 't' },
3973 { "class", required_argument
, NULL
, 'c' },
3974 { "legend", required_argument
, NULL
, ARG_LEGEND
},
3975 { "interface", required_argument
, NULL
, 'i' },
3976 { "protocol", required_argument
, NULL
, 'p' },
3977 { "cname", required_argument
, NULL
, ARG_CNAME
},
3978 { "service", no_argument
, NULL
, ARG_SERVICE
},
3979 { "service-address", required_argument
, NULL
, ARG_SERVICE_ADDRESS
},
3980 { "service-txt", required_argument
, NULL
, ARG_SERVICE_TXT
},
3981 { "openpgp", no_argument
, NULL
, ARG_OPENPGP
},
3982 { "tlsa", optional_argument
, NULL
, ARG_TLSA
},
3983 { "raw", optional_argument
, NULL
, ARG_RAW
},
3984 { "search", required_argument
, NULL
, ARG_SEARCH
},
3985 { "statistics", no_argument
, NULL
, ARG_STATISTICS
, },
3986 { "reset-statistics", no_argument
, NULL
, ARG_RESET_STATISTICS
},
3987 { "status", no_argument
, NULL
, ARG_STATUS
},
3988 { "flush-caches", no_argument
, NULL
, ARG_FLUSH_CACHES
},
3989 { "reset-server-features", no_argument
, NULL
, ARG_RESET_SERVER_FEATURES
},
3990 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
3991 { "set-dns", required_argument
, NULL
, ARG_SET_DNS
},
3992 { "set-domain", required_argument
, NULL
, ARG_SET_DOMAIN
},
3993 { "set-llmnr", required_argument
, NULL
, ARG_SET_LLMNR
},
3994 { "set-mdns", required_argument
, NULL
, ARG_SET_MDNS
},
3995 { "set-dnsovertls", required_argument
, NULL
, ARG_SET_DNS_OVER_TLS
},
3996 { "set-dnssec", required_argument
, NULL
, ARG_SET_DNSSEC
},
3997 { "set-nta", required_argument
, NULL
, ARG_SET_NTA
},
3998 { "revert", no_argument
, NULL
, ARG_REVERT_LINK
},
4007 while ((c
= getopt_long(argc
, argv
, "h46i:t:c:p:", options
, NULL
)) >= 0)
4011 return compat_help();
4017 arg_family
= AF_INET
;
4021 arg_family
= AF_INET6
;
4025 r
= ifname_mangle(optarg
);
4031 if (streq(optarg
, "help")) {
4036 r
= dns_type_from_string(optarg
);
4038 return log_error_errno(r
, "Failed to parse RR record type %s: %m", optarg
);
4040 arg_type
= (uint16_t) r
;
4041 assert((int) arg_type
== r
);
4043 arg_mode
= MODE_RESOLVE_RECORD
;
4047 if (streq(optarg
, "help")) {
4052 r
= dns_class_from_string(optarg
);
4054 return log_error_errno(r
, "Failed to parse RR record class %s: %m", optarg
);
4056 arg_class
= (uint16_t) r
;
4057 assert((int) arg_class
== r
);
4062 r
= parse_boolean_argument("--legend=", optarg
, &arg_legend
);
4068 if (streq(optarg
, "help")) {
4069 help_protocol_types();
4071 } else if (streq(optarg
, "dns"))
4072 arg_flags
|= SD_RESOLVED_DNS
;
4073 else if (streq(optarg
, "llmnr"))
4074 arg_flags
|= SD_RESOLVED_LLMNR
;
4075 else if (streq(optarg
, "llmnr-ipv4"))
4076 arg_flags
|= SD_RESOLVED_LLMNR_IPV4
;
4077 else if (streq(optarg
, "llmnr-ipv6"))
4078 arg_flags
|= SD_RESOLVED_LLMNR_IPV6
;
4079 else if (streq(optarg
, "mdns"))
4080 arg_flags
|= SD_RESOLVED_MDNS
;
4081 else if (streq(optarg
, "mdns-ipv4"))
4082 arg_flags
|= SD_RESOLVED_MDNS_IPV4
;
4083 else if (streq(optarg
, "mdns-ipv6"))
4084 arg_flags
|= SD_RESOLVED_MDNS_IPV6
;
4086 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4087 "Unknown protocol specifier: %s", optarg
);
4092 arg_mode
= MODE_RESOLVE_SERVICE
;
4096 arg_mode
= MODE_RESOLVE_OPENPGP
;
4100 arg_mode
= MODE_RESOLVE_TLSA
;
4101 if (!optarg
|| service_family_is_valid(optarg
))
4102 arg_service_family
= optarg
;
4104 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4105 "Unknown service family \"%s\".", optarg
);
4110 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY
),
4111 "Refusing to write binary data to tty.");
4113 if (optarg
== NULL
|| streq(optarg
, "payload"))
4114 arg_raw
= RAW_PAYLOAD
;
4115 else if (streq(optarg
, "packet"))
4116 arg_raw
= RAW_PACKET
;
4118 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4119 "Unknown --raw specifier \"%s\".",
4126 r
= parse_boolean_argument("--cname=", optarg
, NULL
);
4129 SET_FLAG(arg_flags
, SD_RESOLVED_NO_CNAME
, r
== 0);
4132 case ARG_SERVICE_ADDRESS
:
4133 r
= parse_boolean_argument("--service-address=", optarg
, NULL
);
4136 SET_FLAG(arg_flags
, SD_RESOLVED_NO_ADDRESS
, r
== 0);
4139 case ARG_SERVICE_TXT
:
4140 r
= parse_boolean_argument("--service-txt=", optarg
, NULL
);
4143 SET_FLAG(arg_flags
, SD_RESOLVED_NO_TXT
, r
== 0);
4147 r
= parse_boolean_argument("--search=", optarg
, NULL
);
4150 SET_FLAG(arg_flags
, SD_RESOLVED_NO_SEARCH
, r
== 0);
4153 case ARG_STATISTICS
:
4154 arg_mode
= MODE_STATISTICS
;
4157 case ARG_RESET_STATISTICS
:
4158 arg_mode
= MODE_RESET_STATISTICS
;
4161 case ARG_FLUSH_CACHES
:
4162 arg_mode
= MODE_FLUSH_CACHES
;
4165 case ARG_RESET_SERVER_FEATURES
:
4166 arg_mode
= MODE_RESET_SERVER_FEATURES
;
4170 arg_mode
= MODE_STATUS
;
4174 arg_pager_flags
|= PAGER_DISABLE
;
4178 r
= strv_extend(&arg_set_dns
, optarg
);
4182 arg_mode
= MODE_SET_LINK
;
4185 case ARG_SET_DOMAIN
:
4186 r
= strv_extend(&arg_set_domain
, optarg
);
4190 arg_mode
= MODE_SET_LINK
;
4194 arg_set_llmnr
= optarg
;
4195 arg_mode
= MODE_SET_LINK
;
4199 arg_set_mdns
= optarg
;
4200 arg_mode
= MODE_SET_LINK
;
4203 case ARG_SET_DNS_OVER_TLS
:
4204 arg_set_dns_over_tls
= optarg
;
4205 arg_mode
= MODE_SET_LINK
;
4208 case ARG_SET_DNSSEC
:
4209 arg_set_dnssec
= optarg
;
4210 arg_mode
= MODE_SET_LINK
;
4214 r
= strv_extend(&arg_set_nta
, optarg
);
4218 arg_mode
= MODE_SET_LINK
;
4221 case ARG_REVERT_LINK
:
4222 arg_mode
= MODE_REVERT_LINK
;
4229 assert_not_reached();
4232 if (arg_type
== 0 && arg_class
!= 0)
4233 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4234 "--class= may only be used in conjunction with --type=.");
4236 if (arg_type
!= 0 && arg_mode
== MODE_RESOLVE_SERVICE
)
4237 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4238 "--service and --type= may not be combined.");
4240 if (arg_type
!= 0 && arg_class
== 0)
4241 arg_class
= DNS_CLASS_IN
;
4243 if (arg_class
!= 0 && arg_type
== 0)
4244 arg_type
= DNS_TYPE_A
;
4246 if (IN_SET(arg_mode
, MODE_SET_LINK
, MODE_REVERT_LINK
)) {
4248 if (arg_ifindex
<= 0)
4249 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4250 "--set-dns=, --set-domain=, --set-llmnr=, --set-mdns=, --set-dnsovertls=, --set-dnssec=, --set-nta= and --revert require --interface=.");
4253 return 1 /* work to do */;
4256 static int native_parse_argv(int argc
, char *argv
[]) {
4258 ARG_VERSION
= 0x100,
4267 ARG_SERVICE_ADDRESS
,
4272 ARG_NO_ASK_PASSWORD
,
4275 ARG_RELAX_SINGLE_LABEL
,
4278 static const struct option options
[] = {
4279 { "help", no_argument
, NULL
, 'h' },
4280 { "version", no_argument
, NULL
, ARG_VERSION
},
4281 { "type", required_argument
, NULL
, 't' },
4282 { "class", required_argument
, NULL
, 'c' },
4283 { "legend", required_argument
, NULL
, ARG_LEGEND
},
4284 { "interface", required_argument
, NULL
, 'i' },
4285 { "protocol", required_argument
, NULL
, 'p' },
4286 { "cname", required_argument
, NULL
, ARG_CNAME
},
4287 { "validate", required_argument
, NULL
, ARG_VALIDATE
},
4288 { "synthesize", required_argument
, NULL
, ARG_SYNTHESIZE
},
4289 { "cache", required_argument
, NULL
, ARG_CACHE
},
4290 { "zone", required_argument
, NULL
, ARG_ZONE
},
4291 { "trust-anchor", required_argument
, NULL
, ARG_TRUST_ANCHOR
},
4292 { "network", required_argument
, NULL
, ARG_NETWORK
},
4293 { "service-address", required_argument
, NULL
, ARG_SERVICE_ADDRESS
},
4294 { "service-txt", required_argument
, NULL
, ARG_SERVICE_TXT
},
4295 { "raw", optional_argument
, NULL
, ARG_RAW
},
4296 { "search", required_argument
, NULL
, ARG_SEARCH
},
4297 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
4298 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
4299 { "json", required_argument
, NULL
, ARG_JSON
},
4300 { "stale-data", required_argument
, NULL
, ARG_STALE_DATA
},
4301 { "relax-single-label", required_argument
, NULL
, ARG_RELAX_SINGLE_LABEL
},
4310 while ((c
= getopt_long(argc
, argv
, "h46i:t:c:p:j", options
, NULL
)) >= 0)
4314 return native_help();
4320 arg_family
= AF_INET
;
4324 arg_family
= AF_INET6
;
4328 r
= ifname_mangle(optarg
);
4334 if (streq(optarg
, "help")) {
4339 r
= dns_type_from_string(optarg
);
4341 return log_error_errno(r
, "Failed to parse RR record type %s: %m", optarg
);
4343 arg_type
= (uint16_t) r
;
4344 assert((int) arg_type
== r
);
4349 if (streq(optarg
, "help")) {
4354 r
= dns_class_from_string(optarg
);
4356 return log_error_errno(r
, "Failed to parse RR record class %s: %m", optarg
);
4358 arg_class
= (uint16_t) r
;
4359 assert((int) arg_class
== r
);
4364 r
= parse_boolean_argument("--legend=", optarg
, &arg_legend
);
4370 if (streq(optarg
, "help")) {
4371 help_protocol_types();
4373 } else if (streq(optarg
, "dns"))
4374 arg_flags
|= SD_RESOLVED_DNS
;
4375 else if (streq(optarg
, "llmnr"))
4376 arg_flags
|= SD_RESOLVED_LLMNR
;
4377 else if (streq(optarg
, "llmnr-ipv4"))
4378 arg_flags
|= SD_RESOLVED_LLMNR_IPV4
;
4379 else if (streq(optarg
, "llmnr-ipv6"))
4380 arg_flags
|= SD_RESOLVED_LLMNR_IPV6
;
4381 else if (streq(optarg
, "mdns"))
4382 arg_flags
|= SD_RESOLVED_MDNS
;
4383 else if (streq(optarg
, "mdns-ipv4"))
4384 arg_flags
|= SD_RESOLVED_MDNS_IPV4
;
4385 else if (streq(optarg
, "mdns-ipv6"))
4386 arg_flags
|= SD_RESOLVED_MDNS_IPV6
;
4388 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4389 "Unknown protocol specifier: %s",
4396 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY
),
4397 "Refusing to write binary data to tty.");
4399 if (optarg
== NULL
|| streq(optarg
, "payload"))
4400 arg_raw
= RAW_PAYLOAD
;
4401 else if (streq(optarg
, "packet"))
4402 arg_raw
= RAW_PACKET
;
4404 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4405 "Unknown --raw specifier \"%s\".",
4412 r
= parse_boolean_argument("--cname=", optarg
, NULL
);
4415 SET_FLAG(arg_flags
, SD_RESOLVED_NO_CNAME
, r
== 0);
4419 r
= parse_boolean_argument("--validate=", optarg
, NULL
);
4422 SET_FLAG(arg_flags
, SD_RESOLVED_NO_VALIDATE
, r
== 0);
4425 case ARG_SYNTHESIZE
:
4426 r
= parse_boolean_argument("--synthesize=", optarg
, NULL
);
4429 SET_FLAG(arg_flags
, SD_RESOLVED_NO_SYNTHESIZE
, r
== 0);
4433 r
= parse_boolean_argument("--cache=", optarg
, NULL
);
4436 SET_FLAG(arg_flags
, SD_RESOLVED_NO_CACHE
, r
== 0);
4439 case ARG_STALE_DATA
:
4440 r
= parse_boolean_argument("--stale-data=", optarg
, NULL
);
4443 SET_FLAG(arg_flags
, SD_RESOLVED_NO_STALE
, r
== 0);
4447 r
= parse_boolean_argument("--zone=", optarg
, NULL
);
4450 SET_FLAG(arg_flags
, SD_RESOLVED_NO_ZONE
, r
== 0);
4453 case ARG_TRUST_ANCHOR
:
4454 r
= parse_boolean_argument("--trust-anchor=", optarg
, NULL
);
4457 SET_FLAG(arg_flags
, SD_RESOLVED_NO_TRUST_ANCHOR
, r
== 0);
4461 r
= parse_boolean_argument("--network=", optarg
, NULL
);
4464 SET_FLAG(arg_flags
, SD_RESOLVED_NO_NETWORK
, r
== 0);
4467 case ARG_SERVICE_ADDRESS
:
4468 r
= parse_boolean_argument("--service-address=", optarg
, NULL
);
4471 SET_FLAG(arg_flags
, SD_RESOLVED_NO_ADDRESS
, r
== 0);
4474 case ARG_SERVICE_TXT
:
4475 r
= parse_boolean_argument("--service-txt=", optarg
, NULL
);
4478 SET_FLAG(arg_flags
, SD_RESOLVED_NO_TXT
, r
== 0);
4482 r
= parse_boolean_argument("--search=", optarg
, NULL
);
4485 SET_FLAG(arg_flags
, SD_RESOLVED_NO_SEARCH
, r
== 0);
4488 case ARG_RELAX_SINGLE_LABEL
:
4489 r
= parse_boolean_argument("--relax-single-label=", optarg
, NULL
);
4492 SET_FLAG(arg_flags
, SD_RESOLVED_RELAX_SINGLE_LABEL
, r
> 0);
4496 arg_pager_flags
|= PAGER_DISABLE
;
4499 case ARG_NO_ASK_PASSWORD
:
4500 arg_ask_password
= false;
4504 r
= parse_json_argument(optarg
, &arg_json_format_flags
);
4511 arg_json_format_flags
= SD_JSON_FORMAT_PRETTY_AUTO
|SD_JSON_FORMAT_COLOR_AUTO
;
4518 assert_not_reached();
4521 if (arg_type
== 0 && arg_class
!= 0)
4522 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4523 "--class= may only be used in conjunction with --type=.");
4525 if (arg_type
!= 0 && arg_class
== 0)
4526 arg_class
= DNS_CLASS_IN
;
4528 if (arg_class
!= 0 && arg_type
== 0)
4529 arg_type
= DNS_TYPE_A
;
4531 return 1 /* work to do */;
4534 static int native_main(int argc
, char *argv
[]) {
4536 static const Verb verbs
[] = {
4537 { "help", VERB_ANY
, VERB_ANY
, 0, verb_help
},
4538 { "status", VERB_ANY
, VERB_ANY
, VERB_DEFAULT
, verb_status
},
4539 { "query", 2, VERB_ANY
, 0, verb_query
},
4540 { "service", 2, 4, 0, verb_service
},
4541 { "openpgp", 2, VERB_ANY
, 0, verb_openpgp
},
4542 { "tlsa", 2, VERB_ANY
, 0, verb_tlsa
},
4543 { "statistics", VERB_ANY
, 1, 0, show_statistics
},
4544 { "reset-statistics", VERB_ANY
, 1, 0, reset_statistics
},
4545 { "flush-caches", VERB_ANY
, 1, 0, flush_caches
},
4546 { "reset-server-features", VERB_ANY
, 1, 0, reset_server_features
},
4547 { "dns", VERB_ANY
, VERB_ANY
, 0, verb_dns
},
4548 { "domain", VERB_ANY
, VERB_ANY
, 0, verb_domain
},
4549 { "default-route", VERB_ANY
, 3, 0, verb_default_route
},
4550 { "llmnr", VERB_ANY
, 3, 0, verb_llmnr
},
4551 { "mdns", VERB_ANY
, 3, 0, verb_mdns
},
4552 { "dnsovertls", VERB_ANY
, 3, 0, verb_dns_over_tls
},
4553 { "dnssec", VERB_ANY
, 3, 0, verb_dnssec
},
4554 { "nta", VERB_ANY
, VERB_ANY
, 0, verb_nta
},
4555 { "revert", VERB_ANY
, 2, 0, verb_revert_link
},
4556 { "log-level", VERB_ANY
, 2, 0, verb_log_level
},
4557 { "monitor", VERB_ANY
, 1, 0, verb_monitor
},
4558 { "show-cache", VERB_ANY
, 1, 0, verb_show_cache
},
4559 { "show-server-state", VERB_ANY
, 1, 0, verb_show_server_state
},
4563 return dispatch_verb(argc
, argv
, verbs
, /* userdata = */ NULL
);
4566 static int translate(const char *verb
, const char *single_arg
, size_t num_args
, char **args
) {
4571 assert(num_args
== 0 || args
);
4573 num
= !!single_arg
+ num_args
+ 1;
4575 p
= fake
= newa0(char *, num
+ 1);
4576 *p
++ = (char *) verb
;
4578 *p
++ = (char *) single_arg
;
4579 FOREACH_ARRAY(arg
, args
, num_args
)
4583 return native_main((int) num
, fake
);
4586 static int compat_main(int argc
, char *argv
[]) {
4590 case MODE_RESOLVE_HOST
:
4591 case MODE_RESOLVE_RECORD
:
4592 return translate("query", NULL
, argc
- optind
, argv
+ optind
);
4594 case MODE_RESOLVE_SERVICE
:
4595 return translate("service", NULL
, argc
- optind
, argv
+ optind
);
4597 case MODE_RESOLVE_OPENPGP
:
4598 return translate("openpgp", NULL
, argc
- optind
, argv
+ optind
);
4600 case MODE_RESOLVE_TLSA
:
4601 return translate("tlsa", arg_service_family
, argc
- optind
, argv
+ optind
);
4603 case MODE_STATISTICS
:
4604 return translate("statistics", NULL
, 0, NULL
);
4606 case MODE_RESET_STATISTICS
:
4607 return translate("reset-statistics", NULL
, 0, NULL
);
4609 case MODE_FLUSH_CACHES
:
4610 return translate("flush-caches", NULL
, 0, NULL
);
4612 case MODE_RESET_SERVER_FEATURES
:
4613 return translate("reset-server-features", NULL
, 0, NULL
);
4616 return translate("status", NULL
, argc
- optind
, argv
+ optind
);
4621 if (arg_disable_default_route
) {
4622 r
= translate("default-route", arg_ifname
, 1, STRV_MAKE("no"));
4628 r
= translate("dns", arg_ifname
, strv_length(arg_set_dns
), arg_set_dns
);
4633 if (arg_set_domain
) {
4634 r
= translate("domain", arg_ifname
, strv_length(arg_set_domain
), arg_set_domain
);
4640 r
= translate("nta", arg_ifname
, strv_length(arg_set_nta
), arg_set_nta
);
4645 if (arg_set_llmnr
) {
4646 r
= translate("llmnr", arg_ifname
, 1, (char **) &arg_set_llmnr
);
4652 r
= translate("mdns", arg_ifname
, 1, (char **) &arg_set_mdns
);
4657 if (arg_set_dns_over_tls
) {
4658 r
= translate("dnsovertls", arg_ifname
, 1, (char **) &arg_set_dns_over_tls
);
4663 if (arg_set_dnssec
) {
4664 r
= translate("dnssec", arg_ifname
, 1, (char **) &arg_set_dnssec
);
4671 case MODE_REVERT_LINK
:
4674 return translate("revert", arg_ifname
, 0, NULL
);
4677 assert_not_reached();
4683 static int run(int argc
, char **argv
) {
4684 bool compat
= false;
4687 setlocale(LC_ALL
, "");
4690 if (invoked_as(argv
, "resolvconf")) {
4692 r
= resolvconf_parse_argv(argc
, argv
);
4693 } else if (invoked_as(argv
, "systemd-resolve")) {
4695 r
= compat_parse_argv(argc
, argv
);
4697 r
= native_parse_argv(argc
, argv
);
4702 return compat_main(argc
, argv
);
4704 return native_main(argc
, argv
);
4707 DEFINE_MAIN_FUNCTION(run
);