IPv6 support in resolver

ToSHiC toshic.toshic at gmail.com
Wed Jul 10 17:24:03 UTC 2013


commit 8670b164784032b2911b3c34ac31ef52ddba5b60
Author: Anton Kortunov <toshic.toshic at gmail.com>
Date:   Wed Jul 10 19:53:06 2013 +0400

    IPv6 support in resolver for forward requests

    To resolve name into IPv6 address use NGX_RESOLVE_AAAA,
    NGX_RESOLVE_A_AAAA or NGX_RESOLVE_AAAA_A record type instead of
    NGX_RESOLVE_A

diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index d59d0c4..567368b 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -76,7 +76,7 @@ static void ngx_resolver_process_ptr(ngx_resolver_t *r,
u_char *buf, size_t n,
 static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
     ngx_str_t *name, uint32_t hash);
 static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r,
-    in_addr_t addr);
+    ngx_ipaddr_t addr, uint32_t hash);
 static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
 static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name,
@@ -88,7 +88,7 @@ static void *ngx_resolver_calloc(ngx_resolver_t *r,
size_t size);
 static void ngx_resolver_free(ngx_resolver_t *r, void *p);
 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 in_addr_t *ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src,
+static ngx_ipaddr_t *ngx_resolver_rotate(ngx_resolver_t *r, ngx_ipaddr_t
*src,
     ngx_uint_t n);
 static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t
len);

@@ -270,13 +270,27 @@ ngx_resolver_cleanup_tree(ngx_resolver_t *r,
ngx_rbtree_t *tree)
 ngx_resolver_ctx_t *
 ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
 {
-    in_addr_t            addr;
+    ngx_ipaddr_t         addr;
     ngx_resolver_ctx_t  *ctx;

     if (temp) {
-        addr = ngx_inet_addr(temp->name.data, temp->name.len);
+        addr.family = 0;

-        if (addr != INADDR_NONE) {
+
+        addr.u.v4 = ngx_inet_addr(temp->name.data, temp->name.len);
+
+        if (addr.u.v4 != INADDR_NONE) {
+
+            addr.family = AF_INET;
+
+#if (NGX_HAVE_INET6)
+        } else if (ngx_inet6_addr(temp->name.data, temp->name.len,
addr.u.v6.s6_addr) == NGX_OK) {
+
+            addr.family = AF_INET6;
+#endif
+        }
+
+        if (addr.family) {
             temp->resolver = r;
             temp->state = NGX_OK;
             temp->naddrs = 1;
@@ -417,7 +431,7 @@ static ngx_int_t
 ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
 {
     uint32_t              hash;
-    in_addr_t             addr, *addrs;
+    ngx_ipaddr_t          addr, *addrs;
     ngx_int_t             rc;
     ngx_uint_t            naddrs;
     ngx_resolver_ctx_t   *next;
@@ -429,7 +443,11 @@ ngx_resolve_name_locked(ngx_resolver_t *r,
ngx_resolver_ctx_t *ctx)

     if (rn) {

-        if (rn->valid >= ngx_time()) {
+        if (rn->valid >= ngx_time()
+#if (NGX_HAVE_INET6)
+ && rn->qtype != NGX_RESOLVE_RETRY
+#endif
+                                    ) {

             ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve
cached");

@@ -446,7 +464,6 @@ ngx_resolve_name_locked(ngx_resolver_t *r,
ngx_resolver_ctx_t *ctx)
                 /* NGX_RESOLVE_A answer */

                 if (naddrs != 1) {
-                    addr = 0;
                     addrs = ngx_resolver_rotate(r, rn->u.addrs, naddrs);
                     if (addrs == NULL) {
                         return NGX_ERROR;
@@ -506,6 +523,8 @@ ngx_resolve_name_locked(ngx_resolver_t *r,
ngx_resolver_ctx_t *ctx)
             } while (ctx);

             return NGX_OK;
+        } else {
+            rn->qtype = ctx->type;
         }

         if (rn->waiting) {
@@ -552,6 +571,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r,
ngx_resolver_ctx_t *ctx)
         rn->node.key = hash;
         rn->nlen = (u_short) ctx->name.len;
         rn->query = NULL;
+        rn->qtype = ctx->type;

         ngx_rbtree_insert(&r->name_rbtree, &rn->node);
     }
@@ -1130,6 +1150,9 @@ found:
     switch (qtype) {

     case NGX_RESOLVE_A:
+#if (NGX_HAVE_INET6)
+    case NGX_RESOLVE_AAAA:
+#endif

         ngx_resolver_process_a(r, buf, n, ident, code, nan,
                                i + sizeof(ngx_resolver_qs_t));
@@ -1178,7 +1201,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
*buf, size_t last,
     size_t                len;
     int32_t               ttl;
     uint32_t              hash;
-    in_addr_t             addr, *addrs;
+    ngx_ipaddr_t          addr, *addrs;
     ngx_str_t             name;
     ngx_uint_t            qtype, qident, naddrs, a, i, n, start;
     ngx_resolver_an_t    *an;
@@ -1212,12 +1235,57 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
*buf, size_t last,
         goto failed;
     }

-    ngx_resolver_free(r, name.data);
-
     if (code == 0 && nan == 0) {
+
+#if (NGX_HAVE_INET6)
+       /*
+     * If it was required dual type v4|v6 resolv create one more request
+     */
+       if (rn->qtype == NGX_RESOLVE_A_AAAA
+               || rn->qtype == NGX_RESOLVE_AAAA_A) {
+
+            ngx_queue_remove(&rn->queue);
+
+            rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
+            rn->expire = ngx_time() + r->expire;
+
+            ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
+
+            ctx = rn->waiting;
+            rn->waiting = NULL;
+
+            if (ctx) {
+                ctx->name = name;
+
+                switch (rn->qtype) {
+
+                case NGX_RESOLVE_A_AAAA:
+                    ctx->type = NGX_RESOLVE_AAAA;
+                    break;
+
+                case NGX_RESOLVE_AAAA_A:
+                    ctx->type = NGX_RESOLVE_A;
+                    break;
+                }
+
+                ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
+                              "restarting request for name %V, with type
%ud",
+                              &name, ctx->type);
+
+                rn->qtype = NGX_RESOLVE_RETRY;
+
+                (void) ngx_resolve_name_locked(r, ctx);
+            }
+
+            return;
+        }
+#endif
+
         code = 3; /* NXDOMAIN */
     }

+    ngx_resolver_free(r, name.data);
+
     if (code) {
         next = rn->waiting;
         rn->waiting = NULL;
@@ -1243,7 +1311,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
*buf, size_t last,

     i = ans;
     naddrs = 0;
-    addr = 0;
+    addr.family = 0;
     addrs = NULL;
     cname = NULL;
     qtype = 0;
@@ -1302,13 +1370,30 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
*buf, size_t last,
                 goto short_response;
             }

-            addr = htonl((buf[i] << 24) + (buf[i + 1] << 16)
+            addr.family = AF_INET;
+            addr.u.v4 = htonl((buf[i] << 24) + (buf[i + 1] << 16)
                          + (buf[i + 2] << 8) + (buf[i + 3]));

             naddrs++;

             i += len;

+#if (NGX_HAVE_INET6)
+        } else if (qtype == NGX_RESOLVE_AAAA) {
+
+            i += sizeof(ngx_resolver_an_t);
+
+            if (i + len > last) {
+                goto short_response;
+            }
+
+            addr.family = AF_INET6;
+            ngx_memcpy(&addr.u.v6.s6_addr, &buf[i], 16);
+
+            naddrs++;
+
+            i += len;
+#endif
         } else if (qtype == NGX_RESOLVE_CNAME) {
             cname = &buf[i] + sizeof(ngx_resolver_an_t);
             i += sizeof(ngx_resolver_an_t) + len;
@@ -1333,7 +1418,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
*buf, size_t last,

         } else {

-            addrs = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
+            addrs = ngx_resolver_alloc(r, naddrs * sizeof(ngx_ipaddr_t));
             if (addrs == NULL) {
                 return;
             }
@@ -1369,12 +1454,23 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
*buf, size_t last,

                 if (qtype == NGX_RESOLVE_A) {

-                    addrs[n++] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
+                    addrs[n].family = AF_INET;
+                    addrs[n++].u.v4 = htonl((buf[i] << 24) + (buf[i + 1]
<< 16)
                                        + (buf[i + 2] << 8) + (buf[i + 3]));

                     if (n == naddrs) {
                         break;
                     }
+#if (NGX_HAVE_INET6)
+                } else if (qtype == NGX_RESOLVE_AAAA) {
+
+                    addrs[n].family = AF_INET6;
+                    ngx_memcpy(&addrs[n++].u.v6.s6_addr, &buf[i], 16);
+
+                    if (n == naddrs) {
+                        break;
+                    }
+#endif
                 }

                 i += len;
@@ -1383,7 +1479,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
*buf, size_t last,
             rn->u.addrs = addrs;

             addrs = ngx_resolver_dup(r, rn->u.addrs,
-                                     naddrs * sizeof(in_addr_t));
+                                     naddrs * sizeof(ngx_ipaddr_t));
             if (addrs == NULL) {
                 return;
             }
@@ -1838,7 +1934,20 @@ ngx_resolver_create_name_query(ngx_resolver_node_t
*rn, ngx_resolver_ctx_t *ctx)
     qs = (ngx_resolver_qs_t *) p;

     /* query type */
-    qs->type_hi = 0; qs->type_lo = (u_char) ctx->type;
+    qs->type_hi = 0; qs->type_lo = (u_char) rn->qtype;
+
+#if (NGX_HAVE_INET6)
+    switch (rn->qtype) {
+
+    case NGX_RESOLVE_A_AAAA:
+        qs->type_lo = NGX_RESOLVE_A;
+        break;
+
+    case NGX_RESOLVE_AAAA_A:
+        qs->type_lo = NGX_RESOLVE_AAAA;
+        break;
+    }
+#endif

     /* IP query class */
     qs->class_hi = 0; qs->class_lo = 1;
@@ -2136,13 +2245,13 @@ ngx_resolver_dup(ngx_resolver_t *r, void *src,
size_t size)
 }


-static in_addr_t *
-ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src, ngx_uint_t n)
+static ngx_ipaddr_t *
+ngx_resolver_rotate(ngx_resolver_t *r, ngx_ipaddr_t *src, ngx_uint_t n)
 {
     void        *dst, *p;
     ngx_uint_t   j;

-    dst = ngx_resolver_alloc(r, n * sizeof(in_addr_t));
+    dst = ngx_resolver_alloc(r, n * sizeof(ngx_ipaddr_t));

     if (dst == NULL) {
         return dst;
@@ -2151,12 +2260,12 @@ ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t
*src, ngx_uint_t n)
     j = ngx_random() % n;

     if (j == 0) {
-        ngx_memcpy(dst, src, n * sizeof(in_addr_t));
+        ngx_memcpy(dst, src, n * sizeof(ngx_ipaddr_t));
         return dst;
     }

-    p = ngx_cpymem(dst, &src[j], (n - j) * sizeof(in_addr_t));
-    ngx_memcpy(p, src, j * sizeof(in_addr_t));
+    p = ngx_cpymem(dst, &src[j], (n - j) * sizeof(ngx_ipaddr_t));
+    ngx_memcpy(p, src, j * sizeof(ngx_ipaddr_t));

     return dst;
 }
diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h
index 6fd81fe..d2a4606 100644
--- a/src/core/ngx_resolver.h
+++ b/src/core/ngx_resolver.h
@@ -67,10 +67,11 @@ typedef struct {
     u_short                   qlen;

     u_char                   *query;
+    ngx_int_t                 qtype;

     union {
-        in_addr_t             addr;
-        in_addr_t            *addrs;
+        ngx_ipaddr_t          addr;
+        ngx_ipaddr_t         *addrs;
         u_char               *cname;
     } u;

@@ -130,8 +131,8 @@ struct ngx_resolver_ctx_s {
     ngx_str_t                 name;

     ngx_uint_t                naddrs;
-    in_addr_t                *addrs;
-    in_addr_t                 addr;
+    ngx_ipaddr_t             *addrs;
+    ngx_ipaddr_t              addr;

     ngx_resolver_handler_pt   handler;
     void                     *data;



On Wed, Jul 10, 2013 at 9:17 PM, ToSHiC <toshic.toshic at gmail.com> wrote:

> commit 482bd2a0b6240a2b26409b9c7924ad01c814f293
> Author: Anton Kortunov <toshic.toshic at gmail.com>
> Date:   Wed Jul 10 13:21:27 2013 +0400
>
>     Added NGX_RESOLVE_* constants
>
>     Module developers can decide how to resolve hosts relating to IPv6:
>
>     NGX_RESOLVE_AAAA - try to resolve only to IPv6 address
>     NGX_RESOLVE_AAAA_A - IPv6 is preferred (recommended by standards)
>     NGX_RESOLVE_A_AAAA - IPv4 is preferred (better strategy nowadays)
>
> diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h
> index ae34ca5..6fd81fe 100644
> --- a/src/core/ngx_resolver.h
> +++ b/src/core/ngx_resolver.h
> @@ -20,6 +20,15 @@
>  #define NGX_RESOLVE_TXT       16
>  #define NGX_RESOLVE_DNAME     39
>
> +#if (NGX_HAVE_INET6)
> +
> +#define NGX_RESOLVE_AAAA      28
> +#define NGX_RESOLVE_A_AAAA    1000
> +#define NGX_RESOLVE_AAAA_A    1001
> +#define NGX_RESOLVE_RETRY     1002
> +
> +#endif
> +
>  #define NGX_RESOLVE_FORMERR   1
>  #define NGX_RESOLVE_SERVFAIL  2
>  #define NGX_RESOLVE_NXDOMAIN  3
>
>
>
> On Wed, Jul 10, 2013 at 9:17 PM, ToSHiC <toshic.toshic at gmail.com> wrote:
>
>> Hello,
>>
>> I've split this big patch into several small patches, taking into account
>> your comments. I'll send each part in separate email. Here is the first one.
>>
>> commit 597d09e7ae9247c5466b18aa2ef3f5892e61b708
>> Author: Anton Kortunov <toshic.toshic at gmail.com>
>> Date:   Wed Jul 10 13:14:52 2013 +0400
>>
>>     Added new structure ngx_ipaddr_t
>>
>>     This structure contains family field
>>     and the union of ipv4/ipv6 structures in_addr_t and in6_addr.
>>
>> diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h
>> index 6a5a368..077ed34 100644
>> --- a/src/core/ngx_inet.h
>> +++ b/src/core/ngx_inet.h
>> @@ -68,6 +68,16 @@ typedef struct {
>>
>>
>>  typedef struct {
>> +    ngx_uint_t                family;
>> +    union {
>> +        in_addr_t             v4;
>> +#if (NGX_HAVE_INET6)
>> +        struct in6_addr       v6;
>> +#endif
>> +    } u;
>> +} ngx_ipaddr_t;
>> +
>> +typedef struct {
>>      struct sockaddr          *sockaddr;
>>      socklen_t                 socklen;
>>      ngx_str_t                 name;
>>
>>
>>
>> On Mon, Jun 17, 2013 at 7:30 PM, Maxim Dounin <mdounin at mdounin.ru> wrote:
>>
>>> Hello!
>>>
>>> On Fri, Jun 14, 2013 at 09:44:46PM +0400, ToSHiC wrote:
>>>
>>> > Hello,
>>> >
>>> > We needed this feature in our company, I found that it is in
>>> milestones of
>>> > version 1.5 but doesn't exist yet. So I've implemented it based in 1.3
>>> code
>>> > and merged in current 1.5 code. When I wrote this code I mostly cared
>>> about
>>> > minimum intrusion into other parts of nginx.
>>> >
>>> > IPv6 fallback logic is not a straightforward implementation of
>>> suggested by
>>> > RFC. RFC states that IPv6 resolving have priority over IPv4, and it's
>>> not
>>> > very good for Internet we have currently. With this patch you can
>>> specify
>>> > priority, and in upstream and mail modules I've set IPv4 as preferred
>>> > address family.
>>> >
>>> > Patch is pretty big and I hope it'll not break mailing list or mail
>>> clients.
>>>
>>> You may want to try to split the patch into smaller patches to
>>> simplify review.  See also some hints here:
>>>
>>> http://nginx.org/en/docs/contributing_changes.html
>>>
>>> Some quick comments below.
>>>
>>> [...]
>>>
>>> > -        addr = ntohl(ctx->addr);
>>> > +failed:
>>> > +
>>> > +        //addr = ntohl(ctx->addr);
>>> > +        inet_ntop(ctx->addr.family, &ctx->addr.u, text,
>>> > NGX_SOCKADDR_STRLEN);
>>> >
>>> >          ngx_log_error(NGX_LOG_ALERT, r->log, 0,
>>> > -                      "could not cancel %ud.%ud.%ud.%ud resolving",
>>> > -                      (addr >> 24) & 0xff, (addr >> 16) & 0xff,
>>> > -                      (addr >> 8) & 0xff, addr & 0xff);
>>> > +                      "could not cancel %s resolving", text);
>>>
>>> 1. Don't use inet_ntop(), there is ngx_sock_ntop() instead.
>>>
>>> 2. Don't use C++ style ("//") comments.
>>>
>>> 3. If some data is only needed for debug logging, keep relevant
>>> calculations under #if (NGX_DEBUG).
>>>
>>> [...]
>>>
>>> > @@ -334,6 +362,7 @@
>>> > ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
>>> >              peers->peer[i].current_weight = 0;
>>> >              peers->peer[i].max_fails = 1;
>>> >              peers->peer[i].fail_timeout = 10;
>>> > +
>>> >          }
>>> >      }
>>> >
>>>
>>> Please avoid unrelated changes.
>>>
>>> [...]
>>>
>>> --
>>> Maxim Dounin
>>> http://nginx.org/en/donation.html
>>>
>>> _______________________________________________
>>> nginx-devel mailing list
>>> nginx-devel at nginx.org
>>> http://mailman.nginx.org/mailman/listinfo/nginx-devel
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20130710/6ea6da6c/attachment-0001.html>


More information about the nginx-devel mailing list