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 "errno-list.h"
26 #include "errno-util.h"
28 #include "format-ifname.h"
29 #include "format-table.h"
30 #include "hostname-util.h"
31 #include "json-util.h"
32 #include "main-func.h"
33 #include "missing_network.h"
34 #include "netlink-util.h"
35 #include "openssl-util.h"
37 #include "parse-argument.h"
38 #include "parse-util.h"
39 #include "polkit-agent.h"
40 #include "pretty-print.h"
41 #include "resolvconf-compat.h"
42 #include "resolve-util.h"
43 #include "resolvectl.h"
44 #include "resolved-def.h"
45 #include "resolved-dns-packet.h"
46 #include "resolved-dns-rr.h"
47 #include "resolved-util.h"
48 #include "socket-netlink.h"
49 #include "sort-util.h"
50 #include "stdio-util.h"
51 #include "string-table.h"
52 #include "string-util.h"
54 #include "terminal-util.h"
55 #include "time-util.h"
57 #include "varlink-util.h"
58 #include "verb-log-control.h"
61 static int arg_family
= AF_UNSPEC
;
62 static int arg_ifindex
= 0;
63 static char *arg_ifname
= NULL
;
64 static uint16_t arg_type
= 0;
65 static uint16_t arg_class
= 0;
66 static bool arg_legend
= true;
67 static uint64_t arg_flags
= 0;
68 static sd_json_format_flags_t arg_json_format_flags
= SD_JSON_FORMAT_OFF
;
69 static PagerFlags arg_pager_flags
= 0;
70 bool arg_ifindex_permissive
= false; /* If true, don't generate an error if the specified interface index doesn't exist */
71 static const char *arg_service_family
= NULL
;
72 static bool arg_ask_password
= true;
74 typedef enum RawType
{
79 static RawType arg_raw
= RAW_NONE
;
81 /* Used by compat interfaces: systemd-resolve and resolvconf. */
82 ExecutionMode arg_mode
= MODE_RESOLVE_HOST
;
83 char **arg_set_dns
= NULL
;
84 char **arg_set_domain
= NULL
;
85 bool arg_disable_default_route
= false;
86 static const char *arg_set_llmnr
= NULL
;
87 static const char *arg_set_mdns
= NULL
;
88 static const char *arg_set_dns_over_tls
= NULL
;
89 static const char *arg_set_dnssec
= NULL
;
90 static char **arg_set_nta
= NULL
;
92 STATIC_DESTRUCTOR_REGISTER(arg_ifname
, freep
);
93 STATIC_DESTRUCTOR_REGISTER(arg_set_dns
, strv_freep
);
94 STATIC_DESTRUCTOR_REGISTER(arg_set_domain
, strv_freep
);
95 STATIC_DESTRUCTOR_REGISTER(arg_set_nta
, strv_freep
);
97 typedef enum StatusMode
{
101 STATUS_DEFAULT_ROUTE
,
109 typedef struct InterfaceInfo
{
114 static int acquire_bus(sd_bus
**ret
) {
115 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
120 r
= sd_bus_open_system(&bus
);
122 return log_error_errno(r
, "sd_bus_open_system: %m");
124 (void) sd_bus_set_allow_interactive_authorization(bus
, arg_ask_password
);
126 *ret
= TAKE_PTR(bus
);
130 static int interface_info_compare(const InterfaceInfo
*a
, const InterfaceInfo
*b
) {
133 r
= CMP(a
->index
, b
->index
);
137 return strcmp_ptr(a
->name
, b
->name
);
140 int ifname_mangle_full(const char *s
, bool drop_protocol_specifier
) {
141 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
142 _cleanup_strv_free_
char **found
= NULL
;
147 if (drop_protocol_specifier
) {
148 _cleanup_free_
char *buf
= NULL
;
149 int ifindex_longest_name
= -ENODEV
;
151 /* When invoked as resolvconf, drop the protocol specifier(s) at the end. */
158 r
= rtnl_resolve_interface(&rtnl
, buf
);
160 if (ifindex_longest_name
<= 0)
161 ifindex_longest_name
= r
;
163 r
= strv_extend(&found
, buf
);
168 char *dot
= strrchr(buf
, '.');
175 unsigned n
= strv_length(found
);
177 _cleanup_free_
char *joined
= NULL
;
179 joined
= strv_join(found
, ", ");
180 log_warning("Found multiple interfaces (%s) matching with '%s'. Using '%s' (ifindex=%i).",
181 strna(joined
), s
, found
[0], ifindex_longest_name
);
186 proto
= ASSERT_PTR(startswith(s
, found
[0]));
188 log_info("Dropped protocol specifier '%s' from '%s'. Using '%s' (ifindex=%i).",
189 proto
, s
, found
[0], ifindex_longest_name
);
192 r
= ifindex_longest_name
;
194 r
= rtnl_resolve_interface(&rtnl
, s
);
196 if (ERRNO_IS_DEVICE_ABSENT(r
) && arg_ifindex_permissive
) {
197 log_debug_errno(r
, "Interface '%s' not found, but -f specified, ignoring: %m", s
);
200 return log_error_errno(r
, "Failed to resolve interface \"%s\": %m", s
);
203 if (arg_ifindex
> 0 && arg_ifindex
!= r
)
204 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Specified multiple different interfaces. Refusing.");
207 return free_and_strdup_warn(&arg_ifname
, found
? found
[0] : s
); /* found */
210 static void print_source(uint64_t flags
, usec_t rtt
) {
214 if (sd_json_format_enabled(arg_json_format_flags
))
220 printf("\n%s-- Information acquired via", ansi_grey());
222 printf(" protocol%s%s%s%s%s",
223 flags
& SD_RESOLVED_DNS
? " DNS" :"",
224 flags
& SD_RESOLVED_LLMNR_IPV4
? " LLMNR/IPv4" : "",
225 flags
& SD_RESOLVED_LLMNR_IPV6
? " LLMNR/IPv6" : "",
226 flags
& SD_RESOLVED_MDNS_IPV4
? " mDNS/IPv4" : "",
227 flags
& SD_RESOLVED_MDNS_IPV6
? " mDNS/IPv6" : "");
230 "%s-- Data is authenticated: %s; Data was acquired via local or encrypted transport: %s%s\n",
231 FORMAT_TIMESPAN(rtt
, 100),
234 yes_no(flags
& SD_RESOLVED_AUTHENTICATED
),
235 yes_no(flags
& SD_RESOLVED_CONFIDENTIAL
),
238 if ((flags
& (SD_RESOLVED_FROM_MASK
|SD_RESOLVED_SYNTHETIC
)) != 0)
239 printf("%s-- Data from:%s%s%s%s%s%s\n",
241 FLAGS_SET(flags
, SD_RESOLVED_SYNTHETIC
) ? " synthetic" : "",
242 FLAGS_SET(flags
, SD_RESOLVED_FROM_CACHE
) ? " cache" : "",
243 FLAGS_SET(flags
, SD_RESOLVED_FROM_ZONE
) ? " zone" : "",
244 FLAGS_SET(flags
, SD_RESOLVED_FROM_TRUST_ANCHOR
) ? " trust-anchor" : "",
245 FLAGS_SET(flags
, SD_RESOLVED_FROM_NETWORK
) ? " network" : "",
249 static void print_ifindex_comment(int printed_so_far
, int ifindex
) {
250 char ifname
[IF_NAMESIZE
];
256 r
= format_ifname(ifindex
, ifname
);
258 return (void) log_warning_errno(r
, "Failed to resolve interface name for index %i, ignoring: %m", ifindex
);
260 printf("%*s%s-- link: %s%s",
261 60 > printed_so_far
? 60 - printed_so_far
: 0, " ", /* Align comment to the 60th column */
262 ansi_grey(), ifname
, ansi_normal());
265 static int resolve_host_error(const char *name
, int r
, const sd_bus_error
*error
) {
266 if (sd_bus_error_has_name(error
, BUS_ERROR_DNS_NXDOMAIN
))
267 return log_error_errno(r
, "%s: %s", name
, bus_error_message(error
, r
));
269 return log_error_errno(r
, "%s: resolve call failed: %s", name
, bus_error_message(error
, r
));
272 static int resolve_host(sd_bus
*bus
, const char *name
) {
273 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
274 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
275 const char *canonical
= NULL
;
283 if (sd_json_format_enabled(arg_json_format_flags
))
284 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Use --json=pretty with --type=A or --type=AAAA to acquire address record information in JSON format.");
286 log_debug("Resolving %s (family %s, interface %s).", name
, af_to_name(arg_family
) ?: "*", isempty(arg_ifname
) ? "*" : arg_ifname
);
288 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveHostname");
290 return bus_log_create_error(r
);
292 r
= sd_bus_message_append(req
, "isit", arg_ifindex
, name
, arg_family
, arg_flags
);
294 return bus_log_create_error(r
);
296 ts
= now(CLOCK_MONOTONIC
);
298 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
300 return resolve_host_error(name
, r
, &error
);
302 ts
= now(CLOCK_MONOTONIC
) - ts
;
304 r
= sd_bus_message_enter_container(reply
, 'a', "(iiay)");
306 return bus_log_parse_error(r
);
308 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iiay")) > 0) {
309 _cleanup_free_
char *pretty
= NULL
;
310 int ifindex
, family
, k
;
311 union in_addr_union a
;
313 assert_cc(sizeof(int) == sizeof(int32_t));
315 r
= sd_bus_message_read(reply
, "i", &ifindex
);
317 return bus_log_parse_error(r
);
319 sd_bus_error_free(&error
);
320 r
= bus_message_read_in_addr_auto(reply
, &error
, &family
, &a
);
321 if (r
< 0 && !sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
))
322 return log_error_errno(r
, "%s: systemd-resolved returned invalid result: %s", name
, bus_error_message(&error
, r
));
324 r
= sd_bus_message_exit_container(reply
);
326 return bus_log_parse_error(r
);
328 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
)) {
329 log_debug_errno(r
, "%s: systemd-resolved returned invalid result, ignoring: %s", name
, bus_error_message(&error
, r
));
333 r
= in_addr_ifindex_to_string(family
, &a
, ifindex
, &pretty
);
335 return log_error_errno(r
, "Failed to print address for %s: %m", name
);
337 k
= printf("%*s%s %s%s%s",
338 (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? ":" : " ",
339 ansi_highlight(), pretty
, ansi_normal());
341 print_ifindex_comment(k
, ifindex
);
347 return bus_log_parse_error(r
);
349 r
= sd_bus_message_exit_container(reply
);
351 return bus_log_parse_error(r
);
353 r
= sd_bus_message_read(reply
, "st", &canonical
, &flags
);
355 return bus_log_parse_error(r
);
357 if (!streq(name
, canonical
))
358 printf("%*s%s (%s)\n",
359 (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? ":" : " ",
363 return log_error_errno(SYNTHETIC_ERRNO(ESRCH
),
364 "%s: no addresses found", name
);
366 print_source(flags
, ts
);
371 static int resolve_address(sd_bus
*bus
, int family
, const union in_addr_union
*address
, int ifindex
) {
372 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
373 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
374 _cleanup_free_
char *pretty
= NULL
;
381 assert(IN_SET(family
, AF_INET
, AF_INET6
));
384 if (sd_json_format_enabled(arg_json_format_flags
))
385 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
388 ifindex
= arg_ifindex
;
390 r
= in_addr_ifindex_to_string(family
, address
, ifindex
, &pretty
);
394 log_debug("Resolving %s.", pretty
);
396 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveAddress");
398 return bus_log_create_error(r
);
400 r
= sd_bus_message_append(req
, "ii", ifindex
, family
);
402 return bus_log_create_error(r
);
404 r
= sd_bus_message_append_array(req
, 'y', address
, FAMILY_ADDRESS_SIZE(family
));
406 return bus_log_create_error(r
);
408 r
= sd_bus_message_append(req
, "t", arg_flags
);
410 return bus_log_create_error(r
);
412 ts
= now(CLOCK_MONOTONIC
);
414 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
416 return log_error_errno(r
, "%s: resolve call failed: %s", pretty
, bus_error_message(&error
, r
));
418 ts
= now(CLOCK_MONOTONIC
) - ts
;
420 r
= sd_bus_message_enter_container(reply
, 'a', "(is)");
422 return bus_log_create_error(r
);
424 while ((r
= sd_bus_message_enter_container(reply
, 'r', "is")) > 0) {
428 assert_cc(sizeof(int) == sizeof(int32_t));
430 r
= sd_bus_message_read(reply
, "is", &ifindex
, &n
);
434 r
= sd_bus_message_exit_container(reply
);
438 k
= printf("%*s%s %s%s%s",
439 (int) strlen(pretty
), c
== 0 ? pretty
: "",
441 ansi_highlight(), n
, ansi_normal());
443 print_ifindex_comment(k
, ifindex
);
449 return bus_log_parse_error(r
);
451 r
= sd_bus_message_exit_container(reply
);
453 return bus_log_parse_error(r
);
455 r
= sd_bus_message_read(reply
, "t", &flags
);
457 return bus_log_parse_error(r
);
460 return log_error_errno(SYNTHETIC_ERRNO(ESRCH
),
461 "%s: no names found", pretty
);
463 print_source(flags
, ts
);
468 static int output_rr_packet(const void *d
, size_t l
, int ifindex
) {
469 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
474 r
= dns_resource_record_new_from_raw(&rr
, d
, l
);
476 return log_error_errno(r
, "Failed to parse RR: %m");
478 if (sd_json_format_enabled(arg_json_format_flags
)) {
479 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*j
= NULL
;
480 r
= dns_resource_record_to_json(rr
, &j
);
482 return log_error_errno(r
, "Failed to convert RR to JSON: %m");
485 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
);
487 r
= sd_json_variant_dump(j
, arg_json_format_flags
, NULL
, NULL
);
491 } else if (arg_raw
== RAW_PAYLOAD
) {
495 k
= dns_resource_record_payload(rr
, &data
);
497 return log_error_errno(k
, "Dumping of binary payload not available for RRs of this type: %s", dns_type_to_string(rr
->key
->type
));
499 return log_error_errno(k
, "Cannot dump RR: %m");
500 fwrite(data
, 1, k
, stdout
);
505 s
= dns_resource_record_to_string(rr
);
510 print_ifindex_comment(k
, ifindex
);
517 static int idna_candidate(const char *name
, char **ret
) {
518 _cleanup_free_
char *idnafied
= NULL
;
524 r
= dns_name_apply_idna(name
, &idnafied
);
526 return log_error_errno(r
, "Failed to apply IDNA to name '%s': %m", name
);
527 if (r
> 0 && !streq(name
, idnafied
)) {
528 *ret
= TAKE_PTR(idnafied
);
536 static bool single_label_nonsynthetic(const char *name
) {
537 _cleanup_free_
char *first_label
= NULL
;
540 if (!dns_name_is_single_label(name
))
543 if (is_localhost(name
) ||
544 is_gateway_hostname(name
) ||
545 is_outbound_hostname(name
) ||
546 is_dns_stub_hostname(name
) ||
547 is_dns_proxy_stub_hostname(name
))
550 r
= resolve_system_hostname(NULL
, &first_label
);
552 log_warning_errno(r
, "Failed to determine the hostname: %m");
556 return !streq(name
, first_label
);
559 static int resolve_record(sd_bus
*bus
, const char *name
, uint16_t class, uint16_t type
, bool warn_missing
) {
560 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
561 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
562 _cleanup_free_
char *idnafied
= NULL
;
563 bool needs_authentication
= false;
571 log_debug("Resolving %s %s %s (interface %s).", name
, dns_class_to_string(class), dns_type_to_string(type
), isempty(arg_ifname
) ? "*" : arg_ifname
);
573 if (dns_name_dot_suffixed(name
) == 0 && single_label_nonsynthetic(name
))
574 log_notice("(Note that search domains are not appended when --type= is specified. "
575 "Please specify fully qualified domain names, or remove --type= switch from invocation in order to request regular hostname resolution.)");
577 r
= idna_candidate(name
, &idnafied
);
581 log_notice("(Note that IDNA translation is not applied when --type= is specified. "
582 "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.",
585 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveRecord");
587 return bus_log_create_error(r
);
589 r
= sd_bus_message_append(req
, "isqqt", arg_ifindex
, name
, class, type
, arg_flags
);
591 return bus_log_create_error(r
);
593 ts
= now(CLOCK_MONOTONIC
);
595 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
597 if (warn_missing
|| r
!= -ENXIO
)
598 log_error("%s: resolve call failed: %s", name
, bus_error_message(&error
, r
));
602 ts
= now(CLOCK_MONOTONIC
) - ts
;
604 r
= sd_bus_message_enter_container(reply
, 'a', "(iqqay)");
606 return bus_log_parse_error(r
);
608 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iqqay")) > 0) {
614 assert_cc(sizeof(int) == sizeof(int32_t));
616 r
= sd_bus_message_read(reply
, "iqq", &ifindex
, &c
, &t
);
618 return bus_log_parse_error(r
);
620 r
= sd_bus_message_read_array(reply
, 'y', &d
, &l
);
622 return bus_log_parse_error(r
);
624 r
= sd_bus_message_exit_container(reply
);
626 return bus_log_parse_error(r
);
628 if (arg_raw
== RAW_PACKET
) {
629 uint64_t u64
= htole64(l
);
631 fwrite(&u64
, sizeof(u64
), 1, stdout
);
632 fwrite(d
, 1, l
, stdout
);
634 r
= output_rr_packet(d
, l
, ifindex
);
639 if (dns_type_needs_authentication(t
))
640 needs_authentication
= true;
645 return bus_log_parse_error(r
);
647 r
= sd_bus_message_exit_container(reply
);
649 return bus_log_parse_error(r
);
651 r
= sd_bus_message_read(reply
, "t", &flags
);
653 return bus_log_parse_error(r
);
657 log_error("%s: no records found", name
);
661 print_source(flags
, ts
);
663 if ((flags
& SD_RESOLVED_AUTHENTICATED
) == 0 && needs_authentication
) {
666 fprintf(stderr
, "\n%s"
667 "WARNING: The resources shown contain cryptographic key data which could not be\n"
668 " authenticated. It is not suitable to authenticate any communication.\n"
669 " This is usually indication that DNSSEC authentication was not enabled\n"
670 " or is not available for the selected protocol or DNS servers.%s\n",
671 ansi_highlight_red(),
678 static int resolve_rfc4501(sd_bus
*bus
, const char *name
) {
679 uint16_t type
= 0, class = 0;
680 const char *p
, *q
, *n
;
685 assert(startswith(name
, "dns:"));
687 /* Parse RFC 4501 dns: URIs */
697 e
= strchr(p
+ 2, '/');
702 log_warning("DNS authority specification not supported; ignoring specified authority.");
709 n
= strndupa_safe(p
, q
- p
);
715 f
= startswith_no_case(q
, "class=");
717 _cleanup_free_
char *t
= NULL
;
721 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
722 "DNS class specified twice.");
724 e
= strchrnul(f
, ';');
725 t
= strndup(f
, e
- f
);
729 r
= dns_class_from_string(t
);
731 return log_error_errno(r
, "Unknown DNS class %s.", t
);
743 f
= startswith_no_case(q
, "type=");
745 _cleanup_free_
char *t
= NULL
;
749 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
750 "DNS type specified twice.");
752 e
= strchrnul(f
, ';');
753 t
= strndup(f
, e
- f
);
757 r
= dns_type_from_string(t
);
759 return log_error_errno(r
, "Unknown DNS type %s: %m", t
);
777 class = arg_class
?: DNS_CLASS_IN
;
779 type
= arg_type
?: DNS_TYPE_A
;
781 return resolve_record(bus
, n
, class, type
, true);
784 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
785 "Invalid DNS URI: %s", name
);
788 static int verb_query(int argc
, char **argv
, void *userdata
) {
789 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
792 r
= acquire_bus(&bus
);
797 STRV_FOREACH(p
, strv_skip(argv
, 1))
798 RET_GATHER(ret
, resolve_record(bus
, *p
, arg_class
, arg_type
, true));
801 STRV_FOREACH(p
, strv_skip(argv
, 1)) {
802 if (startswith(*p
, "dns:"))
803 RET_GATHER(ret
, resolve_rfc4501(bus
, *p
));
806 union in_addr_union a
;
808 r
= in_addr_ifindex_from_string_auto(*p
, &family
, &a
, &ifindex
);
810 RET_GATHER(ret
, resolve_address(bus
, family
, &a
, ifindex
));
812 RET_GATHER(ret
, resolve_host(bus
, *p
));
819 static int resolve_service(sd_bus
*bus
, const char *name
, const char *type
, const char *domain
) {
820 const char *canonical_name
, *canonical_type
, *canonical_domain
;
821 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
, *reply
= NULL
;
822 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
833 name
= empty_to_null(name
);
834 type
= empty_to_null(type
);
837 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
);
839 log_debug("Resolving service type %s of %s (family %s, interface %s).", type
, domain
, af_to_name(arg_family
) ?: "*", isempty(arg_ifname
) ? "*" : arg_ifname
);
841 log_debug("Resolving service type %s (family %s, interface %s).", domain
, af_to_name(arg_family
) ?: "*", isempty(arg_ifname
) ? "*" : arg_ifname
);
843 r
= bus_message_new_method_call(bus
, &req
, bus_resolve_mgr
, "ResolveService");
845 return bus_log_create_error(r
);
847 r
= sd_bus_message_append(req
, "isssit", arg_ifindex
, name
, type
, domain
, arg_family
, arg_flags
);
849 return bus_log_create_error(r
);
851 ts
= now(CLOCK_MONOTONIC
);
853 r
= sd_bus_call(bus
, req
, SD_RESOLVED_QUERY_TIMEOUT_USEC
, &error
, &reply
);
855 return log_error_errno(r
, "Resolve call failed: %s", bus_error_message(&error
, r
));
857 ts
= now(CLOCK_MONOTONIC
) - ts
;
859 r
= sd_bus_message_enter_container(reply
, 'a', "(qqqsa(iiay)s)");
861 return bus_log_parse_error(r
);
864 (name
? strlen(name
) + 1 : 0) +
865 (type
? strlen(type
) + 1 : 0) +
869 while ((r
= sd_bus_message_enter_container(reply
, 'r', "qqqsa(iiay)s")) > 0) {
870 uint16_t priority
, weight
, port
;
871 const char *hostname
, *canonical
;
873 r
= sd_bus_message_read(reply
, "qqqs", &priority
, &weight
, &port
, &hostname
);
875 return bus_log_parse_error(r
);
878 printf("%*s%s", (int) strlen(name
), c
== 0 ? name
: "", c
== 0 ? "/" : " ");
880 printf("%*s%s", (int) strlen(type
), c
== 0 ? type
: "", c
== 0 ? "/" : " ");
882 printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
883 (int) strlen(domain
), c
== 0 ? domain
: "",
888 r
= sd_bus_message_enter_container(reply
, 'a', "(iiay)");
890 return bus_log_parse_error(r
);
892 while ((r
= sd_bus_message_enter_container(reply
, 'r', "iiay")) > 0) {
893 _cleanup_free_
char *pretty
= NULL
;
894 int ifindex
, family
, k
;
895 union in_addr_union a
;
897 assert_cc(sizeof(int) == sizeof(int32_t));
899 r
= sd_bus_message_read(reply
, "i", &ifindex
);
901 return bus_log_parse_error(r
);
903 sd_bus_error_free(&error
);
904 r
= bus_message_read_in_addr_auto(reply
, &error
, &family
, &a
);
905 if (r
< 0 && !sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
))
906 return log_error_errno(r
, "%s: systemd-resolved returned invalid result: %s", name
, bus_error_message(&error
, r
));
908 r
= sd_bus_message_exit_container(reply
);
910 return bus_log_parse_error(r
);
912 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
)) {
913 log_debug_errno(r
, "%s: systemd-resolved returned invalid result, ignoring: %s", name
, bus_error_message(&error
, r
));
917 r
= in_addr_ifindex_to_string(family
, &a
, ifindex
, &pretty
);
919 return log_error_errno(r
, "Failed to print address for %s: %m", name
);
921 k
= printf("%*s%s", (int) indent
, "", pretty
);
922 print_ifindex_comment(k
, ifindex
);
926 return bus_log_parse_error(r
);
928 r
= sd_bus_message_exit_container(reply
);
930 return bus_log_parse_error(r
);
932 r
= sd_bus_message_read(reply
, "s", &canonical
);
934 return bus_log_parse_error(r
);
936 if (!streq(hostname
, canonical
))
937 printf("%*s(%s)\n", (int) indent
, "", canonical
);
939 r
= sd_bus_message_exit_container(reply
);
941 return bus_log_parse_error(r
);
946 return bus_log_parse_error(r
);
948 r
= sd_bus_message_exit_container(reply
);
950 return bus_log_parse_error(r
);
952 r
= sd_bus_message_enter_container(reply
, 'a', "ay");
954 return bus_log_parse_error(r
);
956 while ((r
= sd_bus_message_read_array(reply
, 'y', (const void**) &p
, &sz
)) > 0) {
957 _cleanup_free_
char *escaped
= NULL
;
959 escaped
= cescape_length(p
, sz
);
963 printf("%*s%s\n", (int) indent
, "", escaped
);
966 return bus_log_parse_error(r
);
968 r
= sd_bus_message_exit_container(reply
);
970 return bus_log_parse_error(r
);
972 r
= sd_bus_message_read(reply
, "ssst", &canonical_name
, &canonical_type
, &canonical_domain
, &flags
);
974 return bus_log_parse_error(r
);
976 canonical_name
= empty_to_null(canonical_name
);
977 canonical_type
= empty_to_null(canonical_type
);
979 if (!streq_ptr(name
, canonical_name
) ||
980 !streq_ptr(type
, canonical_type
) ||
981 !streq_ptr(domain
, canonical_domain
)) {
983 printf("%*s(", (int) indent
, "");
986 printf("%s/", canonical_name
);
988 printf("%s/", canonical_type
);
990 printf("%s)\n", canonical_domain
);
993 print_source(flags
, ts
);
998 static int verb_service(int argc
, char **argv
, void *userdata
) {
999 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1002 r
= acquire_bus(&bus
);
1006 if (sd_json_format_enabled(arg_json_format_flags
))
1007 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
1010 return resolve_service(bus
, NULL
, NULL
, argv
[1]);
1012 return resolve_service(bus
, NULL
, argv
[1], argv
[2]);
1014 return resolve_service(bus
, argv
[1], argv
[2], argv
[3]);
1017 static int resolve_openpgp(sd_bus
*bus
, const char *address
) {
1018 const char *domain
, *full
;
1020 _cleanup_free_
char *hashed
= NULL
;
1025 domain
= strrchr(address
, '@');
1027 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1028 "Address does not contain '@': \"%s\"", address
);
1029 if (domain
== address
|| domain
[1] == '\0')
1030 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
1031 "Address starts or ends with '@': \"%s\"", address
);
1034 r
= string_hashsum_sha256(address
, domain
- 1 - address
, &hashed
);
1036 return log_error_errno(r
, "Hashing failed: %m");
1038 strshorten(hashed
, 56);
1040 full
= strjoina(hashed
, "._openpgpkey.", domain
);
1041 log_debug("Looking up \"%s\".", full
);
1043 r
= resolve_record(bus
, full
,
1044 arg_class
?: DNS_CLASS_IN
,
1045 arg_type
?: DNS_TYPE_OPENPGPKEY
, false);
1047 if (IN_SET(r
, -ENXIO
, -ESRCH
)) { /* NXDOMAIN or NODATA? */
1048 hashed
= mfree(hashed
);
1049 r
= string_hashsum_sha224(address
, domain
- 1 - address
, &hashed
);
1051 return log_error_errno(r
, "Hashing failed: %m");
1053 full
= strjoina(hashed
, "._openpgpkey.", domain
);
1054 log_debug("Looking up \"%s\".", full
);
1056 return resolve_record(bus
, full
,
1057 arg_class
?: DNS_CLASS_IN
,
1058 arg_type
?: DNS_TYPE_OPENPGPKEY
, true);
1064 static int verb_openpgp(int argc
, char **argv
, void *userdata
) {
1065 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1068 r
= acquire_bus(&bus
);
1072 if (sd_json_format_enabled(arg_json_format_flags
))
1073 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
1075 STRV_FOREACH(p
, strv_skip(argv
, 1))
1076 RET_GATHER(ret
, resolve_openpgp(bus
, *p
));
1081 static int resolve_tlsa(sd_bus
*bus
, const char *family
, const char *address
) {
1083 uint16_t port_num
= 443;
1084 _cleanup_free_
char *full
= NULL
;
1090 port
= strrchr(address
, ':');
1092 r
= parse_ip_port(port
+ 1, &port_num
);
1094 return log_error_errno(r
, "Invalid port \"%s\".", port
+ 1);
1096 address
= strndupa_safe(address
, port
- address
);
1099 r
= asprintf(&full
, "_%u._%s.%s",
1106 log_debug("Looking up \"%s\".", full
);
1108 return resolve_record(bus
, full
,
1109 arg_class
?: DNS_CLASS_IN
,
1110 arg_type
?: DNS_TYPE_TLSA
, true);
1113 static bool service_family_is_valid(const char *s
) {
1114 return STR_IN_SET(s
, "tcp", "udp", "sctp");
1117 static int verb_tlsa(int argc
, char **argv
, void *userdata
) {
1118 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1119 const char *family
= "tcp";
1125 r
= acquire_bus(&bus
);
1129 if (sd_json_format_enabled(arg_json_format_flags
))
1130 return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP
), "Use --json=pretty with --type= to acquire resource record information in JSON format.");
1132 if (service_family_is_valid(argv
[1])) {
1134 args
= strv_skip(argv
, 2);
1136 args
= strv_skip(argv
, 1);
1138 STRV_FOREACH(p
, args
)
1139 RET_GATHER(ret
, resolve_tlsa(bus
, family
, *p
));
1144 static int show_statistics(int argc
, char **argv
, void *userdata
) {
1145 _cleanup_(table_unrefp
) Table
*table
= NULL
;
1146 sd_json_variant
*reply
= NULL
;
1147 _cleanup_(sd_varlink_unrefp
) sd_varlink
*vl
= NULL
;
1150 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
1152 r
= sd_varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
1154 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
1156 r
= varlink_callbo_and_log(
1158 "io.systemd.Resolve.Monitor.DumpStatistics",
1160 SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password
));
1164 if (sd_json_format_enabled(arg_json_format_flags
))
1165 return sd_json_variant_dump(reply
, arg_json_format_flags
, NULL
, NULL
);
1168 sd_json_variant
*transactions
;
1169 sd_json_variant
*cache
;
1170 sd_json_variant
*dnssec
;
1173 static const sd_json_dispatch_field statistics_dispatch_table
[] = {
1174 { "transactions", SD_JSON_VARIANT_OBJECT
, sd_json_dispatch_variant_noref
, offsetof(struct statistics
, transactions
), SD_JSON_MANDATORY
},
1175 { "cache", SD_JSON_VARIANT_OBJECT
, sd_json_dispatch_variant_noref
, offsetof(struct statistics
, cache
), SD_JSON_MANDATORY
},
1176 { "dnssec", SD_JSON_VARIANT_OBJECT
, sd_json_dispatch_variant_noref
, offsetof(struct statistics
, dnssec
), SD_JSON_MANDATORY
},
1180 r
= sd_json_dispatch(reply
, statistics_dispatch_table
, SD_JSON_LOG
, &statistics
);
1184 struct transactions
{
1185 uint64_t n_current_transactions
;
1186 uint64_t n_transactions_total
;
1187 uint64_t n_timeouts_total
;
1188 uint64_t n_timeouts_served_stale_total
;
1189 uint64_t n_failure_responses_total
;
1190 uint64_t n_failure_responses_served_stale_total
;
1193 static const sd_json_dispatch_field transactions_dispatch_table
[] = {
1194 { "currentTransactions", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct transactions
, n_current_transactions
), SD_JSON_MANDATORY
},
1195 { "totalTransactions", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct transactions
, n_transactions_total
), SD_JSON_MANDATORY
},
1196 { "totalTimeouts", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct transactions
, n_timeouts_total
), SD_JSON_MANDATORY
},
1197 { "totalTimeoutsServedStale", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct transactions
, n_timeouts_served_stale_total
), SD_JSON_MANDATORY
},
1198 { "totalFailedResponses", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct transactions
, n_failure_responses_total
), SD_JSON_MANDATORY
},
1199 { "totalFailedResponsesServedStale", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct transactions
, n_failure_responses_served_stale_total
), SD_JSON_MANDATORY
},
1203 r
= sd_json_dispatch(statistics
.transactions
, transactions_dispatch_table
, SD_JSON_LOG
, &transactions
);
1208 uint64_t cache_size
;
1209 uint64_t n_cache_hit
;
1210 uint64_t n_cache_miss
;
1213 static const sd_json_dispatch_field cache_dispatch_table
[] = {
1214 { "size", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct cache
, cache_size
), SD_JSON_MANDATORY
},
1215 { "hits", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct cache
, n_cache_hit
), SD_JSON_MANDATORY
},
1216 { "misses", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct cache
, n_cache_miss
), SD_JSON_MANDATORY
},
1220 r
= sd_json_dispatch(statistics
.cache
, cache_dispatch_table
, SD_JSON_LOG
, &cache
);
1225 uint64_t n_dnssec_secure
;
1226 uint64_t n_dnssec_insecure
;
1227 uint64_t n_dnssec_bogus
;
1228 uint64_t n_dnssec_indeterminate
;
1231 static const sd_json_dispatch_field dnssec_dispatch_table
[] = {
1232 { "secure", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct dnsssec
, n_dnssec_secure
), SD_JSON_MANDATORY
},
1233 { "insecure", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct dnsssec
, n_dnssec_insecure
), SD_JSON_MANDATORY
},
1234 { "bogus", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct dnsssec
, n_dnssec_bogus
), SD_JSON_MANDATORY
},
1235 { "indeterminate", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct dnsssec
, n_dnssec_indeterminate
), SD_JSON_MANDATORY
},
1239 r
= sd_json_dispatch(statistics
.dnssec
, dnssec_dispatch_table
, SD_JSON_LOG
, &dnsssec
);
1243 table
= table_new_vertical();
1247 r
= table_add_many(table
,
1248 TABLE_STRING
, "Transactions",
1249 TABLE_SET_COLOR
, ansi_highlight(),
1250 TABLE_SET_ALIGN_PERCENT
, 0,
1252 TABLE_FIELD
, "Current Transactions",
1253 TABLE_SET_ALIGN_PERCENT
, 100,
1254 TABLE_UINT64
, transactions
.n_current_transactions
,
1255 TABLE_SET_ALIGN_PERCENT
, 100,
1256 TABLE_FIELD
, "Total Transactions",
1257 TABLE_UINT64
, transactions
.n_transactions_total
,
1258 TABLE_EMPTY
, TABLE_EMPTY
,
1259 TABLE_STRING
, "Cache",
1260 TABLE_SET_COLOR
, ansi_highlight(),
1261 TABLE_SET_ALIGN_PERCENT
, 0,
1263 TABLE_FIELD
, "Current Cache Size",
1264 TABLE_SET_ALIGN_PERCENT
, 100,
1265 TABLE_UINT64
, cache
.cache_size
,
1266 TABLE_FIELD
, "Cache Hits",
1267 TABLE_UINT64
, cache
.n_cache_hit
,
1268 TABLE_FIELD
, "Cache Misses",
1269 TABLE_UINT64
, cache
.n_cache_miss
,
1270 TABLE_EMPTY
, TABLE_EMPTY
,
1271 TABLE_STRING
, "Failure Transactions",
1272 TABLE_SET_COLOR
, ansi_highlight(),
1273 TABLE_SET_ALIGN_PERCENT
, 0,
1275 TABLE_FIELD
, "Total Timeouts",
1276 TABLE_SET_ALIGN_PERCENT
, 100,
1277 TABLE_UINT64
, transactions
.n_timeouts_total
,
1278 TABLE_FIELD
, "Total Timeouts (Stale Data Served)",
1279 TABLE_UINT64
, transactions
.n_timeouts_served_stale_total
,
1280 TABLE_FIELD
, "Total Failure Responses",
1281 TABLE_UINT64
, transactions
.n_failure_responses_total
,
1282 TABLE_FIELD
, "Total Failure Responses (Stale Data Served)",
1283 TABLE_UINT64
, transactions
.n_failure_responses_served_stale_total
,
1284 TABLE_EMPTY
, TABLE_EMPTY
,
1285 TABLE_STRING
, "DNSSEC Verdicts",
1286 TABLE_SET_COLOR
, ansi_highlight(),
1287 TABLE_SET_ALIGN_PERCENT
, 0,
1289 TABLE_FIELD
, "Secure",
1290 TABLE_SET_ALIGN_PERCENT
, 100,
1291 TABLE_UINT64
, dnsssec
.n_dnssec_secure
,
1292 TABLE_FIELD
, "Insecure",
1293 TABLE_UINT64
, dnsssec
.n_dnssec_insecure
,
1294 TABLE_FIELD
, "Bogus",
1295 TABLE_UINT64
, dnsssec
.n_dnssec_bogus
,
1296 TABLE_FIELD
, "Indeterminate",
1297 TABLE_UINT64
, dnsssec
.n_dnssec_indeterminate
1300 return table_log_add_error(r
);
1302 r
= table_print(table
, NULL
);
1304 return table_log_print_error(r
);
1309 static int reset_statistics(int argc
, char **argv
, void *userdata
) {
1310 sd_json_variant
*reply
= NULL
;
1311 _cleanup_(sd_varlink_unrefp
) sd_varlink
*vl
= NULL
;
1314 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
1316 r
= sd_varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
1318 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
1320 r
= varlink_callbo_and_log(
1322 "io.systemd.Resolve.Monitor.ResetStatistics",
1324 SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password
));
1328 if (sd_json_format_enabled(arg_json_format_flags
))
1329 return sd_json_variant_dump(reply
, arg_json_format_flags
, NULL
, NULL
);
1334 static int flush_caches(int argc
, char **argv
, void *userdata
) {
1335 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1336 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1339 r
= acquire_bus(&bus
);
1343 r
= bus_call_method(bus
, bus_resolve_mgr
, "FlushCaches", &error
, NULL
, NULL
);
1345 return log_error_errno(r
, "Failed to flush caches: %s", bus_error_message(&error
, r
));
1350 static int reset_server_features(int argc
, char **argv
, void *userdata
) {
1351 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
1352 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1355 r
= acquire_bus(&bus
);
1359 r
= bus_call_method(bus
, bus_resolve_mgr
, "ResetServerFeatures", &error
, NULL
, NULL
);
1361 return log_error_errno(r
, "Failed to reset server features: %s", bus_error_message(&error
, r
));
1367 READ_DNS_WITH_IFINDEX
= 1 << 0, /* read "ifindex" reply that also carries an interface index */
1368 READ_DNS_EXTENDED
= 1 << 1, /* read "extended" reply, i.e. with port number and server name */
1369 READ_DNS_ONLY_GLOBAL
= 1 << 2, /* suppress entries with an (non-loopback) ifindex set (i.e. which are specific to some interface) */
1372 static const char *dns_server_property_signature(ReadDNSFlag flags
) {
1373 switch (flags
& (READ_DNS_WITH_IFINDEX
|READ_DNS_EXTENDED
)) {
1378 case READ_DNS_WITH_IFINDEX
:
1381 case READ_DNS_EXTENDED
:
1384 case READ_DNS_WITH_IFINDEX
|READ_DNS_EXTENDED
:
1388 assert_not_reached();
1392 static int read_dns_server_one(sd_bus_message
*m
, ReadDNSFlag flags
, char **ret
) {
1393 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1394 _cleanup_free_
char *pretty
= NULL
;
1395 union in_addr_union a
;
1396 const char *name
= NULL
;
1397 int32_t ifindex
= 0;
1404 r
= sd_bus_message_enter_container(
1407 dns_server_property_signature(flags
));
1411 if (FLAGS_SET(flags
, READ_DNS_WITH_IFINDEX
)) {
1412 r
= sd_bus_message_read(m
, "i", &ifindex
);
1417 r
= bus_message_read_in_addr_auto(m
, &error
, &family
, &a
);
1419 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_INVALID_ARGS
)) {
1420 /* CurrentDNSServer provides AF_UNSPEC when no current server assigned. */
1421 log_debug("Invalid DNS server, ignoring: %s", bus_error_message(&error
, r
));
1424 r
= sd_bus_message_skip(m
, NULL
);
1425 if (r
== -ENXIO
) /* End of the container */
1431 r
= sd_bus_message_exit_container(m
);
1442 if (FLAGS_SET(flags
, READ_DNS_EXTENDED
)) {
1443 r
= sd_bus_message_read(m
, "qs", &port
, &name
);
1448 r
= sd_bus_message_exit_container(m
);
1452 if (FLAGS_SET(flags
, READ_DNS_ONLY_GLOBAL
) && ifindex
> 0 && ifindex
!= LOOPBACK_IFINDEX
) {
1453 /* This one has an (non-loopback) ifindex set, and we were told to suppress those. Hence do so. */
1458 r
= in_addr_port_ifindex_name_to_string(family
, &a
, port
, ifindex
, name
, &pretty
);
1462 *ret
= TAKE_PTR(pretty
);
1466 static int map_dns_servers_internal(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, ReadDNSFlag flags
, sd_bus_error
*error
, void *userdata
) {
1467 char ***l
= ASSERT_PTR(userdata
);
1474 const char *sig
= strjoina("(", dns_server_property_signature(flags
), ")");
1476 r
= sd_bus_message_enter_container(m
, 'a', sig
);
1481 _cleanup_free_
char *pretty
= NULL
;
1483 r
= read_dns_server_one(m
, flags
, &pretty
);
1489 if (isempty(pretty
))
1492 r
= strv_consume(l
, TAKE_PTR(pretty
));
1497 r
= sd_bus_message_exit_container(m
);
1504 static int map_link_dns_servers(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1505 return map_dns_servers_internal(bus
, member
, m
, /* flags = */ 0, error
, userdata
);
1508 static int map_link_dns_servers_ex(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1509 return map_dns_servers_internal(bus
, member
, m
, READ_DNS_EXTENDED
, error
, userdata
);
1512 static int map_link_current_dns_server(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1516 return read_dns_server_one(m
, /* flags = */ 0, userdata
);
1519 static int map_link_current_dns_server_ex(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1523 return read_dns_server_one(m
, READ_DNS_EXTENDED
, userdata
);
1526 static int read_domain_one(sd_bus_message
*m
, bool with_ifindex
, char **ret
) {
1527 _cleanup_free_
char *str
= NULL
;
1528 int ifindex
, route_only
, r
;
1535 r
= sd_bus_message_read(m
, "(isb)", &ifindex
, &domain
, &route_only
);
1537 r
= sd_bus_message_read(m
, "(sb)", &domain
, &route_only
);
1541 if (with_ifindex
&& ifindex
!= 0) {
1542 /* only show the global ones here */
1548 str
= strjoin("~", domain
);
1550 str
= strdup(domain
);
1554 *ret
= TAKE_PTR(str
);
1558 static int map_domains_internal(
1563 sd_bus_error
*error
,
1566 char ***l
= ASSERT_PTR(userdata
);
1573 r
= sd_bus_message_enter_container(m
, 'a', with_ifindex
? "(isb)" : "(sb)");
1578 _cleanup_free_
char *pretty
= NULL
;
1580 r
= read_domain_one(m
, with_ifindex
, &pretty
);
1586 if (isempty(pretty
))
1589 r
= strv_consume(l
, TAKE_PTR(pretty
));
1594 r
= sd_bus_message_exit_container(m
);
1601 static int map_link_domains(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
1602 return map_domains_internal(bus
, member
, m
, /* with_ifindex= */ false, error
, userdata
);
1605 static int status_print_strv_full(int ifindex
, const char *ifname
, const char *delegate_id
, char **p
) {
1606 const unsigned indent
= strlen("Global: "); /* Use the same indentation everywhere to make things nice */
1610 printf("%s%nLink %i (%s)%n%s:", ansi_highlight(), &pos1
, ifindex
, ifname
, &pos2
, ansi_normal());
1611 else if (delegate_id
)
1612 printf("%s%nDelegate %s%n%s:", ansi_highlight(), &pos1
, delegate_id
, &pos2
, ansi_normal());
1614 printf("%s%nGlobal%n%s:", ansi_highlight(), &pos1
, &pos2
, ansi_normal());
1616 size_t cols
= columns(), position
= pos2
- pos1
+ 2;
1618 STRV_FOREACH(i
, p
) {
1619 size_t our_len
= utf8_console_width(*i
); /* This returns -1 on invalid utf-8 (which shouldn't happen).
1620 * If that happens, we'll just print one item per line. */
1622 if (position
<= indent
|| size_add(size_add(position
, 1), our_len
) < cols
) {
1624 position
= size_add(size_add(position
, 1), our_len
);
1626 printf("\n%*s%s", (int) indent
, "", *i
);
1627 position
= size_add(our_len
, indent
);
1636 static int status_print_strv_ifindex(int ifindex
, const char *ifname
, char **p
) {
1637 return status_print_strv_full(ifindex
, ifname
, NULL
, p
);
1640 static int status_print_strv_delegate(const char *delegate_id
, char **p
) {
1641 return status_print_strv_full(0, NULL
, delegate_id
, p
);
1644 static int status_print_strv_global(char **p
) {
1645 return status_print_strv_full(0, NULL
, NULL
, p
);
1648 typedef struct LinkInfo
{
1649 uint64_t scopes_mask
;
1652 const char *dns_over_tls
;
1655 char *current_dns_ex
;
1660 bool dnssec_supported
;
1664 typedef struct GlobalInfo
{
1666 char *current_dns_ex
;
1669 char **fallback_dns
;
1670 char **fallback_dns_ex
;
1675 const char *dns_over_tls
;
1677 const char *resolv_conf_mode
;
1678 bool dnssec_supported
;
1681 static void link_info_done(LinkInfo
*p
) {
1684 free(p
->current_dns
);
1685 free(p
->current_dns_ex
);
1687 strv_free(p
->dns_ex
);
1688 strv_free(p
->domains
);
1692 static void global_info_done(GlobalInfo
*p
) {
1695 free(p
->current_dns
);
1696 free(p
->current_dns_ex
);
1698 strv_free(p
->dns_ex
);
1699 strv_free(p
->fallback_dns
);
1700 strv_free(p
->fallback_dns_ex
);
1701 strv_free(p
->domains
);
1705 static int dump_list(Table
*table
, const char *field
, char * const *l
) {
1708 if (strv_isempty(l
))
1711 r
= table_add_many(table
,
1713 TABLE_STRV_WRAPPED
, l
);
1715 return table_log_add_error(r
);
1720 static int strv_extend_extended_bool(char ***strv
, const char *name
, const char *value
) {
1724 r
= parse_boolean(value
);
1726 return strv_extendf(strv
, "%s%s", plus_minus(r
), name
);
1729 return strv_extendf(strv
, "%s=%s", name
, value
?: "???");
1732 static char** link_protocol_status(const LinkInfo
*info
) {
1733 _cleanup_strv_free_
char **s
= NULL
;
1735 if (strv_extendf(&s
, "%sDefaultRoute", plus_minus(info
->default_route
)) < 0)
1738 if (strv_extend_extended_bool(&s
, "LLMNR", info
->llmnr
) < 0)
1741 if (strv_extend_extended_bool(&s
, "mDNS", info
->mdns
) < 0)
1744 if (strv_extend_extended_bool(&s
, "DNSOverTLS", info
->dns_over_tls
) < 0)
1747 if (strv_extendf(&s
, "DNSSEC=%s/%s",
1748 info
->dnssec
?: "???",
1749 info
->dnssec_supported
? "supported" : "unsupported") < 0)
1755 static char** global_protocol_status(const GlobalInfo
*info
) {
1756 _cleanup_strv_free_
char **s
= NULL
;
1758 if (strv_extend_extended_bool(&s
, "LLMNR", info
->llmnr
) < 0)
1761 if (strv_extend_extended_bool(&s
, "mDNS", info
->mdns
) < 0)
1764 if (strv_extend_extended_bool(&s
, "DNSOverTLS", info
->dns_over_tls
) < 0)
1767 if (strv_extendf(&s
, "DNSSEC=%s/%s",
1768 info
->dnssec
?: "???",
1769 info
->dnssec_supported
? "supported" : "unsupported") < 0)
1775 static int status_ifindex(sd_bus
*bus
, int ifindex
, const char *name
, StatusMode mode
, bool *empty_line
) {
1776 static const struct bus_properties_map property_map
[] = {
1777 { "ScopesMask", "t", NULL
, offsetof(LinkInfo
, scopes_mask
) },
1778 { "DNS", "a(iay)", map_link_dns_servers
, offsetof(LinkInfo
, dns
) },
1779 { "DNSEx", "a(iayqs)", map_link_dns_servers_ex
, offsetof(LinkInfo
, dns_ex
) },
1780 { "CurrentDNSServer", "(iay)", map_link_current_dns_server
, offsetof(LinkInfo
, current_dns
) },
1781 { "CurrentDNSServerEx", "(iayqs)", map_link_current_dns_server_ex
, offsetof(LinkInfo
, current_dns_ex
) },
1782 { "Domains", "a(sb)", map_link_domains
, offsetof(LinkInfo
, domains
) },
1783 { "DefaultRoute", "b", NULL
, offsetof(LinkInfo
, default_route
) },
1784 { "LLMNR", "s", NULL
, offsetof(LinkInfo
, llmnr
) },
1785 { "MulticastDNS", "s", NULL
, offsetof(LinkInfo
, mdns
) },
1786 { "DNSOverTLS", "s", NULL
, offsetof(LinkInfo
, dns_over_tls
) },
1787 { "DNSSEC", "s", NULL
, offsetof(LinkInfo
, dnssec
) },
1788 { "DNSSECNegativeTrustAnchors", "as", bus_map_strv_sort
, offsetof(LinkInfo
, ntas
) },
1789 { "DNSSECSupported", "b", NULL
, offsetof(LinkInfo
, dnssec_supported
) },
1792 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1793 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
1794 _cleanup_(link_info_done
) LinkInfo link_info
= {};
1795 _cleanup_(table_unrefp
) Table
*table
= NULL
;
1796 _cleanup_free_
char *p
= NULL
;
1797 char ifi
[DECIMAL_STR_MAX(int)], ifname
[IF_NAMESIZE
];
1801 assert(ifindex
> 0);
1804 r
= format_ifname(ifindex
, ifname
);
1806 return log_error_errno(r
, "Failed to resolve interface name for %i: %m", ifindex
);
1811 xsprintf(ifi
, "%i", ifindex
);
1812 r
= sd_bus_path_encode("/org/freedesktop/resolve1/link", ifi
, &p
);
1816 r
= bus_map_all_properties(bus
,
1817 "org.freedesktop.resolve1",
1820 BUS_MAP_BOOLEAN_AS_BOOL
,
1825 return log_error_errno(r
, "Failed to get link data for %i: %s", ifindex
, bus_error_message(&error
, r
));
1827 pager_open(arg_pager_flags
);
1832 return status_print_strv_ifindex(ifindex
, name
, link_info
.dns_ex
?: link_info
.dns
);
1835 return status_print_strv_ifindex(ifindex
, name
, link_info
.domains
);
1838 return status_print_strv_ifindex(ifindex
, name
, link_info
.ntas
);
1840 case STATUS_DEFAULT_ROUTE
:
1841 printf("%sLink %i (%s)%s: %s\n",
1842 ansi_highlight(), ifindex
, name
, ansi_normal(),
1843 yes_no(link_info
.default_route
));
1848 printf("%sLink %i (%s)%s: %s\n",
1849 ansi_highlight(), ifindex
, name
, ansi_normal(),
1850 strna(link_info
.llmnr
));
1855 printf("%sLink %i (%s)%s: %s\n",
1856 ansi_highlight(), ifindex
, name
, ansi_normal(),
1857 strna(link_info
.mdns
));
1861 case STATUS_PRIVATE
:
1862 printf("%sLink %i (%s)%s: %s\n",
1863 ansi_highlight(), ifindex
, name
, ansi_normal(),
1864 strna(link_info
.dns_over_tls
));
1869 printf("%sLink %i (%s)%s: %s\n",
1870 ansi_highlight(), ifindex
, name
, ansi_normal(),
1871 strna(link_info
.dnssec
));
1882 if (empty_line
&& *empty_line
)
1883 fputc('\n', stdout
);
1885 printf("%sLink %i (%s)%s\n",
1886 ansi_highlight(), ifindex
, name
, ansi_normal());
1888 table
= table_new_vertical();
1892 r
= table_add_many(table
,
1893 TABLE_FIELD
, "Current Scopes",
1894 TABLE_SET_MINIMUM_WIDTH
, 19);
1896 return table_log_add_error(r
);
1898 if (link_info
.scopes_mask
== 0)
1899 r
= table_add_cell(table
, NULL
, TABLE_STRING
, "none");
1901 _cleanup_free_
char *buf
= NULL
;
1904 if (asprintf(&buf
, "%s%s%s%s%s",
1905 link_info
.scopes_mask
& SD_RESOLVED_DNS
? "DNS " : "",
1906 link_info
.scopes_mask
& SD_RESOLVED_LLMNR_IPV4
? "LLMNR/IPv4 " : "",
1907 link_info
.scopes_mask
& SD_RESOLVED_LLMNR_IPV6
? "LLMNR/IPv6 " : "",
1908 link_info
.scopes_mask
& SD_RESOLVED_MDNS_IPV4
? "mDNS/IPv4 " : "",
1909 link_info
.scopes_mask
& SD_RESOLVED_MDNS_IPV6
? "mDNS/IPv6 " : "") < 0)
1914 buf
[len
- 1] = '\0';
1916 r
= table_add_cell(table
, NULL
, TABLE_STRING
, buf
);
1919 return table_log_add_error(r
);
1921 _cleanup_strv_free_
char **pstatus
= link_protocol_status(&link_info
);
1925 r
= table_add_many(table
,
1926 TABLE_FIELD
, "Protocols",
1927 TABLE_STRV_WRAPPED
, pstatus
);
1929 return table_log_add_error(r
);
1931 if (link_info
.current_dns
) {
1932 r
= table_add_many(table
,
1933 TABLE_FIELD
, "Current DNS Server",
1934 TABLE_STRING
, link_info
.current_dns_ex
?: link_info
.current_dns
);
1936 return table_log_add_error(r
);
1939 r
= dump_list(table
, "DNS Servers", link_info
.dns_ex
?: link_info
.dns
);
1943 r
= dump_list(table
, "DNS Domain", link_info
.domains
);
1947 r
= table_add_many(table
,
1948 TABLE_FIELD
, "Default Route",
1949 TABLE_BOOLEAN
, link_info
.default_route
);
1951 return table_log_add_error(r
);
1953 r
= table_print(table
, NULL
);
1955 return table_log_print_error(r
);
1963 static int map_global_dns_servers_internal(
1967 sd_bus_error
*error
,
1969 ReadDNSFlag flags
) {
1971 char ***l
= ASSERT_PTR(userdata
);
1978 r
= sd_bus_message_enter_container(m
, 'a', FLAGS_SET(flags
, READ_DNS_EXTENDED
) ? "(iiayqs)" : "(iiay)");
1983 _cleanup_free_
char *pretty
= NULL
;
1985 r
= read_dns_server_one(m
, flags
, &pretty
);
1991 if (isempty(pretty
))
1994 r
= strv_consume(l
, TAKE_PTR(pretty
));
1999 r
= sd_bus_message_exit_container(m
);
2006 static int map_global_dns_servers(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2007 return map_global_dns_servers_internal(bus
, member
, m
, error
, userdata
, READ_DNS_WITH_IFINDEX
| READ_DNS_ONLY_GLOBAL
);
2010 static int map_global_dns_servers_ex(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2011 return map_global_dns_servers_internal(bus
, member
, m
, error
, userdata
, READ_DNS_WITH_IFINDEX
| READ_DNS_ONLY_GLOBAL
| READ_DNS_EXTENDED
);
2014 static int map_global_current_dns_server(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2015 return read_dns_server_one(m
, READ_DNS_WITH_IFINDEX
| READ_DNS_ONLY_GLOBAL
, userdata
);
2018 static int map_global_current_dns_server_ex(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2019 return read_dns_server_one(m
, READ_DNS_WITH_IFINDEX
| READ_DNS_ONLY_GLOBAL
| READ_DNS_EXTENDED
, userdata
);
2022 static int map_global_domains(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2023 return map_domains_internal(bus
, member
, m
, /* with_ifindex= */ true, error
, userdata
);
2026 static int status_global(sd_bus
*bus
, StatusMode mode
, bool *empty_line
) {
2027 static const struct bus_properties_map property_map
[] = {
2028 { "DNS", "a(iiay)", map_global_dns_servers
, offsetof(GlobalInfo
, dns
) },
2029 { "DNSEx", "a(iiayqs)", map_global_dns_servers_ex
, offsetof(GlobalInfo
, dns_ex
) },
2030 { "FallbackDNS", "a(iiay)", map_global_dns_servers
, offsetof(GlobalInfo
, fallback_dns
) },
2031 { "FallbackDNSEx", "a(iiayqs)", map_global_dns_servers_ex
, offsetof(GlobalInfo
, fallback_dns_ex
) },
2032 { "CurrentDNSServer", "(iiay)", map_global_current_dns_server
, offsetof(GlobalInfo
, current_dns
) },
2033 { "CurrentDNSServerEx", "(iiayqs)", map_global_current_dns_server_ex
, offsetof(GlobalInfo
, current_dns_ex
) },
2034 { "Domains", "a(isb)", map_global_domains
, offsetof(GlobalInfo
, domains
) },
2035 { "DNSSECNegativeTrustAnchors", "as", bus_map_strv_sort
, offsetof(GlobalInfo
, ntas
) },
2036 { "LLMNR", "s", NULL
, offsetof(GlobalInfo
, llmnr
) },
2037 { "MulticastDNS", "s", NULL
, offsetof(GlobalInfo
, mdns
) },
2038 { "DNSOverTLS", "s", NULL
, offsetof(GlobalInfo
, dns_over_tls
) },
2039 { "DNSSEC", "s", NULL
, offsetof(GlobalInfo
, dnssec
) },
2040 { "DNSSECSupported", "b", NULL
, offsetof(GlobalInfo
, dnssec_supported
) },
2041 { "ResolvConfMode", "s", NULL
, offsetof(GlobalInfo
, resolv_conf_mode
) },
2044 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2045 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
2046 _cleanup_(global_info_done
) GlobalInfo global_info
= {};
2047 _cleanup_(table_unrefp
) Table
*table
= NULL
;
2053 r
= bus_map_all_properties(bus
,
2054 "org.freedesktop.resolve1",
2055 "/org/freedesktop/resolve1",
2057 BUS_MAP_BOOLEAN_AS_BOOL
,
2062 return log_error_errno(r
, "Failed to get global data: %s", bus_error_message(&error
, r
));
2064 pager_open(arg_pager_flags
);
2069 return status_print_strv_global(global_info
.dns_ex
?: global_info
.dns
);
2072 return status_print_strv_global(global_info
.domains
);
2075 return status_print_strv_global(global_info
.ntas
);
2078 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
2079 strna(global_info
.llmnr
));
2084 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
2085 strna(global_info
.mdns
));
2089 case STATUS_PRIVATE
:
2090 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
2091 strna(global_info
.dns_over_tls
));
2096 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
2097 strna(global_info
.dnssec
));
2108 printf("%sGlobal%s\n", ansi_highlight(), ansi_normal());
2110 table
= table_new_vertical();
2114 _cleanup_strv_free_
char **pstatus
= global_protocol_status(&global_info
);
2118 r
= table_add_many(table
,
2119 TABLE_FIELD
, "Protocols",
2120 TABLE_SET_MINIMUM_WIDTH
, 19,
2121 TABLE_STRV_WRAPPED
, pstatus
);
2123 return table_log_add_error(r
);
2125 if (global_info
.resolv_conf_mode
) {
2126 r
= table_add_many(table
,
2127 TABLE_FIELD
, "resolv.conf mode",
2128 TABLE_STRING
, global_info
.resolv_conf_mode
);
2130 return table_log_add_error(r
);
2133 if (global_info
.current_dns
) {
2134 r
= table_add_many(table
,
2135 TABLE_FIELD
, "Current DNS Server",
2136 TABLE_STRING
, global_info
.current_dns_ex
?: global_info
.current_dns
);
2138 return table_log_add_error(r
);
2141 r
= dump_list(table
, "DNS Servers", global_info
.dns_ex
?: global_info
.dns
);
2145 r
= dump_list(table
, "Fallback DNS Servers", global_info
.fallback_dns_ex
?: global_info
.fallback_dns
);
2149 r
= dump_list(table
, "DNS Domain", global_info
.domains
);
2153 r
= table_print(table
, NULL
);
2155 return table_log_print_error(r
);
2162 static int status_links(sd_bus
*bus
, StatusMode mode
, bool *empty_line
) {
2163 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
, *reply
= NULL
;
2164 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
2169 r
= sd_netlink_open(&rtnl
);
2171 return log_error_errno(r
, "Failed to connect to netlink: %m");
2173 r
= sd_rtnl_message_new_link(rtnl
, &req
, RTM_GETLINK
, 0);
2175 return rtnl_log_create_error(r
);
2177 r
= sd_netlink_message_set_request_dump(req
, true);
2179 return rtnl_log_create_error(r
);
2181 r
= sd_netlink_call(rtnl
, req
, 0, &reply
);
2183 return log_error_errno(r
, "Failed to enumerate links: %m");
2185 _cleanup_free_ InterfaceInfo
*infos
= NULL
;
2188 for (sd_netlink_message
*i
= reply
; i
; i
= sd_netlink_message_next(i
)) {
2193 r
= sd_netlink_message_get_type(i
, &type
);
2195 return rtnl_log_parse_error(r
);
2197 if (type
!= RTM_NEWLINK
)
2200 r
= sd_rtnl_message_link_get_ifindex(i
, &ifindex
);
2202 return rtnl_log_parse_error(r
);
2204 if (ifindex
== LOOPBACK_IFINDEX
)
2207 r
= sd_netlink_message_read_string(i
, IFLA_IFNAME
, &name
);
2209 return rtnl_log_parse_error(r
);
2211 if (!GREEDY_REALLOC(infos
, n_infos
+ 1))
2214 infos
[n_infos
++] = (InterfaceInfo
) { ifindex
, name
};
2217 typesafe_qsort(infos
, n_infos
, interface_info_compare
);
2219 FOREACH_ARRAY(info
, infos
, n_infos
)
2220 RET_GATHER(ret
, status_ifindex(bus
, info
->index
, info
->name
, mode
, empty_line
));
2225 typedef struct DelegateInfo
{
2232 static void delegate_info_done(DelegateInfo
*p
) {
2235 free(p
->current_dns
);
2237 strv_free(p
->domains
);
2240 static int map_delegate_dns_servers(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2241 return map_dns_servers_internal(bus
, member
, m
, READ_DNS_WITH_IFINDEX
|READ_DNS_EXTENDED
, error
, userdata
);
2244 static int map_delegate_current_dns_server(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2245 return read_dns_server_one(m
, READ_DNS_WITH_IFINDEX
|READ_DNS_EXTENDED
, userdata
);
2248 static int map_delegate_domains(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
2249 return map_domains_internal(bus
, member
, m
, /* with_ifindex= */ false, error
, userdata
);
2252 static int status_delegate_one(sd_bus
*bus
, const char *id
, StatusMode mode
, bool *empty_line
) {
2254 static const struct bus_properties_map property_map
[] = {
2255 { "DNS", "a(iiayqs)", map_delegate_dns_servers
, offsetof(DelegateInfo
, dns
) },
2256 { "CurrentDNSServer", "(iiayqs)", map_delegate_current_dns_server
, offsetof(DelegateInfo
, current_dns
) },
2257 { "Domains", "a(sb)", map_delegate_domains
, offsetof(DelegateInfo
, domains
) },
2258 { "DefaultRoute", "b", NULL
, offsetof(DelegateInfo
, default_route
) },
2262 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2263 _cleanup_(delegate_info_done
) DelegateInfo delegate_info
= {};
2264 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
2265 _cleanup_free_
char *p
= NULL
;
2271 r
= sd_bus_path_encode("/org/freedesktop/resolve1/dns_delegate", id
, &p
);
2275 r
= bus_map_all_properties(
2277 "org.freedesktop.resolve1",
2280 BUS_MAP_BOOLEAN_AS_BOOL
,
2285 return log_error_errno(r
, "Failed to get delegate data for %s: %s", id
, bus_error_message(&error
, r
));
2287 pager_open(arg_pager_flags
);
2292 return status_print_strv_delegate(id
, delegate_info
.dns
);
2295 return status_print_strv_delegate(id
, delegate_info
.domains
);
2297 case STATUS_DEFAULT_ROUTE
:
2298 printf("%sDelegate %s%s: %s\n",
2299 ansi_highlight(), id
, ansi_normal(),
2300 yes_no(delegate_info
.default_route
));
2311 if (empty_line
&& *empty_line
)
2312 fputc('\n', stdout
);
2314 printf("%sDelegate %s%s\n",
2315 ansi_highlight(), id
, ansi_normal());
2317 _cleanup_(table_unrefp
) Table
*table
= table_new_vertical();
2321 if (delegate_info
.current_dns
) {
2322 r
= table_add_many(table
,
2323 TABLE_FIELD
, "Current DNS Server",
2324 TABLE_STRING
, delegate_info
.current_dns
);
2326 return table_log_add_error(r
);
2329 r
= dump_list(table
, "DNS Servers", delegate_info
.dns
);
2333 r
= dump_list(table
, "DNS Domain", delegate_info
.domains
);
2337 r
= table_add_many(table
,
2338 TABLE_FIELD
, "Default Route",
2339 TABLE_SET_MINIMUM_WIDTH
, 19,
2340 TABLE_BOOLEAN
, delegate_info
.default_route
);
2342 r
= table_print(table
, NULL
);
2344 return table_log_print_error(r
);
2352 static int status_delegates(sd_bus
*bus
, StatusMode mode
, bool *empty_line
) {
2353 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2354 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2359 r
= bus_call_method(bus
, bus_resolve_mgr
, "ListDelegates", &error
, &reply
, NULL
);
2361 if (sd_bus_error_has_name(&error
, SD_BUS_ERROR_UNKNOWN_METHOD
)) {
2362 log_debug("Delegates not supported, skipping.");
2365 return log_error_errno(r
, "Failed to list delegates: %s", bus_error_message(&error
, r
));
2368 r
= sd_bus_message_enter_container(reply
, 'a', "(so)");
2370 return bus_log_parse_error(r
);
2372 _cleanup_strv_free_
char **l
= NULL
;
2376 r
= sd_bus_message_read(reply
, "(so)", &id
, NULL
);
2378 return bus_log_parse_error(r
);
2382 if (strv_extend(&l
, id
) < 0)
2386 r
= sd_bus_message_exit_container(reply
);
2388 return bus_log_parse_error(r
);
2393 RET_GATHER(ret
, status_delegate_one(bus
, *i
, mode
, empty_line
));
2398 static int status_all(sd_bus
*bus
, StatusMode mode
) {
2399 bool empty_line
= false;
2404 r
= status_global(bus
, mode
, &empty_line
);
2408 r
= status_links(bus
, mode
, &empty_line
);
2412 r
= status_delegates(bus
, mode
, &empty_line
);
2419 static int verb_status(int argc
, char **argv
, void *userdata
) {
2420 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2421 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
2422 bool empty_line
= false;
2425 r
= acquire_bus(&bus
);
2430 return status_all(bus
, STATUS_ALL
);
2432 STRV_FOREACH(ifname
, strv_skip(argv
, 1)) {
2435 ifindex
= rtnl_resolve_interface(&rtnl
, *ifname
);
2437 log_warning_errno(ifindex
, "Failed to resolve interface \"%s\", ignoring: %m", *ifname
);
2441 RET_GATHER(ret
, status_ifindex(bus
, ifindex
, NULL
, STATUS_ALL
, &empty_line
));
2447 static int call_dns(sd_bus
*bus
, char **dns
, const BusLocator
*locator
, sd_bus_error
*error
, bool extended
) {
2448 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
;
2451 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2453 r
= bus_message_new_method_call(bus
, &req
, locator
, extended
? "SetLinkDNSEx" : "SetLinkDNS");
2455 return bus_log_create_error(r
);
2457 r
= sd_bus_message_append(req
, "i", arg_ifindex
);
2459 return bus_log_create_error(r
);
2461 r
= sd_bus_message_open_container(req
, 'a', extended
? "(iayqs)" : "(iay)");
2463 return bus_log_create_error(r
);
2465 /* If only argument is the empty string, then call SetLinkDNS() with an
2466 * empty list, which will clear the list of domains for an interface. */
2467 if (!strv_equal(dns
, STRV_MAKE("")))
2468 STRV_FOREACH(p
, dns
) {
2469 _cleanup_free_
char *name
= NULL
;
2470 struct in_addr_data data
;
2474 r
= in_addr_port_ifindex_name_from_string_auto(*p
, &data
.family
, &data
.address
, &port
, &ifindex
, &name
);
2476 return log_error_errno(r
, "Failed to parse DNS server address: %s", *p
);
2478 if (ifindex
!= 0 && ifindex
!= arg_ifindex
)
2479 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid ifindex: %i", ifindex
);
2481 r
= sd_bus_message_open_container(req
, 'r', extended
? "iayqs" : "iay");
2483 return bus_log_create_error(r
);
2485 r
= sd_bus_message_append(req
, "i", data
.family
);
2487 return bus_log_create_error(r
);
2489 r
= sd_bus_message_append_array(req
, 'y', &data
.address
, FAMILY_ADDRESS_SIZE(data
.family
));
2491 return bus_log_create_error(r
);
2494 r
= sd_bus_message_append(req
, "q", port
);
2496 return bus_log_create_error(r
);
2498 r
= sd_bus_message_append(req
, "s", name
);
2500 return bus_log_create_error(r
);
2503 r
= sd_bus_message_close_container(req
);
2505 return bus_log_create_error(r
);
2508 r
= sd_bus_message_close_container(req
);
2510 return bus_log_create_error(r
);
2512 r
= sd_bus_call(bus
, req
, 0, error
, NULL
);
2513 if (r
< 0 && extended
&& sd_bus_error_has_name(error
, SD_BUS_ERROR_UNKNOWN_METHOD
)) {
2514 sd_bus_error_free(error
);
2515 return call_dns(bus
, dns
, locator
, error
, false);
2520 static int verb_dns(int argc
, char **argv
, void *userdata
) {
2521 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2522 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2525 r
= acquire_bus(&bus
);
2530 r
= ifname_mangle(argv
[1]);
2535 if (arg_ifindex
<= 0)
2536 return status_all(bus
, STATUS_DNS
);
2539 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_DNS
, NULL
);
2541 char **args
= strv_skip(argv
, 2);
2542 r
= call_dns(bus
, args
, bus_resolve_mgr
, &error
, true);
2543 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2544 sd_bus_error_free(&error
);
2546 r
= call_dns(bus
, args
, bus_network_mgr
, &error
, true);
2549 if (arg_ifindex_permissive
&&
2550 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2553 return log_error_errno(r
, "Failed to set DNS configuration: %s", bus_error_message(&error
, r
));
2559 static int call_domain(sd_bus
*bus
, char **domain
, const BusLocator
*locator
, sd_bus_error
*error
) {
2560 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
;
2563 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2565 r
= bus_message_new_method_call(bus
, &req
, locator
, "SetLinkDomains");
2567 return bus_log_create_error(r
);
2569 r
= sd_bus_message_append(req
, "i", arg_ifindex
);
2571 return bus_log_create_error(r
);
2573 r
= sd_bus_message_open_container(req
, 'a', "(sb)");
2575 return bus_log_create_error(r
);
2577 /* If only argument is the empty string, then call SetLinkDomains() with an
2578 * empty list, which will clear the list of domains for an interface. */
2579 if (!strv_equal(domain
, STRV_MAKE("")))
2580 STRV_FOREACH(p
, domain
) {
2583 n
= **p
== '~' ? *p
+ 1 : *p
;
2585 r
= dns_name_is_valid(n
);
2587 return log_error_errno(r
, "Failed to validate specified domain %s: %m", n
);
2589 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2590 "Domain not valid: %s",
2593 r
= sd_bus_message_append(req
, "(sb)", n
, **p
== '~');
2595 return bus_log_create_error(r
);
2598 r
= sd_bus_message_close_container(req
);
2600 return bus_log_create_error(r
);
2602 return sd_bus_call(bus
, req
, 0, error
, NULL
);
2605 static int verb_domain(int argc
, char **argv
, void *userdata
) {
2606 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2607 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2610 r
= acquire_bus(&bus
);
2615 r
= ifname_mangle(argv
[1]);
2620 if (arg_ifindex
<= 0)
2621 return status_all(bus
, STATUS_DOMAIN
);
2624 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_DOMAIN
, NULL
);
2626 char **args
= strv_skip(argv
, 2);
2627 r
= call_domain(bus
, args
, bus_resolve_mgr
, &error
);
2628 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2629 sd_bus_error_free(&error
);
2631 r
= call_domain(bus
, args
, bus_network_mgr
, &error
);
2634 if (arg_ifindex_permissive
&&
2635 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2638 return log_error_errno(r
, "Failed to set domain configuration: %s", bus_error_message(&error
, r
));
2644 static int verb_default_route(int argc
, char **argv
, void *userdata
) {
2645 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2646 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2649 r
= acquire_bus(&bus
);
2654 r
= ifname_mangle(argv
[1]);
2659 if (arg_ifindex
<= 0)
2660 return status_all(bus
, STATUS_DEFAULT_ROUTE
);
2663 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_DEFAULT_ROUTE
, NULL
);
2665 b
= parse_boolean(argv
[2]);
2667 return log_error_errno(b
, "Failed to parse boolean argument: %s", argv
[2]);
2669 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2671 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkDefaultRoute", &error
, NULL
, "ib", arg_ifindex
, b
);
2672 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2673 sd_bus_error_free(&error
);
2675 r
= bus_call_method(bus
, bus_network_mgr
, "SetLinkDefaultRoute", &error
, NULL
, "ib", arg_ifindex
, b
);
2678 if (arg_ifindex_permissive
&&
2679 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2682 return log_error_errno(r
, "Failed to set default route configuration: %s", bus_error_message(&error
, r
));
2688 static int verb_llmnr(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
;
2691 _cleanup_free_
char *global_llmnr_support_str
= NULL
;
2692 ResolveSupport global_llmnr_support
, llmnr_support
;
2695 r
= acquire_bus(&bus
);
2700 r
= ifname_mangle(argv
[1]);
2705 if (arg_ifindex
<= 0)
2706 return status_all(bus
, STATUS_LLMNR
);
2709 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_LLMNR
, NULL
);
2711 llmnr_support
= resolve_support_from_string(argv
[2]);
2712 if (llmnr_support
< 0)
2713 return log_error_errno(llmnr_support
, "Invalid LLMNR setting: %s", argv
[2]);
2715 r
= bus_get_property_string(bus
, bus_resolve_mgr
, "LLMNR", &error
, &global_llmnr_support_str
);
2717 return log_error_errno(r
, "Failed to get the global LLMNR support state: %s", bus_error_message(&error
, r
));
2719 global_llmnr_support
= resolve_support_from_string(global_llmnr_support_str
);
2720 if (global_llmnr_support
< 0)
2721 return log_error_errno(global_llmnr_support
, "Received invalid global LLMNR setting: %s", global_llmnr_support_str
);
2723 if (global_llmnr_support
< llmnr_support
)
2724 log_warning("Setting LLMNR support level \"%s\" for \"%s\", but the global support level is \"%s\".",
2725 argv
[2], arg_ifname
, global_llmnr_support_str
);
2727 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2729 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkLLMNR", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2730 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2731 sd_bus_error_free(&error
);
2733 r
= bus_call_method(bus
, bus_network_mgr
, "SetLinkLLMNR", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2736 if (arg_ifindex_permissive
&&
2737 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2740 return log_error_errno(r
, "Failed to set LLMNR configuration: %s", bus_error_message(&error
, r
));
2746 static int verb_mdns(int argc
, char **argv
, void *userdata
) {
2747 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2748 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2749 _cleanup_free_
char *global_mdns_support_str
= NULL
;
2750 ResolveSupport global_mdns_support
, mdns_support
;
2753 r
= acquire_bus(&bus
);
2758 r
= ifname_mangle(argv
[1]);
2763 if (arg_ifindex
<= 0)
2764 return status_all(bus
, STATUS_MDNS
);
2767 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_MDNS
, NULL
);
2769 mdns_support
= resolve_support_from_string(argv
[2]);
2770 if (mdns_support
< 0)
2771 return log_error_errno(mdns_support
, "Invalid mDNS setting: %s", argv
[2]);
2773 r
= bus_get_property_string(bus
, bus_resolve_mgr
, "MulticastDNS", &error
, &global_mdns_support_str
);
2775 return log_error_errno(r
, "Failed to get the global mDNS support state: %s", bus_error_message(&error
, r
));
2777 global_mdns_support
= resolve_support_from_string(global_mdns_support_str
);
2778 if (global_mdns_support
< 0)
2779 return log_error_errno(global_mdns_support
, "Received invalid global mDNS setting: %s", global_mdns_support_str
);
2781 if (global_mdns_support
< mdns_support
)
2782 log_warning("Setting mDNS support level \"%s\" for \"%s\", but the global support level is \"%s\".",
2783 argv
[2], arg_ifname
, global_mdns_support_str
);
2785 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2787 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkMulticastDNS", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2788 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2789 sd_bus_error_free(&error
);
2791 r
= bus_call_method(
2794 "SetLinkMulticastDNS",
2797 "is", arg_ifindex
, argv
[2]);
2800 if (arg_ifindex_permissive
&&
2801 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2804 return log_error_errno(r
, "Failed to set MulticastDNS configuration: %s", bus_error_message(&error
, r
));
2810 static int verb_dns_over_tls(int argc
, char **argv
, void *userdata
) {
2811 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2812 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2815 r
= acquire_bus(&bus
);
2820 r
= ifname_mangle(argv
[1]);
2825 if (arg_ifindex
<= 0)
2826 return status_all(bus
, STATUS_PRIVATE
);
2829 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_PRIVATE
, NULL
);
2831 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2833 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkDNSOverTLS", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2834 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2835 sd_bus_error_free(&error
);
2837 r
= bus_call_method(
2840 "SetLinkDNSOverTLS",
2843 "is", arg_ifindex
, argv
[2]);
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 DNSOverTLS configuration: %s", bus_error_message(&error
, r
));
2856 static int verb_dnssec(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
;
2861 r
= acquire_bus(&bus
);
2866 r
= ifname_mangle(argv
[1]);
2871 if (arg_ifindex
<= 0)
2872 return status_all(bus
, STATUS_DNSSEC
);
2875 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_DNSSEC
, NULL
);
2877 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2879 r
= bus_call_method(bus
, bus_resolve_mgr
, "SetLinkDNSSEC", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2880 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2881 sd_bus_error_free(&error
);
2883 r
= bus_call_method(bus
, bus_network_mgr
, "SetLinkDNSSEC", &error
, NULL
, "is", arg_ifindex
, argv
[2]);
2886 if (arg_ifindex_permissive
&&
2887 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2890 return log_error_errno(r
, "Failed to set DNSSEC configuration: %s", bus_error_message(&error
, r
));
2896 static int call_nta(sd_bus
*bus
, char **nta
, const BusLocator
*locator
, sd_bus_error
*error
) {
2897 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*req
= NULL
;
2900 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2902 r
= bus_message_new_method_call(bus
, &req
, locator
, "SetLinkDNSSECNegativeTrustAnchors");
2904 return bus_log_create_error(r
);
2906 r
= sd_bus_message_append(req
, "i", arg_ifindex
);
2908 return bus_log_create_error(r
);
2910 r
= sd_bus_message_append_strv(req
, nta
);
2912 return bus_log_create_error(r
);
2914 return sd_bus_call(bus
, req
, 0, error
, NULL
);
2917 static int verb_nta(int argc
, char **argv
, void *userdata
) {
2918 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2919 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2924 r
= acquire_bus(&bus
);
2929 r
= ifname_mangle(argv
[1]);
2934 if (arg_ifindex
<= 0)
2935 return status_all(bus
, STATUS_NTA
);
2938 return status_ifindex(bus
, arg_ifindex
, NULL
, STATUS_NTA
, NULL
);
2940 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2942 /* If only argument is the empty string, then call SetLinkDNSSECNegativeTrustAnchors()
2943 * with an empty list, which will clear the list of domains for an interface. */
2944 args
= strv_skip(argv
, 2);
2945 clear
= strv_equal(args
, STRV_MAKE(""));
2948 STRV_FOREACH(p
, args
) {
2949 r
= dns_name_is_valid(*p
);
2951 return log_error_errno(r
, "Failed to validate specified domain %s: %m", *p
);
2953 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2954 "Domain not valid: %s",
2958 r
= call_nta(bus
, clear
? NULL
: args
, bus_resolve_mgr
, &error
);
2959 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2960 sd_bus_error_free(&error
);
2962 r
= call_nta(bus
, clear
? NULL
: args
, bus_network_mgr
, &error
);
2965 if (arg_ifindex_permissive
&&
2966 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
2969 return log_error_errno(r
, "Failed to set DNSSEC NTA configuration: %s", bus_error_message(&error
, r
));
2975 static int verb_revert_link(int argc
, char **argv
, void *userdata
) {
2976 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
2977 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
2980 r
= acquire_bus(&bus
);
2985 r
= ifname_mangle(argv
[1]);
2990 if (arg_ifindex
<= 0)
2991 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Interface argument required.");
2993 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
2995 r
= bus_call_method(bus
, bus_resolve_mgr
, "RevertLink", &error
, NULL
, "i", arg_ifindex
);
2996 if (r
< 0 && sd_bus_error_has_name(&error
, BUS_ERROR_LINK_BUSY
)) {
2997 sd_bus_error_free(&error
);
2999 r
= bus_call_method(bus
, bus_network_mgr
, "RevertLinkDNS", &error
, NULL
, "i", arg_ifindex
);
3002 if (arg_ifindex_permissive
&&
3003 sd_bus_error_has_name(&error
, BUS_ERROR_NO_SUCH_LINK
))
3006 return log_error_errno(r
, "Failed to revert interface configuration: %s", bus_error_message(&error
, r
));
3012 static int verb_log_level(int argc
, char *argv
[], void *userdata
) {
3013 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*bus
= NULL
;
3016 r
= acquire_bus(&bus
);
3020 assert(IN_SET(argc
, 1, 2));
3022 return verb_log_control_common(bus
, "org.freedesktop.resolve1", argv
[0], argc
== 2 ? argv
[1] : NULL
);
3025 static int print_question(char prefix
, const char *color
, sd_json_variant
*question
) {
3026 sd_json_variant
*q
= NULL
;
3031 JSON_VARIANT_ARRAY_FOREACH(q
, question
) {
3032 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*key
= NULL
;
3033 char buf
[DNS_RESOURCE_KEY_STRING_MAX
];
3035 r
= dns_resource_key_from_json(q
, &key
);
3037 log_warning_errno(r
, "Received monitor message with invalid question key, ignoring: %m");
3041 printf("%s%s %c%s: %s\n",
3043 glyph(GLYPH_ARROW_RIGHT
),
3046 dns_resource_key_to_string(key
, buf
, sizeof(buf
)));
3052 static int print_answer(sd_json_variant
*answer
) {
3056 JSON_VARIANT_ARRAY_FOREACH(a
, answer
) {
3057 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
3058 _cleanup_free_
void *d
= NULL
;
3059 sd_json_variant
*jraw
;
3063 jraw
= sd_json_variant_by_key(a
, "raw");
3065 log_warning("Received monitor answer lacking valid raw data, ignoring.");
3069 r
= sd_json_variant_unbase64(jraw
, &d
, &l
);
3071 log_warning_errno(r
, "Failed to undo base64 encoding of monitor answer raw data, ignoring.");
3075 r
= dns_resource_record_new_from_raw(&rr
, d
, l
);
3077 log_warning_errno(r
, "Failed to parse monitor answer RR, ignoring: %m");
3081 s
= dns_resource_record_to_string(rr
);
3085 printf("%s%s A%s: %s\n",
3086 ansi_highlight_yellow(),
3087 glyph(GLYPH_ARROW_LEFT
),
3095 typedef struct MonitorQueryParams
{
3096 sd_json_variant
*question
;
3097 sd_json_variant
*answer
;
3098 sd_json_variant
*collected_questions
;
3104 const char *ede_msg
;
3105 } MonitorQueryParams
;
3107 static void monitor_query_params_done(MonitorQueryParams
*p
) {
3110 sd_json_variant_unref(p
->question
);
3111 sd_json_variant_unref(p
->answer
);
3112 sd_json_variant_unref(p
->collected_questions
);
3115 static void monitor_query_dump(sd_json_variant
*v
) {
3116 static const sd_json_dispatch_field dispatch_table
[] = {
3117 { "question", SD_JSON_VARIANT_ARRAY
, sd_json_dispatch_variant
, offsetof(MonitorQueryParams
, question
), SD_JSON_MANDATORY
},
3118 { "answer", SD_JSON_VARIANT_ARRAY
, sd_json_dispatch_variant
, offsetof(MonitorQueryParams
, answer
), 0 },
3119 { "collectedQuestions", SD_JSON_VARIANT_ARRAY
, sd_json_dispatch_variant
, offsetof(MonitorQueryParams
, collected_questions
), 0 },
3120 { "state", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(MonitorQueryParams
, state
), SD_JSON_MANDATORY
},
3121 { "result", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(MonitorQueryParams
, result
), 0 },
3122 { "rcode", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_int
, offsetof(MonitorQueryParams
, rcode
), 0 },
3123 { "errno", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_int
, offsetof(MonitorQueryParams
, error
), 0 },
3124 { "extendedDNSErrorCode", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_int
, offsetof(MonitorQueryParams
, ede_code
), 0 },
3125 { "extendedDNSErrorMessage", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(MonitorQueryParams
, ede_msg
), 0 },
3129 _cleanup_(monitor_query_params_done
) MonitorQueryParams p
= {
3136 if (sd_json_dispatch(v
, dispatch_table
, SD_JSON_LOG
|SD_JSON_ALLOW_EXTENSIONS
, &p
) < 0)
3139 /* First show the current question */
3140 print_question('Q', ansi_highlight_cyan(), p
.question
);
3142 /* And then show the questions that led to this one in case this was a CNAME chain */
3143 print_question('C', ansi_highlight_grey(), p
.collected_questions
);
3145 printf("%s%s S%s: %s",
3146 streq_ptr(p
.state
, "success") ? ansi_highlight_green() : ansi_highlight_red(),
3147 glyph(GLYPH_ARROW_LEFT
),
3149 strna(streq_ptr(p
.state
, "errno") ? errno_to_name(p
.error
) :
3150 streq_ptr(p
.state
, "rcode-failure") ? dns_rcode_to_string(p
.rcode
) :
3153 if (!isempty(p
.result
))
3154 printf(": %s", p
.result
);
3156 if (p
.ede_code
>= 0)
3158 FORMAT_DNS_EDE_RCODE(p
.ede_code
),
3159 !isempty(p
.ede_msg
) ? ": " : "",
3160 strempty(p
.ede_msg
));
3164 print_answer(p
.answer
);
3167 static int monitor_reply(
3169 sd_json_variant
*parameters
,
3170 const char *error_id
,
3171 sd_varlink_reply_flags_t flags
,
3179 disconnect
= streq(error_id
, SD_VARLINK_ERROR_DISCONNECTED
);
3181 log_info("Disconnected.");
3183 log_error("Varlink error: %s", error_id
);
3185 (void) sd_event_exit(ASSERT_PTR(sd_varlink_get_event(link
)), disconnect
? EXIT_SUCCESS
: EXIT_FAILURE
);
3189 if (sd_json_variant_by_key(parameters
, "ready")) {
3190 /* The first message coming in will just indicate that we are now subscribed. We let our
3191 * caller know if they asked for it. Once the caller sees this they should know that we are
3192 * not going to miss any queries anymore. */
3193 (void) sd_notify(/* unset_environment=false */ false, "READY=1");
3197 if (!sd_json_format_enabled(arg_json_format_flags
)) {
3198 monitor_query_dump(parameters
);
3201 sd_json_variant_dump(parameters
, arg_json_format_flags
, NULL
, NULL
);
3208 static int verb_monitor(int argc
, char *argv
[], void *userdata
) {
3209 _cleanup_(sd_event_unrefp
) sd_event
*event
= NULL
;
3210 _cleanup_(sd_varlink_unrefp
) sd_varlink
*vl
= NULL
;
3213 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
3215 r
= sd_event_default(&event
);
3217 return log_error_errno(r
, "Failed to get event loop: %m");
3219 r
= sd_event_set_signal_exit(event
, true);
3221 return log_error_errno(r
, "Failed to enable exit on SIGINT/SIGTERM: %m");
3223 r
= sd_varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
3225 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
3227 r
= sd_varlink_set_relative_timeout(vl
, USEC_INFINITY
); /* We want the monitor to run basically forever */
3229 return log_error_errno(r
, "Failed to set varlink timeout: %m");
3231 r
= sd_varlink_attach_event(vl
, event
, SD_EVENT_PRIORITY_NORMAL
);
3233 return log_error_errno(r
, "Failed to attach varlink connection to event loop: %m");
3235 r
= sd_varlink_bind_reply(vl
, monitor_reply
);
3237 return log_error_errno(r
, "Failed to bind reply callback to varlink connection: %m");
3239 r
= sd_varlink_observebo(
3241 "io.systemd.Resolve.Monitor.SubscribeQueryResults",
3242 SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password
));
3244 return log_error_errno(r
, "Failed to issue SubscribeQueryResults() varlink call: %m");
3246 r
= sd_event_loop(event
);
3248 return log_error_errno(r
, "Failed to run event loop: %m");
3250 r
= sd_event_get_exit_code(event
, &c
);
3252 return log_error_errno(r
, "Failed to get exit code: %m");
3257 static int dump_cache_item(sd_json_variant
*item
) {
3260 sd_json_variant
*key
;
3261 sd_json_variant
*rrs
;
3266 static const sd_json_dispatch_field dispatch_table
[] = {
3267 { "key", SD_JSON_VARIANT_OBJECT
, sd_json_dispatch_variant_noref
, offsetof(struct item_info
, key
), SD_JSON_MANDATORY
},
3268 { "rrs", SD_JSON_VARIANT_ARRAY
, sd_json_dispatch_variant_noref
, offsetof(struct item_info
, rrs
), 0 },
3269 { "type", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct item_info
, type
), 0 },
3270 { "until", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct item_info
, until
), 0 },
3274 _cleanup_(dns_resource_key_unrefp
) DnsResourceKey
*k
= NULL
;
3277 r
= sd_json_dispatch(item
, dispatch_table
, SD_JSON_LOG
|SD_JSON_ALLOW_EXTENSIONS
, &item_info
);
3281 r
= dns_resource_key_from_json(item_info
.key
, &k
);
3283 return log_error_errno(r
, "Failed to turn JSON data to resource key: %m");
3286 printf("%s %s%s%s\n", DNS_RESOURCE_KEY_TO_STRING(k
), ansi_highlight_red(), item_info
.type
, ansi_normal());
3290 JSON_VARIANT_ARRAY_FOREACH(i
, item_info
.rrs
) {
3291 _cleanup_(dns_resource_record_unrefp
) DnsResourceRecord
*rr
= NULL
;
3292 _cleanup_free_
void *data
= NULL
;
3293 sd_json_variant
*raw
;
3296 raw
= sd_json_variant_by_key(i
, "raw");
3298 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
), "raw field missing from RR JSON data.");
3300 r
= sd_json_variant_unbase64(raw
, &data
, &size
);
3302 return log_error_errno(r
, "Unable to decode raw RR JSON data: %m");
3304 r
= dns_resource_record_new_from_raw(&rr
, data
, size
);
3306 return log_error_errno(r
, "Failed to parse DNS data: %m");
3308 printf("%s\n", dns_resource_record_to_string(rr
));
3316 static int dump_cache_scope(sd_json_variant
*scope
) {
3319 const char *protocol
;
3323 sd_json_variant
*cache
;
3325 .family
= AF_UNSPEC
,
3330 static const sd_json_dispatch_field dispatch_table
[] = {
3331 { "protocol", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct scope_info
, protocol
), SD_JSON_MANDATORY
},
3332 { "family", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_int
, offsetof(struct scope_info
, family
), 0 },
3333 { "ifindex", _SD_JSON_VARIANT_TYPE_INVALID
, json_dispatch_ifindex
, offsetof(struct scope_info
, ifindex
), SD_JSON_RELAX
},
3334 { "ifname", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct scope_info
, ifname
), 0 },
3335 { "cache", SD_JSON_VARIANT_ARRAY
, sd_json_dispatch_variant_noref
, offsetof(struct scope_info
, cache
), SD_JSON_MANDATORY
},
3339 r
= sd_json_dispatch(scope
, dispatch_table
, SD_JSON_LOG
|SD_JSON_ALLOW_EXTENSIONS
, &scope_info
);
3343 printf("%sScope protocol=%s", ansi_underline(), scope_info
.protocol
);
3345 if (scope_info
.family
!= AF_UNSPEC
)
3346 printf(" family=%s", af_to_name(scope_info
.family
));
3348 if (scope_info
.ifindex
> 0)
3349 printf(" ifindex=%i", scope_info
.ifindex
);
3350 if (scope_info
.ifname
)
3351 printf(" ifname=%s", scope_info
.ifname
);
3353 printf("%s\n", ansi_normal());
3355 JSON_VARIANT_ARRAY_FOREACH(i
, scope_info
.cache
) {
3356 r
= dump_cache_item(i
);
3364 printf("%sNo entries.%s\n\n", ansi_grey(), ansi_normal());
3371 static int verb_show_cache(int argc
, char *argv
[], void *userdata
) {
3372 sd_json_variant
*reply
= NULL
, *d
= NULL
;
3373 _cleanup_(sd_varlink_unrefp
) sd_varlink
*vl
= NULL
;
3376 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
3378 r
= sd_varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
3380 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
3382 r
= varlink_callbo_and_log(
3384 "io.systemd.Resolve.Monitor.DumpCache",
3386 SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password
));
3390 d
= sd_json_variant_by_key(reply
, "dump");
3392 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
3393 "DumpCache() response is missing 'dump' key.");
3395 if (!sd_json_variant_is_array(d
))
3396 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
3397 "DumpCache() response 'dump' field not an array");
3399 if (!sd_json_format_enabled(arg_json_format_flags
)) {
3402 JSON_VARIANT_ARRAY_FOREACH(i
, d
) {
3403 r
= dump_cache_scope(i
);
3411 return sd_json_variant_dump(d
, arg_json_format_flags
, NULL
, NULL
);
3414 static int dump_server_state(sd_json_variant
*server
) {
3415 _cleanup_(table_unrefp
) Table
*table
= NULL
;
3418 struct server_state
{
3419 const char *server_name
;
3423 const char *verified_feature_level
;
3424 const char *possible_feature_level
;
3425 const char *dnssec_mode
;
3426 bool dnssec_supported
;
3427 size_t received_udp_fragment_max
;
3428 uint64_t n_failed_udp
;
3429 uint64_t n_failed_tcp
;
3430 bool packet_truncated
;
3431 bool packet_bad_opt
;
3432 bool packet_rrsig_missing
;
3433 bool packet_invalid
;
3441 static const sd_json_dispatch_field dispatch_table
[] = {
3442 { "Server", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct server_state
, server_name
), SD_JSON_MANDATORY
},
3443 { "Type", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct server_state
, type
), SD_JSON_MANDATORY
},
3444 { "Interface", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct server_state
, ifname
), 0 },
3445 { "InterfaceIndex", _SD_JSON_VARIANT_TYPE_INVALID
, json_dispatch_ifindex
, offsetof(struct server_state
, ifindex
), SD_JSON_RELAX
},
3446 { "VerifiedFeatureLevel", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct server_state
, verified_feature_level
), 0 },
3447 { "PossibleFeatureLevel", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct server_state
, possible_feature_level
), 0 },
3448 { "DNSSECMode", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct server_state
, dnssec_mode
), SD_JSON_MANDATORY
},
3449 { "DNSSECSupported", SD_JSON_VARIANT_BOOLEAN
, sd_json_dispatch_stdbool
, offsetof(struct server_state
, dnssec_supported
), SD_JSON_MANDATORY
},
3450 { "ReceivedUDPFragmentMax", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct server_state
, received_udp_fragment_max
), SD_JSON_MANDATORY
},
3451 { "FailedUDPAttempts", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct server_state
, n_failed_udp
), SD_JSON_MANDATORY
},
3452 { "FailedTCPAttempts", _SD_JSON_VARIANT_TYPE_INVALID
, sd_json_dispatch_uint64
, offsetof(struct server_state
, n_failed_tcp
), SD_JSON_MANDATORY
},
3453 { "PacketTruncated", SD_JSON_VARIANT_BOOLEAN
, sd_json_dispatch_stdbool
, offsetof(struct server_state
, packet_truncated
), SD_JSON_MANDATORY
},
3454 { "PacketBadOpt", SD_JSON_VARIANT_BOOLEAN
, sd_json_dispatch_stdbool
, offsetof(struct server_state
, packet_bad_opt
), SD_JSON_MANDATORY
},
3455 { "PacketRRSIGMissing", SD_JSON_VARIANT_BOOLEAN
, sd_json_dispatch_stdbool
, offsetof(struct server_state
, packet_rrsig_missing
), SD_JSON_MANDATORY
},
3456 { "PacketInvalid", SD_JSON_VARIANT_BOOLEAN
, sd_json_dispatch_stdbool
, offsetof(struct server_state
, packet_invalid
), SD_JSON_MANDATORY
},
3457 { "PacketDoOff", SD_JSON_VARIANT_BOOLEAN
, sd_json_dispatch_stdbool
, offsetof(struct server_state
, packet_do_off
), SD_JSON_MANDATORY
},
3461 r
= sd_json_dispatch(server
, dispatch_table
, SD_JSON_LOG
|SD_JSON_ALLOW_EXTENSIONS
, &server_state
);
3465 table
= table_new_vertical();
3469 assert_se(cell
= table_get_cell(table
, 0, 0));
3470 (void) table_set_ellipsize_percent(table
, cell
, 100);
3471 (void) table_set_align_percent(table
, cell
, 0);
3473 r
= table_add_cell_stringf(table
, NULL
, "Server: %s", server_state
.server_name
);
3475 return table_log_add_error(r
);
3477 r
= table_add_many(table
,
3479 TABLE_FIELD
, "Type",
3480 TABLE_SET_ALIGN_PERCENT
, 100,
3481 TABLE_STRING
, server_state
.type
);
3483 return table_log_add_error(r
);
3485 if (server_state
.ifname
) {
3486 r
= table_add_many(table
,
3487 TABLE_FIELD
, "Interface",
3488 TABLE_STRING
, server_state
.ifname
);
3490 return table_log_add_error(r
);
3493 if (server_state
.ifindex
>= 0) {
3494 r
= table_add_many(table
,
3495 TABLE_FIELD
, "Interface Index",
3496 TABLE_INT
, server_state
.ifindex
);
3498 return table_log_add_error(r
);
3501 if (server_state
.verified_feature_level
) {
3502 r
= table_add_many(table
,
3503 TABLE_FIELD
, "Verified feature level",
3504 TABLE_STRING
, server_state
.verified_feature_level
);
3506 return table_log_add_error(r
);
3509 if (server_state
.possible_feature_level
) {
3510 r
= table_add_many(table
,
3511 TABLE_FIELD
, "Possible feature level",
3512 TABLE_STRING
, server_state
.possible_feature_level
);
3514 return table_log_add_error(r
);
3517 r
= table_add_many(table
,
3518 TABLE_FIELD
, "DNSSEC Mode",
3519 TABLE_STRING
, server_state
.dnssec_mode
,
3520 TABLE_FIELD
, "DNSSEC Supported",
3521 TABLE_STRING
, yes_no(server_state
.dnssec_supported
),
3522 TABLE_FIELD
, "Maximum UDP fragment size received",
3523 TABLE_UINT64
, server_state
.received_udp_fragment_max
,
3524 TABLE_FIELD
, "Failed UDP attempts",
3525 TABLE_UINT64
, server_state
.n_failed_udp
,
3526 TABLE_FIELD
, "Failed TCP attempts",
3527 TABLE_UINT64
, server_state
.n_failed_tcp
,
3528 TABLE_FIELD
, "Seen truncated packet",
3529 TABLE_STRING
, yes_no(server_state
.packet_truncated
),
3530 TABLE_FIELD
, "Seen OPT RR getting lost",
3531 TABLE_STRING
, yes_no(server_state
.packet_bad_opt
),
3532 TABLE_FIELD
, "Seen RRSIG RR missing",
3533 TABLE_STRING
, yes_no(server_state
.packet_rrsig_missing
),
3534 TABLE_FIELD
, "Seen invalid packet",
3535 TABLE_STRING
, yes_no(server_state
.packet_invalid
),
3536 TABLE_FIELD
, "Server dropped DO flag",
3537 TABLE_STRING
, yes_no(server_state
.packet_do_off
),
3538 TABLE_SET_ALIGN_PERCENT
, 0,
3539 TABLE_EMPTY
, TABLE_EMPTY
);
3542 return table_log_add_error(r
);
3544 r
= table_print(table
, NULL
);
3546 return table_log_print_error(r
);
3551 static int verb_show_server_state(int argc
, char *argv
[], void *userdata
) {
3552 sd_json_variant
*reply
= NULL
, *d
= NULL
;
3553 _cleanup_(sd_varlink_unrefp
) sd_varlink
*vl
= NULL
;
3556 (void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL
, arg_ask_password
);
3558 r
= sd_varlink_connect_address(&vl
, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
3560 return log_error_errno(r
, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
3562 r
= varlink_callbo_and_log(
3564 "io.systemd.Resolve.Monitor.DumpServerState",
3566 SD_JSON_BUILD_PAIR_BOOLEAN("allowInteractiveAuthentication", arg_ask_password
));
3570 d
= sd_json_variant_by_key(reply
, "dump");
3572 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
3573 "DumpCache() response is missing 'dump' key.");
3575 if (!sd_json_variant_is_array(d
))
3576 return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE
),
3577 "DumpCache() response 'dump' field not an array");
3579 if (!sd_json_format_enabled(arg_json_format_flags
)) {
3582 JSON_VARIANT_ARRAY_FOREACH(i
, d
) {
3583 r
= dump_server_state(i
);
3591 return sd_json_variant_dump(d
, arg_json_format_flags
, NULL
, NULL
);
3594 static void help_protocol_types(void) {
3596 puts("Known protocol types:");
3606 static void help_dns_types(void) {
3608 puts("Known DNS RR types:");
3610 DUMP_STRING_TABLE(dns_type
, int, _DNS_TYPE_MAX
);
3613 static void help_dns_classes(void) {
3615 puts("Known DNS RR classes:");
3617 DUMP_STRING_TABLE(dns_class
, int, _DNS_CLASS_MAX
);
3620 static int compat_help(void) {
3621 _cleanup_free_
char *link
= NULL
;
3624 r
= terminal_urlify_man("resolvectl", "1", &link
);
3628 printf("%1$s [OPTIONS...] HOSTNAME|ADDRESS...\n"
3629 "%1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n"
3630 "%1$s [OPTIONS...] --openpgp EMAIL@DOMAIN...\n"
3631 "%1$s [OPTIONS...] --statistics\n"
3632 "%1$s [OPTIONS...] --reset-statistics\n"
3634 "%2$sResolve domain names, IPv4 and IPv6 addresses, DNS records, and services.%3$s\n\n"
3635 " -h --help Show this help\n"
3636 " --version Show package version\n"
3637 " --no-pager Do not pipe output into a pager\n"
3638 " -4 Resolve IPv4 addresses\n"
3639 " -6 Resolve IPv6 addresses\n"
3640 " -i --interface=INTERFACE Look on interface\n"
3641 " -p --protocol=PROTO|help Look via protocol\n"
3642 " -t --type=TYPE|help Query RR with DNS type\n"
3643 " -c --class=CLASS|help Query RR with DNS class\n"
3644 " --service Resolve service (SRV)\n"
3645 " --service-address=BOOL Resolve address for services (default: yes)\n"
3646 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
3647 " --openpgp Query OpenPGP public key\n"
3648 " --tlsa Query TLS public key\n"
3649 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
3650 " --search=BOOL Use search domains for single-label names\n"
3652 " --raw[=payload|packet] Dump the answer as binary data\n"
3653 " --legend=BOOL Print headers and additional info (default: yes)\n"
3654 " --statistics Show resolver statistics\n"
3655 " --reset-statistics Reset resolver statistics\n"
3656 " --status Show link and server status\n"
3657 " --flush-caches Flush all local DNS caches\n"
3658 " --reset-server-features\n"
3659 " Forget learnt DNS server feature levels\n"
3660 " --set-dns=SERVER Set per-interface DNS server address\n"
3661 " --set-domain=DOMAIN Set per-interface search domain\n"
3662 " --set-llmnr=MODE Set per-interface LLMNR mode\n"
3663 " --set-mdns=MODE Set per-interface MulticastDNS mode\n"
3664 " --set-dnsovertls=MODE Set per-interface DNS-over-TLS mode\n"
3665 " --set-dnssec=MODE Set per-interface DNSSEC mode\n"
3666 " --set-nta=DOMAIN Set per-interface DNSSEC NTA\n"
3667 " --revert Revert per-interface configuration\n"
3668 "\nSee the %4$s for details.\n",
3669 program_invocation_short_name
,
3677 static int native_help(void) {
3678 _cleanup_free_
char *link
= NULL
;
3681 r
= terminal_urlify_man("resolvectl", "1", &link
);
3685 printf("%1$s [OPTIONS...] COMMAND ...\n"
3687 "%5$sSend control commands to the network name resolution manager, or%6$s\n"
3688 "%5$sresolve domain names, IPv4 and IPv6 addresses, DNS records, and services.%6$s\n"
3689 "\n%3$sCommands:%4$s\n"
3690 " query HOSTNAME|ADDRESS... Resolve domain names, IPv4 and IPv6 addresses\n"
3691 " service [[NAME] TYPE] DOMAIN Resolve service (SRV)\n"
3692 " openpgp EMAIL@DOMAIN... Query OpenPGP public key\n"
3693 " tlsa DOMAIN[:PORT]... Query TLS public key\n"
3694 " status [LINK...] Show link and server status\n"
3695 " statistics Show resolver statistics\n"
3696 " reset-statistics Reset resolver statistics\n"
3697 " flush-caches Flush all local DNS caches\n"
3698 " reset-server-features Forget learnt DNS server feature levels\n"
3699 " monitor Monitor DNS queries\n"
3700 " show-cache Show cache contents\n"
3701 " show-server-state Show servers state\n"
3702 " dns [LINK [SERVER...]] Get/set per-interface DNS server address\n"
3703 " domain [LINK [DOMAIN...]] Get/set per-interface search domain\n"
3704 " default-route [LINK [BOOL]] Get/set per-interface default route flag\n"
3705 " llmnr [LINK [MODE]] Get/set per-interface LLMNR mode\n"
3706 " mdns [LINK [MODE]] Get/set per-interface MulticastDNS mode\n"
3707 " dnsovertls [LINK [MODE]] Get/set per-interface DNS-over-TLS mode\n"
3708 " dnssec [LINK [MODE]] Get/set per-interface DNSSEC mode\n"
3709 " nta [LINK [DOMAIN...]] Get/set per-interface DNSSEC NTA\n"
3710 " revert LINK Revert per-interface configuration\n"
3711 " log-level [LEVEL] Get/set logging threshold for systemd-resolved\n"
3712 "\n%3$sOptions:%4$s\n"
3713 " -h --help Show this help\n"
3714 " --version Show package version\n"
3715 " --no-pager Do not pipe output into a pager\n"
3716 " --no-ask-password Do not prompt for password\n"
3717 " -4 Resolve IPv4 addresses\n"
3718 " -6 Resolve IPv6 addresses\n"
3719 " -i --interface=INTERFACE Look on interface\n"
3720 " -p --protocol=PROTO|help Look via protocol\n"
3721 " -t --type=TYPE|help Query RR with DNS type\n"
3722 " -c --class=CLASS|help Query RR with DNS class\n"
3723 " --service-address=BOOL Resolve address for services (default: yes)\n"
3724 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
3725 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
3726 " --validate=BOOL Allow DNSSEC validation (default: yes)\n"
3727 " --synthesize=BOOL Allow synthetic response (default: yes)\n"
3728 " --cache=BOOL Allow response from cache (default: yes)\n"
3729 " --stale-data=BOOL Allow response from cache with stale data (default: yes)\n"
3730 " --relax-single-label=BOOL Allow single label lookups to go upstream (default: no)\n"
3731 " --zone=BOOL Allow response from locally registered mDNS/LLMNR\n"
3732 " records (default: yes)\n"
3733 " --trust-anchor=BOOL Allow response from local trust anchor (default:\n"
3735 " --network=BOOL Allow response from network (default: yes)\n"
3736 " --search=BOOL Use search domains for single-label names (default:\n"
3738 " --raw[=payload|packet] Dump the answer as binary data\n"
3739 " --legend=BOOL Print headers and additional info (default: yes)\n"
3740 " --json=MODE Output as JSON\n"
3741 " -j Same as --json=pretty on tty, --json=short\n"
3743 "\nSee the %2$s for details.\n",
3744 program_invocation_short_name
,
3754 static int verb_help(int argc
, char **argv
, void *userdata
) {
3755 return native_help();
3758 static int compat_parse_argv(int argc
, char *argv
[]) {
3760 ARG_VERSION
= 0x100,
3764 ARG_SERVICE_ADDRESS
,
3771 ARG_RESET_STATISTICS
,
3774 ARG_RESET_SERVER_FEATURES
,
3780 ARG_SET_DNS_OVER_TLS
,
3786 static const struct option options
[] = {
3787 { "help", no_argument
, NULL
, 'h' },
3788 { "version", no_argument
, NULL
, ARG_VERSION
},
3789 { "type", required_argument
, NULL
, 't' },
3790 { "class", required_argument
, NULL
, 'c' },
3791 { "legend", required_argument
, NULL
, ARG_LEGEND
},
3792 { "interface", required_argument
, NULL
, 'i' },
3793 { "protocol", required_argument
, NULL
, 'p' },
3794 { "cname", required_argument
, NULL
, ARG_CNAME
},
3795 { "service", no_argument
, NULL
, ARG_SERVICE
},
3796 { "service-address", required_argument
, NULL
, ARG_SERVICE_ADDRESS
},
3797 { "service-txt", required_argument
, NULL
, ARG_SERVICE_TXT
},
3798 { "openpgp", no_argument
, NULL
, ARG_OPENPGP
},
3799 { "tlsa", optional_argument
, NULL
, ARG_TLSA
},
3800 { "raw", optional_argument
, NULL
, ARG_RAW
},
3801 { "search", required_argument
, NULL
, ARG_SEARCH
},
3802 { "statistics", no_argument
, NULL
, ARG_STATISTICS
, },
3803 { "reset-statistics", no_argument
, NULL
, ARG_RESET_STATISTICS
},
3804 { "status", no_argument
, NULL
, ARG_STATUS
},
3805 { "flush-caches", no_argument
, NULL
, ARG_FLUSH_CACHES
},
3806 { "reset-server-features", no_argument
, NULL
, ARG_RESET_SERVER_FEATURES
},
3807 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
3808 { "set-dns", required_argument
, NULL
, ARG_SET_DNS
},
3809 { "set-domain", required_argument
, NULL
, ARG_SET_DOMAIN
},
3810 { "set-llmnr", required_argument
, NULL
, ARG_SET_LLMNR
},
3811 { "set-mdns", required_argument
, NULL
, ARG_SET_MDNS
},
3812 { "set-dnsovertls", required_argument
, NULL
, ARG_SET_DNS_OVER_TLS
},
3813 { "set-dnssec", required_argument
, NULL
, ARG_SET_DNSSEC
},
3814 { "set-nta", required_argument
, NULL
, ARG_SET_NTA
},
3815 { "revert", no_argument
, NULL
, ARG_REVERT_LINK
},
3824 while ((c
= getopt_long(argc
, argv
, "h46i:t:c:p:", options
, NULL
)) >= 0)
3828 return compat_help();
3834 arg_family
= AF_INET
;
3838 arg_family
= AF_INET6
;
3842 r
= ifname_mangle(optarg
);
3848 if (streq(optarg
, "help")) {
3853 r
= dns_type_from_string(optarg
);
3855 return log_error_errno(r
, "Failed to parse RR record type %s: %m", optarg
);
3857 arg_type
= (uint16_t) r
;
3858 assert((int) arg_type
== r
);
3860 arg_mode
= MODE_RESOLVE_RECORD
;
3864 if (streq(optarg
, "help")) {
3869 r
= dns_class_from_string(optarg
);
3871 return log_error_errno(r
, "Failed to parse RR record class %s: %m", optarg
);
3873 arg_class
= (uint16_t) r
;
3874 assert((int) arg_class
== r
);
3879 r
= parse_boolean_argument("--legend=", optarg
, &arg_legend
);
3885 if (streq(optarg
, "help")) {
3886 help_protocol_types();
3888 } else if (streq(optarg
, "dns"))
3889 arg_flags
|= SD_RESOLVED_DNS
;
3890 else if (streq(optarg
, "llmnr"))
3891 arg_flags
|= SD_RESOLVED_LLMNR
;
3892 else if (streq(optarg
, "llmnr-ipv4"))
3893 arg_flags
|= SD_RESOLVED_LLMNR_IPV4
;
3894 else if (streq(optarg
, "llmnr-ipv6"))
3895 arg_flags
|= SD_RESOLVED_LLMNR_IPV6
;
3896 else if (streq(optarg
, "mdns"))
3897 arg_flags
|= SD_RESOLVED_MDNS
;
3898 else if (streq(optarg
, "mdns-ipv4"))
3899 arg_flags
|= SD_RESOLVED_MDNS_IPV4
;
3900 else if (streq(optarg
, "mdns-ipv6"))
3901 arg_flags
|= SD_RESOLVED_MDNS_IPV6
;
3903 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
3904 "Unknown protocol specifier: %s", optarg
);
3909 arg_mode
= MODE_RESOLVE_SERVICE
;
3913 arg_mode
= MODE_RESOLVE_OPENPGP
;
3917 arg_mode
= MODE_RESOLVE_TLSA
;
3918 if (!optarg
|| service_family_is_valid(optarg
))
3919 arg_service_family
= optarg
;
3921 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
3922 "Unknown service family \"%s\".", optarg
);
3927 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY
),
3928 "Refusing to write binary data to tty.");
3930 if (optarg
== NULL
|| streq(optarg
, "payload"))
3931 arg_raw
= RAW_PAYLOAD
;
3932 else if (streq(optarg
, "packet"))
3933 arg_raw
= RAW_PACKET
;
3935 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
3936 "Unknown --raw specifier \"%s\".",
3943 r
= parse_boolean_argument("--cname=", optarg
, NULL
);
3946 SET_FLAG(arg_flags
, SD_RESOLVED_NO_CNAME
, r
== 0);
3949 case ARG_SERVICE_ADDRESS
:
3950 r
= parse_boolean_argument("--service-address=", optarg
, NULL
);
3953 SET_FLAG(arg_flags
, SD_RESOLVED_NO_ADDRESS
, r
== 0);
3956 case ARG_SERVICE_TXT
:
3957 r
= parse_boolean_argument("--service-txt=", optarg
, NULL
);
3960 SET_FLAG(arg_flags
, SD_RESOLVED_NO_TXT
, r
== 0);
3964 r
= parse_boolean_argument("--search=", optarg
, NULL
);
3967 SET_FLAG(arg_flags
, SD_RESOLVED_NO_SEARCH
, r
== 0);
3970 case ARG_STATISTICS
:
3971 arg_mode
= MODE_STATISTICS
;
3974 case ARG_RESET_STATISTICS
:
3975 arg_mode
= MODE_RESET_STATISTICS
;
3978 case ARG_FLUSH_CACHES
:
3979 arg_mode
= MODE_FLUSH_CACHES
;
3982 case ARG_RESET_SERVER_FEATURES
:
3983 arg_mode
= MODE_RESET_SERVER_FEATURES
;
3987 arg_mode
= MODE_STATUS
;
3991 arg_pager_flags
|= PAGER_DISABLE
;
3995 r
= strv_extend(&arg_set_dns
, optarg
);
3999 arg_mode
= MODE_SET_LINK
;
4002 case ARG_SET_DOMAIN
:
4003 r
= strv_extend(&arg_set_domain
, optarg
);
4007 arg_mode
= MODE_SET_LINK
;
4011 arg_set_llmnr
= optarg
;
4012 arg_mode
= MODE_SET_LINK
;
4016 arg_set_mdns
= optarg
;
4017 arg_mode
= MODE_SET_LINK
;
4020 case ARG_SET_DNS_OVER_TLS
:
4021 arg_set_dns_over_tls
= optarg
;
4022 arg_mode
= MODE_SET_LINK
;
4025 case ARG_SET_DNSSEC
:
4026 arg_set_dnssec
= optarg
;
4027 arg_mode
= MODE_SET_LINK
;
4031 r
= strv_extend(&arg_set_nta
, optarg
);
4035 arg_mode
= MODE_SET_LINK
;
4038 case ARG_REVERT_LINK
:
4039 arg_mode
= MODE_REVERT_LINK
;
4046 assert_not_reached();
4049 if (arg_type
== 0 && arg_class
!= 0)
4050 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4051 "--class= may only be used in conjunction with --type=.");
4053 if (arg_type
!= 0 && arg_mode
== MODE_RESOLVE_SERVICE
)
4054 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4055 "--service and --type= may not be combined.");
4057 if (arg_type
!= 0 && arg_class
== 0)
4058 arg_class
= DNS_CLASS_IN
;
4060 if (arg_class
!= 0 && arg_type
== 0)
4061 arg_type
= DNS_TYPE_A
;
4063 if (IN_SET(arg_mode
, MODE_SET_LINK
, MODE_REVERT_LINK
)) {
4065 if (arg_ifindex
<= 0)
4066 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4067 "--set-dns=, --set-domain=, --set-llmnr=, --set-mdns=, --set-dnsovertls=, --set-dnssec=, --set-nta= and --revert require --interface=.");
4070 return 1 /* work to do */;
4073 static int native_parse_argv(int argc
, char *argv
[]) {
4075 ARG_VERSION
= 0x100,
4084 ARG_SERVICE_ADDRESS
,
4089 ARG_NO_ASK_PASSWORD
,
4092 ARG_RELAX_SINGLE_LABEL
,
4095 static const struct option options
[] = {
4096 { "help", no_argument
, NULL
, 'h' },
4097 { "version", no_argument
, NULL
, ARG_VERSION
},
4098 { "type", required_argument
, NULL
, 't' },
4099 { "class", required_argument
, NULL
, 'c' },
4100 { "legend", required_argument
, NULL
, ARG_LEGEND
},
4101 { "interface", required_argument
, NULL
, 'i' },
4102 { "protocol", required_argument
, NULL
, 'p' },
4103 { "cname", required_argument
, NULL
, ARG_CNAME
},
4104 { "validate", required_argument
, NULL
, ARG_VALIDATE
},
4105 { "synthesize", required_argument
, NULL
, ARG_SYNTHESIZE
},
4106 { "cache", required_argument
, NULL
, ARG_CACHE
},
4107 { "zone", required_argument
, NULL
, ARG_ZONE
},
4108 { "trust-anchor", required_argument
, NULL
, ARG_TRUST_ANCHOR
},
4109 { "network", required_argument
, NULL
, ARG_NETWORK
},
4110 { "service-address", required_argument
, NULL
, ARG_SERVICE_ADDRESS
},
4111 { "service-txt", required_argument
, NULL
, ARG_SERVICE_TXT
},
4112 { "raw", optional_argument
, NULL
, ARG_RAW
},
4113 { "search", required_argument
, NULL
, ARG_SEARCH
},
4114 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
4115 { "no-ask-password", no_argument
, NULL
, ARG_NO_ASK_PASSWORD
},
4116 { "json", required_argument
, NULL
, ARG_JSON
},
4117 { "stale-data", required_argument
, NULL
, ARG_STALE_DATA
},
4118 { "relax-single-label", required_argument
, NULL
, ARG_RELAX_SINGLE_LABEL
},
4127 while ((c
= getopt_long(argc
, argv
, "h46i:t:c:p:j", options
, NULL
)) >= 0)
4131 return native_help();
4137 arg_family
= AF_INET
;
4141 arg_family
= AF_INET6
;
4145 r
= ifname_mangle(optarg
);
4151 if (streq(optarg
, "help")) {
4156 r
= dns_type_from_string(optarg
);
4158 return log_error_errno(r
, "Failed to parse RR record type %s: %m", optarg
);
4160 arg_type
= (uint16_t) r
;
4161 assert((int) arg_type
== r
);
4166 if (streq(optarg
, "help")) {
4171 r
= dns_class_from_string(optarg
);
4173 return log_error_errno(r
, "Failed to parse RR record class %s: %m", optarg
);
4175 arg_class
= (uint16_t) r
;
4176 assert((int) arg_class
== r
);
4181 r
= parse_boolean_argument("--legend=", optarg
, &arg_legend
);
4187 if (streq(optarg
, "help")) {
4188 help_protocol_types();
4190 } else if (streq(optarg
, "dns"))
4191 arg_flags
|= SD_RESOLVED_DNS
;
4192 else if (streq(optarg
, "llmnr"))
4193 arg_flags
|= SD_RESOLVED_LLMNR
;
4194 else if (streq(optarg
, "llmnr-ipv4"))
4195 arg_flags
|= SD_RESOLVED_LLMNR_IPV4
;
4196 else if (streq(optarg
, "llmnr-ipv6"))
4197 arg_flags
|= SD_RESOLVED_LLMNR_IPV6
;
4198 else if (streq(optarg
, "mdns"))
4199 arg_flags
|= SD_RESOLVED_MDNS
;
4200 else if (streq(optarg
, "mdns-ipv4"))
4201 arg_flags
|= SD_RESOLVED_MDNS_IPV4
;
4202 else if (streq(optarg
, "mdns-ipv6"))
4203 arg_flags
|= SD_RESOLVED_MDNS_IPV6
;
4205 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4206 "Unknown protocol specifier: %s",
4213 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY
),
4214 "Refusing to write binary data to tty.");
4216 if (optarg
== NULL
|| streq(optarg
, "payload"))
4217 arg_raw
= RAW_PAYLOAD
;
4218 else if (streq(optarg
, "packet"))
4219 arg_raw
= RAW_PACKET
;
4221 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4222 "Unknown --raw specifier \"%s\".",
4229 r
= parse_boolean_argument("--cname=", optarg
, NULL
);
4232 SET_FLAG(arg_flags
, SD_RESOLVED_NO_CNAME
, r
== 0);
4236 r
= parse_boolean_argument("--validate=", optarg
, NULL
);
4239 SET_FLAG(arg_flags
, SD_RESOLVED_NO_VALIDATE
, r
== 0);
4242 case ARG_SYNTHESIZE
:
4243 r
= parse_boolean_argument("--synthesize=", optarg
, NULL
);
4246 SET_FLAG(arg_flags
, SD_RESOLVED_NO_SYNTHESIZE
, r
== 0);
4250 r
= parse_boolean_argument("--cache=", optarg
, NULL
);
4253 SET_FLAG(arg_flags
, SD_RESOLVED_NO_CACHE
, r
== 0);
4256 case ARG_STALE_DATA
:
4257 r
= parse_boolean_argument("--stale-data=", optarg
, NULL
);
4260 SET_FLAG(arg_flags
, SD_RESOLVED_NO_STALE
, r
== 0);
4264 r
= parse_boolean_argument("--zone=", optarg
, NULL
);
4267 SET_FLAG(arg_flags
, SD_RESOLVED_NO_ZONE
, r
== 0);
4270 case ARG_TRUST_ANCHOR
:
4271 r
= parse_boolean_argument("--trust-anchor=", optarg
, NULL
);
4274 SET_FLAG(arg_flags
, SD_RESOLVED_NO_TRUST_ANCHOR
, r
== 0);
4278 r
= parse_boolean_argument("--network=", optarg
, NULL
);
4281 SET_FLAG(arg_flags
, SD_RESOLVED_NO_NETWORK
, r
== 0);
4284 case ARG_SERVICE_ADDRESS
:
4285 r
= parse_boolean_argument("--service-address=", optarg
, NULL
);
4288 SET_FLAG(arg_flags
, SD_RESOLVED_NO_ADDRESS
, r
== 0);
4291 case ARG_SERVICE_TXT
:
4292 r
= parse_boolean_argument("--service-txt=", optarg
, NULL
);
4295 SET_FLAG(arg_flags
, SD_RESOLVED_NO_TXT
, r
== 0);
4299 r
= parse_boolean_argument("--search=", optarg
, NULL
);
4302 SET_FLAG(arg_flags
, SD_RESOLVED_NO_SEARCH
, r
== 0);
4305 case ARG_RELAX_SINGLE_LABEL
:
4306 r
= parse_boolean_argument("--relax-single-label=", optarg
, NULL
);
4309 SET_FLAG(arg_flags
, SD_RESOLVED_RELAX_SINGLE_LABEL
, r
> 0);
4313 arg_pager_flags
|= PAGER_DISABLE
;
4316 case ARG_NO_ASK_PASSWORD
:
4317 arg_ask_password
= false;
4321 r
= parse_json_argument(optarg
, &arg_json_format_flags
);
4328 arg_json_format_flags
= SD_JSON_FORMAT_PRETTY_AUTO
|SD_JSON_FORMAT_COLOR_AUTO
;
4335 assert_not_reached();
4338 if (arg_type
== 0 && arg_class
!= 0)
4339 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
4340 "--class= may only be used in conjunction with --type=.");
4342 if (arg_type
!= 0 && arg_class
== 0)
4343 arg_class
= DNS_CLASS_IN
;
4345 if (arg_class
!= 0 && arg_type
== 0)
4346 arg_type
= DNS_TYPE_A
;
4348 return 1 /* work to do */;
4351 static int native_main(int argc
, char *argv
[]) {
4353 static const Verb verbs
[] = {
4354 { "help", VERB_ANY
, VERB_ANY
, 0, verb_help
},
4355 { "status", VERB_ANY
, VERB_ANY
, VERB_DEFAULT
, verb_status
},
4356 { "query", 2, VERB_ANY
, 0, verb_query
},
4357 { "service", 2, 4, 0, verb_service
},
4358 { "openpgp", 2, VERB_ANY
, 0, verb_openpgp
},
4359 { "tlsa", 2, VERB_ANY
, 0, verb_tlsa
},
4360 { "statistics", VERB_ANY
, 1, 0, show_statistics
},
4361 { "reset-statistics", VERB_ANY
, 1, 0, reset_statistics
},
4362 { "flush-caches", VERB_ANY
, 1, 0, flush_caches
},
4363 { "reset-server-features", VERB_ANY
, 1, 0, reset_server_features
},
4364 { "dns", VERB_ANY
, VERB_ANY
, 0, verb_dns
},
4365 { "domain", VERB_ANY
, VERB_ANY
, 0, verb_domain
},
4366 { "default-route", VERB_ANY
, 3, 0, verb_default_route
},
4367 { "llmnr", VERB_ANY
, 3, 0, verb_llmnr
},
4368 { "mdns", VERB_ANY
, 3, 0, verb_mdns
},
4369 { "dnsovertls", VERB_ANY
, 3, 0, verb_dns_over_tls
},
4370 { "dnssec", VERB_ANY
, 3, 0, verb_dnssec
},
4371 { "nta", VERB_ANY
, VERB_ANY
, 0, verb_nta
},
4372 { "revert", VERB_ANY
, 2, 0, verb_revert_link
},
4373 { "log-level", VERB_ANY
, 2, 0, verb_log_level
},
4374 { "monitor", VERB_ANY
, 1, 0, verb_monitor
},
4375 { "show-cache", VERB_ANY
, 1, 0, verb_show_cache
},
4376 { "show-server-state", VERB_ANY
, 1, 0, verb_show_server_state
},
4380 return dispatch_verb(argc
, argv
, verbs
, /* userdata = */ NULL
);
4383 static int translate(const char *verb
, const char *single_arg
, size_t num_args
, char **args
) {
4388 assert(num_args
== 0 || args
);
4390 num
= !!single_arg
+ num_args
+ 1;
4392 p
= fake
= newa0(char *, num
+ 1);
4393 *p
++ = (char *) verb
;
4395 *p
++ = (char *) single_arg
;
4396 FOREACH_ARRAY(arg
, args
, num_args
)
4400 return native_main((int) num
, fake
);
4403 static int compat_main(int argc
, char *argv
[]) {
4407 case MODE_RESOLVE_HOST
:
4408 case MODE_RESOLVE_RECORD
:
4409 return translate("query", NULL
, argc
- optind
, argv
+ optind
);
4411 case MODE_RESOLVE_SERVICE
:
4412 return translate("service", NULL
, argc
- optind
, argv
+ optind
);
4414 case MODE_RESOLVE_OPENPGP
:
4415 return translate("openpgp", NULL
, argc
- optind
, argv
+ optind
);
4417 case MODE_RESOLVE_TLSA
:
4418 return translate("tlsa", arg_service_family
, argc
- optind
, argv
+ optind
);
4420 case MODE_STATISTICS
:
4421 return translate("statistics", NULL
, 0, NULL
);
4423 case MODE_RESET_STATISTICS
:
4424 return translate("reset-statistics", NULL
, 0, NULL
);
4426 case MODE_FLUSH_CACHES
:
4427 return translate("flush-caches", NULL
, 0, NULL
);
4429 case MODE_RESET_SERVER_FEATURES
:
4430 return translate("reset-server-features", NULL
, 0, NULL
);
4433 return translate("status", NULL
, argc
- optind
, argv
+ optind
);
4438 if (arg_disable_default_route
) {
4439 r
= translate("default-route", arg_ifname
, 1, STRV_MAKE("no"));
4445 r
= translate("dns", arg_ifname
, strv_length(arg_set_dns
), arg_set_dns
);
4450 if (arg_set_domain
) {
4451 r
= translate("domain", arg_ifname
, strv_length(arg_set_domain
), arg_set_domain
);
4457 r
= translate("nta", arg_ifname
, strv_length(arg_set_nta
), arg_set_nta
);
4462 if (arg_set_llmnr
) {
4463 r
= translate("llmnr", arg_ifname
, 1, (char **) &arg_set_llmnr
);
4469 r
= translate("mdns", arg_ifname
, 1, (char **) &arg_set_mdns
);
4474 if (arg_set_dns_over_tls
) {
4475 r
= translate("dnsovertls", arg_ifname
, 1, (char **) &arg_set_dns_over_tls
);
4480 if (arg_set_dnssec
) {
4481 r
= translate("dnssec", arg_ifname
, 1, (char **) &arg_set_dnssec
);
4488 case MODE_REVERT_LINK
:
4491 return translate("revert", arg_ifname
, 0, NULL
);
4494 assert_not_reached();
4500 static int run(int argc
, char **argv
) {
4501 bool compat
= false;
4504 setlocale(LC_ALL
, "");
4507 if (invoked_as(argv
, "resolvconf")) {
4509 r
= resolvconf_parse_argv(argc
, argv
);
4510 } else if (invoked_as(argv
, "systemd-resolve")) {
4512 r
= compat_parse_argv(argc
, argv
);
4514 r
= native_parse_argv(argc
, argv
);
4519 return compat_main(argc
, argv
);
4521 return native_main(argc
, argv
);
4524 DEFINE_MAIN_FUNCTION(run
);