IPv6 support in resolver

ToSHiC toshic.toshic at gmail.com
Fri Jun 14 17:44:46 UTC 2013


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.

>From b98c8cd3bd0bca9df88a8d6d660015a502b9727c Mon Sep 17 00:00:00 2001
From: Anton Kortunov <toshic.toshic at gmail.com>
Date: Fri, 14 Jun 2013 20:38:41 +0400
Subject: [PATCH] IPv6 resolver

---
 src/core/ngx_inet.h                      |   10 +
 src/core/ngx_resolver.c                  |  436
+++++++++++++++++++++++++-----
 src/core/ngx_resolver.h                  |   23 ++-
 src/http/ngx_http_upstream.c             |   16 +-
 src/http/ngx_http_upstream.h             |    2 +-
 src/http/ngx_http_upstream_round_robin.c |   49 +++-
 src/mail/ngx_mail_smtp_handler.c         |   95 ++++++--
 7 files changed, 524 insertions(+), 107 deletions(-)

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;
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index d59d0c4..5953b9c 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -71,12 +71,12 @@ static void
ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf,
     size_t n);
 static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t
n,
     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans);
-static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf,
size_t n,
+void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan);
 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);
     }
@@ -629,17 +649,40 @@ failed:
 ngx_int_t
 ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
 {
+    uint32_t              hash;
     u_char               *name;
     ngx_resolver_t       *r;
     ngx_resolver_node_t  *rn;

     r = ctx->resolver;
+    rn = NULL;
+
+    hash = ctx->addr.family;

-    ctx->addr = ntohl(ctx->addr);
+    switch(ctx->addr.family) {
+
+    case AF_INET:
+        ctx->addr.u.v4 = ntohl(ctx->addr.u.v4);
+        ngx_crc32_update(&hash, (u_char *)&ctx->addr.u.v4,
sizeof(in_addr_t));
+ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
+               "resolve addr hash: %xd, addr:%xd, family: %d", hash,
ctx->addr.u.v4, ctx->addr.family);
+        break;
+
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+        ngx_crc32_update(&hash, (u_char *)&ctx->addr.u.v6, sizeof(struct
in6_addr));
+        break;
+#endif
+
+    default:
+        goto failed;
+    }

     /* lock addr mutex */

-    rn = ngx_resolver_lookup_addr(r, ctx->addr);
+    rn = ngx_resolver_lookup_addr(r, ctx->addr, hash);
+    ngx_log_error(r->log_level, r->log, 0,
+                  "resolve: in resolve_addr searching, hash = %xd, rn =
%p", hash, rn);

     if (rn) {

@@ -694,8 +737,10 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
             goto failed;
         }

-        rn->node.key = ctx->addr;
+        rn->node.key = hash;
         rn->query = NULL;
+        rn->qtype = ctx->type;
+        rn->u.addr = ctx->addr;

         ngx_rbtree_insert(&r->addr_rbtree, &rn->node);
     }
@@ -768,10 +813,11 @@ failed:
 void
 ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
 {
-    in_addr_t             addr;
+    uint32_t              hash;
     ngx_resolver_t       *r;
     ngx_resolver_ctx_t   *w, **p;
     ngx_resolver_node_t  *rn;
+    char                  text[NGX_SOCKADDR_STRLEN];

     r = ctx->resolver;

@@ -786,7 +832,25 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)

     if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {

-        rn = ngx_resolver_lookup_addr(r, ctx->addr);
+        hash = ctx->addr.family;
+
+        switch(ctx->addr.family) {
+
+        case AF_INET:
+            ngx_crc32_update(&hash, (u_char *)&ctx->addr.u.v4,
sizeof(in_addr_t));
+            break;
+
+#if (NGX_HAVE_INET6)
+        case AF_INET6:
+            ngx_crc32_update(&hash, (u_char *)&ctx->addr.u.v6,
sizeof(struct in6_addr));
+            break;
+#endif
+
+        default:
+            goto failed;
+        }
+
+        rn = ngx_resolver_lookup_addr(r, ctx->addr, hash);

         if (rn) {
             p = &rn->waiting;
@@ -804,12 +868,13 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
             }
         }

-        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);
     }

 done:
@@ -1130,6 +1195,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 +1246,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 +1280,55 @@ 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 +1354,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 +1413,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 +1461,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 +1497,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 +1522,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;
             }
@@ -1486,13 +1625,14 @@ failed:
 }


-static void
+void
 ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
     ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan)
 {
-    char                 *err;
+    char                 *err = NULL;
+    uint32_t              hash = 0;
     size_t                len;
-    in_addr_t             addr;
+    ngx_ipaddr_t          addr;
     int32_t               ttl;
     ngx_int_t             digit;
     ngx_str_t             name;
@@ -1500,12 +1640,16 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char
*buf, size_t n,
     ngx_resolver_an_t    *an;
     ngx_resolver_ctx_t   *ctx, *next;
     ngx_resolver_node_t  *rn;
+    char                  text[NGX_SOCKADDR_STRLEN];

     if (ngx_resolver_copy(r, NULL, buf, &buf[12], &buf[n]) != NGX_OK) {
         goto invalid_in_addr_arpa;
     }

-    addr = 0;
+    ngx_memzero(&addr, sizeof(ngx_ipaddr_t));
+
+    /* Try to parse request as in-addr.arpa */
+    addr.family = AF_INET;
     i = 12;

     for (mask = 0; mask < 32; mask += 8) {
@@ -1516,7 +1660,7 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char
*buf, size_t n,
             goto invalid_in_addr_arpa;
         }

-        addr += digit << mask;
+        addr.u.v4 += digit << mask;
         i += len;
     }

@@ -1524,15 +1668,79 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char
*buf, size_t n,
         goto invalid_in_addr_arpa;
     }

+    i += sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t);
+
+    goto found;
+
+invalid_in_addr_arpa:
+
+#if (NGX_HAVE_INET6)
+    /* Try to parse request as ip6.arpa */
+    addr.family = AF_INET6;
+    i = 12;
+
+    for (len = 15; len < 16; len--) {
+        if (buf[i++] != 1)
+            goto invalid_arpa;
+
+        digit = ngx_hextoi(&buf[i++], 1);
+        if (digit == NGX_ERROR || digit > 16) {
+            goto invalid_arpa;
+        }
+
+        addr.u.v6.s6_addr[len] = digit;
+
+        if (buf[i++] != 1)
+            goto invalid_arpa;
+
+
+        digit = ngx_hextoi(&buf[i++], 1);
+        if (digit == NGX_ERROR || digit > 16) {
+            goto invalid_arpa;
+        }
+
+        addr.u.v6.s6_addr[len] += digit << 4;
+    }
+
+    if (ngx_strcmp(&buf[i], "\3ip6\4arpa") != 0) {
+        goto invalid_arpa;
+    }
+
+    i += sizeof("\3ip6\4arpa") + sizeof(ngx_resolver_qs_t);
+
+#else /* NGX_HAVE_INET6 */
+    goto invalid_arpa;
+#endif
+
+found:
+
     /* lock addr mutex */

-    rn = ngx_resolver_lookup_addr(r, addr);
+    hash = addr.family;
+
+    switch(addr.family) {
+
+    case AF_INET:
+        ngx_crc32_update(&hash, (u_char *)&addr.u.v4, sizeof(in_addr_t));
+        break;
+
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+        ngx_crc32_update(&hash, (u_char *)&addr.u.v6, sizeof(struct
in6_addr));
+        break;
+#endif
+
+    default:
+        goto invalid;
+    }
+
+    rn = ngx_resolver_lookup_addr(r, addr, hash);
+
+    inet_ntop(addr.family, &addr.u, text, NGX_SOCKADDR_STRLEN);

     if (rn == NULL || rn->query == NULL) {
         ngx_log_error(r->log_level, r->log, 0,
-                      "unexpected response for %ud.%ud.%ud.%ud",
-                      (addr >> 24) & 0xff, (addr >> 16) & 0xff,
-                      (addr >> 8) & 0xff, addr & 0xff);
+                      "unexpected response for %s", text);
         goto failed;
     }

@@ -1540,12 +1748,15 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char
*buf, size_t n,

     if (ident != qident) {
         ngx_log_error(r->log_level, r->log, 0,
-                    "wrong ident %ui response for %ud.%ud.%ud.%ud, expect
%ui",
-                    ident, (addr >> 24) & 0xff, (addr >> 16) & 0xff,
-                    (addr >> 8) & 0xff, addr & 0xff, qident);
+                    "wrong ident %ui response for %s, expect %ui",
+                    ident, text, qident);
         goto failed;
     }

+    ngx_log_error(r->log_level, r->log, 0,
+                "code: %d, nan: %d",
+                code, nan);
+
     if (code == 0 && nan == 0) {
         code = 3; /* NXDOMAIN */
     }
@@ -1573,8 +1784,6 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char
*buf, size_t n,
         return;
     }

-    i += sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t);
-
     if (i + 2 + sizeof(ngx_resolver_an_t) > (ngx_uint_t) n) {
         goto short_response;
     }
@@ -1654,10 +1863,10 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char
*buf, size_t n,

     return;

-invalid_in_addr_arpa:
+invalid_arpa:

     ngx_log_error(r->log_level, r->log, 0,
-                  "invalid in-addr.arpa name in DNS response");
+                  "invalid in-addr.arpa or ip6.arpa name in DNS response");
     return;

 short_response:
@@ -1722,28 +1931,54 @@ 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_resolver_lookup_addr(ngx_resolver_t *r, ngx_ipaddr_t addr, uint32_t
hash)
 {
+    ngx_int_t             rc;
     ngx_rbtree_node_t  *node, *sentinel;
+    ngx_resolver_node_t  *rn;

     node = r->addr_rbtree.root;
     sentinel = r->addr_rbtree.sentinel;

     while (node != sentinel) {

-        if (addr < node->key) {
+        if (hash < node->key) {
             node = node->left;
             continue;
         }

-        if (addr > node->key) {
+        if (hash > node->key) {
             node = node->right;
             continue;
         }

-        /* addr == node->key */
+        /* hash == node->key */
+
+        rn = (ngx_resolver_node_t *) node;
+
+        rc = addr.family - rn->u.addr.family;
+
+        if (rc == 0) {
+
+            switch (addr.family) {
+            case AF_INET:
+                rc = ngx_memn2cmp((u_char *)&addr.u.v4, (u_char
*)&rn->u.addr.u.v4, sizeof(in_addr_t), sizeof(in_addr_t));
+                break;
+
+#if (NGX_HAVE_INET6)
+            case AF_INET6:
+                rc = ngx_memn2cmp((u_char *)&addr.u.v6, (u_char
*)&rn->u.addr.u.v6, sizeof(struct in6_addr), sizeof(struct in6_addr));
+                break;
+#endif
+            }
+
+            if (rc == 0) {
+                return rn;
+            }
+
+        }

-        return (ngx_resolver_node_t *) node;
+        node = (rc < 0) ? node->left : node->right;
     }

     /* not found */
@@ -1758,6 +1993,7 @@ ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t
*temp,
 {
     ngx_rbtree_node_t    **p;
     ngx_resolver_node_t   *rn, *rn_temp;
+    ngx_int_t              rc;

     for ( ;; ) {

@@ -1774,8 +2010,29 @@ ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t
*temp,
             rn = (ngx_resolver_node_t *) node;
             rn_temp = (ngx_resolver_node_t *) temp;

-            p = (ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen,
rn_temp->nlen)
-                 < 0) ? &temp->left : &temp->right;
+            if (rn->qtype == NGX_RESOLVE_PTR) {
+                rc = rn->u.addr.family - rn_temp->u.addr.family;
+
+                if (rc == 0) {
+
+                    switch (rn->u.addr.family) {
+                    case AF_INET:
+                        rc = ngx_memn2cmp((u_char *)&rn->u.addr.u.v4,
(u_char *)&rn_temp->u.addr.u.v4, sizeof(in_addr_t), sizeof(in_addr_t));
+                        break;
+
+        #if (NGX_HAVE_INET6)
+                    case AF_INET6:
+                        rc = ngx_memn2cmp((u_char *)&rn->u.addr.u.v6,
(u_char *)&rn_temp->u.addr.u.v6, sizeof(struct in6_addr), sizeof(struct
in6_addr));
+                        break;
+        #endif
+                    }
+                }
+
+            } else {
+                rc = ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen,
rn_temp->nlen);
+            }
+
+            p = (rc < 0) ? &temp->left : &temp->right;
         }

         if (*p == sentinel) {
@@ -1838,7 +2095,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;
@@ -1880,8 +2150,6 @@ ngx_resolver_create_name_query(ngx_resolver_node_t
*rn, ngx_resolver_ctx_t *ctx)
 }


-/* AF_INET only */
-
 static ngx_int_t
 ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t
*ctx)
 {
@@ -1892,7 +2160,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t
*rn, ngx_resolver_ctx_t *ctx)
     ngx_resolver_query_t  *query;

     len = sizeof(ngx_resolver_query_t)
-          + sizeof(".255.255.255.255.in-addr.arpa.") - 1
+          + NGX_PTR_QUERY_LEN
           + sizeof(ngx_resolver_qs_t);

     p = ngx_resolver_alloc(ctx->resolver, len);
@@ -1919,18 +2187,50 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t
*rn, ngx_resolver_ctx_t *ctx)

     p += sizeof(ngx_resolver_query_t);

-    for (n = 0; n < 32; n += 8) {
-        d = ngx_sprintf(&p[1], "%ud", (ctx->addr >> n) & 0xff);
-        *p = (u_char) (d - &p[1]);
-        p = d;
+    switch (ctx->addr.family) {
+
+    case AF_INET:
+        for (n = 0; n < 32; n += 8) {
+            d = ngx_sprintf(&p[1], "%ud", (ctx->addr.u.v4 >> n) & 0xff);
+            *p = (u_char) (d - &p[1]);
+            p = d;
+        }
+
+        /* query type "PTR", IP query class */
+        ngx_memcpy(p, "\7in-addr\4arpa\0\0\14\0\1", 18);
+
+        rn->qlen = (u_short)
+                      (p + sizeof("\7in-addr\4arpa") +
sizeof(ngx_resolver_qs_t)
+                       - rn->query);
+
+        break;
+
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+        for (n = 15; n >= 0; n--) {
+            p = ngx_sprintf(p, "\1%xd\1%xd",
+                            (ctx->addr.u.v6.s6_addr[n]) & 0xf,
+                            (ctx->addr.u.v6.s6_addr[n] >> 4) & 0xf);
+
+        }
+
+        /* query type "PTR", IP query class */
+        ngx_memcpy(p, "\3ip6\4arpa\0\0\14\0\1", 18);
+
+        rn->qlen = (u_short)
+                      (p + sizeof("\3ip6\4arpa") +
sizeof(ngx_resolver_qs_t)
+                       - rn->query);
+
+        break;
+#endif
+
+    default:
+        return NGX_ERROR;
     }

-    /* query type "PTR", IP query class */
-    ngx_memcpy(p, "\7in-addr\4arpa\0\0\14\0\1", 18);
+ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
+               "resolve: query %s, ident %i", (rn->query+12), ident &
0xffff);

-    rn->qlen = (u_short)
-                  (p + sizeof("\7in-addr\4arpa") +
sizeof(ngx_resolver_qs_t)
-                   - rn->query);

     return NGX_OK;
 }
@@ -2136,13 +2436,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 +2451,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 ae34ca5..a45b244 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
@@ -32,6 +41,11 @@

 #define NGX_RESOLVER_MAX_RECURSION    50

+#if (NGX_HAVE_INET6)
+#define NGX_PTR_QUERY_LEN
(sizeof(".f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.f.ip6.arpa.")
- 1)
+#else
+#define NGX_PTR_QUERY_LEN   (sizeof(".255.255.255.255.in-addr.arpa.") - 1)
+#endif

 typedef struct {
     ngx_connection_t         *connection;
@@ -58,10 +72,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;

@@ -121,8 +136,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;
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index 16e6602..7a8035c 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -638,7 +638,11 @@ ngx_http_upstream_init_request(ngx_http_request_t *r)
         }

         ctx->name = *host;
+#if (NGX_HAVE_INET6)
+        ctx->type = NGX_RESOLVE_A_AAAA;
+#else
         ctx->type = NGX_RESOLVE_A;
+#endif
         ctx->handler = ngx_http_upstream_resolve_handler;
         ctx->data = r;
         ctx->timeout = clcf->resolver_timeout;
@@ -912,16 +916,14 @@ ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t
*ctx)

 #if (NGX_DEBUG)
     {
-    in_addr_t   addr;
+    char        text[NGX_SOCKADDR_STRLEN];
     ngx_uint_t  i;

-    for (i = 0; i < ctx->naddrs; i++) {
-        addr = ntohl(ur->addrs[i]);
+    for (i = 0; i < ur->naddrs; i++) {
+        inet_ntop(ur->addrs[i].family, &ur->addrs[i].u, text,
NGX_SOCKADDR_STRLEN);

-        ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "name was resolved to %ud.%ud.%ud.%ud",
-                       (addr >> 24) & 0xff, (addr >> 16) & 0xff,
-                       (addr >> 8) & 0xff, addr & 0xff);
+        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "name was resolved to %s", text);
     }
     }
 #endif
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index fd4e36b..9e88a9a 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -254,7 +254,7 @@ typedef struct {
     ngx_uint_t                       no_port; /* unsigned no_port:1 */

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

     struct sockaddr                 *sockaddr;
     socklen_t                        socklen;
diff --git a/src/http/ngx_http_upstream_round_robin.c
b/src/http/ngx_http_upstream_round_robin.c
index e0c6c58..92fa825 100644
--- a/src/http/ngx_http_upstream_round_robin.c
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -268,6 +268,9 @@
ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
     size_t                             len;
     ngx_uint_t                         i, n;
     struct sockaddr_in                *sin;
+#if (NGX_HAVE_INET6)
+    struct sockaddr_in6               *sin6;
+#endif
     ngx_http_upstream_rr_peers_t      *peers;
     ngx_http_upstream_rr_peer_data_t  *rrp;

@@ -306,27 +309,52 @@
ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,

         for (i = 0; i < ur->naddrs; i++) {

-            len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;
+            len = NGX_SOCKADDR_STRLEN;

             p = ngx_pnalloc(r->pool, len);
             if (p == NULL) {
                 return NGX_ERROR;
             }

-            len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p,
NGX_INET_ADDRSTRLEN);
+            len = ngx_inet_ntop(ur->addrs[i].family, &ur->addrs[i].u, p,
NGX_SOCKADDR_STRLEN - sizeof(":65535") + 1);
             len = ngx_sprintf(&p[len], ":%d", ur->port) - p;

-            sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));
-            if (sin == NULL) {
+            switch (ur->addrs[i].family) {
+
+            case AF_INET:
+                sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));
+                if (sin == NULL) {
+                    return NGX_ERROR;
+                }
+
+                sin->sin_family = AF_INET;
+                sin->sin_port = htons(ur->port);
+                sin->sin_addr.s_addr = ur->addrs[i].u.v4;
+
+                peers->peer[i].sockaddr = (struct sockaddr *) sin;
+                peers->peer[i].socklen = sizeof(struct sockaddr_in);
+                break;
+
+#if (NGX_HAVE_INET6)
+            case AF_INET6:
+                sin6 = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in6));
+                if (sin6 == NULL) {
+                    return NGX_ERROR;
+                }
+
+                sin6->sin6_family = AF_INET6;
+                sin6->sin6_port = htons(ur->port);
+                sin6->sin6_addr = ur->addrs[i].u.v6;
+
+                peers->peer[i].sockaddr = (struct sockaddr *) sin6;
+                peers->peer[i].socklen = sizeof(struct sockaddr_in6);
+                break;
+#endif
+
+            default:
                 return NGX_ERROR;
             }

-            sin->sin_family = AF_INET;
-            sin->sin_port = htons(ur->port);
-            sin->sin_addr.s_addr = ur->addrs[i];
-
-            peers->peer[i].sockaddr = (struct sockaddr *) sin;
-            peers->peer[i].socklen = sizeof(struct sockaddr_in);
             peers->peer[i].name.len = len;
             peers->peer[i].name.data = p;
             peers->peer[i].weight = 1;
@@ -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;
+
         }
     }

diff --git a/src/mail/ngx_mail_smtp_handler.c
b/src/mail/ngx_mail_smtp_handler.c
index 2171423..668424e 100644
--- a/src/mail/ngx_mail_smtp_handler.c
+++ b/src/mail/ngx_mail_smtp_handler.c
@@ -56,6 +56,9 @@ void
 ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
 {
     struct sockaddr_in        *sin;
+#if (NGX_HAVE_INET6)
+    struct sockaddr_in6       *sin6;
+#endif
     ngx_resolver_ctx_t        *ctx;
     ngx_mail_core_srv_conf_t  *cscf;

@@ -67,7 +70,11 @@ ngx_mail_smtp_init_session(ngx_mail_session_t *s,
ngx_connection_t *c)
         return;
     }

-    if (c->sockaddr->sa_family != AF_INET) {
+    if (c->sockaddr->sa_family != AF_INET
+#if (NGX_HAVE_INET6)
+        && c->sockaddr->sa_family != AF_INET6
+#endif
+                                        ) {
         s->host = smtp_tempunavail;
         ngx_mail_smtp_greeting(s, c);
         return;
@@ -81,11 +88,23 @@ ngx_mail_smtp_init_session(ngx_mail_session_t *s,
ngx_connection_t *c)
         return;
     }

-    /* AF_INET only */
+    ctx->addr.family = c->sockaddr->sa_family;

-    sin = (struct sockaddr_in *) c->sockaddr;
+    switch (c->sockaddr->sa_family) {
+
+    case AF_INET:
+        sin = (struct sockaddr_in *) c->sockaddr;
+        ctx->addr.u.v4 = sin->sin_addr.s_addr;
+        break;
+
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+        sin6 = (struct sockaddr_in6 *) c->sockaddr;
+        ctx->addr.u.v6 = sin6->sin6_addr;
+        break;
+#endif
+    }

-    ctx->addr = sin->sin_addr.s_addr;
     ctx->handler = ngx_mail_smtp_resolve_addr_handler;
     ctx->data = s;
     ctx->timeout = cscf->resolver_timeout;
@@ -167,11 +186,23 @@ ngx_mail_smtp_resolve_name(ngx_event_t *rev)
     }

     ctx->name = s->host;
-    ctx->type = NGX_RESOLVE_A;
     ctx->handler = ngx_mail_smtp_resolve_name_handler;
     ctx->data = s;
     ctx->timeout = cscf->resolver_timeout;

+    switch (c->sockaddr->sa_family) {
+
+    case AF_INET:
+        ctx->type = NGX_RESOLVE_A;
+        break;
+
+#if (NGX_HAVE_INET6)
+    case AF_INET6:
+        ctx->type = NGX_RESOLVE_AAAA_A;
+        break;
+#endif
+    }
+
     if (ngx_resolve_name(ctx) != NGX_OK) {
         ngx_mail_close_connection(c);
     }
@@ -181,11 +212,15 @@ ngx_mail_smtp_resolve_name(ngx_event_t *rev)
 static void
 ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx)
 {
-    in_addr_t            addr;
+    ngx_ipaddr_t         addr;
     ngx_uint_t           i;
     ngx_connection_t    *c;
     struct sockaddr_in  *sin;
+#if (NGX_HAVE_INET6)
+    struct sockaddr_in6 *sin6;
+#endif
     ngx_mail_session_t  *s;
+    char                 text[NGX_SOCKADDR_STRLEN];

     s = ctx->data;
     c = s->connection;
@@ -205,23 +240,49 @@ ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t
*ctx)

     } else {

-        /* AF_INET only */
+        addr.family = c->sockaddr->sa_family;

-        sin = (struct sockaddr_in *) c->sockaddr;
+        switch (c->sockaddr->sa_family) {
+
+        case AF_INET:
+            sin = (struct sockaddr_in *) c->sockaddr;
+            addr.u.v4 = sin->sin_addr.s_addr;
+            break;
+
+#if (NGX_HAVE_INET6)
+        case AF_INET6:
+            sin6 = (struct sockaddr_in6 *) c->sockaddr;
+            addr.u.v6 = sin6->sin6_addr;
+            break;
+#endif
+        }

         for (i = 0; i < ctx->naddrs; i++) {

-            addr = ctx->addrs[i];
+            inet_ntop(ctx->addrs[i].family, &ctx->addrs[i].u, text,
NGX_SOCKADDR_STRLEN);

-            ngx_log_debug4(NGX_LOG_DEBUG_MAIL, c->log, 0,
-                           "name was resolved to %ud.%ud.%ud.%ud",
-                           (ntohl(addr) >> 24) & 0xff,
-                           (ntohl(addr) >> 16) & 0xff,
-                           (ntohl(addr) >> 8) & 0xff,
-                           ntohl(addr) & 0xff);
+            ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
+                           "name was resolved to %s", text);

-            if (addr == sin->sin_addr.s_addr) {
-                goto found;
+            if (addr.family != ctx->addrs[i].family) {
+                continue;
+            }
+
+            switch (addr.family) {
+
+            case AF_INET:
+                if (addr.u.v4 == ctx->addrs[i].u.v4) {
+                    goto found;
+                }
+                break;
+
+#if (NGX_HAVE_INET6)
+            case AF_INET6:
+                if (!ngx_memcmp(&addr.u.v6, &ctx->addrs[i].u.v6,
sizeof(addr.u.v6))) {
+                    goto found;
+                }
+                break;
+#endif
             }
         }

-- 
1.7.0.4
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20130614/df3af501/attachment-0001.html>


More information about the nginx-devel mailing list