]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/resolve/resolve-tool.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / resolve / resolve-tool.c
index 4e1e916669068385028587ee8e0efb5f29ddd1dc..a963454da0eb1ef5516b131ec88386ea0cde5c4d 100644 (file)
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
 /***
   This file is part of systemd.
 
@@ -38,7 +39,7 @@
 #include "strv.h"
 #include "terminal-util.h"
 
-#define DNS_CALL_TIMEOUT_USEC (45*USEC_PER_SEC)
+#define DNS_CALL_TIMEOUT_USEC (90*USEC_PER_SEC)
 
 static int arg_family = AF_UNSPEC;
 static int arg_ifindex = 0;
@@ -72,6 +73,7 @@ static enum {
         MODE_STATISTICS,
         MODE_RESET_STATISTICS,
         MODE_FLUSH_CACHES,
+        MODE_RESET_SERVER_FEATURES,
         MODE_STATUS,
 } arg_mode = MODE_RESOLVE_HOST;
 
@@ -114,8 +116,8 @@ static void print_source(uint64_t flags, usec_t rtt) {
                        flags & SD_RESOLVED_DNS ? " DNS" :"",
                        flags & SD_RESOLVED_LLMNR_IPV4 ? " LLMNR/IPv4" : "",
                        flags & SD_RESOLVED_LLMNR_IPV6 ? " LLMNR/IPv6" : "",
-                       flags & SD_RESOLVED_MDNS_IPV4 ? "mDNS/IPv4" : "",
-                       flags & SD_RESOLVED_MDNS_IPV6 ? "mDNS/IPv6" : "");
+                       flags & SD_RESOLVED_MDNS_IPV4 ? " mDNS/IPv4" : "",
+                       flags & SD_RESOLVED_MDNS_IPV6 ? " mDNS/IPv6" : "");
 
         assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100));
 
@@ -357,7 +359,7 @@ static int output_rr_packet(const void *d, size_t l, int ifindex) {
         int r;
         char ifname[IF_NAMESIZE] = "";
 
-        r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0);
+        r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, DNS_PACKET_SIZE_MAX);
         if (r < 0)
                 return log_oom();
 
@@ -395,7 +397,7 @@ static int output_rr_packet(const void *d, size_t l, int ifindex) {
         return 0;
 }
 
-static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type) {
+static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type, bool warn_missing) {
         _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         char ifname[IF_NAMESIZE] = "";
@@ -430,7 +432,8 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
 
         r = sd_bus_call(bus, req, DNS_CALL_TIMEOUT_USEC, &error, &reply);
         if (r < 0) {
-                log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
+                if (warn_missing || r != -ENXIO)
+                        log_error("%s: resolve call failed: %s", name, bus_error_message(&error, r));
                 return r;
         }
 
@@ -488,7 +491,8 @@ static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_
                 return bus_log_parse_error(r);
 
         if (n == 0) {
-                log_error("%s: no records found", name);
+                if (warn_missing)
+                        log_error("%s: no records found", name);
                 return -ESRCH;
         }
 
@@ -618,7 +622,7 @@ static int resolve_rfc4501(sd_bus *bus, const char *name) {
         if (type == 0)
                 type = arg_type ?: DNS_TYPE_A;
 
-        return resolve_record(bus, n, class, type);
+        return resolve_record(bus, n, class, type, true);
 
 invalid:
         log_error("Invalid DNS URI: %s", name);
@@ -778,7 +782,6 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons
         if (r < 0)
                 return bus_log_parse_error(r);
 
-        c = 0;
         while ((r = sd_bus_message_read_array(reply, 'y', (const void**) &p, &sz)) > 0) {
                 _cleanup_free_ char *escaped = NULL;
 
@@ -787,7 +790,6 @@ static int resolve_service(sd_bus *bus, const char *name, const char *type, cons
                         return log_oom();
 
                 printf("%*s%s\n", (int) indent, "", escaped);
-                c++;
         }
         if (r < 0)
                 return bus_log_parse_error(r);
@@ -840,16 +842,34 @@ static int resolve_openpgp(sd_bus *bus, const char *address) {
         }
         domain++;
 
-        r = string_hashsum_sha224(address, domain - 1 - address, &hashed);
+        r = string_hashsum_sha256(address, domain - 1 - address, &hashed);
         if (r < 0)
                 return log_error_errno(r, "Hashing failed: %m");
 
+        strshorten(hashed, 56);
+
         full = strjoina(hashed, "._openpgpkey.", domain);
         log_debug("Looking up \"%s\".", full);
 
-        return resolve_record(bus, full,
-                              arg_class ?: DNS_CLASS_IN,
-                              arg_type ?: DNS_TYPE_OPENPGPKEY);
+        r = resolve_record(bus, full,
+                           arg_class ?: DNS_CLASS_IN,
+                           arg_type ?: DNS_TYPE_OPENPGPKEY, false);
+
+        if (IN_SET(r, -ENXIO, -ESRCH)) { /* NXDOMAIN or NODATA? */
+              hashed = NULL;
+              r = string_hashsum_sha224(address, domain - 1 - address, &hashed);
+              if (r < 0)
+                    return log_error_errno(r, "Hashing failed: %m");
+
+              full = strjoina(hashed, "._openpgpkey.", domain);
+              log_debug("Looking up \"%s\".", full);
+
+              return resolve_record(bus, full,
+                                    arg_class ?: DNS_CLASS_IN,
+                                    arg_type ?: DNS_TYPE_OPENPGPKEY, true);
+        }
+
+        return r;
 }
 
 static int resolve_tlsa(sd_bus *bus, const char *address) {
@@ -863,8 +883,8 @@ static int resolve_tlsa(sd_bus *bus, const char *address) {
 
         port = strrchr(address, ':');
         if (port) {
-                r = safe_atou16(port + 1, &port_num);
-                if (r < 0 || port_num == 0)
+                r = parse_ip_port(port + 1, &port_num);
+                if (r < 0)
                         return log_error_errno(r, "Invalid port \"%s\".", port + 1);
 
                 address = strndupa(address, port - address);
@@ -881,7 +901,7 @@ static int resolve_tlsa(sd_bus *bus, const char *address) {
 
         return resolve_record(bus, full,
                               arg_class ?: DNS_CLASS_IN,
-                              arg_type ?: DNS_TYPE_TLSA);
+                              arg_type ?: DNS_TYPE_TLSA, true);
 }
 
 static int show_statistics(sd_bus *bus) {
@@ -1037,6 +1057,24 @@ static int flush_caches(sd_bus *bus) {
         return 0;
 }
 
+static int reset_server_features(sd_bus *bus) {
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+        int r;
+
+        r = sd_bus_call_method(bus,
+                               "org.freedesktop.resolve1",
+                               "/org/freedesktop/resolve1",
+                               "org.freedesktop.resolve1.Manager",
+                               "ResetServerFeatures",
+                               &error,
+                               NULL,
+                               NULL);
+        if (r < 0)
+                return log_error_errno(r, "Failed to reset server features: %s", bus_error_message(&error, r));
+
+        return 0;
+}
+
 static int map_link_dns_servers(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
         char ***l = userdata;
         int r;
@@ -1168,6 +1206,7 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, bool *empt
                 {}
         };
 
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_free_ char *ifi = NULL, *p = NULL;
         char ifname[IF_NAMESIZE] = "";
         char **i;
@@ -1195,9 +1234,10 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, bool *empt
                                    "org.freedesktop.resolve1",
                                    p,
                                    property_map,
+                                   &error,
                                    &link_info);
         if (r < 0) {
-                log_error_errno(r, "Failed to get link data for %i: %m", ifindex);
+                log_error_errno(r, "Failed to get link data for %i: %s", ifindex, bus_error_message(&error, r));
                 goto finish;
         }
 
@@ -1229,8 +1269,8 @@ static int status_ifindex(sd_bus *bus, int ifindex, const char *name, bool *empt
                yes_no(link_info.dnssec_supported));
 
         STRV_FOREACH(i, link_info.dns) {
-                printf("          %s %s\n",
-                       i == link_info.dns ? "DNS Server:" : "           ",
+                printf("         %s %s\n",
+                       i == link_info.dns ? "DNS Servers:" : "            ",
                        *i);
         }
 
@@ -1387,6 +1427,7 @@ static int status_global(sd_bus *bus, bool *empty_line) {
                 {}
         };
 
+        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
         char **i;
         int r;
 
@@ -1397,9 +1438,10 @@ static int status_global(sd_bus *bus, bool *empty_line) {
                                    "org.freedesktop.resolve1",
                                    "/org/freedesktop/resolve1",
                                    property_map,
+                                   &error,
                                    &global_info);
         if (r < 0) {
-                log_error_errno(r, "Failed to get global data: %m");
+                log_error_errno(r, "Failed to get global data: %s", bus_error_message(&error, r));
                 goto finish;
         }
 
@@ -1412,8 +1454,8 @@ static int status_global(sd_bus *bus, bool *empty_line) {
 
         printf("%sGlobal%s\n", ansi_highlight(), ansi_normal());
         STRV_FOREACH(i, global_info.dns) {
-                printf("          %s %s\n",
-                       i == global_info.dns ? "DNS Server:" : "           ",
+                printf("         %s %s\n",
+                       i == global_info.dns ? "DNS Servers:" : "            ",
                        *i);
         }
 
@@ -1446,7 +1488,7 @@ static int status_all(sd_bus *bus) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
         _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
         sd_netlink_message *i;
-        bool empty_line = true;
+        bool empty_line = false;
         int r;
 
         assert(bus);
@@ -1506,7 +1548,7 @@ static int status_all(sd_bus *bus) {
 static void help_protocol_types(void) {
         if (arg_legend)
                 puts("Known protocol types:");
-        puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6");
+        puts("dns\nllmnr\nllmnr-ipv4\nllmnr-ipv6\nmdns\nmnds-ipv4\nmdns-ipv6");
 }
 
 static void help_dns_types(void) {
@@ -1542,7 +1584,7 @@ static void help(void) {
                "%1$s [OPTIONS...] --statistics\n"
                "%1$s [OPTIONS...] --reset-statistics\n"
                "\n"
-               "Resolve domain names, IPv4 and IPv6 addresses, DNS resource records, and services.\n\n"
+               "Resolve domain names, IPv4 and IPv6 addresses, DNS records, and services.\n\n"
                "  -h --help                 Show this help\n"
                "     --version              Show package version\n"
                "     --no-pager             Do not pipe output into a pager\n"
@@ -1566,6 +1608,8 @@ static void help(void) {
                "     --reset-statistics     Reset resolver statistics\n"
                "     --status               Show link and server status\n"
                "     --flush-caches         Flush all local DNS caches\n"
+               "     --reset-server-features\n"
+               "                            Forget learnt DNS server feature levels\n"
                , program_invocation_short_name);
 }
 
@@ -1585,30 +1629,32 @@ static int parse_argv(int argc, char *argv[]) {
                 ARG_RESET_STATISTICS,
                 ARG_STATUS,
                 ARG_FLUSH_CACHES,
+                ARG_RESET_SERVER_FEATURES,
                 ARG_NO_PAGER,
         };
 
         static const struct option options[] = {
-                { "help",             no_argument,       NULL, 'h'                  },
-                { "version",          no_argument,       NULL, ARG_VERSION          },
-                { "type",             required_argument, NULL, 't'                  },
-                { "class",            required_argument, NULL, 'c'                  },
-                { "legend",           required_argument, NULL, ARG_LEGEND           },
-                { "interface",        required_argument, NULL, 'i'                  },
-                { "protocol",         required_argument, NULL, 'p'                  },
-                { "cname",            required_argument, NULL, ARG_CNAME            },
-                { "service",          no_argument,       NULL, ARG_SERVICE          },
-                { "service-address",  required_argument, NULL, ARG_SERVICE_ADDRESS  },
-                { "service-txt",      required_argument, NULL, ARG_SERVICE_TXT      },
-                { "openpgp",          no_argument,       NULL, ARG_OPENPGP          },
-                { "tlsa",             optional_argument, NULL, ARG_TLSA             },
-                { "raw",              optional_argument, NULL, ARG_RAW              },
-                { "search",           required_argument, NULL, ARG_SEARCH           },
-                { "statistics",       no_argument,       NULL, ARG_STATISTICS,      },
-                { "reset-statistics", no_argument,       NULL, ARG_RESET_STATISTICS },
-                { "status",           no_argument,       NULL, ARG_STATUS           },
-                { "flush-caches",     no_argument,       NULL, ARG_FLUSH_CACHES     },
-                { "no-pager",         no_argument,       NULL, ARG_NO_PAGER         },
+                { "help",                  no_argument,       NULL, 'h'                       },
+                { "version",               no_argument,       NULL, ARG_VERSION               },
+                { "type",                  required_argument, NULL, 't'                       },
+                { "class",                 required_argument, NULL, 'c'                       },
+                { "legend",                required_argument, NULL, ARG_LEGEND                },
+                { "interface",             required_argument, NULL, 'i'                       },
+                { "protocol",              required_argument, NULL, 'p'                       },
+                { "cname",                 required_argument, NULL, ARG_CNAME                 },
+                { "service",               no_argument,       NULL, ARG_SERVICE               },
+                { "service-address",       required_argument, NULL, ARG_SERVICE_ADDRESS       },
+                { "service-txt",           required_argument, NULL, ARG_SERVICE_TXT           },
+                { "openpgp",               no_argument,       NULL, ARG_OPENPGP               },
+                { "tlsa",                  optional_argument, NULL, ARG_TLSA                  },
+                { "raw",                   optional_argument, NULL, ARG_RAW                   },
+                { "search",                required_argument, NULL, ARG_SEARCH                },
+                { "statistics",            no_argument,       NULL, ARG_STATISTICS,           },
+                { "reset-statistics",      no_argument,       NULL, ARG_RESET_STATISTICS      },
+                { "status",                no_argument,       NULL, ARG_STATUS                },
+                { "flush-caches",          no_argument,       NULL, ARG_FLUSH_CACHES          },
+                { "reset-server-features", no_argument,       NULL, ARG_RESET_SERVER_FEATURES },
+                { "no-pager",              no_argument,       NULL, ARG_NO_PAGER              },
                 {}
         };
 
@@ -1704,6 +1750,12 @@ static int parse_argv(int argc, char *argv[]) {
                                 arg_flags |= SD_RESOLVED_LLMNR_IPV4;
                         else if (streq(optarg, "llmnr-ipv6"))
                                 arg_flags |= SD_RESOLVED_LLMNR_IPV6;
+                        else if (streq(optarg, "mdns"))
+                                arg_flags |= SD_RESOLVED_MDNS;
+                        else if (streq(optarg, "mdns-ipv4"))
+                                arg_flags |= SD_RESOLVED_MDNS_IPV4;
+                        else if (streq(optarg, "mdns-ipv6"))
+                                arg_flags |= SD_RESOLVED_MDNS_IPV6;
                         else {
                                 log_error("Unknown protocol specifier: %s", optarg);
                                 return -EINVAL;
@@ -1786,6 +1838,10 @@ static int parse_argv(int argc, char *argv[]) {
                         arg_mode = MODE_FLUSH_CACHES;
                         break;
 
+                case ARG_RESET_SERVER_FEATURES:
+                        arg_mode = MODE_RESET_SERVER_FEATURES;
+                        break;
+
                 case ARG_STATUS:
                         arg_mode = MODE_STATUS;
                         break;
@@ -1877,7 +1933,7 @@ int main(int argc, char **argv) {
                 while (argv[optind]) {
                         int k;
 
-                        k = resolve_record(bus, argv[optind], arg_class, arg_type);
+                        k = resolve_record(bus, argv[optind], arg_class, arg_type, true);
                         if (r == 0)
                                 r = k;
 
@@ -1971,6 +2027,16 @@ int main(int argc, char **argv) {
                 r = flush_caches(bus);
                 break;
 
+        case MODE_RESET_SERVER_FEATURES:
+                if (argc > optind) {
+                        log_error("Too many arguments.");
+                        r = -EINVAL;
+                        goto finish;
+                }
+
+                r = reset_server_features(bus);
+                break;
+
         case MODE_STATUS:
 
                 if (argc > optind) {