]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/resolve/resolvectl.c
Merge pull request #25389 from fbuihuu/update-test-for-opensuse
[thirdparty/systemd.git] / src / resolve / resolvectl.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
bdef7319 2
bdef7319 3#include <getopt.h>
ca78ad1d 4#include <locale.h>
cf0fbc49 5#include <net/if.h>
bdef7319
ZJS
6
7#include "sd-bus.h"
be371fe0 8#include "sd-netlink.h"
3f6fd1ba
LP
9
10#include "af-list.h"
b5efdb8a 11#include "alloc-util.h"
d6b4d1c7 12#include "build.h"
14965b94 13#include "bus-common-errors.h"
bdef7319 14#include "bus-error.h"
9b71e4ab 15#include "bus-locator.h"
807542be 16#include "bus-map-properties.h"
a574b7d1 17#include "bus-message-util.h"
14965b94 18#include "dns-domain.h"
fffbf1dc 19#include "errno-list.h"
45ec7efb 20#include "escape.h"
29e15e98 21#include "format-table.h"
518a66ec 22#include "format-util.h"
4ac2ca1b 23#include "gcrypt-util.h"
058946d1 24#include "hostname-util.h"
fffbf1dc 25#include "json.h"
f6aa6190 26#include "main-func.h"
ef118d00 27#include "missing_network.h"
be371fe0 28#include "netlink-util.h"
7e8facb3 29#include "openssl-util.h"
be371fe0 30#include "pager.h"
599c7c54 31#include "parse-argument.h"
6bedfcbb 32#include "parse-util.h"
294bf0c3 33#include "pretty-print.h"
2306d177 34#include "process-util.h"
088c1363 35#include "resolvconf-compat.h"
c38a03df 36#include "resolve-util.h"
c2e84cab 37#include "resolvectl.h"
51323288 38#include "resolved-def.h"
3f6fd1ba 39#include "resolved-dns-packet.h"
058946d1 40#include "resolved-util.h"
5c3fa98d 41#include "socket-netlink.h"
eb107675 42#include "sort-util.h"
957d9df3 43#include "stdio-util.h"
5c828e66 44#include "string-table.h"
be371fe0 45#include "strv.h"
a150ff5e 46#include "terminal-util.h"
7c502303 47#include "utf8.h"
fffbf1dc 48#include "varlink.h"
a87b151a 49#include "verb-log-control.h"
a7a4c60a 50#include "verbs.h"
2d4c5cbc 51
bdef7319 52static int arg_family = AF_UNSPEC;
a661dc36
YW
53static int arg_ifindex = 0;
54static char *arg_ifname = NULL;
4b548ef3 55static uint16_t arg_type = 0;
2d4c5cbc 56static uint16_t arg_class = 0;
b93312f5 57static bool arg_legend = true;
51323288 58static uint64_t arg_flags = 0;
fffbf1dc 59static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
0221d68a 60static PagerFlags arg_pager_flags = 0;
088c1363 61bool arg_ifindex_permissive = false; /* If true, don't generate an error if the specified interface index doesn't exist */
a7a4c60a 62static const char *arg_service_family = NULL;
82d1d240 63
dab48ea6
ZJS
64typedef enum RawType {
65 RAW_NONE,
66 RAW_PAYLOAD,
67 RAW_PACKET,
68} RawType;
dab48ea6 69static RawType arg_raw = RAW_NONE;
a150ff5e 70
088c1363
LP
71ExecutionMode arg_mode = MODE_RESOLVE_HOST;
72
a7a4c60a 73char **arg_set_dns = NULL;
088c1363 74char **arg_set_domain = NULL;
a7a4c60a
YW
75static const char *arg_set_llmnr = NULL;
76static const char *arg_set_mdns = NULL;
c9299be2 77static const char *arg_set_dns_over_tls = NULL;
a7a4c60a 78static const char *arg_set_dnssec = NULL;
14965b94
LP
79static char **arg_set_nta = NULL;
80
f6aa6190
YW
81STATIC_DESTRUCTOR_REGISTER(arg_ifname, freep);
82STATIC_DESTRUCTOR_REGISTER(arg_set_dns, strv_freep);
83STATIC_DESTRUCTOR_REGISTER(arg_set_domain, strv_freep);
84STATIC_DESTRUCTOR_REGISTER(arg_set_nta, strv_freep);
85
a7a4c60a
YW
86typedef enum StatusMode {
87 STATUS_ALL,
88 STATUS_DNS,
89 STATUS_DOMAIN,
f2fd3cdb 90 STATUS_DEFAULT_ROUTE,
a7a4c60a
YW
91 STATUS_LLMNR,
92 STATUS_MDNS,
d050561a 93 STATUS_PRIVATE,
a7a4c60a
YW
94 STATUS_DNSSEC,
95 STATUS_NTA,
96} StatusMode;
97
eb107675
ZJS
98typedef struct InterfaceInfo {
99 int index;
100 const char *name;
101} InterfaceInfo;
102
103static int interface_info_compare(const InterfaceInfo *a, const InterfaceInfo *b) {
104 int r;
105
106 r = CMP(a->index, b->index);
107 if (r != 0)
108 return r;
109
110 return strcmp_ptr(a->name, b->name);
111}
112
7d4e8503
YW
113int ifname_mangle_full(const char *s, bool drop_protocol_specifier) {
114 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
115 _cleanup_strv_free_ char **found = NULL;
116 int r;
a661dc36
YW
117
118 assert(s);
119
7d4e8503
YW
120 if (drop_protocol_specifier) {
121 _cleanup_free_ char *buf = NULL;
122 int ifindex_longest_name = -ENODEV;
a661dc36 123
7d4e8503 124 /* When invoked as resolvconf, drop the protocol specifier(s) at the end. */
8e5385b4 125
7d4e8503
YW
126 buf = strdup(s);
127 if (!buf)
128 return log_oom();
a661dc36 129
7d4e8503
YW
130 for (;;) {
131 r = rtnl_resolve_interface(&rtnl, buf);
132 if (r > 0) {
133 if (ifindex_longest_name <= 0)
134 ifindex_longest_name = r;
a661dc36 135
7d4e8503
YW
136 r = strv_extend(&found, buf);
137 if (r < 0)
138 return log_oom();
139 }
a661dc36 140
7d4e8503
YW
141 char *dot = strrchr(buf, '.');
142 if (!dot)
143 break;
a661dc36 144
7d4e8503
YW
145 *dot = '\0';
146 }
7875170f 147
7d4e8503
YW
148 unsigned n = strv_length(found);
149 if (n > 1) {
150 _cleanup_free_ char *joined = NULL;
7875170f 151
7d4e8503
YW
152 joined = strv_join(found, ", ");
153 log_warning("Found multiple interfaces (%s) matching with '%s'. Using '%s' (ifindex=%i).",
154 strna(joined), s, found[0], ifindex_longest_name);
7875170f 155
7d4e8503
YW
156 } else if (n == 1) {
157 const char *proto;
158
159 proto = ASSERT_PTR(startswith(s, found[0]));
160 if (!isempty(proto))
161 log_info("Dropped protocol specifier '%s' from '%s'. Using '%s' (ifindex=%i).",
162 proto, s, found[0], ifindex_longest_name);
163 }
164
165 r = ifindex_longest_name;
7875170f 166 } else
7d4e8503
YW
167 r = rtnl_resolve_interface(&rtnl, s);
168 if (r < 0) {
169 if (ERRNO_IS_DEVICE_ABSENT(r) && arg_ifindex_permissive) {
170 log_debug_errno(r, "Interface '%s' not found, but -f specified, ignoring: %m", s);
171 return 0; /* done */
172 }
173 return log_error_errno(r, "Failed to resolve interface \"%s\": %m", s);
174 }
175
176 if (arg_ifindex > 0 && arg_ifindex != r)
177 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Specified multiple different interfaces. Refusing.");
178
179 arg_ifindex = r;
180 return free_and_strdup_warn(&arg_ifname, found ? found[0] : s); /* found */
7875170f
MC
181}
182
78c6a153 183static void print_source(uint64_t flags, usec_t rtt) {
51323288
LP
184 if (!arg_legend)
185 return;
186
78c6a153 187 if (flags == 0)
51323288
LP
188 return;
189
ec4b9671 190 printf("\n%s-- Information acquired via", ansi_grey());
51323288 191
283ec789
YW
192 printf(" protocol%s%s%s%s%s",
193 flags & SD_RESOLVED_DNS ? " DNS" :"",
194 flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
195 flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "",
196 flags & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4" : "",
197 flags & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6" : "");
51323288 198
ec4b9671 199 printf(" in %s.%s\n"
43fc4baa 200 "%s-- Data is authenticated: %s; Data was acquired via local or encrypted transport: %s%s\n",
5291f26d
ZJS
201 FORMAT_TIMESPAN(rtt, 100),
202 ansi_normal(),
43fc4baa
LP
203 ansi_grey(),
204 yes_no(flags & SD_RESOLVED_AUTHENTICATED),
205 yes_no(flags & SD_RESOLVED_CONFIDENTIAL),
206 ansi_normal());
5c1790d1
LP
207
208 if ((flags & (SD_RESOLVED_FROM_MASK|SD_RESOLVED_SYNTHETIC)) != 0)
209 printf("%s-- Data from:%s%s%s%s%s%s\n",
210 ansi_grey(),
211 FLAGS_SET(flags, SD_RESOLVED_SYNTHETIC) ? " synthetic" : "",
212 FLAGS_SET(flags, SD_RESOLVED_FROM_CACHE) ? " cache" : "",
213 FLAGS_SET(flags, SD_RESOLVED_FROM_ZONE) ? " zone" : "",
214 FLAGS_SET(flags, SD_RESOLVED_FROM_TRUST_ANCHOR) ? " trust-anchor" : "",
215 FLAGS_SET(flags, SD_RESOLVED_FROM_NETWORK) ? " network" : "",
216 ansi_normal());
51323288 217}
bdef7319 218
ff4a77c3 219static void print_ifindex_comment(int printed_so_far, int ifindex) {
01afd0f7
YW
220 char ifname[IF_NAMESIZE];
221 int r;
74998408 222
ff4a77c3
LP
223 if (ifindex <= 0)
224 return;
931851e8 225
01afd0f7
YW
226 r = format_ifname(ifindex, ifname);
227 if (r < 0)
228 return (void) log_warning_errno(r, "Failed to resolve interface name for index %i, ignoring: %m", ifindex);
229
230 printf("%*s%s-- link: %s%s",
231 60 > printed_so_far ? 60 - printed_so_far : 0, " ", /* Align comment to the 60th column */
232 ansi_grey(), ifname, ansi_normal());
51323288 233}
bdef7319 234
79266746 235static int resolve_host(sd_bus *bus, const char *name) {
4afd3348
LP
236 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
237 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
79266746 238 const char *canonical = NULL;
bdef7319 239 unsigned c = 0;
51323288 240 uint64_t flags;
74998408 241 usec_t ts;
a661dc36 242 int r;
bdef7319
ZJS
243
244 assert(name);
245
a661dc36 246 log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
bdef7319 247
d96f9abc 248 r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
02dd6e18
LP
249 if (r < 0)
250 return bus_log_create_error(r);
bdef7319 251
51323288 252 r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
02dd6e18
LP
253 if (r < 0)
254 return bus_log_create_error(r);
bdef7319 255
74998408
TG
256 ts = now(CLOCK_MONOTONIC);
257
4cbfd62b 258 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
45ec7efb
LP
259 if (r < 0)
260 return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(&error, r));
bdef7319 261
74998408
TG
262 ts = now(CLOCK_MONOTONIC) - ts;
263
78c6a153 264 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
02dd6e18
LP
265 if (r < 0)
266 return bus_log_parse_error(r);
bdef7319 267
78c6a153 268 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
bdef7319 269 _cleanup_free_ char *pretty = NULL;
ff4a77c3 270 int ifindex, family, k;
a574b7d1 271 union in_addr_union a;
78c6a153
LP
272
273 assert_cc(sizeof(int) == sizeof(int32_t));
bdef7319 274
a574b7d1 275 r = sd_bus_message_read(reply, "i", &ifindex);
02dd6e18
LP
276 if (r < 0)
277 return bus_log_parse_error(r);
bdef7319 278
a574b7d1
YW
279 sd_bus_error_free(&error);
280 r = bus_message_read_in_addr_auto(reply, &error, &family, &a);
281 if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
282 return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&error, r));
bdef7319 283
bdef7319 284 r = sd_bus_message_exit_container(reply);
02dd6e18
LP
285 if (r < 0)
286 return bus_log_parse_error(r);
bdef7319 287
a574b7d1
YW
288 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
289 log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r));
bdef7319
ZJS
290 continue;
291 }
292
a574b7d1 293 r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty);
78c6a153
LP
294 if (r < 0)
295 return log_error_errno(r, "Failed to print address for %s: %m", name);
bdef7319 296
38585af3 297 k = printf("%*s%s %s%s%s",
ff4a77c3 298 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
38585af3 299 ansi_highlight(), pretty, ansi_normal());
ff4a77c3
LP
300
301 print_ifindex_comment(k, ifindex);
302 fputc('\n', stdout);
bdef7319
ZJS
303
304 c++;
305 }
79266746
LP
306 if (r < 0)
307 return bus_log_parse_error(r);
308
309 r = sd_bus_message_exit_container(reply);
310 if (r < 0)
311 return bus_log_parse_error(r);
312
51323288 313 r = sd_bus_message_read(reply, "st", &canonical, &flags);
79266746
LP
314 if (r < 0)
315 return bus_log_parse_error(r);
316
ece174c5 317 if (!streq(name, canonical))
79266746
LP
318 printf("%*s%s (%s)\n",
319 (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
320 canonical);
bdef7319 321
d7a0f1f4
FS
322 if (c == 0)
323 return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
324 "%s: no addresses found", name);
79266746 325
78c6a153 326 print_source(flags, ts);
51323288 327
79266746
LP
328 return 0;
329}
330
331static int resolve_address(sd_bus *bus, int family, const union in_addr_union *address, int ifindex) {
4afd3348
LP
332 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
333 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
79266746 334 _cleanup_free_ char *pretty = NULL;
51323288 335 uint64_t flags;
79266746 336 unsigned c = 0;
74998408 337 usec_t ts;
79266746
LP
338 int r;
339
340 assert(bus);
341 assert(IN_SET(family, AF_INET, AF_INET6));
342 assert(address);
343
78c6a153
LP
344 if (ifindex <= 0)
345 ifindex = arg_ifindex;
346
145fab1e 347 r = in_addr_ifindex_to_string(family, address, ifindex, &pretty);
79266746
LP
348 if (r < 0)
349 return log_oom();
350
0889b815 351 log_debug("Resolving %s.", pretty);
79266746 352
d96f9abc 353 r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveAddress");
79266746
LP
354 if (r < 0)
355 return bus_log_create_error(r);
356
51323288 357 r = sd_bus_message_append(req, "ii", ifindex, family);
79266746
LP
358 if (r < 0)
359 return bus_log_create_error(r);
360
361 r = sd_bus_message_append_array(req, 'y', address, FAMILY_ADDRESS_SIZE(family));
362 if (r < 0)
363 return bus_log_create_error(r);
364
51323288 365 r = sd_bus_message_append(req, "t", arg_flags);
79266746
LP
366 if (r < 0)
367 return bus_log_create_error(r);
368
74998408
TG
369 ts = now(CLOCK_MONOTONIC);
370
4cbfd62b 371 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
4ae25393
YW
372 if (r < 0)
373 return log_error_errno(r, "%s: resolve call failed: %s", pretty, bus_error_message(&error, r));
79266746 374
74998408
TG
375 ts = now(CLOCK_MONOTONIC) - ts;
376
78c6a153 377 r = sd_bus_message_enter_container(reply, 'a', "(is)");
79266746
LP
378 if (r < 0)
379 return bus_log_create_error(r);
380
78c6a153
LP
381 while ((r = sd_bus_message_enter_container(reply, 'r', "is")) > 0) {
382 const char *n;
0889b815 383 int k;
78c6a153
LP
384
385 assert_cc(sizeof(int) == sizeof(int32_t));
79266746 386
78c6a153
LP
387 r = sd_bus_message_read(reply, "is", &ifindex, &n);
388 if (r < 0)
389 return r;
390
391 r = sd_bus_message_exit_container(reply);
392 if (r < 0)
393 return r;
394
38585af3
LP
395 k = printf("%*s%s %s%s%s",
396 (int) strlen(pretty), c == 0 ? pretty : "",
397 c == 0 ? ":" : " ",
398 ansi_highlight(), n, ansi_normal());
78c6a153 399
0889b815
LP
400 print_ifindex_comment(k, ifindex);
401 fputc('\n', stdout);
79266746
LP
402
403 c++;
bdef7319 404 }
79266746
LP
405 if (r < 0)
406 return bus_log_parse_error(r);
bdef7319 407
02dd6e18
LP
408 r = sd_bus_message_exit_container(reply);
409 if (r < 0)
410 return bus_log_parse_error(r);
411
51323288
LP
412 r = sd_bus_message_read(reply, "t", &flags);
413 if (r < 0)
414 return bus_log_parse_error(r);
415
d7a0f1f4
FS
416 if (c == 0)
417 return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
418 "%s: no names found", pretty);
79266746 419
78c6a153 420 print_source(flags, ts);
51323288 421
79266746
LP
422 return 0;
423}
424
dab48ea6
ZJS
425static int output_rr_packet(const void *d, size_t l, int ifindex) {
426 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
dab48ea6 427 int r;
dab48ea6 428
ab26cdf7 429 r = dns_resource_record_new_from_raw(&rr, d, l);
dab48ea6
ZJS
430 if (r < 0)
431 return log_error_errno(r, "Failed to parse RR: %m");
432
433 if (arg_raw == RAW_PAYLOAD) {
434 void *data;
435 ssize_t k;
436
437 k = dns_resource_record_payload(rr, &data);
438 if (k < 0)
439 return log_error_errno(k, "Cannot dump RR: %m");
440 fwrite(data, 1, k, stdout);
441 } else {
442 const char *s;
0889b815 443 int k;
dab48ea6
ZJS
444
445 s = dns_resource_record_to_string(rr);
446 if (!s)
447 return log_oom();
448
0889b815
LP
449 k = printf("%s", s);
450 print_ifindex_comment(k, ifindex);
451 fputc('\n', stdout);
dab48ea6
ZJS
452 }
453
454 return 0;
455}
456
018b642a
LP
457static int idna_candidate(const char *name, char **ret) {
458 _cleanup_free_ char *idnafied = NULL;
459 int r;
460
461 assert(name);
462 assert(ret);
463
464 r = dns_name_apply_idna(name, &idnafied);
465 if (r < 0)
466 return log_error_errno(r, "Failed to apply IDNA to name '%s': %m", name);
467 if (r > 0 && !streq(name, idnafied)) {
468 *ret = TAKE_PTR(idnafied);
469 return true;
470 }
471
472 *ret = NULL;
473 return false;
474}
475
058946d1
ZJS
476static bool single_label_nonsynthetic(const char *name) {
477 _cleanup_free_ char *first_label = NULL;
478 int r;
479
480 if (!dns_name_is_single_label(name))
481 return false;
482
483 if (is_localhost(name) || is_gateway_hostname(name))
484 return false;
485
486 r = resolve_system_hostname(NULL, &first_label);
487 if (r < 0) {
488 log_warning_errno(r, "Failed to determine the hostname: %m");
489 return false;
490 }
491
492 return !streq(name, first_label);
493}
494
a60f4d0b 495static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type, bool warn_missing) {
4afd3348
LP
496 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
497 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
018b642a
LP
498 _cleanup_free_ char *idnafied = NULL;
499 bool needs_authentication = false;
2d4c5cbc 500 unsigned n = 0;
51323288 501 uint64_t flags;
74998408 502 usec_t ts;
018b642a 503 int r;
2d4c5cbc
LP
504
505 assert(name);
506
a661dc36 507 log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(arg_ifname) ? "*" : arg_ifname);
2d4c5cbc 508
200b4f3d 509 if (dns_name_dot_suffixed(name) == 0 && single_label_nonsynthetic(name))
20e994b3
ZJS
510 log_notice("(Note that search domains are not appended when --type= is specified. "
511 "Please specify fully qualified domain names, or remove --type= switch from invocation in order to request regular hostname resolution.)");
018b642a
LP
512
513 r = idna_candidate(name, &idnafied);
514 if (r < 0)
515 return r;
516 if (r > 0)
20e994b3 517 log_notice("(Note that IDNA translation is not applied when --type= is specified. "
018b642a
LP
518 "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.",
519 idnafied);
520
d96f9abc 521 r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveRecord");
2d4c5cbc
LP
522 if (r < 0)
523 return bus_log_create_error(r);
524
c1dafe4f 525 r = sd_bus_message_append(req, "isqqt", arg_ifindex, name, class, type, arg_flags);
2d4c5cbc
LP
526 if (r < 0)
527 return bus_log_create_error(r);
528
74998408
TG
529 ts = now(CLOCK_MONOTONIC);
530
4cbfd62b 531 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
2d4c5cbc 532 if (r < 0) {
a60f4d0b
SS
533 if (warn_missing || r != -ENXIO)
534 log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
2d4c5cbc
LP
535 return r;
536 }
537
74998408
TG
538 ts = now(CLOCK_MONOTONIC) - ts;
539
78c6a153 540 r = sd_bus_message_enter_container(reply, 'a', "(iqqay)");
51323288
LP
541 if (r < 0)
542 return bus_log_parse_error(r);
543
78c6a153 544 while ((r = sd_bus_message_enter_container(reply, 'r', "iqqay")) > 0) {
2d4c5cbc 545 uint16_t c, t;
78c6a153 546 int ifindex;
2d4c5cbc
LP
547 const void *d;
548 size_t l;
549
78c6a153
LP
550 assert_cc(sizeof(int) == sizeof(int32_t));
551
552 r = sd_bus_message_read(reply, "iqq", &ifindex, &c, &t);
2d4c5cbc
LP
553 if (r < 0)
554 return bus_log_parse_error(r);
555
556 r = sd_bus_message_read_array(reply, 'y', &d, &l);
557 if (r < 0)
558 return bus_log_parse_error(r);
559
560 r = sd_bus_message_exit_container(reply);
561 if (r < 0)
562 return bus_log_parse_error(r);
563
dab48ea6
ZJS
564 if (arg_raw == RAW_PACKET) {
565 uint64_t u64 = htole64(l);
2d4c5cbc 566
dab48ea6
ZJS
567 fwrite(&u64, sizeof(u64), 1, stdout);
568 fwrite(d, 1, l, stdout);
2e74028a 569 } else {
dab48ea6
ZJS
570 r = output_rr_packet(d, l, ifindex);
571 if (r < 0)
572 return r;
2e74028a 573 }
78c6a153 574
41815a4a
LP
575 if (dns_type_needs_authentication(t))
576 needs_authentication = true;
577
2d4c5cbc
LP
578 n++;
579 }
580 if (r < 0)
581 return bus_log_parse_error(r);
582
583 r = sd_bus_message_exit_container(reply);
584 if (r < 0)
585 return bus_log_parse_error(r);
586
51323288
LP
587 r = sd_bus_message_read(reply, "t", &flags);
588 if (r < 0)
589 return bus_log_parse_error(r);
590
2d4c5cbc 591 if (n == 0) {
a60f4d0b
SS
592 if (warn_missing)
593 log_error("%s: no records found", name);
2d4c5cbc
LP
594 return -ESRCH;
595 }
596
78c6a153 597 print_source(flags, ts);
51323288 598
41815a4a
LP
599 if ((flags & SD_RESOLVED_AUTHENTICATED) == 0 && needs_authentication) {
600 fflush(stdout);
601
602 fprintf(stderr, "\n%s"
603 "WARNING: The resources shown contain cryptographic key data which could not be\n"
604 " authenticated. It is not suitable to authenticate any communication.\n"
605 " This is usually indication that DNSSEC authentication was not enabled\n"
606 " or is not available for the selected protocol or DNS servers.%s\n",
607 ansi_highlight_red(),
608 ansi_normal());
609 }
610
2d4c5cbc
LP
611 return 0;
612}
613
c1dafe4f
LP
614static int resolve_rfc4501(sd_bus *bus, const char *name) {
615 uint16_t type = 0, class = 0;
616 const char *p, *q, *n;
617 int r;
618
619 assert(bus);
620 assert(name);
621 assert(startswith(name, "dns:"));
622
623 /* Parse RFC 4501 dns: URIs */
624
625 p = name + 4;
626
627 if (p[0] == '/') {
628 const char *e;
629
630 if (p[1] != '/')
631 goto invalid;
632
633 e = strchr(p + 2, '/');
634 if (!e)
635 goto invalid;
636
637 if (e != p + 2)
638 log_warning("DNS authority specification not supported; ignoring specified authority.");
639
640 p = e + 1;
641 }
642
643 q = strchr(p, '?');
644 if (q) {
2f82562b 645 n = strndupa_safe(p, q - p);
c1dafe4f
LP
646 q++;
647
648 for (;;) {
649 const char *f;
650
651 f = startswith_no_case(q, "class=");
652 if (f) {
653 _cleanup_free_ char *t = NULL;
654 const char *e;
655
baaa35ad
ZJS
656 if (class != 0)
657 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
658 "DNS class specified twice.");
c1dafe4f
LP
659
660 e = strchrnul(f, ';');
661 t = strndup(f, e - f);
662 if (!t)
663 return log_oom();
664
665 r = dns_class_from_string(t);
baaa35ad 666 if (r < 0)
7211c853 667 return log_error_errno(r, "Unknown DNS class %s.", t);
c1dafe4f
LP
668
669 class = r;
670
671 if (*e == ';') {
672 q = e + 1;
673 continue;
674 }
675
676 break;
677 }
678
679 f = startswith_no_case(q, "type=");
680 if (f) {
681 _cleanup_free_ char *t = NULL;
682 const char *e;
683
baaa35ad
ZJS
684 if (type != 0)
685 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
686 "DNS type specified twice.");
c1dafe4f
LP
687
688 e = strchrnul(f, ';');
689 t = strndup(f, e - f);
690 if (!t)
691 return log_oom();
692
693 r = dns_type_from_string(t);
baaa35ad 694 if (r < 0)
7211c853 695 return log_error_errno(r, "Unknown DNS type %s: %m", t);
c1dafe4f
LP
696
697 type = r;
698
699 if (*e == ';') {
700 q = e + 1;
701 continue;
702 }
703
704 break;
705 }
706
707 goto invalid;
708 }
709 } else
710 n = p;
711
c1dafe4f 712 if (class == 0)
4ac2ca1b
ZJS
713 class = arg_class ?: DNS_CLASS_IN;
714 if (type == 0)
715 type = arg_type ?: DNS_TYPE_A;
c1dafe4f 716
a60f4d0b 717 return resolve_record(bus, n, class, type, true);
c1dafe4f
LP
718
719invalid:
baaa35ad
ZJS
720 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
721 "Invalid DNS URI: %s", name);
c1dafe4f
LP
722}
723
a7a4c60a
YW
724static int verb_query(int argc, char **argv, void *userdata) {
725 sd_bus *bus = userdata;
a7a4c60a
YW
726 int q, r = 0;
727
728 if (arg_type != 0)
729 STRV_FOREACH(p, argv + 1) {
730 q = resolve_record(bus, *p, arg_class, arg_type, true);
731 if (q < 0)
732 r = q;
733 }
734
735 else
736 STRV_FOREACH(p, argv + 1) {
737 if (startswith(*p, "dns:"))
738 q = resolve_rfc4501(bus, *p);
739 else {
740 int family, ifindex;
741 union in_addr_union a;
742
743 q = in_addr_ifindex_from_string_auto(*p, &family, &a, &ifindex);
744 if (q >= 0)
745 q = resolve_address(bus, family, &a, ifindex);
746 else
747 q = resolve_host(bus, *p);
748 }
749 if (q < 0)
750 r = q;
751 }
752
753 return r;
754}
755
45ec7efb
LP
756static int resolve_service(sd_bus *bus, const char *name, const char *type, const char *domain) {
757 const char *canonical_name, *canonical_type, *canonical_domain;
4afd3348
LP
758 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
759 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
45ec7efb
LP
760 size_t indent, sz;
761 uint64_t flags;
762 const char *p;
763 unsigned c;
764 usec_t ts;
765 int r;
766
767 assert(bus);
768 assert(domain);
769
3c6f7c34
LP
770 name = empty_to_null(name);
771 type = empty_to_null(type);
45ec7efb 772
45ec7efb 773 if (name)
a661dc36 774 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);
45ec7efb 775 else if (type)
a661dc36 776 log_debug("Resolving service type %s of %s (family %s, interface %s).", type, domain, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
45ec7efb 777 else
a661dc36 778 log_debug("Resolving service type %s (family %s, interface %s).", domain, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
45ec7efb 779
d96f9abc 780 r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveService");
45ec7efb
LP
781 if (r < 0)
782 return bus_log_create_error(r);
783
784 r = sd_bus_message_append(req, "isssit", arg_ifindex, name, type, domain, arg_family, arg_flags);
785 if (r < 0)
786 return bus_log_create_error(r);
787
788 ts = now(CLOCK_MONOTONIC);
789
4cbfd62b 790 r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
45ec7efb
LP
791 if (r < 0)
792 return log_error_errno(r, "Resolve call failed: %s", bus_error_message(&error, r));
793
794 ts = now(CLOCK_MONOTONIC) - ts;
795
796 r = sd_bus_message_enter_container(reply, 'a', "(qqqsa(iiay)s)");
797 if (r < 0)
798 return bus_log_parse_error(r);
799
800 indent =
801 (name ? strlen(name) + 1 : 0) +
802 (type ? strlen(type) + 1 : 0) +
803 strlen(domain) + 2;
804
805 c = 0;
806 while ((r = sd_bus_message_enter_container(reply, 'r', "qqqsa(iiay)s")) > 0) {
807 uint16_t priority, weight, port;
808 const char *hostname, *canonical;
809
810 r = sd_bus_message_read(reply, "qqqs", &priority, &weight, &port, &hostname);
811 if (r < 0)
812 return bus_log_parse_error(r);
813
814 if (name)
815 printf("%*s%s", (int) strlen(name), c == 0 ? name : "", c == 0 ? "/" : " ");
816 if (type)
817 printf("%*s%s", (int) strlen(type), c == 0 ? type : "", c == 0 ? "/" : " ");
818
819 printf("%*s%s %s:%u [priority=%u, weight=%u]\n",
820 (int) strlen(domain), c == 0 ? domain : "",
821 c == 0 ? ":" : " ",
822 hostname, port,
823 priority, weight);
824
825 r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
826 if (r < 0)
827 return bus_log_parse_error(r);
828
829 while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
830 _cleanup_free_ char *pretty = NULL;
0889b815 831 int ifindex, family, k;
aea29a30 832 union in_addr_union a;
45ec7efb
LP
833
834 assert_cc(sizeof(int) == sizeof(int32_t));
835
a574b7d1 836 r = sd_bus_message_read(reply, "i", &ifindex);
45ec7efb
LP
837 if (r < 0)
838 return bus_log_parse_error(r);
839
a574b7d1
YW
840 sd_bus_error_free(&error);
841 r = bus_message_read_in_addr_auto(reply, &error, &family, &a);
842 if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
843 return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&error, r));
45ec7efb
LP
844
845 r = sd_bus_message_exit_container(reply);
846 if (r < 0)
847 return bus_log_parse_error(r);
848
a574b7d1
YW
849 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
850 log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r));
45ec7efb
LP
851 continue;
852 }
853
a574b7d1 854 r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty);
45ec7efb
LP
855 if (r < 0)
856 return log_error_errno(r, "Failed to print address for %s: %m", name);
857
0889b815
LP
858 k = printf("%*s%s", (int) indent, "", pretty);
859 print_ifindex_comment(k, ifindex);
860 fputc('\n', stdout);
45ec7efb
LP
861 }
862 if (r < 0)
863 return bus_log_parse_error(r);
864
865 r = sd_bus_message_exit_container(reply);
866 if (r < 0)
867 return bus_log_parse_error(r);
868
869 r = sd_bus_message_read(reply, "s", &canonical);
870 if (r < 0)
871 return bus_log_parse_error(r);
872
873 if (!streq(hostname, canonical))
874 printf("%*s(%s)\n", (int) indent, "", canonical);
875
876 r = sd_bus_message_exit_container(reply);
877 if (r < 0)
878 return bus_log_parse_error(r);
879
880 c++;
881 }
882 if (r < 0)
883 return bus_log_parse_error(r);
884
885 r = sd_bus_message_exit_container(reply);
886 if (r < 0)
887 return bus_log_parse_error(r);
888
889 r = sd_bus_message_enter_container(reply, 'a', "ay");
890 if (r < 0)
891 return bus_log_parse_error(r);
892
45ec7efb
LP
893 while ((r = sd_bus_message_read_array(reply, 'y', (const void**) &p, &sz)) > 0) {
894 _cleanup_free_ char *escaped = NULL;
895
896 escaped = cescape_length(p, sz);
897 if (!escaped)
898 return log_oom();
899
900 printf("%*s%s\n", (int) indent, "", escaped);
45ec7efb
LP
901 }
902 if (r < 0)
903 return bus_log_parse_error(r);
904
905 r = sd_bus_message_exit_container(reply);
906 if (r < 0)
907 return bus_log_parse_error(r);
908
909 r = sd_bus_message_read(reply, "ssst", &canonical_name, &canonical_type, &canonical_domain, &flags);
910 if (r < 0)
911 return bus_log_parse_error(r);
912
3c6f7c34
LP
913 canonical_name = empty_to_null(canonical_name);
914 canonical_type = empty_to_null(canonical_type);
45ec7efb
LP
915
916 if (!streq_ptr(name, canonical_name) ||
917 !streq_ptr(type, canonical_type) ||
918 !streq_ptr(domain, canonical_domain)) {
919
920 printf("%*s(", (int) indent, "");
921
922 if (canonical_name)
923 printf("%s/", canonical_name);
924 if (canonical_type)
925 printf("%s/", canonical_type);
926
927 printf("%s)\n", canonical_domain);
928 }
929
930 print_source(flags, ts);
931
932 return 0;
933}
934
a7a4c60a
YW
935static int verb_service(int argc, char **argv, void *userdata) {
936 sd_bus *bus = userdata;
937
938 if (argc == 2)
939 return resolve_service(bus, NULL, NULL, argv[1]);
940 else if (argc == 3)
941 return resolve_service(bus, NULL, argv[1], argv[2]);
942 else
943 return resolve_service(bus, argv[1], argv[2], argv[3]);
944}
945
4ac2ca1b
ZJS
946static int resolve_openpgp(sd_bus *bus, const char *address) {
947 const char *domain, *full;
948 int r;
949 _cleanup_free_ char *hashed = NULL;
950
951 assert(bus);
952 assert(address);
953
954 domain = strrchr(address, '@');
baaa35ad
ZJS
955 if (!domain)
956 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
957 "Address does not contain '@': \"%s\"", address);
958 if (domain == address || domain[1] == '\0')
959 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
960 "Address starts or ends with '@': \"%s\"", address);
4ac2ca1b
ZJS
961 domain++;
962
a60f4d0b 963 r = string_hashsum_sha256(address, domain - 1 - address, &hashed);
4ac2ca1b
ZJS
964 if (r < 0)
965 return log_error_errno(r, "Hashing failed: %m");
966
a60f4d0b
SS
967 strshorten(hashed, 56);
968
4ac2ca1b
ZJS
969 full = strjoina(hashed, "._openpgpkey.", domain);
970 log_debug("Looking up \"%s\".", full);
971
a60f4d0b
SS
972 r = resolve_record(bus, full,
973 arg_class ?: DNS_CLASS_IN,
974 arg_type ?: DNS_TYPE_OPENPGPKEY, false);
975
976 if (IN_SET(r, -ENXIO, -ESRCH)) { /* NXDOMAIN or NODATA? */
670e95ae 977 hashed = mfree(hashed);
a60f4d0b
SS
978 r = string_hashsum_sha224(address, domain - 1 - address, &hashed);
979 if (r < 0)
980 return log_error_errno(r, "Hashing failed: %m");
981
982 full = strjoina(hashed, "._openpgpkey.", domain);
983 log_debug("Looking up \"%s\".", full);
984
985 return resolve_record(bus, full,
986 arg_class ?: DNS_CLASS_IN,
987 arg_type ?: DNS_TYPE_OPENPGPKEY, true);
988 }
989
990 return r;
4ac2ca1b
ZJS
991}
992
a7a4c60a
YW
993static int verb_openpgp(int argc, char **argv, void *userdata) {
994 sd_bus *bus = userdata;
a7a4c60a
YW
995 int q, r = 0;
996
997 STRV_FOREACH(p, argv + 1) {
998 q = resolve_openpgp(bus, *p);
999 if (q < 0)
1000 r = q;
1001 }
1002
1003 return r;
1004}
1005
ebbc70e5 1006static int resolve_tlsa(sd_bus *bus, const char *family, const char *address) {
82d1d240
ZJS
1007 const char *port;
1008 uint16_t port_num = 443;
1009 _cleanup_free_ char *full = NULL;
1010 int r;
1011
1012 assert(bus);
1013 assert(address);
1014
1015 port = strrchr(address, ':');
1016 if (port) {
10452f7c
SS
1017 r = parse_ip_port(port + 1, &port_num);
1018 if (r < 0)
82d1d240
ZJS
1019 return log_error_errno(r, "Invalid port \"%s\".", port + 1);
1020
2f82562b 1021 address = strndupa_safe(address, port - address);
82d1d240
ZJS
1022 }
1023
ebbc70e5 1024 r = asprintf(&full, "_%u._%s.%s",
82d1d240 1025 port_num,
ebbc70e5 1026 family,
82d1d240
ZJS
1027 address);
1028 if (r < 0)
1029 return log_oom();
1030
1031 log_debug("Looking up \"%s\".", full);
1032
1033 return resolve_record(bus, full,
1034 arg_class ?: DNS_CLASS_IN,
a60f4d0b 1035 arg_type ?: DNS_TYPE_TLSA, true);
82d1d240
ZJS
1036}
1037
ebbc70e5
YW
1038static bool service_family_is_valid(const char *s) {
1039 return STR_IN_SET(s, "tcp", "udp", "sctp");
1040}
1041
a7a4c60a
YW
1042static int verb_tlsa(int argc, char **argv, void *userdata) {
1043 sd_bus *bus = userdata;
de010b0b 1044 char **args = argv + 1;
ebbc70e5 1045 const char *family = "tcp";
a7a4c60a
YW
1046 int q, r = 0;
1047
ebbc70e5
YW
1048 if (service_family_is_valid(argv[1])) {
1049 family = argv[1];
a7a4c60a 1050 args++;
ebbc70e5 1051 }
a7a4c60a
YW
1052
1053 STRV_FOREACH(p, args) {
1054 q = resolve_tlsa(bus, family, *p);
1055 if (q < 0)
1056 r = q;
1057 }
1058
1059 return r;
1060}
1061
1062static int show_statistics(int argc, char **argv, void *userdata) {
a150ff5e
LP
1063 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1064 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
29e15e98 1065 _cleanup_(table_unrefp) Table *table = NULL;
99534007 1066 sd_bus *bus = ASSERT_PTR(userdata);
a150ff5e
LP
1067 uint64_t n_current_transactions, n_total_transactions,
1068 cache_size, n_cache_hit, n_cache_miss,
1069 n_dnssec_secure, n_dnssec_insecure, n_dnssec_bogus, n_dnssec_indeterminate;
593f665c 1070 int r, dnssec_supported;
a150ff5e 1071
d96f9abc 1072 r = bus_get_property_trivial(bus, bus_resolve_mgr, "DNSSECSupported", &error, 'b', &dnssec_supported);
593f665c
LP
1073 if (r < 0)
1074 return log_error_errno(r, "Failed to get DNSSEC supported state: %s", bus_error_message(&error, r));
1075
1076 printf("DNSSEC supported by current servers: %s%s%s\n\n",
1077 ansi_highlight(),
1078 yes_no(dnssec_supported),
1079 ansi_normal());
1080
d96f9abc 1081 r = bus_get_property(bus, bus_resolve_mgr, "TransactionStatistics", &error, &reply, "(tt)");
a150ff5e
LP
1082 if (r < 0)
1083 return log_error_errno(r, "Failed to get transaction statistics: %s", bus_error_message(&error, r));
1084
1085 r = sd_bus_message_read(reply, "(tt)",
1086 &n_current_transactions,
1087 &n_total_transactions);
1088 if (r < 0)
1089 return bus_log_parse_error(r);
1090
a150ff5e
LP
1091 reply = sd_bus_message_unref(reply);
1092
d96f9abc 1093 r = bus_get_property(bus, bus_resolve_mgr, "CacheStatistics", &error, &reply, "(ttt)");
f7700834
TA
1094 if (r < 0)
1095 return log_error_errno(r, "Failed to get cache statistics: %s", bus_error_message(&error, r));
a150ff5e
LP
1096
1097 r = sd_bus_message_read(reply, "(ttt)",
1098 &cache_size,
1099 &n_cache_hit,
1100 &n_cache_miss);
1101 if (r < 0)
1102 return bus_log_parse_error(r);
1103
a150ff5e
LP
1104 reply = sd_bus_message_unref(reply);
1105
d96f9abc 1106 r = bus_get_property(bus, bus_resolve_mgr, "DNSSECStatistics", &error, &reply, "(tttt)");
f7700834
TA
1107 if (r < 0)
1108 return log_error_errno(r, "Failed to get DNSSEC statistics: %s", bus_error_message(&error, r));
a150ff5e
LP
1109
1110 r = sd_bus_message_read(reply, "(tttt)",
1111 &n_dnssec_secure,
1112 &n_dnssec_insecure,
1113 &n_dnssec_bogus,
1114 &n_dnssec_indeterminate);
1115 if (r < 0)
1116 return bus_log_parse_error(r);
1117
37a50123 1118 table = table_new_vertical();
29e15e98
YW
1119 if (!table)
1120 return log_oom();
1121
29e15e98
YW
1122 r = table_add_many(table,
1123 TABLE_STRING, "Transactions",
1124 TABLE_SET_COLOR, ansi_highlight(),
37a50123 1125 TABLE_SET_ALIGN_PERCENT, 0,
29e15e98 1126 TABLE_EMPTY,
37a50123 1127 TABLE_FIELD, "Current Transactions",
29e15e98
YW
1128 TABLE_SET_ALIGN_PERCENT, 100,
1129 TABLE_UINT64, n_current_transactions,
37a50123
LP
1130 TABLE_SET_ALIGN_PERCENT, 100,
1131 TABLE_FIELD, "Total Transactions",
29e15e98
YW
1132 TABLE_UINT64, n_total_transactions,
1133 TABLE_EMPTY, TABLE_EMPTY,
1134 TABLE_STRING, "Cache",
1135 TABLE_SET_COLOR, ansi_highlight(),
1136 TABLE_SET_ALIGN_PERCENT, 0,
1137 TABLE_EMPTY,
37a50123 1138 TABLE_FIELD, "Current Cache Size",
29e15e98
YW
1139 TABLE_SET_ALIGN_PERCENT, 100,
1140 TABLE_UINT64, cache_size,
37a50123 1141 TABLE_FIELD, "Cache Hits",
29e15e98 1142 TABLE_UINT64, n_cache_hit,
37a50123 1143 TABLE_FIELD, "Cache Misses",
29e15e98
YW
1144 TABLE_UINT64, n_cache_miss,
1145 TABLE_EMPTY, TABLE_EMPTY,
1146 TABLE_STRING, "DNSSEC Verdicts",
1147 TABLE_SET_COLOR, ansi_highlight(),
1148 TABLE_SET_ALIGN_PERCENT, 0,
1149 TABLE_EMPTY,
37a50123 1150 TABLE_FIELD, "Secure",
29e15e98
YW
1151 TABLE_SET_ALIGN_PERCENT, 100,
1152 TABLE_UINT64, n_dnssec_secure,
37a50123 1153 TABLE_FIELD, "Insecure",
29e15e98 1154 TABLE_UINT64, n_dnssec_insecure,
37a50123 1155 TABLE_FIELD, "Bogus",
29e15e98 1156 TABLE_UINT64, n_dnssec_bogus,
37a50123 1157 TABLE_FIELD, "Indeterminate:",
29e15e98
YW
1158 TABLE_UINT64, n_dnssec_indeterminate);
1159 if (r < 0)
85840949 1160 return table_log_add_error(r);
29e15e98
YW
1161
1162 r = table_print(table, NULL);
1163 if (r < 0)
4b6607d9 1164 return table_log_print_error(r);
a150ff5e
LP
1165
1166 return 0;
1167}
1168
a7a4c60a 1169static int reset_statistics(int argc, char **argv, void *userdata) {
a150ff5e 1170 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
a7a4c60a 1171 sd_bus *bus = userdata;
a150ff5e
LP
1172 int r;
1173
d96f9abc 1174 r = bus_call_method(bus, bus_resolve_mgr, "ResetStatistics", &error, NULL, NULL);
a150ff5e
LP
1175 if (r < 0)
1176 return log_error_errno(r, "Failed to reset statistics: %s", bus_error_message(&error, r));
1177
1178 return 0;
1179}
1180
a7a4c60a 1181static int flush_caches(int argc, char **argv, void *userdata) {
ba35662f 1182 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
a7a4c60a 1183 sd_bus *bus = userdata;
ba35662f
LP
1184 int r;
1185
d96f9abc 1186 r = bus_call_method(bus, bus_resolve_mgr, "FlushCaches", &error, NULL, NULL);
ba35662f
LP
1187 if (r < 0)
1188 return log_error_errno(r, "Failed to flush caches: %s", bus_error_message(&error, r));
1189
1190 return 0;
1191}
1192
a7a4c60a 1193static int reset_server_features(int argc, char **argv, void *userdata) {
d55b0463 1194 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
a7a4c60a 1195 sd_bus *bus = userdata;
d55b0463
LP
1196 int r;
1197
d96f9abc 1198 r = bus_call_method(bus, bus_resolve_mgr, "ResetServerFeatures", &error, NULL, NULL);
d55b0463
LP
1199 if (r < 0)
1200 return log_error_errno(r, "Failed to reset server features: %s", bus_error_message(&error, r));
1201
1202 return 0;
1203}
1204
a747e71c 1205static int read_dns_server_one(sd_bus_message *m, bool with_ifindex, bool extended, char **ret) {
a574b7d1 1206 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
58f48a56 1207 _cleanup_free_ char *pretty = NULL;
a574b7d1
YW
1208 int ifindex, family, r, k;
1209 union in_addr_union a;
a747e71c
YW
1210 const char *name = NULL;
1211 uint16_t port = 0;
58f48a56
YW
1212
1213 assert(m);
1214 assert(ret);
1215
a747e71c 1216 r = sd_bus_message_enter_container(m, 'r', with_ifindex ? (extended ? "iiayqs" : "iiay") : (extended ? "iayqs" : "iay"));
58f48a56
YW
1217 if (r <= 0)
1218 return r;
1219
1220 if (with_ifindex) {
1221 r = sd_bus_message_read(m, "i", &ifindex);
1222 if (r < 0)
1223 return r;
1224 }
1225
a574b7d1
YW
1226 k = bus_message_read_in_addr_auto(m, &error, &family, &a);
1227 if (k < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
1228 return k;
58f48a56 1229
a747e71c
YW
1230 if (extended) {
1231 r = sd_bus_message_read(m, "q", &port);
1232 if (r < 0)
1233 return r;
1234
1235 r = sd_bus_message_read(m, "s", &name);
1236 if (r < 0)
1237 return r;
1238 }
1239
58f48a56
YW
1240 r = sd_bus_message_exit_container(m);
1241 if (r < 0)
1242 return r;
1243
a574b7d1
YW
1244 if (k < 0) {
1245 log_debug("Invalid DNS server, ignoring: %s", bus_error_message(&error, k));
58f48a56
YW
1246 *ret = NULL;
1247 return 1;
1248 }
1249
a574b7d1
YW
1250 if (with_ifindex && ifindex != 0) {
1251 /* only show the global ones here */
58f48a56
YW
1252 *ret = NULL;
1253 return 1;
1254 }
1255
a574b7d1 1256 r = in_addr_port_ifindex_name_to_string(family, &a, port, ifindex, name, &pretty);
58f48a56
YW
1257 if (r < 0)
1258 return r;
1259
1260 *ret = TAKE_PTR(pretty);
1261
1262 return 1;
1263}
1264
a747e71c 1265static int map_link_dns_servers_internal(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata, bool extended) {
99534007 1266 char ***l = ASSERT_PTR(userdata);
be371fe0
LP
1267 int r;
1268
1269 assert(bus);
1270 assert(member);
1271 assert(m);
be371fe0 1272
a747e71c 1273 r = sd_bus_message_enter_container(m, 'a', extended ? "(iayqs)" : "(iay)");
be371fe0
LP
1274 if (r < 0)
1275 return r;
1276
1277 for (;;) {
6abdec98 1278 _cleanup_free_ char *pretty = NULL;
be371fe0 1279
a747e71c 1280 r = read_dns_server_one(m, false, extended, &pretty);
be371fe0
LP
1281 if (r < 0)
1282 return r;
1283 if (r == 0)
1284 break;
1285
58f48a56 1286 if (isempty(pretty))
be371fe0 1287 continue;
be371fe0 1288
6abdec98 1289 r = strv_consume(l, TAKE_PTR(pretty));
be371fe0
LP
1290 if (r < 0)
1291 return r;
1292 }
1293
1294 r = sd_bus_message_exit_container(m);
1295 if (r < 0)
1296 return r;
1297
1298 return 0;
1299}
1300
a747e71c
YW
1301static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1302 return map_link_dns_servers_internal(bus, member, m, error, userdata, false);
1303}
1304
1305static int map_link_dns_servers_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1306 return map_link_dns_servers_internal(bus, member, m, error, userdata, true);
1307}
1308
446c6415
YW
1309static int map_link_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1310 assert(m);
1311 assert(userdata);
1312
a747e71c
YW
1313 return read_dns_server_one(m, false, false, userdata);
1314}
1315
1316static int map_link_current_dns_server_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1317 assert(m);
1318 assert(userdata);
1319
1320 return read_dns_server_one(m, false, true, userdata);
446c6415
YW
1321}
1322
c513bb6e
YW
1323static int read_domain_one(sd_bus_message *m, bool with_ifindex, char **ret) {
1324 _cleanup_free_ char *str = NULL;
1325 int ifindex, route_only, r;
1326 const char *domain;
1327
1328 assert(m);
1329 assert(ret);
1330
1331 if (with_ifindex)
1332 r = sd_bus_message_read(m, "(isb)", &ifindex, &domain, &route_only);
1333 else
1334 r = sd_bus_message_read(m, "(sb)", &domain, &route_only);
1335 if (r <= 0)
1336 return r;
1337
1338 if (with_ifindex && ifindex != 0) {
1339 /* only show the global ones here */
1340 *ret = NULL;
1341 return 1;
1342 }
1343
1344 if (route_only)
b910cc72 1345 str = strjoin("~", domain);
c513bb6e
YW
1346 else
1347 str = strdup(domain);
1348 if (!str)
1349 return -ENOMEM;
1350
1351 *ret = TAKE_PTR(str);
1352
1353 return 1;
1354}
1355
be371fe0 1356static int map_link_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
99534007 1357 char ***l = ASSERT_PTR(userdata);
be371fe0
LP
1358 int r;
1359
1360 assert(bus);
1361 assert(member);
1362 assert(m);
be371fe0
LP
1363
1364 r = sd_bus_message_enter_container(m, 'a', "(sb)");
1365 if (r < 0)
1366 return r;
1367
1368 for (;;) {
6abdec98 1369 _cleanup_free_ char *pretty = NULL;
be371fe0 1370
c513bb6e 1371 r = read_domain_one(m, false, &pretty);
be371fe0
LP
1372 if (r < 0)
1373 return r;
1374 if (r == 0)
1375 break;
1376
c513bb6e
YW
1377 if (isempty(pretty))
1378 continue;
be371fe0 1379
6abdec98 1380 r = strv_consume(l, TAKE_PTR(pretty));
be371fe0
LP
1381 if (r < 0)
1382 return r;
1383 }
1384
1385 r = sd_bus_message_exit_container(m);
1386 if (r < 0)
1387 return r;
1388
af781878
ZJS
1389 strv_sort(*l);
1390
be371fe0
LP
1391 return 0;
1392}
1393
a7a4c60a 1394static int status_print_strv_ifindex(int ifindex, const char *ifname, char **p) {
7c502303
ZJS
1395 const unsigned indent = strlen("Global: "); /* Use the same indentation everywhere to make things nice */
1396 int pos1, pos2;
1397
1398 if (ifname)
1399 printf("%s%nLink %i (%s)%n%s:", ansi_highlight(), &pos1, ifindex, ifname, &pos2, ansi_normal());
1400 else
1401 printf("%s%nGlobal%n%s:", ansi_highlight(), &pos1, &pos2, ansi_normal());
1402
1403 size_t cols = columns(), position = pos2 - pos1 + 2;
a7a4c60a 1404
7c502303
ZJS
1405 STRV_FOREACH(i, p) {
1406 size_t our_len = utf8_console_width(*i); /* This returns -1 on invalid utf-8 (which shouldn't happen).
1407 * If that happens, we'll just print one item per line. */
a7a4c60a 1408
b0e3d799 1409 if (position <= indent || size_add(size_add(position, 1), our_len) < cols) {
7c502303 1410 printf(" %s", *i);
b0e3d799 1411 position = size_add(size_add(position, 1), our_len);
7c502303 1412 } else {
f996072f 1413 printf("\n%*s%s", (int) indent, "", *i);
b0e3d799 1414 position = size_add(our_len, indent);
7c502303
ZJS
1415 }
1416 }
a7a4c60a
YW
1417
1418 printf("\n");
1419
1420 return 0;
1421}
1422
7c502303
ZJS
1423static int status_print_strv_global(char **p) {
1424 return status_print_strv_ifindex(0, NULL, p);
1425}
1426
80b8c3d7 1427typedef struct LinkInfo {
906119c0
YW
1428 uint64_t scopes_mask;
1429 const char *llmnr;
1430 const char *mdns;
1431 const char *dns_over_tls;
1432 const char *dnssec;
1433 char *current_dns;
a747e71c 1434 char *current_dns_ex;
906119c0 1435 char **dns;
a747e71c 1436 char **dns_ex;
906119c0
YW
1437 char **domains;
1438 char **ntas;
1439 bool dnssec_supported;
f2fd3cdb 1440 bool default_route;
80b8c3d7 1441} LinkInfo;
906119c0 1442
80b8c3d7
ZJS
1443typedef struct GlobalInfo {
1444 char *current_dns;
1445 char *current_dns_ex;
1446 char **dns;
1447 char **dns_ex;
1448 char **fallback_dns;
1449 char **fallback_dns_ex;
1450 char **domains;
1451 char **ntas;
1452 const char *llmnr;
1453 const char *mdns;
1454 const char *dns_over_tls;
1455 const char *dnssec;
1456 const char *resolv_conf_mode;
1457 bool dnssec_supported;
1458} GlobalInfo;
1459
1460static void link_info_clear(LinkInfo *p) {
1461 free(p->current_dns);
1462 free(p->current_dns_ex);
1463 strv_free(p->dns);
1464 strv_free(p->dns_ex);
1465 strv_free(p->domains);
1466 strv_free(p->ntas);
1467}
1468
1469static void global_info_clear(GlobalInfo *p) {
906119c0 1470 free(p->current_dns);
a747e71c 1471 free(p->current_dns_ex);
906119c0 1472 strv_free(p->dns);
a747e71c 1473 strv_free(p->dns_ex);
80b8c3d7
ZJS
1474 strv_free(p->fallback_dns);
1475 strv_free(p->fallback_dns_ex);
906119c0
YW
1476 strv_free(p->domains);
1477 strv_free(p->ntas);
1478}
be371fe0 1479
37a50123 1480static int dump_list(Table *table, const char *field, char * const *l) {
29e15e98
YW
1481 int r;
1482
1483 if (strv_isempty(l))
1484 return 0;
1485
1486 r = table_add_many(table,
37a50123 1487 TABLE_FIELD, field,
f08a64c5 1488 TABLE_STRV_WRAPPED, l);
29e15e98
YW
1489 if (r < 0)
1490 return table_log_add_error(r);
1491
1492 return 0;
1493}
1494
fe37e5a5
ZJS
1495static int strv_extend_extended_bool(char ***strv, const char *name, const char *value) {
1496 int r;
1497
1498 if (value) {
1499 r = parse_boolean(value);
1500 if (r >= 0)
1501 return strv_extendf(strv, "%s%s", plus_minus(r), name);
1502 }
1503
1504 return strv_extendf(strv, "%s=%s", name, value ?: "???");
1505}
1506
7d1e1afe 1507static char** link_protocol_status(const LinkInfo *info) {
fe37e5a5
ZJS
1508 _cleanup_strv_free_ char **s = NULL;
1509
1510 if (strv_extendf(&s, "%sDefaultRoute", plus_minus(info->default_route)) < 0)
1511 return NULL;
1512
1513 if (strv_extend_extended_bool(&s, "LLMNR", info->llmnr) < 0)
1514 return NULL;
1515
1516 if (strv_extend_extended_bool(&s, "mDNS", info->mdns) < 0)
1517 return NULL;
1518
1519 if (strv_extend_extended_bool(&s, "DNSOverTLS", info->dns_over_tls) < 0)
1520 return NULL;
1521
1522 if (strv_extendf(&s, "DNSSEC=%s/%s",
1523 info->dnssec ?: "???",
1524 info->dnssec_supported ? "supported" : "unsupported") < 0)
1525 return NULL;
1526
7d1e1afe 1527 return TAKE_PTR(s);
fe37e5a5
ZJS
1528}
1529
7d1e1afe 1530static char** global_protocol_status(const GlobalInfo *info) {
fe37e5a5
ZJS
1531 _cleanup_strv_free_ char **s = NULL;
1532
1533 if (strv_extend_extended_bool(&s, "LLMNR", info->llmnr) < 0)
1534 return NULL;
1535
1536 if (strv_extend_extended_bool(&s, "mDNS", info->mdns) < 0)
1537 return NULL;
1538
1539 if (strv_extend_extended_bool(&s, "DNSOverTLS", info->dns_over_tls) < 0)
1540 return NULL;
1541
1542 if (strv_extendf(&s, "DNSSEC=%s/%s",
1543 info->dnssec ?: "???",
1544 info->dnssec_supported ? "supported" : "unsupported") < 0)
1545 return NULL;
1546
7d1e1afe 1547 return TAKE_PTR(s);
fe37e5a5
ZJS
1548}
1549
906119c0 1550static int status_ifindex(sd_bus *bus, int ifindex, const char *name, StatusMode mode, bool *empty_line) {
be371fe0 1551 static const struct bus_properties_map property_map[] = {
80b8c3d7
ZJS
1552 { "ScopesMask", "t", NULL, offsetof(LinkInfo, scopes_mask) },
1553 { "DNS", "a(iay)", map_link_dns_servers, offsetof(LinkInfo, dns) },
1554 { "DNSEx", "a(iayqs)", map_link_dns_servers_ex, offsetof(LinkInfo, dns_ex) },
1555 { "CurrentDNSServer", "(iay)", map_link_current_dns_server, offsetof(LinkInfo, current_dns) },
1556 { "CurrentDNSServerEx", "(iayqs)", map_link_current_dns_server_ex, offsetof(LinkInfo, current_dns_ex) },
1557 { "Domains", "a(sb)", map_link_domains, offsetof(LinkInfo, domains) },
1558 { "DefaultRoute", "b", NULL, offsetof(LinkInfo, default_route) },
1559 { "LLMNR", "s", NULL, offsetof(LinkInfo, llmnr) },
1560 { "MulticastDNS", "s", NULL, offsetof(LinkInfo, mdns) },
1561 { "DNSOverTLS", "s", NULL, offsetof(LinkInfo, dns_over_tls) },
1562 { "DNSSEC", "s", NULL, offsetof(LinkInfo, dnssec) },
af781878 1563 { "DNSSECNegativeTrustAnchors", "as", bus_map_strv_sort, offsetof(LinkInfo, ntas) },
80b8c3d7 1564 { "DNSSECSupported", "b", NULL, offsetof(LinkInfo, dnssec_supported) },
be371fe0
LP
1565 {}
1566 };
f9e0eefc 1567 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
f37f8a61 1568 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
80b8c3d7 1569 _cleanup_(link_info_clear) LinkInfo link_info = {};
29e15e98 1570 _cleanup_(table_unrefp) Table *table = NULL;
957d9df3 1571 _cleanup_free_ char *p = NULL;
01afd0f7 1572 char ifi[DECIMAL_STR_MAX(int)], ifname[IF_NAMESIZE];
be371fe0
LP
1573 int r;
1574
1575 assert(bus);
1576 assert(ifindex > 0);
be371fe0
LP
1577
1578 if (!name) {
01afd0f7
YW
1579 r = format_ifname(ifindex, ifname);
1580 if (r < 0)
1581 return log_error_errno(r, "Failed to resolve interface name for %i: %m", ifindex);
be371fe0
LP
1582
1583 name = ifname;
1584 }
1585
957d9df3 1586 xsprintf(ifi, "%i", ifindex);
be371fe0
LP
1587 r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifi, &p);
1588 if (r < 0)
1589 return log_oom();
1590
1591 r = bus_map_all_properties(bus,
1592 "org.freedesktop.resolve1",
1593 p,
1594 property_map,
a7e4861c 1595 BUS_MAP_BOOLEAN_AS_BOOL,
f9e0eefc 1596 &error,
f37f8a61 1597 &m,
be371fe0 1598 &link_info);
906119c0
YW
1599 if (r < 0)
1600 return log_error_errno(r, "Failed to get link data for %i: %s", ifindex, bus_error_message(&error, r));
be371fe0 1601
384c2c32 1602 pager_open(arg_pager_flags);
be371fe0 1603
906119c0 1604 if (mode == STATUS_DNS)
a747e71c 1605 return status_print_strv_ifindex(ifindex, name, link_info.dns_ex ?: link_info.dns);
a7a4c60a 1606
906119c0
YW
1607 if (mode == STATUS_DOMAIN)
1608 return status_print_strv_ifindex(ifindex, name, link_info.domains);
a7a4c60a 1609
906119c0
YW
1610 if (mode == STATUS_NTA)
1611 return status_print_strv_ifindex(ifindex, name, link_info.ntas);
a7a4c60a 1612
f2fd3cdb
LP
1613 if (mode == STATUS_DEFAULT_ROUTE) {
1614 printf("%sLink %i (%s)%s: %s\n",
1615 ansi_highlight(), ifindex, name, ansi_normal(),
1616 yes_no(link_info.default_route));
1617
1618 return 0;
1619 }
1620
a7a4c60a
YW
1621 if (mode == STATUS_LLMNR) {
1622 printf("%sLink %i (%s)%s: %s\n",
1623 ansi_highlight(), ifindex, name, ansi_normal(),
1624 strna(link_info.llmnr));
1625
906119c0 1626 return 0;
a7a4c60a
YW
1627 }
1628
1629 if (mode == STATUS_MDNS) {
1630 printf("%sLink %i (%s)%s: %s\n",
1631 ansi_highlight(), ifindex, name, ansi_normal(),
1632 strna(link_info.mdns));
1633
906119c0 1634 return 0;
a7a4c60a
YW
1635 }
1636
d050561a
IT
1637 if (mode == STATUS_PRIVATE) {
1638 printf("%sLink %i (%s)%s: %s\n",
1639 ansi_highlight(), ifindex, name, ansi_normal(),
c9299be2 1640 strna(link_info.dns_over_tls));
d050561a 1641
906119c0 1642 return 0;
d050561a
IT
1643 }
1644
a7a4c60a
YW
1645 if (mode == STATUS_DNSSEC) {
1646 printf("%sLink %i (%s)%s: %s\n",
1647 ansi_highlight(), ifindex, name, ansi_normal(),
1648 strna(link_info.dnssec));
1649
906119c0 1650 return 0;
a7a4c60a
YW
1651 }
1652
1653 if (empty_line && *empty_line)
be371fe0
LP
1654 fputc('\n', stdout);
1655
1656 printf("%sLink %i (%s)%s\n",
1657 ansi_highlight(), ifindex, name, ansi_normal());
1658
37a50123 1659 table = table_new_vertical();
29e15e98
YW
1660 if (!table)
1661 return log_oom();
1662
29e15e98 1663 r = table_add_many(table,
37a50123
LP
1664 TABLE_FIELD, "Current Scopes",
1665 TABLE_SET_MINIMUM_WIDTH, 19);
29e15e98
YW
1666 if (r < 0)
1667 return table_log_add_error(r);
1668
be371fe0 1669 if (link_info.scopes_mask == 0)
29e15e98
YW
1670 r = table_add_cell(table, NULL, TABLE_STRING, "none");
1671 else {
1672 _cleanup_free_ char *buf = NULL;
1673 size_t len;
1674
1675 if (asprintf(&buf, "%s%s%s%s%s",
1676 link_info.scopes_mask & SD_RESOLVED_DNS ? "DNS " : "",
1677 link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV4 ? "LLMNR/IPv4 " : "",
1678 link_info.scopes_mask & SD_RESOLVED_LLMNR_IPV6 ? "LLMNR/IPv6 " : "",
1679 link_info.scopes_mask & SD_RESOLVED_MDNS_IPV4 ? "mDNS/IPv4 " : "",
1680 link_info.scopes_mask & SD_RESOLVED_MDNS_IPV6 ? "mDNS/IPv6 " : "") < 0)
1681 return log_oom();
be371fe0 1682
29e15e98
YW
1683 len = strlen(buf);
1684 assert(len > 0);
1685 buf[len - 1] = '\0';
be371fe0 1686
29e15e98
YW
1687 r = table_add_cell(table, NULL, TABLE_STRING, buf);
1688 }
1689 if (r < 0)
1690 return table_log_add_error(r);
1691
7d1e1afe 1692 _cleanup_strv_free_ char **pstatus = link_protocol_status(&link_info);
fe37e5a5
ZJS
1693 if (!pstatus)
1694 return log_oom();
1695
29e15e98 1696 r = table_add_many(table,
37a50123 1697 TABLE_FIELD, "Protocols",
7d1e1afe 1698 TABLE_STRV_WRAPPED, pstatus);
29e15e98
YW
1699 if (r < 0)
1700 return table_log_add_error(r);
1701
1702 if (link_info.current_dns) {
1703 r = table_add_many(table,
37a50123 1704 TABLE_FIELD, "Current DNS Server",
a747e71c 1705 TABLE_STRING, link_info.current_dns_ex ?: link_info.current_dns);
29e15e98
YW
1706 if (r < 0)
1707 return table_log_add_error(r);
be371fe0
LP
1708 }
1709
37a50123 1710 r = dump_list(table, "DNS Servers", link_info.dns_ex ?: link_info.dns);
29e15e98
YW
1711 if (r < 0)
1712 return r;
1713
37a50123 1714 r = dump_list(table, "DNS Domain", link_info.domains);
29e15e98
YW
1715 if (r < 0)
1716 return r;
1717
29e15e98
YW
1718 r = table_print(table, NULL);
1719 if (r < 0)
4b6607d9 1720 return table_log_print_error(r);
29e15e98 1721
a7a4c60a
YW
1722 if (empty_line)
1723 *empty_line = true;
be371fe0 1724
906119c0 1725 return 0;
be371fe0
LP
1726}
1727
a747e71c 1728static int map_global_dns_servers_internal(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata, bool extended) {
99534007 1729 char ***l = ASSERT_PTR(userdata);
be371fe0
LP
1730 int r;
1731
1732 assert(bus);
1733 assert(member);
1734 assert(m);
be371fe0 1735
a747e71c 1736 r = sd_bus_message_enter_container(m, 'a', extended ? "(iiayqs)" : "(iiay)");
be371fe0
LP
1737 if (r < 0)
1738 return r;
1739
1740 for (;;) {
6abdec98 1741 _cleanup_free_ char *pretty = NULL;
be371fe0 1742
a747e71c 1743 r = read_dns_server_one(m, true, extended, &pretty);
be371fe0
LP
1744 if (r < 0)
1745 return r;
1746 if (r == 0)
1747 break;
1748
58f48a56 1749 if (isempty(pretty))
be371fe0
LP
1750 continue;
1751
6abdec98 1752 r = strv_consume(l, TAKE_PTR(pretty));
be371fe0
LP
1753 if (r < 0)
1754 return r;
1755 }
1756
1757 r = sd_bus_message_exit_container(m);
1758 if (r < 0)
1759 return r;
1760
1761 return 0;
1762}
1763
a747e71c
YW
1764static int map_global_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1765 return map_global_dns_servers_internal(bus, member, m, error, userdata, false);
1766}
1767
1768static int map_global_dns_servers_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1769 return map_global_dns_servers_internal(bus, member, m, error, userdata, true);
1770}
1771
446c6415
YW
1772static int map_global_current_dns_server(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1773 assert(m);
1774 assert(userdata);
1775
a747e71c
YW
1776 return read_dns_server_one(m, true, false, userdata);
1777}
1778
1779static int map_global_current_dns_server_ex(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
1780 assert(m);
1781 assert(userdata);
1782
1783 return read_dns_server_one(m, true, true, userdata);
446c6415
YW
1784}
1785
be371fe0 1786static int map_global_domains(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
99534007 1787 char ***l = ASSERT_PTR(userdata);
be371fe0
LP
1788 int r;
1789
1790 assert(bus);
1791 assert(member);
1792 assert(m);
be371fe0
LP
1793
1794 r = sd_bus_message_enter_container(m, 'a', "(isb)");
1795 if (r < 0)
1796 return r;
1797
1798 for (;;) {
6abdec98 1799 _cleanup_free_ char *pretty = NULL;
be371fe0 1800
c513bb6e 1801 r = read_domain_one(m, true, &pretty);
be371fe0
LP
1802 if (r < 0)
1803 return r;
1804 if (r == 0)
1805 break;
1806
c513bb6e 1807 if (isempty(pretty))
be371fe0
LP
1808 continue;
1809
6abdec98 1810 r = strv_consume(l, TAKE_PTR(pretty));
be371fe0
LP
1811 if (r < 0)
1812 return r;
1813 }
1814
1815 r = sd_bus_message_exit_container(m);
1816 if (r < 0)
1817 return r;
1818
af781878 1819 strv_sort(*l);
a7a4c60a
YW
1820
1821 return 0;
1822}
1823
906119c0 1824static int status_global(sd_bus *bus, StatusMode mode, bool *empty_line) {
be371fe0 1825 static const struct bus_properties_map property_map[] = {
80b8c3d7
ZJS
1826 { "DNS", "a(iiay)", map_global_dns_servers, offsetof(GlobalInfo, dns) },
1827 { "DNSEx", "a(iiayqs)", map_global_dns_servers_ex, offsetof(GlobalInfo, dns_ex) },
1828 { "FallbackDNS", "a(iiay)", map_global_dns_servers, offsetof(GlobalInfo, fallback_dns) },
1829 { "FallbackDNSEx", "a(iiayqs)", map_global_dns_servers_ex, offsetof(GlobalInfo, fallback_dns_ex) },
1830 { "CurrentDNSServer", "(iiay)", map_global_current_dns_server, offsetof(GlobalInfo, current_dns) },
1831 { "CurrentDNSServerEx", "(iiayqs)", map_global_current_dns_server_ex, offsetof(GlobalInfo, current_dns_ex) },
1832 { "Domains", "a(isb)", map_global_domains, offsetof(GlobalInfo, domains) },
af781878 1833 { "DNSSECNegativeTrustAnchors", "as", bus_map_strv_sort, offsetof(GlobalInfo, ntas) },
80b8c3d7
ZJS
1834 { "LLMNR", "s", NULL, offsetof(GlobalInfo, llmnr) },
1835 { "MulticastDNS", "s", NULL, offsetof(GlobalInfo, mdns) },
1836 { "DNSOverTLS", "s", NULL, offsetof(GlobalInfo, dns_over_tls) },
1837 { "DNSSEC", "s", NULL, offsetof(GlobalInfo, dnssec) },
1838 { "DNSSECSupported", "b", NULL, offsetof(GlobalInfo, dnssec_supported) },
1839 { "ResolvConfMode", "s", NULL, offsetof(GlobalInfo, resolv_conf_mode) },
be371fe0
LP
1840 {}
1841 };
f9e0eefc 1842 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
f37f8a61 1843 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
80b8c3d7 1844 _cleanup_(global_info_clear) GlobalInfo global_info = {};
29e15e98 1845 _cleanup_(table_unrefp) Table *table = NULL;
be371fe0
LP
1846 int r;
1847
1848 assert(bus);
1849 assert(empty_line);
1850
1851 r = bus_map_all_properties(bus,
1852 "org.freedesktop.resolve1",
1853 "/org/freedesktop/resolve1",
1854 property_map,
a7e4861c 1855 BUS_MAP_BOOLEAN_AS_BOOL,
f9e0eefc 1856 &error,
f37f8a61 1857 &m,
be371fe0 1858 &global_info);
906119c0
YW
1859 if (r < 0)
1860 return log_error_errno(r, "Failed to get global data: %s", bus_error_message(&error, r));
be371fe0 1861
384c2c32 1862 pager_open(arg_pager_flags);
be371fe0 1863
906119c0 1864 if (mode == STATUS_DNS)
a747e71c 1865 return status_print_strv_global(global_info.dns_ex ?: global_info.dns);
a7a4c60a 1866
906119c0
YW
1867 if (mode == STATUS_DOMAIN)
1868 return status_print_strv_global(global_info.domains);
a7a4c60a 1869
906119c0
YW
1870 if (mode == STATUS_NTA)
1871 return status_print_strv_global(global_info.ntas);
a7a4c60a
YW
1872
1873 if (mode == STATUS_LLMNR) {
1874 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
1875 strna(global_info.llmnr));
1876
906119c0 1877 return 0;
a7a4c60a
YW
1878 }
1879
1880 if (mode == STATUS_MDNS) {
1881 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
1882 strna(global_info.mdns));
1883
906119c0 1884 return 0;
a7a4c60a
YW
1885 }
1886
d050561a
IT
1887 if (mode == STATUS_PRIVATE) {
1888 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
c9299be2 1889 strna(global_info.dns_over_tls));
d050561a 1890
906119c0 1891 return 0;
d050561a
IT
1892 }
1893
a7a4c60a
YW
1894 if (mode == STATUS_DNSSEC) {
1895 printf("%sGlobal%s: %s\n", ansi_highlight(), ansi_normal(),
1896 strna(global_info.dnssec));
1897
906119c0 1898 return 0;
a7a4c60a
YW
1899 }
1900
be371fe0 1901 printf("%sGlobal%s\n", ansi_highlight(), ansi_normal());
11d6e9e9 1902
37a50123 1903 table = table_new_vertical();
29e15e98
YW
1904 if (!table)
1905 return log_oom();
be371fe0 1906
7d1e1afe 1907 _cleanup_strv_free_ char **pstatus = global_protocol_status(&global_info);
fe37e5a5
ZJS
1908 if (!pstatus)
1909 return log_oom();
1910
29e15e98 1911 r = table_add_many(table,
37a50123
LP
1912 TABLE_FIELD, "Protocols",
1913 TABLE_SET_MINIMUM_WIDTH, 19,
7d1e1afe 1914 TABLE_STRV_WRAPPED, pstatus);
29e15e98
YW
1915 if (r < 0)
1916 return table_log_add_error(r);
1917
147a5046
LP
1918 if (global_info.resolv_conf_mode) {
1919 r = table_add_many(table,
37a50123 1920 TABLE_FIELD, "resolv.conf mode",
147a5046
LP
1921 TABLE_STRING, global_info.resolv_conf_mode);
1922 if (r < 0)
1923 return table_log_add_error(r);
1924 }
1925
29e15e98
YW
1926 if (global_info.current_dns) {
1927 r = table_add_many(table,
37a50123 1928 TABLE_FIELD, "Current DNS Server",
a747e71c 1929 TABLE_STRING, global_info.current_dns_ex ?: global_info.current_dns);
29e15e98
YW
1930 if (r < 0)
1931 return table_log_add_error(r);
4b320ac5
YW
1932 }
1933
a747e71c 1934 r = dump_list(table, "DNS Servers:", global_info.dns_ex ?: global_info.dns);
29e15e98
YW
1935 if (r < 0)
1936 return r;
1937
a747e71c 1938 r = dump_list(table, "Fallback DNS Servers:", global_info.fallback_dns_ex ?: global_info.fallback_dns);
29e15e98
YW
1939 if (r < 0)
1940 return r;
1941
1942 r = dump_list(table, "DNS Domain:", global_info.domains);
1943 if (r < 0)
1944 return r;
be371fe0 1945
29e15e98
YW
1946 r = table_print(table, NULL);
1947 if (r < 0)
4b6607d9 1948 return table_log_print_error(r);
be371fe0
LP
1949
1950 *empty_line = true;
1951
906119c0 1952 return 0;
be371fe0
LP
1953}
1954
a7a4c60a 1955static int status_all(sd_bus *bus, StatusMode mode) {
be371fe0
LP
1956 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
1957 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
96ace31d 1958 bool empty_line = false;
be371fe0
LP
1959 int r;
1960
1961 assert(bus);
1962
a7a4c60a 1963 r = status_global(bus, mode, &empty_line);
be371fe0
LP
1964 if (r < 0)
1965 return r;
1966
1967 r = sd_netlink_open(&rtnl);
1968 if (r < 0)
1969 return log_error_errno(r, "Failed to connect to netlink: %m");
1970
1971 r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, 0);
1972 if (r < 0)
1973 return rtnl_log_create_error(r);
1974
24c0f385 1975 r = sd_netlink_message_set_request_dump(req, true);
be371fe0
LP
1976 if (r < 0)
1977 return rtnl_log_create_error(r);
1978
1979 r = sd_netlink_call(rtnl, req, 0, &reply);
1980 if (r < 0)
1981 return log_error_errno(r, "Failed to enumerate links: %m");
1982
eb107675 1983 _cleanup_free_ InterfaceInfo *infos = NULL;
319a4f4b 1984 size_t n_infos = 0;
eb107675 1985
c9d243cd 1986 for (sd_netlink_message *i = reply; i; i = sd_netlink_message_next(i)) {
be371fe0 1987 const char *name;
eb107675 1988 int ifindex;
be371fe0
LP
1989 uint16_t type;
1990
eb107675
ZJS
1991 r = sd_netlink_message_get_type(i, &type);
1992 if (r < 0)
1993 return rtnl_log_parse_error(r);
be371fe0
LP
1994
1995 if (type != RTM_NEWLINK)
1996 continue;
1997
eb107675
ZJS
1998 r = sd_rtnl_message_link_get_ifindex(i, &ifindex);
1999 if (r < 0)
2000 return rtnl_log_parse_error(r);
be371fe0
LP
2001
2002 if (ifindex == LOOPBACK_IFINDEX)
2003 continue;
2004
eb107675
ZJS
2005 r = sd_netlink_message_read_string(i, IFLA_IFNAME, &name);
2006 if (r < 0)
2007 return rtnl_log_parse_error(r);
be371fe0 2008
319a4f4b 2009 if (!GREEDY_REALLOC(infos, n_infos + 1))
eb107675
ZJS
2010 return log_oom();
2011
2012 infos[n_infos++] = (InterfaceInfo) { ifindex, name };
2013 }
2014
2015 typesafe_qsort(infos, n_infos, interface_info_compare);
2016
2017 r = 0;
2018 for (size_t i = 0; i < n_infos; i++) {
2019 int q = status_ifindex(bus, infos[i].index, infos[i].name, mode, &empty_line);
be371fe0
LP
2020 if (q < 0 && r >= 0)
2021 r = q;
2022 }
2023
2024 return r;
2025}
2026
a7a4c60a
YW
2027static int verb_status(int argc, char **argv, void *userdata) {
2028 sd_bus *bus = userdata;
957d9df3 2029 _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
597da51b 2030 int r = 0;
14965b94 2031
a7a4c60a 2032 if (argc > 1) {
a7a4c60a 2033 bool empty_line = false;
14965b94 2034
a7a4c60a 2035 STRV_FOREACH(ifname, argv + 1) {
597da51b 2036 int ifindex, q;
14965b94 2037
f6e49154 2038 ifindex = rtnl_resolve_interface(&rtnl, *ifname);
597da51b 2039 if (ifindex < 0) {
d308bb99 2040 log_warning_errno(ifindex, "Failed to resolve interface \"%s\", ignoring: %m", *ifname);
a7a4c60a 2041 continue;
8e5385b4 2042 }
14965b94 2043
a7a4c60a
YW
2044 q = status_ifindex(bus, ifindex, NULL, STATUS_ALL, &empty_line);
2045 if (q < 0)
2046 r = q;
2047 }
2048 } else
2049 r = status_all(bus, STATUS_ALL);
14965b94 2050
a7a4c60a
YW
2051 return r;
2052}
14965b94 2053
b1881e83 2054static int call_dns(sd_bus *bus, char **dns, const BusLocator *locator, sd_bus_error *error, bool extended) {
a7a4c60a 2055 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
a661dc36 2056 int r;
14965b94 2057
b1881e83 2058 r = bus_message_new_method_call(bus, &req, locator, extended ? "SetLinkDNSEx" : "SetLinkDNS");
a7a4c60a
YW
2059 if (r < 0)
2060 return bus_log_create_error(r);
14965b94 2061
a661dc36 2062 r = sd_bus_message_append(req, "i", arg_ifindex);
a7a4c60a
YW
2063 if (r < 0)
2064 return bus_log_create_error(r);
14965b94 2065
b1881e83 2066 r = sd_bus_message_open_container(req, 'a', extended ? "(iayqs)" : "(iay)");
a7a4c60a
YW
2067 if (r < 0)
2068 return bus_log_create_error(r);
14965b94 2069
06c28aa0
FB
2070 /* If only argument is the empty string, then call SetLinkDNS() with an
2071 * empty list, which will clear the list of domains for an interface. */
65856bf2
YW
2072 if (!strv_equal(dns, STRV_MAKE("")))
2073 STRV_FOREACH(p, dns) {
b1881e83 2074 _cleanup_free_ char *name = NULL;
06c28aa0 2075 struct in_addr_data data;
b1881e83
YW
2076 uint16_t port;
2077 int ifindex;
14965b94 2078
b1881e83 2079 r = in_addr_port_ifindex_name_from_string_auto(*p, &data.family, &data.address, &port, &ifindex, &name);
06c28aa0
FB
2080 if (r < 0)
2081 return log_error_errno(r, "Failed to parse DNS server address: %s", *p);
14965b94 2082
b1881e83
YW
2083 if (ifindex != 0 && ifindex != arg_ifindex)
2084 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid ifindex: %i", ifindex);
2085
2086 r = sd_bus_message_open_container(req, 'r', extended ? "iayqs" : "iay");
06c28aa0
FB
2087 if (r < 0)
2088 return bus_log_create_error(r);
14965b94 2089
06c28aa0
FB
2090 r = sd_bus_message_append(req, "i", data.family);
2091 if (r < 0)
2092 return bus_log_create_error(r);
14965b94 2093
06c28aa0
FB
2094 r = sd_bus_message_append_array(req, 'y', &data.address, FAMILY_ADDRESS_SIZE(data.family));
2095 if (r < 0)
2096 return bus_log_create_error(r);
a7a4c60a 2097
b1881e83
YW
2098 if (extended) {
2099 r = sd_bus_message_append(req, "q", port);
2100 if (r < 0)
2101 return bus_log_create_error(r);
2102
2103 r = sd_bus_message_append(req, "s", name);
2104 if (r < 0)
2105 return bus_log_create_error(r);
2106 }
2107
06c28aa0
FB
2108 r = sd_bus_message_close_container(req);
2109 if (r < 0)
2110 return bus_log_create_error(r);
2111 }
14965b94 2112
a7a4c60a
YW
2113 r = sd_bus_message_close_container(req);
2114 if (r < 0)
2115 return bus_log_create_error(r);
2116
b1881e83 2117 r = sd_bus_call(bus, req, 0, error, NULL);
f527c6fa
YW
2118 if (r < 0 && extended && sd_bus_error_has_name(error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
2119 sd_bus_error_free(error);
b1881e83 2120 return call_dns(bus, dns, locator, error, false);
f527c6fa 2121 }
b1881e83 2122 return r;
a7a4c60a
YW
2123}
2124
65856bf2 2125static int verb_dns(int argc, char **argv, void *userdata) {
a7a4c60a 2126 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
99534007 2127 sd_bus *bus = ASSERT_PTR(userdata);
a661dc36 2128 int r;
a7a4c60a 2129
d1293049 2130 if (argc >= 2) {
df87a53d 2131 r = ifname_mangle(argv[1]);
d1293049
LP
2132 if (r < 0)
2133 return r;
2134 }
a7a4c60a 2135
d1293049 2136 if (arg_ifindex <= 0)
65856bf2 2137 return status_all(bus, STATUS_DNS);
14965b94 2138
d1293049 2139 if (argc < 3)
65856bf2
YW
2140 return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNS, NULL);
2141
b1881e83 2142 r = call_dns(bus, argv + 2, bus_resolve_mgr, &error, true);
65856bf2
YW
2143 if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
2144 sd_bus_error_free(&error);
2145
b1881e83 2146 r = call_dns(bus, argv + 2, bus_network_mgr, &error, true);
65856bf2
YW
2147 }
2148 if (r < 0) {
2149 if (arg_ifindex_permissive &&
2150 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2151 return 0;
2152
2153 return log_error_errno(r, "Failed to set DNS configuration: %s", bus_error_message(&error, r));
2154 }
2155
2156 return 0;
2157}
2158
d96f9abc 2159static int call_domain(sd_bus *bus, char **domain, const BusLocator *locator, sd_bus_error *error) {
65856bf2 2160 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
65856bf2 2161 int r;
14965b94 2162
d96f9abc 2163 r = bus_message_new_method_call(bus, &req, locator, "SetLinkDomains");
a7a4c60a
YW
2164 if (r < 0)
2165 return bus_log_create_error(r);
14965b94 2166
a661dc36 2167 r = sd_bus_message_append(req, "i", arg_ifindex);
a7a4c60a
YW
2168 if (r < 0)
2169 return bus_log_create_error(r);
14965b94 2170
a7a4c60a
YW
2171 r = sd_bus_message_open_container(req, 'a', "(sb)");
2172 if (r < 0)
2173 return bus_log_create_error(r);
2174
06c28aa0
FB
2175 /* If only argument is the empty string, then call SetLinkDomains() with an
2176 * empty list, which will clear the list of domains for an interface. */
65856bf2
YW
2177 if (!strv_equal(domain, STRV_MAKE("")))
2178 STRV_FOREACH(p, domain) {
06c28aa0 2179 const char *n;
14965b94 2180
06c28aa0 2181 n = **p == '~' ? *p + 1 : *p;
14965b94 2182
06c28aa0
FB
2183 r = dns_name_is_valid(n);
2184 if (r < 0)
2185 return log_error_errno(r, "Failed to validate specified domain %s: %m", n);
d7a0f1f4
FS
2186 if (r == 0)
2187 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2188 "Domain not valid: %s",
2189 n);
a7a4c60a 2190
06c28aa0
FB
2191 r = sd_bus_message_append(req, "(sb)", n, **p == '~');
2192 if (r < 0)
2193 return bus_log_create_error(r);
2194 }
14965b94 2195
a7a4c60a
YW
2196 r = sd_bus_message_close_container(req);
2197 if (r < 0)
2198 return bus_log_create_error(r);
2199
65856bf2
YW
2200 return sd_bus_call(bus, req, 0, error, NULL);
2201}
2202
2203static int verb_domain(int argc, char **argv, void *userdata) {
2204 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
99534007 2205 sd_bus *bus = ASSERT_PTR(userdata);
65856bf2
YW
2206 int r;
2207
65856bf2
YW
2208 if (argc >= 2) {
2209 r = ifname_mangle(argv[1]);
2210 if (r < 0)
2211 return r;
2212 }
2213
2214 if (arg_ifindex <= 0)
2215 return status_all(bus, STATUS_DOMAIN);
2216
2217 if (argc < 3)
2218 return status_ifindex(bus, arg_ifindex, NULL, STATUS_DOMAIN, NULL);
2219
d96f9abc 2220 r = call_domain(bus, argv + 2, bus_resolve_mgr, &error);
65856bf2
YW
2221 if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
2222 sd_bus_error_free(&error);
14965b94 2223
d96f9abc 2224 r = call_domain(bus, argv + 2, bus_network_mgr, &error);
65856bf2
YW
2225 }
2226 if (r < 0) {
a7a4c60a
YW
2227 if (arg_ifindex_permissive &&
2228 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2229 return 0;
14965b94 2230
a7a4c60a 2231 return log_error_errno(r, "Failed to set domain configuration: %s", bus_error_message(&error, r));
14965b94 2232 }
a7a4c60a
YW
2233
2234 return 0;
14965b94
LP
2235}
2236
f2fd3cdb
LP
2237static int verb_default_route(int argc, char **argv, void *userdata) {
2238 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
99534007 2239 sd_bus *bus = ASSERT_PTR(userdata);
f2fd3cdb
LP
2240 int r, b;
2241
f2fd3cdb
LP
2242 if (argc >= 2) {
2243 r = ifname_mangle(argv[1]);
2244 if (r < 0)
2245 return r;
2246 }
2247
2248 if (arg_ifindex <= 0)
2249 return status_all(bus, STATUS_DEFAULT_ROUTE);
2250
2251 if (argc < 3)
2252 return status_ifindex(bus, arg_ifindex, NULL, STATUS_DEFAULT_ROUTE, NULL);
2253
2254 b = parse_boolean(argv[2]);
2255 if (b < 0)
2256 return log_error_errno(b, "Failed to parse boolean argument: %s", argv[2]);
2257
d96f9abc 2258 r = bus_call_method(bus, bus_resolve_mgr, "SetLinkDefaultRoute", &error, NULL, "ib", arg_ifindex, b);
65856bf2
YW
2259 if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
2260 sd_bus_error_free(&error);
2261
d96f9abc 2262 r = bus_call_method(bus, bus_network_mgr, "SetLinkDefaultRoute", &error, NULL, "ib", arg_ifindex, b);
65856bf2 2263 }
f2fd3cdb 2264 if (r < 0) {
f2fd3cdb
LP
2265 if (arg_ifindex_permissive &&
2266 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2267 return 0;
2268
2269 return log_error_errno(r, "Failed to set default route configuration: %s", bus_error_message(&error, r));
2270 }
2271
2272 return 0;
2273}
2274
a7a4c60a 2275static int verb_llmnr(int argc, char **argv, void *userdata) {
14965b94 2276 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
c38a03df
YW
2277 _cleanup_free_ char *global_llmnr_support_str = NULL;
2278 ResolveSupport global_llmnr_support, llmnr_support;
99534007 2279 sd_bus *bus = ASSERT_PTR(userdata);
a661dc36 2280 int r;
14965b94 2281
d1293049 2282 if (argc >= 2) {
df87a53d 2283 r = ifname_mangle(argv[1]);
d1293049
LP
2284 if (r < 0)
2285 return r;
2286 }
a7a4c60a 2287
d1293049
LP
2288 if (arg_ifindex <= 0)
2289 return status_all(bus, STATUS_LLMNR);
a7a4c60a 2290
d1293049 2291 if (argc < 3)
a661dc36 2292 return status_ifindex(bus, arg_ifindex, NULL, STATUS_LLMNR, NULL);
a7a4c60a 2293
c38a03df
YW
2294 llmnr_support = resolve_support_from_string(argv[2]);
2295 if (llmnr_support < 0)
2296 return log_error_errno(llmnr_support, "Invalid LLMNR setting: %s", argv[2]);
2297
2298 r = bus_get_property_string(bus, bus_resolve_mgr, "LLMNR", &error, &global_llmnr_support_str);
2299 if (r < 0)
2300 return log_error_errno(r, "Failed to get the global LLMNR support state: %s", bus_error_message(&error, r));
2301
2302 global_llmnr_support = resolve_support_from_string(global_llmnr_support_str);
2303 if (global_llmnr_support < 0)
2304 return log_error_errno(global_llmnr_support, "Received invalid global LLMNR setting: %s", global_llmnr_support_str);
2305
2306 if (global_llmnr_support < llmnr_support)
2307 log_warning("Setting LLMNR support level \"%s\" for \"%s\", but the global support level is \"%s\".",
2308 argv[2], arg_ifname, global_llmnr_support_str);
2309
d96f9abc 2310 r = bus_call_method(bus, bus_resolve_mgr, "SetLinkLLMNR", &error, NULL, "is", arg_ifindex, argv[2]);
65856bf2
YW
2311 if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
2312 sd_bus_error_free(&error);
2313
d96f9abc 2314 r = bus_call_method(bus, bus_network_mgr, "SetLinkLLMNR", &error, NULL, "is", arg_ifindex, argv[2]);
65856bf2 2315 }
088c1363
LP
2316 if (r < 0) {
2317 if (arg_ifindex_permissive &&
2318 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2319 return 0;
2320
a7a4c60a 2321 return log_error_errno(r, "Failed to set LLMNR configuration: %s", bus_error_message(&error, r));
088c1363 2322 }
14965b94
LP
2323
2324 return 0;
2325}
2326
a7a4c60a
YW
2327static int verb_mdns(int argc, char **argv, void *userdata) {
2328 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
c38a03df
YW
2329 _cleanup_free_ char *global_mdns_support_str = NULL;
2330 ResolveSupport global_mdns_support, mdns_support;
99534007 2331 sd_bus *bus = ASSERT_PTR(userdata);
a661dc36 2332 int r;
ba82da3b 2333
d1293049 2334 if (argc >= 2) {
df87a53d 2335 r = ifname_mangle(argv[1]);
d1293049
LP
2336 if (r < 0)
2337 return r;
2338 }
a7a4c60a 2339
d1293049
LP
2340 if (arg_ifindex <= 0)
2341 return status_all(bus, STATUS_MDNS);
a7a4c60a 2342
d1293049 2343 if (argc < 3)
a661dc36 2344 return status_ifindex(bus, arg_ifindex, NULL, STATUS_MDNS, NULL);
a7a4c60a 2345
c38a03df
YW
2346 mdns_support = resolve_support_from_string(argv[2]);
2347 if (mdns_support < 0)
2348 return log_error_errno(mdns_support, "Invalid mDNS setting: %s", argv[2]);
2349
2350 r = bus_get_property_string(bus, bus_resolve_mgr, "MulticastDNS", &error, &global_mdns_support_str);
2351 if (r < 0)
2352 return log_error_errno(r, "Failed to get the global mDNS support state: %s", bus_error_message(&error, r));
2353
2354 global_mdns_support = resolve_support_from_string(global_mdns_support_str);
2355 if (global_mdns_support < 0)
2356 return log_error_errno(global_mdns_support, "Received invalid global mDNS setting: %s", global_mdns_support_str);
2357
2358 if (global_mdns_support < mdns_support)
2359 log_warning("Setting mDNS support level \"%s\" for \"%s\", but the global support level is \"%s\".",
2360 argv[2], arg_ifname, global_mdns_support_str);
2361
d96f9abc 2362 r = bus_call_method(bus, bus_resolve_mgr, "SetLinkMulticastDNS", &error, NULL, "is", arg_ifindex, argv[2]);
65856bf2
YW
2363 if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
2364 sd_bus_error_free(&error);
2365
d96f9abc 2366 r = bus_call_method(
65856bf2 2367 bus,
d96f9abc 2368 bus_network_mgr,
65856bf2
YW
2369 "SetLinkMulticastDNS",
2370 &error,
2371 NULL,
2372 "is", arg_ifindex, argv[2]);
2373 }
a7a4c60a 2374 if (r < 0) {
a7a4c60a
YW
2375 if (arg_ifindex_permissive &&
2376 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2377 return 0;
2378
2379 return log_error_errno(r, "Failed to set MulticastDNS configuration: %s", bus_error_message(&error, r));
2380 }
2381
2382 return 0;
2383}
2384
c9299be2 2385static int verb_dns_over_tls(int argc, char **argv, void *userdata) {
d050561a 2386 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
99534007 2387 sd_bus *bus = ASSERT_PTR(userdata);
a661dc36 2388 int r;
d050561a 2389
d1293049 2390 if (argc >= 2) {
df87a53d 2391 r = ifname_mangle(argv[1]);
d1293049
LP
2392 if (r < 0)
2393 return r;
2394 }
d050561a 2395
d1293049
LP
2396 if (arg_ifindex <= 0)
2397 return status_all(bus, STATUS_PRIVATE);
d050561a 2398
d1293049 2399 if (argc < 3)
a661dc36 2400 return status_ifindex(bus, arg_ifindex, NULL, STATUS_PRIVATE, NULL);
d050561a 2401
d96f9abc 2402 r = bus_call_method(bus, bus_resolve_mgr, "SetLinkDNSOverTLS", &error, NULL, "is", arg_ifindex, argv[2]);
65856bf2
YW
2403 if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
2404 sd_bus_error_free(&error);
2405
d96f9abc 2406 r = bus_call_method(
65856bf2 2407 bus,
d96f9abc 2408 bus_network_mgr,
65856bf2
YW
2409 "SetLinkDNSOverTLS",
2410 &error,
2411 NULL,
2412 "is", arg_ifindex, argv[2]);
2413 }
d050561a 2414 if (r < 0) {
d050561a
IT
2415 if (arg_ifindex_permissive &&
2416 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2417 return 0;
2418
c9299be2 2419 return log_error_errno(r, "Failed to set DNSOverTLS configuration: %s", bus_error_message(&error, r));
d050561a
IT
2420 }
2421
2422 return 0;
2423}
2424
a7a4c60a
YW
2425static int verb_dnssec(int argc, char **argv, void *userdata) {
2426 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
99534007 2427 sd_bus *bus = ASSERT_PTR(userdata);
a661dc36 2428 int r;
a7a4c60a 2429
d1293049 2430 if (argc >= 2) {
df87a53d 2431 r = ifname_mangle(argv[1]);
d1293049
LP
2432 if (r < 0)
2433 return r;
2434 }
a7a4c60a 2435
d1293049
LP
2436 if (arg_ifindex <= 0)
2437 return status_all(bus, STATUS_DNSSEC);
a7a4c60a 2438
d1293049 2439 if (argc < 3)
a661dc36 2440 return status_ifindex(bus, arg_ifindex, NULL, STATUS_DNSSEC, NULL);
a7a4c60a 2441
d96f9abc 2442 r = bus_call_method(bus, bus_resolve_mgr, "SetLinkDNSSEC", &error, NULL, "is", arg_ifindex, argv[2]);
65856bf2
YW
2443 if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
2444 sd_bus_error_free(&error);
2445
d96f9abc 2446 r = bus_call_method(bus, bus_network_mgr, "SetLinkDNSSEC", &error, NULL, "is", arg_ifindex, argv[2]);
65856bf2 2447 }
a7a4c60a 2448 if (r < 0) {
a7a4c60a
YW
2449 if (arg_ifindex_permissive &&
2450 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2451 return 0;
2452
2453 return log_error_errno(r, "Failed to set DNSSEC configuration: %s", bus_error_message(&error, r));
2454 }
2455
2456 return 0;
2457}
2458
d96f9abc 2459static int call_nta(sd_bus *bus, char **nta, const BusLocator *locator, sd_bus_error *error) {
65856bf2
YW
2460 _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL;
2461 int r;
2462
d96f9abc 2463 r = bus_message_new_method_call(bus, &req, locator, "SetLinkDNSSECNegativeTrustAnchors");
65856bf2
YW
2464 if (r < 0)
2465 return bus_log_create_error(r);
2466
2467 r = sd_bus_message_append(req, "i", arg_ifindex);
2468 if (r < 0)
2469 return bus_log_create_error(r);
2470
2471 r = sd_bus_message_append_strv(req, nta);
2472 if (r < 0)
2473 return bus_log_create_error(r);
2474
2475 return sd_bus_call(bus, req, 0, error, NULL);
2476}
2477
a7a4c60a
YW
2478static int verb_nta(int argc, char **argv, void *userdata) {
2479 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
99534007 2480 sd_bus *bus = ASSERT_PTR(userdata);
a661dc36 2481 int r;
06c28aa0 2482 bool clear;
a7a4c60a 2483
d1293049 2484 if (argc >= 2) {
df87a53d 2485 r = ifname_mangle(argv[1]);
d1293049
LP
2486 if (r < 0)
2487 return r;
2488 }
a7a4c60a 2489
d1293049
LP
2490 if (arg_ifindex <= 0)
2491 return status_all(bus, STATUS_NTA);
a7a4c60a 2492
d1293049 2493 if (argc < 3)
a661dc36 2494 return status_ifindex(bus, arg_ifindex, NULL, STATUS_NTA, NULL);
a7a4c60a 2495
06c28aa0
FB
2496 /* If only argument is the empty string, then call SetLinkDNSSECNegativeTrustAnchors()
2497 * with an empty list, which will clear the list of domains for an interface. */
2498 clear = strv_equal(argv + 2, STRV_MAKE(""));
2499
2500 if (!clear)
2501 STRV_FOREACH(p, argv + 2) {
2502 r = dns_name_is_valid(*p);
2503 if (r < 0)
2504 return log_error_errno(r, "Failed to validate specified domain %s: %m", *p);
d7a0f1f4
FS
2505 if (r == 0)
2506 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2507 "Domain not valid: %s",
2508 *p);
a7a4c60a 2509 }
a7a4c60a 2510
d96f9abc 2511 r = call_nta(bus, clear ? NULL : argv + 2, bus_resolve_mgr, &error);
65856bf2
YW
2512 if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
2513 sd_bus_error_free(&error);
a7a4c60a 2514
d96f9abc 2515 r = call_nta(bus, clear ? NULL : argv + 2, bus_network_mgr, &error);
65856bf2 2516 }
a7a4c60a 2517 if (r < 0) {
a7a4c60a
YW
2518 if (arg_ifindex_permissive &&
2519 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2520 return 0;
2521
2522 return log_error_errno(r, "Failed to set DNSSEC NTA configuration: %s", bus_error_message(&error, r));
2523 }
2524
2525 return 0;
2526}
2527
2528static int verb_revert_link(int argc, char **argv, void *userdata) {
2529 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
99534007 2530 sd_bus *bus = ASSERT_PTR(userdata);
a661dc36 2531 int r;
a7a4c60a 2532
d1293049 2533 if (argc >= 2) {
df87a53d 2534 r = ifname_mangle(argv[1]);
d1293049
LP
2535 if (r < 0)
2536 return r;
2537 }
2538
2539 if (arg_ifindex <= 0)
2540 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Interface argument required.");
a7a4c60a 2541
d96f9abc 2542 r = bus_call_method(bus, bus_resolve_mgr, "RevertLink", &error, NULL, "i", arg_ifindex);
65856bf2
YW
2543 if (r < 0 && sd_bus_error_has_name(&error, BUS_ERROR_LINK_BUSY)) {
2544 sd_bus_error_free(&error);
2545
d96f9abc 2546 r = bus_call_method(bus, bus_network_mgr, "RevertLinkDNS", &error, NULL, "i", arg_ifindex);
65856bf2 2547 }
a7a4c60a
YW
2548 if (r < 0) {
2549 if (arg_ifindex_permissive &&
2550 sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_LINK))
2551 return 0;
2552
2553 return log_error_errno(r, "Failed to revert interface configuration: %s", bus_error_message(&error, r));
2554 }
2555
2556 return 0;
2557}
2558
df957849 2559static int verb_log_level(int argc, char *argv[], void *userdata) {
99534007 2560 sd_bus *bus = ASSERT_PTR(userdata);
df957849 2561
b98416e1 2562 assert(IN_SET(argc, 1, 2));
df957849 2563
a87b151a 2564 return verb_log_control_common(bus, "org.freedesktop.resolve1", argv[0], argc == 2 ? argv[1] : NULL);
df957849
ZJS
2565}
2566
fffbf1dc
LP
2567static int monitor_rkey_from_json(JsonVariant *v, DnsResourceKey **ret_key) {
2568 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
2569 uint16_t type = 0, class = 0;
2570 const char *name = NULL;
2571 int r;
2572
2573 JsonDispatch dispatch_table[] = {
2574 { "class", JSON_VARIANT_INTEGER, json_dispatch_uint16, PTR_TO_SIZE(&class), JSON_MANDATORY },
2575 { "type", JSON_VARIANT_INTEGER, json_dispatch_uint16, PTR_TO_SIZE(&type), JSON_MANDATORY },
2576 { "name", JSON_VARIANT_STRING, json_dispatch_const_string, PTR_TO_SIZE(&name), JSON_MANDATORY },
2577 {}
2578 };
2579
2580 assert(v);
2581 assert(ret_key);
2582
2583 r = json_dispatch(v, dispatch_table, NULL, 0, NULL);
2584 if (r < 0)
2585 return r;
2586
2587 key = dns_resource_key_new(class, type, name);
2588 if (!key)
2589 return -ENOMEM;
2590
2591 *ret_key = TAKE_PTR(key);
2592 return 0;
2593}
2594
2595static int print_question(char prefix, const char *color, JsonVariant *question) {
2596 JsonVariant *q = NULL;
2597 int r;
2598
2599 assert(color);
2600
2601 JSON_VARIANT_ARRAY_FOREACH(q, question) {
2602 _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
2603 char buf[DNS_RESOURCE_KEY_STRING_MAX];
2604
2605 r = monitor_rkey_from_json(q, &key);
2606 if (r < 0) {
2607 log_warning_errno(r, "Received monitor message with invalid question key, ignoring: %m");
2608 continue;
2609 }
2610
2611 printf("%s%s %c%s: %s\n",
2612 color,
2613 special_glyph(SPECIAL_GLYPH_ARROW_RIGHT),
2614 prefix,
2615 ansi_normal(),
2616 dns_resource_key_to_string(key, buf, sizeof(buf)));
2617 }
2618
2619 return 0;
2620}
2621
2622static int print_answer(JsonVariant *answer) {
2623 JsonVariant *a;
2624 int r;
2625
2626 JSON_VARIANT_ARRAY_FOREACH(a, answer) {
2627 _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;
2628 _cleanup_free_ void *d = NULL;
2629 JsonVariant *jraw;
2630 const char *s;
2631 size_t l;
2632
2633 jraw = json_variant_by_key(a, "raw");
2634 if (!jraw) {
2635 log_warning("Received monitor answer lacking valid raw data, ignoring.");
2636 continue;
2637 }
2638
2639 r = json_variant_unbase64(jraw, &d, &l);
2640 if (r < 0) {
2641 log_warning_errno(r, "Failed to undo base64 encoding of monitor answer raw data, ignoring.");
2642 continue;
2643 }
2644
2645 r = dns_resource_record_new_from_raw(&rr, d, l);
2646 if (r < 0) {
64ebc0da 2647 log_warning_errno(r, "Failed to parse monitor answer RR, ignoring: %m");
fffbf1dc
LP
2648 continue;
2649 }
2650
2651 s = dns_resource_record_to_string(rr);
2652 if (!s)
2653 return log_oom();
2654
2655 printf("%s%s A%s: %s\n",
2656 ansi_highlight_yellow(),
2657 special_glyph(SPECIAL_GLYPH_ARROW_LEFT),
2658 ansi_normal(),
2659 s);
2660 }
2661
2662 return 0;
2663}
2664
2665static void monitor_query_dump(JsonVariant *v) {
2666 _cleanup_(json_variant_unrefp) JsonVariant *question = NULL, *answer = NULL, *collected_questions = NULL;
2667 int rcode = -1, error = 0, r;
2668 const char *state = NULL;
2669
2670 assert(v);
2671
2672 JsonDispatch dispatch_table[] = {
2673 { "question", JSON_VARIANT_ARRAY, json_dispatch_variant, PTR_TO_SIZE(&question), JSON_MANDATORY },
2674 { "answer", JSON_VARIANT_ARRAY, json_dispatch_variant, PTR_TO_SIZE(&answer), 0 },
2675 { "collectedQuestions", JSON_VARIANT_ARRAY, json_dispatch_variant, PTR_TO_SIZE(&collected_questions), 0 },
2676 { "state", JSON_VARIANT_STRING, json_dispatch_const_string, PTR_TO_SIZE(&state), JSON_MANDATORY },
2677 { "rcode", JSON_VARIANT_INTEGER, json_dispatch_int, PTR_TO_SIZE(&rcode), 0 },
2678 { "errno", JSON_VARIANT_INTEGER, json_dispatch_int, PTR_TO_SIZE(&error), 0 },
2679 {}
2680 };
2681
2682 r = json_dispatch(v, dispatch_table, NULL, 0, NULL);
2683 if (r < 0)
2684 return (void) log_warning("Received malformed monitor message, ignoring.");
2685
2686 /* First show the current question */
2687 print_question('Q', ansi_highlight_cyan(), question);
2688
2689 /* And then show the questions that led to this one in case this was a CNAME chain */
2690 print_question('C', ansi_highlight_grey(), collected_questions);
2691
2692 printf("%s%s S%s: %s\n",
2693 streq_ptr(state, "success") ? ansi_highlight_green() : ansi_highlight_red(),
2694 special_glyph(SPECIAL_GLYPH_ARROW_LEFT),
2695 ansi_normal(),
2696 strna(streq_ptr(state, "errno") ? errno_to_name(error) :
2697 streq_ptr(state, "rcode-failure") ? dns_rcode_to_string(rcode) :
2698 state));
2699
2700 print_answer(answer);
2701}
2702
2703static int monitor_reply(
2704 Varlink *link,
2705 JsonVariant *parameters,
2706 const char *error_id,
2707 VarlinkReplyFlags flags,
2708 void *userdata) {
2709
2710 assert(link);
2711
2712 if (error_id) {
2713 bool disconnect;
2714
2715 disconnect = streq(error_id, VARLINK_ERROR_DISCONNECTED);
2716 if (disconnect)
2717 log_info("Disconnected.");
2718 else
2719 log_error("Varlink error: %s", error_id);
2720
2721 (void) sd_event_exit(ASSERT_PTR(varlink_get_event(link)), disconnect ? EXIT_SUCCESS : EXIT_FAILURE);
2722 return 0;
2723 }
2724
2725 if (json_variant_by_key(parameters, "ready")) {
2726 /* The first message coming in will just indicate that we are now subscribed. We let our
2727 * caller know if they asked for it. Once the caller sees this they should know that we are
2728 * not going to miss any queries anymore. */
2729 (void) sd_notify(/* unset_environment=false */ false, "READY=1");
2730 return 0;
2731 }
2732
2733 if (arg_json_format_flags & JSON_FORMAT_OFF) {
2734 monitor_query_dump(parameters);
2735 printf("\n");
2736 } else
2737 json_variant_dump(parameters, arg_json_format_flags, NULL, NULL);
2738
2739 fflush(stdout);
2740
2741 return 0;
2742}
2743
2744static int verb_monitor(int argc, char *argv[], void *userdata) {
2745 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
2746 _cleanup_(varlink_unrefp) Varlink *vl = NULL;
2747 int r, c;
2748
2749 r = sd_event_default(&event);
2750 if (r < 0)
2751 return log_error_errno(r, "Failed to get event loop: %m");
2752
2753 r = sd_event_set_signal_exit(event, true);
2754 if (r < 0)
2755 return log_error_errno(r, "Failed to enable exit on SIGINT/SIGTERM: %m");
2756
2757 r = varlink_connect_address(&vl, "/run/systemd/resolve/io.systemd.Resolve.Monitor");
2758 if (r < 0)
2759 return log_error_errno(r, "Failed to connect to query monitoring service /run/systemd/resolve/io.systemd.Resolve.Monitor: %m");
2760
2761 r = varlink_set_relative_timeout(vl, USEC_INFINITY); /* We want the monitor to run basically forever */
2762 if (r < 0)
2763 return log_error_errno(r, "Failed to set varlink time-out: %m");
2764
2765 r = varlink_attach_event(vl, event, SD_EVENT_PRIORITY_NORMAL);
2766 if (r < 0)
2767 return log_error_errno(r, "Failed to attach varlink connection to event loop: %m");
2768
2769 r = varlink_bind_reply(vl, monitor_reply);
2770 if (r < 0)
2771 return log_error_errno(r, "Failed to bind reply callback to varlink connection: %m");
2772
2773 r = varlink_observe(vl, "io.systemd.Resolve.Monitor.SubscribeQueryResults", NULL);
2774 if (r < 0)
2775 return log_error_errno(r, "Failed to issue SubscribeQueryResults() varlink call: %m");
2776
2777 r = sd_event_loop(event);
2778 if (r < 0)
2779 return log_error_errno(r, "Failed to run event loop: %m");
2780
2781 r = sd_event_get_exit_code(event, &c);
2782 if (r < 0)
2783 return log_error_errno(r, "Failed to get exit code: %m");
2784
2785 return c;
2786}
2787
a7a4c60a
YW
2788static void help_protocol_types(void) {
2789 if (arg_legend)
2790 puts("Known protocol types:");
5cf4b2e5
LP
2791 puts("dns\n"
2792 "llmnr\n"
2793 "llmnr-ipv4\n"
2794 "llmnr-ipv6\n"
2795 "mdns\n"
2796 "mdns-ipv4\n"
2797 "mdns-ipv6");
a7a4c60a
YW
2798}
2799
2800static void help_dns_types(void) {
a7a4c60a
YW
2801 if (arg_legend)
2802 puts("Known DNS RR types:");
5c828e66
LP
2803
2804 DUMP_STRING_TABLE(dns_type, int, _DNS_TYPE_MAX);
b93312f5
ZJS
2805}
2806
2807static void help_dns_classes(void) {
b93312f5 2808 if (arg_legend)
09b1fe14 2809 puts("Known DNS RR classes:");
5c828e66
LP
2810
2811 DUMP_STRING_TABLE(dns_class, int, _DNS_CLASS_MAX);
b93312f5
ZJS
2812}
2813
37ec0fdd
LP
2814static int compat_help(void) {
2815 _cleanup_free_ char *link = NULL;
2816 int r;
2817
2818 r = terminal_urlify_man("resolvectl", "1", &link);
2819 if (r < 0)
2820 return log_oom();
2821
1ace2438
ZJS
2822 printf("%1$s [OPTIONS...] HOSTNAME|ADDRESS...\n"
2823 "%1$s [OPTIONS...] --service [[NAME] TYPE] DOMAIN\n"
2824 "%1$s [OPTIONS...] --openpgp EMAIL@DOMAIN...\n"
2825 "%1$s [OPTIONS...] --statistics\n"
2826 "%1$s [OPTIONS...] --reset-statistics\n"
2827 "\n"
353b2baa 2828 "%2$sResolve domain names, IPv4 and IPv6 addresses, DNS records, and services.%3$s\n\n"
1ace2438
ZJS
2829 " -h --help Show this help\n"
2830 " --version Show package version\n"
be371fe0 2831 " --no-pager Do not pipe output into a pager\n"
1ace2438
ZJS
2832 " -4 Resolve IPv4 addresses\n"
2833 " -6 Resolve IPv6 addresses\n"
2834 " -i --interface=INTERFACE Look on interface\n"
2835 " -p --protocol=PROTO|help Look via protocol\n"
2836 " -t --type=TYPE|help Query RR with DNS type\n"
2837 " -c --class=CLASS|help Query RR with DNS class\n"
2838 " --service Resolve service (SRV)\n"
2839 " --service-address=BOOL Resolve address for services (default: yes)\n"
2840 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
2841 " --openpgp Query OpenPGP public key\n"
82d1d240 2842 " --tlsa Query TLS public key\n"
1ace2438
ZJS
2843 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
2844 " --search=BOOL Use search domains for single-label names\n"
2845 " (default: yes)\n"
dab48ea6 2846 " --raw[=payload|packet] Dump the answer as binary data\n"
1ace2438
ZJS
2847 " --legend=BOOL Print headers and additional info (default: yes)\n"
2848 " --statistics Show resolver statistics\n"
2849 " --reset-statistics Reset resolver statistics\n"
be371fe0 2850 " --status Show link and server status\n"
ba35662f 2851 " --flush-caches Flush all local DNS caches\n"
d55b0463
LP
2852 " --reset-server-features\n"
2853 " Forget learnt DNS server feature levels\n"
14965b94
LP
2854 " --set-dns=SERVER Set per-interface DNS server address\n"
2855 " --set-domain=DOMAIN Set per-interface search domain\n"
2856 " --set-llmnr=MODE Set per-interface LLMNR mode\n"
2857 " --set-mdns=MODE Set per-interface MulticastDNS mode\n"
c9299be2 2858 " --set-dnsovertls=MODE Set per-interface DNS-over-TLS mode\n"
14965b94
LP
2859 " --set-dnssec=MODE Set per-interface DNSSEC mode\n"
2860 " --set-nta=DOMAIN Set per-interface DNSSEC NTA\n"
2861 " --revert Revert per-interface configuration\n"
bc556335
DDM
2862 "\nSee the %4$s for details.\n",
2863 program_invocation_short_name,
2864 ansi_highlight(),
2865 ansi_normal(),
2866 link);
37ec0fdd
LP
2867
2868 return 0;
bdef7319
ZJS
2869}
2870
37ec0fdd
LP
2871static int native_help(void) {
2872 _cleanup_free_ char *link = NULL;
2873 int r;
2874
2875 r = terminal_urlify_man("resolvectl", "1", &link);
2876 if (r < 0)
2877 return log_oom();
2878
353b2baa 2879 printf("%s [OPTIONS...] COMMAND ...\n"
a7a4c60a 2880 "\n"
353b2baa
LP
2881 "%sSend control commands to the network name resolution manager, or%s\n"
2882 "%sresolve domain names, IPv4 and IPv6 addresses, DNS records, and services.%s\n"
e1fac8a6 2883 "\nCommands:\n"
a7a4c60a
YW
2884 " query HOSTNAME|ADDRESS... Resolve domain names, IPv4 and IPv6 addresses\n"
2885 " service [[NAME] TYPE] DOMAIN Resolve service (SRV)\n"
2886 " openpgp EMAIL@DOMAIN... Query OpenPGP public key\n"
2887 " tlsa DOMAIN[:PORT]... Query TLS public key\n"
2888 " status [LINK...] Show link and server status\n"
2889 " statistics Show resolver statistics\n"
2890 " reset-statistics Reset resolver statistics\n"
2891 " flush-caches Flush all local DNS caches\n"
2892 " reset-server-features Forget learnt DNS server feature levels\n"
fffbf1dc 2893 " monitor Monitor DNS queries\n"
a7a4c60a
YW
2894 " dns [LINK [SERVER...]] Get/set per-interface DNS server address\n"
2895 " domain [LINK [DOMAIN...]] Get/set per-interface search domain\n"
f2fd3cdb 2896 " default-route [LINK [BOOL]] Get/set per-interface default route flag\n"
a7a4c60a
YW
2897 " llmnr [LINK [MODE]] Get/set per-interface LLMNR mode\n"
2898 " mdns [LINK [MODE]] Get/set per-interface MulticastDNS mode\n"
c9299be2 2899 " dnsovertls [LINK [MODE]] Get/set per-interface DNS-over-TLS mode\n"
a7a4c60a
YW
2900 " dnssec [LINK [MODE]] Get/set per-interface DNSSEC mode\n"
2901 " nta [LINK [DOMAIN...]] Get/set per-interface DNSSEC NTA\n"
2902 " revert LINK Revert per-interface configuration\n"
bde4bc9b 2903 " log-level [LEVEL] Get/set logging threshold for systemd-resolved\n"
353b2baa 2904 "\nOptions:\n"
e1fac8a6
ZJS
2905 " -h --help Show this help\n"
2906 " --version Show package version\n"
2907 " --no-pager Do not pipe output into a pager\n"
2908 " -4 Resolve IPv4 addresses\n"
2909 " -6 Resolve IPv6 addresses\n"
2910 " -i --interface=INTERFACE Look on interface\n"
2911 " -p --protocol=PROTO|help Look via protocol\n"
2912 " -t --type=TYPE|help Query RR with DNS type\n"
2913 " -c --class=CLASS|help Query RR with DNS class\n"
2914 " --service-address=BOOL Resolve address for services (default: yes)\n"
2915 " --service-txt=BOOL Resolve TXT records for services (default: yes)\n"
2916 " --cname=BOOL Follow CNAME redirects (default: yes)\n"
d711322c
LP
2917 " --validate=BOOL Allow DNSSEC validation (default: yes)\n"
2918 " --synthesize=BOOL Allow synthetic response (default: yes)\n"
2919 " --cache=BOOL Allow response from cache (default: yes)\n"
2920 " --zone=BOOL Allow response from locally registered mDNS/LLMNR\n"
2921 " records (default: yes)\n"
fffbf1dc
LP
2922 " --trust-anchor=BOOL Allow response from local trust anchor (default:\n"
2923 " yes)\n"
d711322c 2924 " --network=BOOL Allow response from network (default: yes)\n"
fffbf1dc
LP
2925 " --search=BOOL Use search domains for single-label names (default:\n"
2926 " yes)\n"
e1fac8a6
ZJS
2927 " --raw[=payload|packet] Dump the answer as binary data\n"
2928 " --legend=BOOL Print headers and additional info (default: yes)\n"
fffbf1dc
LP
2929 " --json=MODE Output as JSON\n"
2930 " -j Same as --json=pretty on tty, --json=short\n"
2931 " otherwise\n"
bc556335
DDM
2932 "\nSee the %s for details.\n",
2933 program_invocation_short_name,
2934 ansi_highlight(),
2935 ansi_normal(),
2936 ansi_highlight(),
2937 ansi_normal(),
2938 link);
37ec0fdd
LP
2939
2940 return 0;
a7a4c60a
YW
2941}
2942
2943static int verb_help(int argc, char **argv, void *userdata) {
37ec0fdd 2944 return native_help();
a7a4c60a
YW
2945}
2946
2947static int compat_parse_argv(int argc, char *argv[]) {
bdef7319
ZJS
2948 enum {
2949 ARG_VERSION = 0x100,
dad29dff 2950 ARG_LEGEND,
45ec7efb
LP
2951 ARG_SERVICE,
2952 ARG_CNAME,
2953 ARG_SERVICE_ADDRESS,
2954 ARG_SERVICE_TXT,
4ac2ca1b 2955 ARG_OPENPGP,
82d1d240 2956 ARG_TLSA,
2e74028a 2957 ARG_RAW,
801ad6a6 2958 ARG_SEARCH,
a150ff5e
LP
2959 ARG_STATISTICS,
2960 ARG_RESET_STATISTICS,
be371fe0 2961 ARG_STATUS,
ba35662f 2962 ARG_FLUSH_CACHES,
d55b0463 2963 ARG_RESET_SERVER_FEATURES,
be371fe0 2964 ARG_NO_PAGER,
14965b94
LP
2965 ARG_SET_DNS,
2966 ARG_SET_DOMAIN,
2967 ARG_SET_LLMNR,
2968 ARG_SET_MDNS,
d050561a 2969 ARG_SET_PRIVATE,
14965b94
LP
2970 ARG_SET_DNSSEC,
2971 ARG_SET_NTA,
2972 ARG_REVERT_LINK,
bdef7319
ZJS
2973 };
2974
2975 static const struct option options[] = {
d55b0463
LP
2976 { "help", no_argument, NULL, 'h' },
2977 { "version", no_argument, NULL, ARG_VERSION },
2978 { "type", required_argument, NULL, 't' },
2979 { "class", required_argument, NULL, 'c' },
2980 { "legend", required_argument, NULL, ARG_LEGEND },
2981 { "interface", required_argument, NULL, 'i' },
2982 { "protocol", required_argument, NULL, 'p' },
2983 { "cname", required_argument, NULL, ARG_CNAME },
2984 { "service", no_argument, NULL, ARG_SERVICE },
2985 { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
2986 { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
2987 { "openpgp", no_argument, NULL, ARG_OPENPGP },
2988 { "tlsa", optional_argument, NULL, ARG_TLSA },
2989 { "raw", optional_argument, NULL, ARG_RAW },
2990 { "search", required_argument, NULL, ARG_SEARCH },
2991 { "statistics", no_argument, NULL, ARG_STATISTICS, },
2992 { "reset-statistics", no_argument, NULL, ARG_RESET_STATISTICS },
2993 { "status", no_argument, NULL, ARG_STATUS },
2994 { "flush-caches", no_argument, NULL, ARG_FLUSH_CACHES },
2995 { "reset-server-features", no_argument, NULL, ARG_RESET_SERVER_FEATURES },
2996 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
14965b94
LP
2997 { "set-dns", required_argument, NULL, ARG_SET_DNS },
2998 { "set-domain", required_argument, NULL, ARG_SET_DOMAIN },
2999 { "set-llmnr", required_argument, NULL, ARG_SET_LLMNR },
3000 { "set-mdns", required_argument, NULL, ARG_SET_MDNS },
c9299be2 3001 { "set-dnsovertls", required_argument, NULL, ARG_SET_PRIVATE },
14965b94
LP
3002 { "set-dnssec", required_argument, NULL, ARG_SET_DNSSEC },
3003 { "set-nta", required_argument, NULL, ARG_SET_NTA },
3004 { "revert", no_argument, NULL, ARG_REVERT_LINK },
bdef7319
ZJS
3005 {}
3006 };
3007
2d4c5cbc 3008 int c, r;
bdef7319
ZJS
3009
3010 assert(argc >= 0);
3011 assert(argv);
3012
51323288 3013 while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
79893116 3014 switch (c) {
bdef7319
ZJS
3015
3016 case 'h':
37ec0fdd 3017 return compat_help();
bdef7319
ZJS
3018
3019 case ARG_VERSION:
3f6fd1ba 3020 return version();
bdef7319
ZJS
3021
3022 case '4':
3023 arg_family = AF_INET;
3024 break;
3025
3026 case '6':
3027 arg_family = AF_INET6;
3028 break;
3029
27d8af3e 3030 case 'i':
df87a53d 3031 r = ifname_mangle(optarg);
a7a4c60a
YW
3032 if (r < 0)
3033 return r;
2d4c5cbc
LP
3034 break;
3035
3036 case 't':
b93312f5
ZJS
3037 if (streq(optarg, "help")) {
3038 help_dns_types();
3039 return 0;
3040 }
3041
4b548ef3 3042 r = dns_type_from_string(optarg);
7211c853
ZJS
3043 if (r < 0)
3044 return log_error_errno(r, "Failed to parse RR record type %s: %m", optarg);
3045
4b548ef3
LP
3046 arg_type = (uint16_t) r;
3047 assert((int) arg_type == r);
b93312f5 3048
a150ff5e 3049 arg_mode = MODE_RESOLVE_RECORD;
2d4c5cbc
LP
3050 break;
3051
3052 case 'c':
b93312f5
ZJS
3053 if (streq(optarg, "help")) {
3054 help_dns_classes();
3055 return 0;
3056 }
3057
4b548ef3 3058 r = dns_class_from_string(optarg);
7211c853
ZJS
3059 if (r < 0)
3060 return log_error_errno(r, "Failed to parse RR record class %s: %m", optarg);
3061
4b548ef3
LP
3062 arg_class = (uint16_t) r;
3063 assert((int) arg_class == r);
b93312f5
ZJS
3064
3065 break;
3066
dad29dff 3067 case ARG_LEGEND:
599c7c54 3068 r = parse_boolean_argument("--legend=", optarg, &arg_legend);
45ec7efb 3069 if (r < 0)
599c7c54 3070 return r;
bdef7319
ZJS
3071 break;
3072
51323288 3073 case 'p':
ba82da3b
ZJS
3074 if (streq(optarg, "help")) {
3075 help_protocol_types();
3076 return 0;
3077 } else if (streq(optarg, "dns"))
51323288
LP
3078 arg_flags |= SD_RESOLVED_DNS;
3079 else if (streq(optarg, "llmnr"))
3080 arg_flags |= SD_RESOLVED_LLMNR;
3081 else if (streq(optarg, "llmnr-ipv4"))
3082 arg_flags |= SD_RESOLVED_LLMNR_IPV4;
3083 else if (streq(optarg, "llmnr-ipv6"))
3084 arg_flags |= SD_RESOLVED_LLMNR_IPV6;
062aabb9
DR
3085 else if (streq(optarg, "mdns"))
3086 arg_flags |= SD_RESOLVED_MDNS;
3087 else if (streq(optarg, "mdns-ipv4"))
3088 arg_flags |= SD_RESOLVED_MDNS_IPV4;
3089 else if (streq(optarg, "mdns-ipv6"))
3090 arg_flags |= SD_RESOLVED_MDNS_IPV6;
baaa35ad
ZJS
3091 else
3092 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3093 "Unknown protocol specifier: %s", optarg);
51323288
LP
3094
3095 break;
3096
45ec7efb 3097 case ARG_SERVICE:
a150ff5e 3098 arg_mode = MODE_RESOLVE_SERVICE;
45ec7efb
LP
3099 break;
3100
4ac2ca1b
ZJS
3101 case ARG_OPENPGP:
3102 arg_mode = MODE_RESOLVE_OPENPGP;
3103 break;
3104
82d1d240
ZJS
3105 case ARG_TLSA:
3106 arg_mode = MODE_RESOLVE_TLSA;
ebbc70e5
YW
3107 if (!optarg || service_family_is_valid(optarg))
3108 arg_service_family = optarg;
baaa35ad
ZJS
3109 else
3110 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3111 "Unknown service family \"%s\".", optarg);
82d1d240
ZJS
3112 break;
3113
2e74028a 3114 case ARG_RAW:
baaa35ad
ZJS
3115 if (on_tty())
3116 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY),
3117 "Refusing to write binary data to tty.");
2e74028a 3118
dab48ea6
ZJS
3119 if (optarg == NULL || streq(optarg, "payload"))
3120 arg_raw = RAW_PAYLOAD;
3121 else if (streq(optarg, "packet"))
3122 arg_raw = RAW_PACKET;
baaa35ad
ZJS
3123 else
3124 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3125 "Unknown --raw specifier \"%s\".",
3126 optarg);
dab48ea6 3127
2e74028a
ZJS
3128 arg_legend = false;
3129 break;
3130
45ec7efb 3131 case ARG_CNAME:
c3470872 3132 r = parse_boolean_argument("--cname=", optarg, NULL);
45ec7efb 3133 if (r < 0)
c3470872 3134 return r;
5883ff60 3135 SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0);
45ec7efb
LP
3136 break;
3137
3138 case ARG_SERVICE_ADDRESS:
c3470872 3139 r = parse_boolean_argument("--service-address=", optarg, NULL);
45ec7efb 3140 if (r < 0)
c3470872 3141 return r;
5883ff60 3142 SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0);
45ec7efb
LP
3143 break;
3144
3145 case ARG_SERVICE_TXT:
c3470872 3146 r = parse_boolean_argument("--service-txt=", optarg, NULL);
45ec7efb 3147 if (r < 0)
c3470872 3148 return r;
5883ff60 3149 SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
45ec7efb
LP
3150 break;
3151
801ad6a6 3152 case ARG_SEARCH:
c3470872 3153 r = parse_boolean_argument("--search=", optarg, NULL);
801ad6a6 3154 if (r < 0)
c3470872 3155 return r;
5883ff60 3156 SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0);
801ad6a6
LP
3157 break;
3158
a150ff5e
LP
3159 case ARG_STATISTICS:
3160 arg_mode = MODE_STATISTICS;
3161 break;
3162
3163 case ARG_RESET_STATISTICS:
3164 arg_mode = MODE_RESET_STATISTICS;
3165 break;
3166
ba35662f
LP
3167 case ARG_FLUSH_CACHES:
3168 arg_mode = MODE_FLUSH_CACHES;
3169 break;
3170
d55b0463
LP
3171 case ARG_RESET_SERVER_FEATURES:
3172 arg_mode = MODE_RESET_SERVER_FEATURES;
3173 break;
3174
be371fe0
LP
3175 case ARG_STATUS:
3176 arg_mode = MODE_STATUS;
3177 break;
3178
3179 case ARG_NO_PAGER:
0221d68a 3180 arg_pager_flags |= PAGER_DISABLE;
be371fe0
LP
3181 break;
3182
a7a4c60a
YW
3183 case ARG_SET_DNS:
3184 r = strv_extend(&arg_set_dns, optarg);
14965b94 3185 if (r < 0)
14965b94 3186 return log_oom();
14965b94 3187
14965b94
LP
3188 arg_mode = MODE_SET_LINK;
3189 break;
14965b94 3190
a7a4c60a 3191 case ARG_SET_DOMAIN:
14965b94
LP
3192 r = strv_extend(&arg_set_domain, optarg);
3193 if (r < 0)
3194 return log_oom();
3195
3196 arg_mode = MODE_SET_LINK;
3197 break;
14965b94
LP
3198
3199 case ARG_SET_LLMNR:
a7a4c60a 3200 arg_set_llmnr = optarg;
14965b94
LP
3201 arg_mode = MODE_SET_LINK;
3202 break;
3203
3204 case ARG_SET_MDNS:
a7a4c60a 3205 arg_set_mdns = optarg;
14965b94
LP
3206 arg_mode = MODE_SET_LINK;
3207 break;
3208
d050561a 3209 case ARG_SET_PRIVATE:
c9299be2 3210 arg_set_dns_over_tls = optarg;
d050561a
IT
3211 arg_mode = MODE_SET_LINK;
3212 break;
3213
14965b94 3214 case ARG_SET_DNSSEC:
a7a4c60a 3215 arg_set_dnssec = optarg;
14965b94
LP
3216 arg_mode = MODE_SET_LINK;
3217 break;
3218
3219 case ARG_SET_NTA:
14965b94
LP
3220 r = strv_extend(&arg_set_nta, optarg);
3221 if (r < 0)
3222 return log_oom();
3223
3224 arg_mode = MODE_SET_LINK;
3225 break;
3226
3227 case ARG_REVERT_LINK:
3228 arg_mode = MODE_REVERT_LINK;
3229 break;
3230
bdef7319
ZJS
3231 case '?':
3232 return -EINVAL;
3233
3234 default:
04499a70 3235 assert_not_reached();
bdef7319
ZJS
3236 }
3237
baaa35ad
ZJS
3238 if (arg_type == 0 && arg_class != 0)
3239 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3240 "--class= may only be used in conjunction with --type=.");
45ec7efb 3241
baaa35ad
ZJS
3242 if (arg_type != 0 && arg_mode == MODE_RESOLVE_SERVICE)
3243 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3244 "--service and --type= may not be combined.");
2d4c5cbc
LP
3245
3246 if (arg_type != 0 && arg_class == 0)
3247 arg_class = DNS_CLASS_IN;
3248
c1dafe4f
LP
3249 if (arg_class != 0 && arg_type == 0)
3250 arg_type = DNS_TYPE_A;
3251
14965b94
LP
3252 if (IN_SET(arg_mode, MODE_SET_LINK, MODE_REVERT_LINK)) {
3253
baaa35ad
ZJS
3254 if (arg_ifindex <= 0)
3255 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3256 "--set-dns=, --set-domain=, --set-llmnr=, --set-mdns=, --set-dnsovertls=, --set-dnssec=, --set-nta= and --revert require --interface=.");
14965b94
LP
3257 }
3258
bdef7319
ZJS
3259 return 1 /* work to do */;
3260}
3261
a7a4c60a
YW
3262static int native_parse_argv(int argc, char *argv[]) {
3263 enum {
3264 ARG_VERSION = 0x100,
3265 ARG_LEGEND,
3266 ARG_CNAME,
d711322c
LP
3267 ARG_VALIDATE,
3268 ARG_SYNTHESIZE,
3269 ARG_CACHE,
3270 ARG_ZONE,
3271 ARG_TRUST_ANCHOR,
3272 ARG_NETWORK,
a7a4c60a
YW
3273 ARG_SERVICE_ADDRESS,
3274 ARG_SERVICE_TXT,
3275 ARG_RAW,
3276 ARG_SEARCH,
3277 ARG_NO_PAGER,
fffbf1dc 3278 ARG_JSON,
a7a4c60a 3279 };
bdef7319 3280
a7a4c60a
YW
3281 static const struct option options[] = {
3282 { "help", no_argument, NULL, 'h' },
3283 { "version", no_argument, NULL, ARG_VERSION },
3284 { "type", required_argument, NULL, 't' },
3285 { "class", required_argument, NULL, 'c' },
3286 { "legend", required_argument, NULL, ARG_LEGEND },
3287 { "interface", required_argument, NULL, 'i' },
3288 { "protocol", required_argument, NULL, 'p' },
3289 { "cname", required_argument, NULL, ARG_CNAME },
d711322c
LP
3290 { "validate", required_argument, NULL, ARG_VALIDATE },
3291 { "synthesize", required_argument, NULL, ARG_SYNTHESIZE },
3292 { "cache", required_argument, NULL, ARG_CACHE },
3293 { "zone", required_argument, NULL, ARG_ZONE },
3294 { "trust-anchor", required_argument, NULL, ARG_TRUST_ANCHOR },
3295 { "network", required_argument, NULL, ARG_NETWORK },
a7a4c60a
YW
3296 { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS },
3297 { "service-txt", required_argument, NULL, ARG_SERVICE_TXT },
3298 { "raw", optional_argument, NULL, ARG_RAW },
3299 { "search", required_argument, NULL, ARG_SEARCH },
3300 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
fffbf1dc 3301 { "json", required_argument, NULL, ARG_JSON },
a7a4c60a
YW
3302 {}
3303 };
bdef7319 3304
a7a4c60a 3305 int c, r;
79266746 3306
a7a4c60a
YW
3307 assert(argc >= 0);
3308 assert(argv);
bdef7319 3309
fffbf1dc 3310 while ((c = getopt_long(argc, argv, "h46i:t:c:p:j", options, NULL)) >= 0)
79893116 3311 switch (c) {
45ec7efb 3312
a7a4c60a 3313 case 'h':
37ec0fdd 3314 return native_help();
a7a4c60a
YW
3315
3316 case ARG_VERSION:
3317 return version();
a150ff5e 3318
a7a4c60a
YW
3319 case '4':
3320 arg_family = AF_INET;
3321 break;
a150ff5e 3322
a7a4c60a
YW
3323 case '6':
3324 arg_family = AF_INET6;
3325 break;
3326
3327 case 'i':
df87a53d 3328 r = ifname_mangle(optarg);
a7a4c60a
YW
3329 if (r < 0)
3330 return r;
a7a4c60a
YW
3331 break;
3332
3333 case 't':
3334 if (streq(optarg, "help")) {
3335 help_dns_types();
3336 return 0;
3337 }
3338
3339 r = dns_type_from_string(optarg);
7211c853
ZJS
3340 if (r < 0)
3341 return log_error_errno(r, "Failed to parse RR record type %s: %m", optarg);
3342
a7a4c60a
YW
3343 arg_type = (uint16_t) r;
3344 assert((int) arg_type == r);
3345
3346 break;
3347
3348 case 'c':
3349 if (streq(optarg, "help")) {
3350 help_dns_classes();
3351 return 0;
3352 }
3353
3354 r = dns_class_from_string(optarg);
7211c853
ZJS
3355 if (r < 0)
3356 return log_error_errno(r, "Failed to parse RR record class %s: %m", optarg);
3357
a7a4c60a
YW
3358 arg_class = (uint16_t) r;
3359 assert((int) arg_class == r);
3360
3361 break;
3362
3363 case ARG_LEGEND:
599c7c54 3364 r = parse_boolean_argument("--legend=", optarg, &arg_legend);
a7a4c60a 3365 if (r < 0)
599c7c54 3366 return r;
a7a4c60a
YW
3367 break;
3368
3369 case 'p':
3370 if (streq(optarg, "help")) {
3371 help_protocol_types();
3372 return 0;
3373 } else if (streq(optarg, "dns"))
3374 arg_flags |= SD_RESOLVED_DNS;
3375 else if (streq(optarg, "llmnr"))
3376 arg_flags |= SD_RESOLVED_LLMNR;
3377 else if (streq(optarg, "llmnr-ipv4"))
3378 arg_flags |= SD_RESOLVED_LLMNR_IPV4;
3379 else if (streq(optarg, "llmnr-ipv6"))
3380 arg_flags |= SD_RESOLVED_LLMNR_IPV6;
3381 else if (streq(optarg, "mdns"))
3382 arg_flags |= SD_RESOLVED_MDNS;
3383 else if (streq(optarg, "mdns-ipv4"))
3384 arg_flags |= SD_RESOLVED_MDNS_IPV4;
3385 else if (streq(optarg, "mdns-ipv6"))
3386 arg_flags |= SD_RESOLVED_MDNS_IPV6;
baaa35ad
ZJS
3387 else
3388 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3389 "Unknown protocol specifier: %s",
3390 optarg);
a150ff5e 3391
a7a4c60a 3392 break;
a150ff5e 3393
a7a4c60a 3394 case ARG_RAW:
baaa35ad
ZJS
3395 if (on_tty())
3396 return log_error_errno(SYNTHETIC_ERRNO(ENOTTY),
3397 "Refusing to write binary data to tty.");
a150ff5e 3398
a7a4c60a
YW
3399 if (optarg == NULL || streq(optarg, "payload"))
3400 arg_raw = RAW_PAYLOAD;
3401 else if (streq(optarg, "packet"))
3402 arg_raw = RAW_PACKET;
baaa35ad
ZJS
3403 else
3404 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3405 "Unknown --raw specifier \"%s\".",
3406 optarg);
a150ff5e 3407
a7a4c60a
YW
3408 arg_legend = false;
3409 break;
a150ff5e 3410
a7a4c60a 3411 case ARG_CNAME:
c3470872 3412 r = parse_boolean_argument("--cname=", optarg, NULL);
a7a4c60a 3413 if (r < 0)
c3470872 3414 return r;
a7a4c60a
YW
3415 SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0);
3416 break;
a150ff5e 3417
d711322c 3418 case ARG_VALIDATE:
c3470872 3419 r = parse_boolean_argument("--validate=", optarg, NULL);
d711322c 3420 if (r < 0)
c3470872 3421 return r;
d711322c
LP
3422 SET_FLAG(arg_flags, SD_RESOLVED_NO_VALIDATE, r == 0);
3423 break;
3424
3425 case ARG_SYNTHESIZE:
c3470872 3426 r = parse_boolean_argument("--synthesize=", optarg, NULL);
d711322c 3427 if (r < 0)
c3470872 3428 return r;
d711322c
LP
3429 SET_FLAG(arg_flags, SD_RESOLVED_NO_SYNTHESIZE, r == 0);
3430 break;
3431
3432 case ARG_CACHE:
c3470872 3433 r = parse_boolean_argument("--cache=", optarg, NULL);
d711322c 3434 if (r < 0)
c3470872 3435 return r;
d711322c
LP
3436 SET_FLAG(arg_flags, SD_RESOLVED_NO_CACHE, r == 0);
3437 break;
3438
3439 case ARG_ZONE:
c3470872 3440 r = parse_boolean_argument("--zone=", optarg, NULL);
d711322c 3441 if (r < 0)
c3470872 3442 return r;
d711322c
LP
3443 SET_FLAG(arg_flags, SD_RESOLVED_NO_ZONE, r == 0);
3444 break;
3445
3446 case ARG_TRUST_ANCHOR:
c3470872 3447 r = parse_boolean_argument("--trust-anchor=", optarg, NULL);
d711322c 3448 if (r < 0)
c3470872 3449 return r;
d711322c
LP
3450 SET_FLAG(arg_flags, SD_RESOLVED_NO_TRUST_ANCHOR, r == 0);
3451 break;
3452
3453 case ARG_NETWORK:
c3470872 3454 r = parse_boolean_argument("--network=", optarg, NULL);
d711322c 3455 if (r < 0)
c3470872 3456 return r;
d711322c
LP
3457 SET_FLAG(arg_flags, SD_RESOLVED_NO_NETWORK, r == 0);
3458 break;
3459
a7a4c60a 3460 case ARG_SERVICE_ADDRESS:
c3470872 3461 r = parse_boolean_argument("--service-address=", optarg, NULL);
a7a4c60a 3462 if (r < 0)
c3470872 3463 return r;
a7a4c60a
YW
3464 SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0);
3465 break;
a150ff5e 3466
a7a4c60a 3467 case ARG_SERVICE_TXT:
c3470872 3468 r = parse_boolean_argument("--service-txt=", optarg, NULL);
a7a4c60a 3469 if (r < 0)
c3470872 3470 return r;
a7a4c60a
YW
3471 SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0);
3472 break;
45ec7efb 3473
a7a4c60a 3474 case ARG_SEARCH:
c3470872 3475 r = parse_boolean_argument("--search=", optarg, NULL);
a7a4c60a 3476 if (r < 0)
c3470872 3477 return r;
a7a4c60a
YW
3478 SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0);
3479 break;
79266746 3480
a7a4c60a 3481 case ARG_NO_PAGER:
0221d68a 3482 arg_pager_flags |= PAGER_DISABLE;
a7a4c60a
YW
3483 break;
3484
fffbf1dc
LP
3485 case ARG_JSON:
3486 r = parse_json_argument(optarg, &arg_json_format_flags);
3487 if (r <= 0)
3488 return r;
3489
3490 break;
3491
3492 case 'j':
3493 arg_json_format_flags = JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO;
3494 break;
3495
a7a4c60a
YW
3496 case '?':
3497 return -EINVAL;
4ac2ca1b 3498
a7a4c60a 3499 default:
04499a70 3500 assert_not_reached();
4ac2ca1b
ZJS
3501 }
3502
baaa35ad
ZJS
3503 if (arg_type == 0 && arg_class != 0)
3504 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
3505 "--class= may only be used in conjunction with --type=.");
4ac2ca1b 3506
a7a4c60a
YW
3507 if (arg_type != 0 && arg_class == 0)
3508 arg_class = DNS_CLASS_IN;
4ac2ca1b 3509
a7a4c60a
YW
3510 if (arg_class != 0 && arg_type == 0)
3511 arg_type = DNS_TYPE_A;
82d1d240 3512
a7a4c60a
YW
3513 return 1 /* work to do */;
3514}
82d1d240 3515
a7a4c60a
YW
3516static int native_main(int argc, char *argv[], sd_bus *bus) {
3517
3518 static const Verb verbs[] = {
3519 { "help", VERB_ANY, VERB_ANY, 0, verb_help },
3520 { "status", VERB_ANY, VERB_ANY, VERB_DEFAULT, verb_status },
3521 { "query", 2, VERB_ANY, 0, verb_query },
3522 { "service", 2, 4, 0, verb_service },
3523 { "openpgp", 2, VERB_ANY, 0, verb_openpgp },
3524 { "tlsa", 2, VERB_ANY, 0, verb_tlsa },
3525 { "statistics", VERB_ANY, 1, 0, show_statistics },
3526 { "reset-statistics", VERB_ANY, 1, 0, reset_statistics },
3527 { "flush-caches", VERB_ANY, 1, 0, flush_caches },
3528 { "reset-server-features", VERB_ANY, 1, 0, reset_server_features },
3529 { "dns", VERB_ANY, VERB_ANY, 0, verb_dns },
3530 { "domain", VERB_ANY, VERB_ANY, 0, verb_domain },
f2fd3cdb 3531 { "default-route", VERB_ANY, 3, 0, verb_default_route },
a7a4c60a
YW
3532 { "llmnr", VERB_ANY, 3, 0, verb_llmnr },
3533 { "mdns", VERB_ANY, 3, 0, verb_mdns },
efe55c81 3534 { "dnsovertls", VERB_ANY, 3, 0, verb_dns_over_tls },
a7a4c60a
YW
3535 { "dnssec", VERB_ANY, 3, 0, verb_dnssec },
3536 { "nta", VERB_ANY, VERB_ANY, 0, verb_nta },
d1293049 3537 { "revert", VERB_ANY, 2, 0, verb_revert_link },
df957849 3538 { "log-level", VERB_ANY, 2, 0, verb_log_level },
fffbf1dc 3539 { "monitor", VERB_ANY, 1, 0, verb_monitor },
a7a4c60a
YW
3540 {}
3541 };
82d1d240 3542
a7a4c60a
YW
3543 return dispatch_verb(argc, argv, verbs, bus);
3544}
82d1d240 3545
da6053d0 3546static int translate(const char *verb, const char *single_arg, size_t num_args, char **args, sd_bus *bus) {
a7a4c60a 3547 char **fake, **p;
c9d243cd 3548 size_t num;
bdef7319 3549
a7a4c60a
YW
3550 assert(verb);
3551 assert(num_args == 0 || args);
a150ff5e 3552
a7a4c60a 3553 num = !!single_arg + num_args + 1;
79266746 3554
a7a4c60a
YW
3555 p = fake = newa0(char *, num + 1);
3556 *p++ = (char *) verb;
3557 if (single_arg)
3558 *p++ = (char *) single_arg;
c9d243cd 3559 for (size_t i = 0; i < num_args; i++)
a7a4c60a 3560 *p++ = args[i];
ba35662f 3561
a7a4c60a 3562 optind = 0;
da6053d0 3563 return native_main((int) num, fake, bus);
a7a4c60a 3564}
ba35662f 3565
a7a4c60a
YW
3566static int compat_main(int argc, char *argv[], sd_bus *bus) {
3567 int r = 0;
be371fe0 3568
a7a4c60a
YW
3569 switch (arg_mode) {
3570 case MODE_RESOLVE_HOST:
3571 case MODE_RESOLVE_RECORD:
3572 return translate("query", NULL, argc - optind, argv + optind, bus);
d55b0463 3573
a7a4c60a
YW
3574 case MODE_RESOLVE_SERVICE:
3575 return translate("service", NULL, argc - optind, argv + optind, bus);
d55b0463 3576
a7a4c60a
YW
3577 case MODE_RESOLVE_OPENPGP:
3578 return translate("openpgp", NULL, argc - optind, argv + optind, bus);
be371fe0 3579
a7a4c60a
YW
3580 case MODE_RESOLVE_TLSA:
3581 return translate("tlsa", arg_service_family, argc - optind, argv + optind, bus);
be371fe0 3582
a7a4c60a
YW
3583 case MODE_STATISTICS:
3584 return translate("statistics", NULL, 0, NULL, bus);
3585
3586 case MODE_RESET_STATISTICS:
3587 return translate("reset-statistics", NULL, 0, NULL, bus);
3588
3589 case MODE_FLUSH_CACHES:
3590 return translate("flush-caches", NULL, 0, NULL, bus);
3591
3592 case MODE_RESET_SERVER_FEATURES:
3593 return translate("reset-server-features", NULL, 0, NULL, bus);
be371fe0 3594
a7a4c60a
YW
3595 case MODE_STATUS:
3596 return translate("status", NULL, argc - optind, argv + optind, bus);
14965b94 3597
14965b94 3598 case MODE_SET_LINK:
a661dc36
YW
3599 assert(arg_ifname);
3600
a7a4c60a
YW
3601 if (arg_set_dns) {
3602 r = translate("dns", arg_ifname, strv_length(arg_set_dns), arg_set_dns, bus);
3603 if (r < 0)
3604 return r;
3605 }
3606
3607 if (arg_set_domain) {
3608 r = translate("domain", arg_ifname, strv_length(arg_set_domain), arg_set_domain, bus);
3609 if (r < 0)
3610 return r;
14965b94
LP
3611 }
3612
a7a4c60a
YW
3613 if (arg_set_nta) {
3614 r = translate("nta", arg_ifname, strv_length(arg_set_nta), arg_set_nta, bus);
3615 if (r < 0)
3616 return r;
3617 }
14965b94 3618
a7a4c60a
YW
3619 if (arg_set_llmnr) {
3620 r = translate("llmnr", arg_ifname, 1, (char **) &arg_set_llmnr, bus);
3621 if (r < 0)
3622 return r;
3623 }
3624
3625 if (arg_set_mdns) {
3626 r = translate("mdns", arg_ifname, 1, (char **) &arg_set_mdns, bus);
3627 if (r < 0)
3628 return r;
3629 }
3630
c9299be2
IT
3631 if (arg_set_dns_over_tls) {
3632 r = translate("dnsovertls", arg_ifname, 1, (char **) &arg_set_dns_over_tls, bus);
d050561a
IT
3633 if (r < 0)
3634 return r;
3635 }
3636
a7a4c60a
YW
3637 if (arg_set_dnssec) {
3638 r = translate("dnssec", arg_ifname, 1, (char **) &arg_set_dnssec, bus);
3639 if (r < 0)
3640 return r;
14965b94
LP
3641 }
3642
a7a4c60a
YW
3643 return r;
3644
3645 case MODE_REVERT_LINK:
a661dc36
YW
3646 assert(arg_ifname);
3647
a7a4c60a 3648 return translate("revert", arg_ifname, 0, NULL, bus);
088c1363
LP
3649
3650 case _MODE_INVALID:
04499a70 3651 assert_not_reached();
bdef7319
ZJS
3652 }
3653
a7a4c60a
YW
3654 return 0;
3655}
3656
f6aa6190
YW
3657static int run(int argc, char **argv) {
3658 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
427eeb44 3659 bool compat = false;
a7a4c60a
YW
3660 int r;
3661
3662 setlocale(LC_ALL, "");
d2acb93d 3663 log_setup();
a7a4c60a 3664
427eeb44
YW
3665 if (invoked_as(argv, "resolvconf")) {
3666 compat = true;
a7a4c60a 3667 r = resolvconf_parse_argv(argc, argv);
427eeb44
YW
3668 } else if (invoked_as(argv, "systemd-resolve")) {
3669 compat = true;
a7a4c60a 3670 r = compat_parse_argv(argc, argv);
427eeb44 3671 } else
a7a4c60a
YW
3672 r = native_parse_argv(argc, argv);
3673 if (r <= 0)
f6aa6190 3674 return r;
a7a4c60a
YW
3675
3676 r = sd_bus_open_system(&bus);
f6aa6190
YW
3677 if (r < 0)
3678 return log_error_errno(r, "sd_bus_open_system: %m");
a7a4c60a 3679
427eeb44 3680 if (compat)
f6aa6190 3681 return compat_main(argc, argv, bus);
be371fe0 3682
f6aa6190 3683 return native_main(argc, argv, bus);
bdef7319 3684}
f6aa6190
YW
3685
3686DEFINE_MAIN_FUNCTION(run);