]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolvectl: clarify IDNA and search path logic in combination with "resolvectl query...
authorLennart Poettering <lennart@poettering.net>
Fri, 6 Nov 2020 19:10:40 +0000 (20:10 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 16 Feb 2021 08:51:17 +0000 (09:51 +0100)
When low-level RR resolution is requested from "resolvectl query" via
"--type=" or "--class=" no search domain logic is applied and no IDNA
translation.

Explain this in detail in the documentation, and also mentions this when
users attempt to resolve single-label names or names with international
characters in the output.

I believe the current behaviour is correct, but it is indeed surprising.
Hence the documentation and output improvement.

Fixes: #11325 #10737
man/resolvectl.xml
src/resolve/resolvectl.c

index 7662349cc54b45acf92e707e70479d7284526dd0..c87b6fd44b340c8e69d97feb881b440ce388b886 100644 (file)
       <varlistentry>
         <term><command>query</command> <replaceable>HOSTNAME|ADDRESS</replaceable>…</term>
 
-        <listitem><para>Resolve domain names, IPv4 and IPv6 addresses.</para></listitem>
+        <listitem><para>Resolve domain names, as well as IPv4 and IPv6 addresses. When used in conjuntion
+        with <option>--type=</option> or <option>--class=</option> (see below), resolves low-level DNS
+        resource records.</para>
+
+        <para>If a single-label domain name is specified it is searched for according to the configured
+        search domains — unless <option>--search=no</option> or
+        <option>--type=</option>/<option>--class=</option> are specified, both of which turn this logic
+        off.</para>
+
+        <para>If an international domain name is specified, it is automatically translated according to IDNA
+        rules when resolved via classic DNS — but not for look-ups via MulticastDNS or LLMNR. If
+        <option>--type=</option>/<option>--class=</option> is used IDNA translation is turned off and domain
+        names are processed as specified.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><option>-c</option> <replaceable>CLASS</replaceable></term>
         <term><option>--class=</option><replaceable>CLASS</replaceable></term>
 
-        <listitem><para>Specifies the DNS resource record type (e.g. A, AAAA, MX, …) and class (e.g. IN, ANY, …) to
-        look up. If these options are used a DNS resource record set matching the specified class and type is
-        requested. The class defaults to IN if only a type is specified.
-        The special value <literal>help</literal> may be used to list known values.
-        </para></listitem>
+        <listitem><para>When used in conjunction with the <command>query</command> command, specifies the DNS
+        resource record type (e.g. A, AAAA, MX, …) and class (e.g. IN, ANY, …) to look up. If these options
+        are used a DNS resource record set matching the specified class and type is requested. The class
+        defaults to IN if only a type is specified. The special value <literal>help</literal> may be used to
+        list known values.</para>
+
+        <para>Without these options <command>resolvectl query</command> provides high-level domain name to
+        address and address to domain name resolution. With these options it provides low-level DNS resource
+        record resolution. The search domain logic is automatically turned off when these options are used,
+        i.e. specified domain names need to be fully qualified domain names. Moreover, IDNA internal domain
+        name translation is turned off as well, i.e. international domain names should be specified in
+        <literal>xn--…</literal> notation, unless look-up in MulticastDNS/LLMNR is desired, in which case
+        UTF-8 characters should be used.</para></listitem>
       </varlistentry>
 
       <varlistentry>
       <varlistentry>
         <term><option>--search=</option><replaceable>BOOL</replaceable></term>
 
-        <listitem><para>Takes a boolean parameter. If true (the default), any specified single-label hostnames will be
-        searched in the domains configured in the search domain list, if it is non-empty. Otherwise, the search domain
-        logic is disabled.</para></listitem>
+        <listitem><para>Takes a boolean parameter. If true (the default), any specified single-label
+        hostnames will be searched in the domains configured in the search domain list, if it is
+        non-empty. Otherwise, the search domain logic is disabled. Note that this option has no effect if
+        <option>--type=</option> is used (see above), in which case the search domain logic is
+        unconditionally turned off.</para></listitem>
       </varlistentry>
 
       <varlistentry>
index e7ee7354287630ee71121bd00f1c441725e4f3c2..6301b6ba09b6e9cc2cc9cb89a3d35aac41b0c945 100644 (file)
@@ -407,19 +407,51 @@ static int output_rr_packet(const void *d, size_t l, int ifindex) {
         return 0;
 }
 
+static int idna_candidate(const char *name, char **ret) {
+        _cleanup_free_ char *idnafied = NULL;
+        int r;
+
+        assert(name);
+        assert(ret);
+
+        r = dns_name_apply_idna(name, &idnafied);
+        if (r < 0)
+                return log_error_errno(r, "Failed to apply IDNA to name '%s': %m", name);
+        if (r > 0 && !streq(name, idnafied)) {
+                *ret = TAKE_PTR(idnafied);
+                return true;
+        }
+
+        *ret = NULL;
+        return false;
+}
+
 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;
+        _cleanup_free_ char *idnafied = NULL;
+        bool needs_authentication = false;
         unsigned n = 0;
         uint64_t flags;
-        int r;
         usec_t ts;
-        bool needs_authentication = false;
+        int r;
 
         assert(name);
 
         log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(arg_ifname) ? "*" : arg_ifname);
 
+        if (dns_name_is_single_label(name))
+                log_notice("(Note that search domains are not appended when resolving raw record types. "
+                           "Please specify fully qualified domain names when resolving raw records, or remove --type= switch from invocation in order to request regular hostname resolution.)");
+
+        r = idna_candidate(name, &idnafied);
+        if (r < 0)
+                return r;
+        if (r > 0)
+                log_notice("(Note that IDNA translation is not applied when resolving raw record types. "
+                           "Please specify translated domain names — i.e. '%s' — when resolving raw records, or remove --type= switch from invocation in order to request regular hostname resolution.",
+                           idnafied);
+
         r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveRecord");
         if (r < 0)
                 return bus_log_create_error(r);