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