]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: properly signal transient errors back to NSS stack
authorLennart Poettering <lennart@poettering.net>
Mon, 22 Nov 2021 14:17:34 +0000 (15:17 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 22 Nov 2021 21:33:40 +0000 (22:33 +0100)
NSS mostly knows four error cases: SUCCESS, NOTFOUND, UNAVAIL, TRYAGAIN,
and they can all be used in nsswitch.conf to route requests.

So far nss-resolve would return SUCCESS + NOTFOUND + UNAVAIL. Let's also
return TRYAGAIN in some cases, specifically the ones where we are
currntly unable to resolve a request but likely could later. i.e.
errors caused by networking issues or such.

Fixes: #20786
src/nss-resolve/nss-resolve.c

index d77ffdd9f22a41395c835762d1128abad43e45e0..951d141f35274e6292d33460815e239dc618cccf 100644 (file)
@@ -41,6 +41,9 @@ NSS_GETHOSTBYNAME_PROTOTYPES(resolve);
 NSS_GETHOSTBYADDR_PROTOTYPES(resolve);
 
 static bool error_shall_fallback(const char *error_id) {
+        /* The Varlink errors where we shall signal "please fallback" back to the NSS stack, so that some
+         * fallback module can be loaded. (These are mostly all Varlink-internal errors, as apparently we
+         * then were unable to even do IPC with systemd-resolved.) */
         return STR_IN_SET(error_id,
                           VARLINK_ERROR_DISCONNECTED,
                           VARLINK_ERROR_TIMEOUT,
@@ -50,6 +53,16 @@ static bool error_shall_fallback(const char *error_id) {
                           VARLINK_ERROR_METHOD_NOT_IMPLEMENTED);
 }
 
+static bool error_shall_try_again(const char *error_id) {
+        /* The Varlink errors where we shall signal "can't answer now but might be able to later" back to the
+         * NSS stack. These are all errors that indicate lack of configuration or network problems. */
+        return STR_IN_SET(error_id,
+                          "io.systemd.Resolve.NoNameServers",
+                          "io.systemd.Resolve.QueryTimedOut",
+                          "io.systemd.Resolve.MaxAttemptsReached",
+                          "io.systemd.Resolve.NetworkDown");
+}
+
 static int connect_to_resolved(Varlink **ret) {
         _cleanup_(varlink_unrefp) Varlink *link = NULL;
         int r;
@@ -242,9 +255,11 @@ enum nss_status _nss_resolve_gethostbyname4_r(
         if (r < 0)
                 goto fail;
         if (!isempty(error_id)) {
-                if (!error_shall_fallback(error_id))
-                        goto not_found;
-                goto fail;
+                if (error_shall_try_again(error_id))
+                        goto try_again;
+                if (error_shall_fallback(error_id))
+                        goto fail;
+                goto not_found;
         }
 
         r = json_dispatch(rparams, resolve_hostname_reply_dispatch_table, NULL, json_dispatch_flags, &p);
@@ -341,6 +356,12 @@ fail:
 not_found:
         *h_errnop = HOST_NOT_FOUND;
         return NSS_STATUS_NOTFOUND;
+
+try_again:
+        UNPROTECT_ERRNO;
+        *errnop = -r;
+        *h_errnop = TRY_AGAIN;
+        return NSS_STATUS_TRYAGAIN;
 }
 
 enum nss_status _nss_resolve_gethostbyname3_r(
@@ -390,9 +411,11 @@ enum nss_status _nss_resolve_gethostbyname3_r(
         if (r < 0)
                 goto fail;
         if (!isempty(error_id)) {
-                if (!error_shall_fallback(error_id))
-                        goto not_found;
-                goto fail;
+                if (error_shall_try_again(error_id))
+                        goto try_again;
+                if (error_shall_fallback(error_id))
+                        goto fail;
+                goto not_found;
         }
 
         r = json_dispatch(rparams, resolve_hostname_reply_dispatch_table, NULL, json_dispatch_flags, &p);
@@ -508,6 +531,12 @@ fail:
 not_found:
         *h_errnop = HOST_NOT_FOUND;
         return NSS_STATUS_NOTFOUND;
+
+try_again:
+        UNPROTECT_ERRNO;
+        *errnop = -r;
+        *h_errnop = TRY_AGAIN;
+        return NSS_STATUS_TRYAGAIN;
 }
 
 typedef struct ResolveAddressReply {
@@ -594,9 +623,11 @@ enum nss_status _nss_resolve_gethostbyaddr2_r(
         if (r < 0)
                 goto fail;
         if (!isempty(error_id)) {
-                if (!error_shall_fallback(error_id))
-                        goto not_found;
-                goto fail;
+                if (error_shall_try_again(error_id))
+                        goto try_again;
+                if (error_shall_fallback(error_id))
+                        goto fail;
+                goto not_found;
         }
 
         r = json_dispatch(rparams, resolve_address_reply_dispatch_table, NULL, json_dispatch_flags, &p);
@@ -694,6 +725,12 @@ fail:
 not_found:
         *h_errnop = HOST_NOT_FOUND;
         return NSS_STATUS_NOTFOUND;
+
+try_again:
+        UNPROTECT_ERRNO;
+        *errnop = -r;
+        *h_errnop = TRY_AGAIN;
+        return NSS_STATUS_TRYAGAIN;
 }
 
 NSS_GETHOSTBYNAME_FALLBACKS(resolve);