LCOV - code coverage report
Current view: top level - resolve - resolvectl.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 31 1655 1.9 %
Date: 2019-08-22 15:41:25 Functions: 8 65 12.3 %

          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           4 : STATIC_DESTRUCTOR_REGISTER(arg_ifname, freep);
      64           4 : STATIC_DESTRUCTOR_REGISTER(arg_set_dns, strv_freep);
      65           4 : STATIC_DESTRUCTOR_REGISTER(arg_set_domain, strv_freep);
      66           4 : 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           3 : static int native_help(void) {
    2519           3 :         _cleanup_free_ char *link = NULL;
    2520             :         int r;
    2521             : 
    2522           3 :         r = terminal_urlify_man("resolvectl", "1", &link);
    2523           3 :         if (r < 0)
    2524           0 :                 return log_oom();
    2525             : 
    2526           3 :         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           3 :         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           4 : 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           4 :         assert(argc >= 0);
    2930           4 :         assert(argv);
    2931             : 
    2932           4 :         while ((c = getopt_long(argc, argv, "h46i:t:c:p:", options, NULL)) >= 0)
    2933           4 :                 switch(c) {
    2934             : 
    2935           3 :                 case 'h':
    2936           3 :                         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           1 :                 case '?':
    3070           1 :                         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           4 : static int run(int argc, char **argv) {
    3229           4 :         _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
    3230             :         int r;
    3231             : 
    3232           4 :         setlocale(LC_ALL, "");
    3233           4 :         log_show_color(true);
    3234           4 :         log_parse_environment();
    3235           4 :         log_open();
    3236             : 
    3237           4 :         if (streq(program_invocation_short_name, "resolvconf"))
    3238           0 :                 r = resolvconf_parse_argv(argc, argv);
    3239           4 :         else if (streq(program_invocation_short_name, "systemd-resolve"))
    3240           0 :                 r = compat_parse_argv(argc, argv);
    3241             :         else
    3242           4 :                 r = native_parse_argv(argc, argv);
    3243           4 :         if (r <= 0)
    3244           4 :                 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           4 : DEFINE_MAIN_FUNCTION(run);

Generated by: LCOV version 1.14