[PATCH] Prefer address family matching to local address in resolver (ticket #1535)

Lukas Lihotzki lukas at lihotzki.de
Wed Jan 19 15:08:32 UTC 2022


# HG changeset patch
# User Lukas Lihotzki <lukas at lihotzki.de>
# Date 1642576371 -3600
#      Wed Jan 19 08:12:51 2022 +0100
# Node ID f922980f06b1162ae933c99c03bef09cfc12582f
# Parent  aeab41dfd2606dd36cabbf01f1472726e27e8aea
Prefer address family matching to local address in resolver (ticket #1535).

Without this change, upstream connections fail randomly for dual-stack
host names when specifying a proxy_bind address (ticket #1535).

This changeset adds two flags for avoiding resolving to either IPv4 or IPv6
addresses. stream and http set these flags based on the proxy_bind address.
Avoided addresses are still returned if there are none of the other family, so
the same error message as before is produced when connecting is impossible.

diff -r aeab41dfd260 -r f922980f06b1 src/core/ngx_resolver.c
--- a/src/core/ngx_resolver.c	Mon Jan 17 17:05:12 2022 +0300
+++ b/src/core/ngx_resolver.c	Wed Jan 19 08:12:51 2022 +0100
@@ -113,7 +113,7 @@
 static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
 static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
 static ngx_resolver_addr_t *ngx_resolver_export(ngx_resolver_t *r,
-    ngx_resolver_node_t *rn, ngx_uint_t rotate);
+    ngx_resolver_node_t *rn, ngx_uint_t rotate, sa_family_t af, ngx_uint_t *na);
 static void ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx);
 static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len);
 static void ngx_resolver_resolve_srv_names(ngx_resolver_ctx_t *ctx,
@@ -580,6 +580,7 @@
     ngx_str_t *name)
 {
     uint32_t              hash;
+    sa_family_t           sa;
     ngx_int_t             rc;
     ngx_str_t             cname;
     ngx_uint_t            i, naddrs;
@@ -634,7 +635,15 @@
                     addrs = NULL;
 
                 } else {
-                    addrs = ngx_resolver_export(r, rn, 1);
+                    sa = AF_UNSPEC;
+#if (NGX_HAVE_INET6)
+                    if (ctx->avoid_ipv4 && rn->naddrs6) {
+                        sa = AF_INET6;
+                    } else if (ctx->avoid_ipv6 && rn->naddrs) {
+                        sa = AF_INET;
+                    }
+#endif
+                    addrs = ngx_resolver_export(r, rn, 1, sa, &naddrs);
                     if (addrs == NULL) {
                         return NGX_ERROR;
                     }
@@ -2403,7 +2412,7 @@
             addrs = NULL;
 
         } else {
-            addrs = ngx_resolver_export(r, rn, 0);
+            addrs = ngx_resolver_export(r, rn, 0, AF_UNSPEC, &naddrs);
             if (addrs == NULL) {
                 goto failed;
             }
@@ -2425,7 +2434,7 @@
             ctx = next;
             ctx->state = NGX_OK;
             ctx->valid = rn->valid;
-            ctx->naddrs = naddrs;
+            ctx->naddrs = (ctx->avoid_ipv6 && rn->naddrs) ? rn->naddrs : naddrs;
 
             if (addrs == NULL) {
                 ctx->addrs = &ctx->addr;
@@ -2437,6 +2446,12 @@
 
             } else {
                 ctx->addrs = addrs;
+#if (NGX_HAVE_INET6)
+                if (ctx->avoid_ipv4 && rn->naddrs6) {
+                    ctx->addrs = addrs + rn->naddrs;
+                    ctx->naddrs = rn->naddrs6;
+                }
+#endif
             }
 
             next = ctx->next;
@@ -4183,7 +4198,7 @@
 
 static ngx_resolver_addr_t *
 ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn,
-    ngx_uint_t rotate)
+    ngx_uint_t rotate, sa_family_t af, ngx_uint_t *na)
 {
     ngx_uint_t            d, i, j, n;
     in_addr_t            *addr;
@@ -4197,7 +4212,11 @@
 
     n = rn->naddrs;
 #if (NGX_HAVE_INET6)
-    n += rn->naddrs6;
+    if (af == AF_INET6) {
+        n = rn->naddrs6;
+    } else if (af != AF_INET) {
+        n += rn->naddrs6;
+    }
 #endif
 
     dst = ngx_resolver_calloc(r, n * sizeof(ngx_resolver_addr_t));
@@ -4214,7 +4233,11 @@
     i = 0;
     d = rotate ? ngx_random() % n : 0;
 
-    if (rn->naddrs) {
+    if (rn->naddrs
+#if (NGX_HAVE_INET6)
+            && af != AF_INET6
+#endif
+            ) {
         j = rotate ? ngx_random() % rn->naddrs : 0;
 
         addr = (rn->naddrs == 1) ? &rn->u.addr : rn->u.addrs;
@@ -4237,7 +4260,7 @@
     }
 
 #if (NGX_HAVE_INET6)
-    if (rn->naddrs6) {
+    if (rn->naddrs6 && af != AF_INET) {
         j = rotate ? ngx_random() % rn->naddrs6 : 0;
 
         addr6 = (rn->naddrs6 == 1) ? &rn->u6.addr6 : rn->u6.addrs6;
@@ -4260,6 +4283,7 @@
     }
 #endif
 
+    *na = n;
     return dst;
 }
 
diff -r aeab41dfd260 -r f922980f06b1 src/core/ngx_resolver.h
--- a/src/core/ngx_resolver.h	Mon Jan 17 17:05:12 2022 +0300
+++ b/src/core/ngx_resolver.h	Wed Jan 19 08:12:51 2022 +0100
@@ -221,6 +221,8 @@
     unsigned                  quick:1;
     unsigned                  async:1;
     unsigned                  cancelable:1;
+    unsigned                  avoid_ipv4:1;
+    unsigned                  avoid_ipv6:1;
     ngx_uint_t                recursion;
     ngx_event_t              *event;
 };
diff -r aeab41dfd260 -r f922980f06b1 src/http/ngx_http_upstream.c
--- a/src/http/ngx_http_upstream.c	Mon Jan 17 17:05:12 2022 +0300
+++ b/src/http/ngx_http_upstream.c	Wed Jan 19 08:12:51 2022 +0100
@@ -770,6 +770,18 @@
         ctx->handler = ngx_http_upstream_resolve_handler;
         ctx->data = r;
         ctx->timeout = clcf->resolver_timeout;
+#if (NGX_HAVE_INET6)
+        if (u->peer.local) {
+            switch (u->peer.local->sockaddr->sa_family) {
+                case AF_INET:
+                    ctx->avoid_ipv6 = 1;
+                    break;
+                case AF_INET6:
+                    ctx->avoid_ipv4 = 1;
+                    break;
+            }
+        }
+#endif
 
         u->resolved->ctx = ctx;
 
diff -r aeab41dfd260 -r f922980f06b1 src/stream/ngx_stream_proxy_module.c
--- a/src/stream/ngx_stream_proxy_module.c	Mon Jan 17 17:05:12 2022 +0300
+++ b/src/stream/ngx_stream_proxy_module.c	Wed Jan 19 08:12:51 2022 +0100
@@ -547,6 +547,18 @@
         ctx->handler = ngx_stream_proxy_resolve_handler;
         ctx->data = s;
         ctx->timeout = cscf->resolver_timeout;
+#if (NGX_HAVE_INET6)
+        if (u->peer.local) {
+            switch (u->peer.local->sockaddr->sa_family) {
+                case AF_INET:
+                    ctx->avoid_ipv6 = 1;
+                    break;
+                case AF_INET6:
+                    ctx->avoid_ipv4 = 1;
+                    break;
+            }
+        }
+#endif
 
         u->resolved->ctx = ctx;
 



More information about the nginx-devel mailing list