<div dir="ltr">Hello,<div><br></div><div style>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.</div>
<div style><br></div><div style>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.</div>
<div style><br></div><div style>Patch is pretty big and I hope it'll not break mailing list or mail clients.</div><div style><br></div><div style><div>From b98c8cd3bd0bca9df88a8d6d660015a502b9727c Mon Sep 17 00:00:00 2001</div>
<div>From: Anton Kortunov <<a href="mailto:toshic.toshic@gmail.com">toshic.toshic@gmail.com</a>></div><div>Date: Fri, 14 Jun 2013 20:38:41 +0400</div><div>Subject: [PATCH] IPv6 resolver</div><div><br></div><div>---</div>
<div> src/core/ngx_inet.h | 10 +</div><div> src/core/ngx_resolver.c | 436 +++++++++++++++++++++++++-----</div><div> src/core/ngx_resolver.h | 23 ++-</div><div> src/http/ngx_http_upstream.c | 16 +-</div>
<div> src/http/ngx_http_upstream.h | 2 +-</div><div> src/http/ngx_http_upstream_round_robin.c | 49 +++-</div><div> src/mail/ngx_mail_smtp_handler.c | 95 ++++++--</div><div> 7 files changed, 524 insertions(+), 107 deletions(-)</div>
<div><br></div><div>diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h</div><div>index 6a5a368..077ed34 100644</div><div>--- a/src/core/ngx_inet.h</div><div>+++ b/src/core/ngx_inet.h</div><div>@@ -68,6 +68,16 @@ typedef struct {</div>
<div> </div><div> </div><div> typedef struct {</div><div>+ ngx_uint_t family;</div><div>+ union {</div><div>+ in_addr_t v4;</div><div>+#if (NGX_HAVE_INET6)</div><div>+ struct in6_addr v6;</div>
<div>+#endif</div><div>+ } u;</div><div>+} ngx_ipaddr_t;</div><div>+</div><div>+typedef struct {</div><div> struct sockaddr *sockaddr;</div><div> socklen_t socklen;</div><div> ngx_str_t name;</div>
<div>diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c</div><div>index d59d0c4..5953b9c 100644</div><div>--- a/src/core/ngx_resolver.c</div><div>+++ b/src/core/ngx_resolver.c</div><div>@@ -71,12 +71,12 @@ static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf,</div>
<div> size_t n);</div><div> static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,</div><div> ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans);</div><div>-static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,</div>
<div>+void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,</div><div> ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan);</div><div> static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,</div>
<div> ngx_str_t *name, uint32_t hash);</div><div> static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r,</div><div>- in_addr_t addr);</div><div>+ ngx_ipaddr_t addr, uint32_t hash);</div><div> static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,</div>
<div> ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);</div><div> static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name,</div><div>@@ -88,7 +88,7 @@ static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size);</div>
<div> static void ngx_resolver_free(ngx_resolver_t *r, void *p);</div><div> static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);</div><div> static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);</div>
<div>-static in_addr_t *ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src,</div><div>+static ngx_ipaddr_t *ngx_resolver_rotate(ngx_resolver_t *r, ngx_ipaddr_t *src,</div><div> ngx_uint_t n);</div><div> static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len);</div>
<div> </div><div>@@ -270,13 +270,27 @@ ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree)</div><div> ngx_resolver_ctx_t *</div><div> ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)</div><div> {</div>
<div>- in_addr_t addr;</div><div>+ ngx_ipaddr_t addr;</div><div> ngx_resolver_ctx_t *ctx;</div><div> </div><div> if (temp) {</div><div>- addr = ngx_inet_addr(temp->name.data, temp->name.len);</div>
<div>+ addr.family = 0;</div><div> </div><div>- if (addr != INADDR_NONE) {</div><div>+</div><div>+ addr.u.v4 = ngx_inet_addr(temp->name.data, temp->name.len);</div><div>+</div><div>+ if (addr.u.v4 != INADDR_NONE) {</div>
<div>+</div><div>+ addr.family = AF_INET;</div><div>+</div><div>+#if (NGX_HAVE_INET6)</div><div>+ } else if (ngx_inet6_addr(temp->name.data, temp->name.len, addr.u.v6.s6_addr) == NGX_OK) {</div><div>
+</div><div>+ addr.family = AF_INET6;</div><div>+#endif</div><div>+ }</div><div>+ </div><div>+ if (addr.family) {</div><div> temp->resolver = r;</div><div> temp->state = NGX_OK;</div>
<div> temp->naddrs = 1;</div><div>@@ -417,7 +431,7 @@ static ngx_int_t</div><div> ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)</div><div> {</div><div> uint32_t hash;</div>
<div>- in_addr_t addr, *addrs;</div><div>+ ngx_ipaddr_t addr, *addrs;</div><div> ngx_int_t rc;</div><div> ngx_uint_t naddrs;</div><div> ngx_resolver_ctx_t *next;</div>
<div>@@ -429,7 +443,11 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)</div><div> </div><div> if (rn) {</div><div> </div><div>- if (rn->valid >= ngx_time()) {</div><div>+ if (rn->valid >= ngx_time()</div>
<div>+#if (NGX_HAVE_INET6)</div><div>+ && rn->qtype != NGX_RESOLVE_RETRY</div><div>+#endif</div><div>+ ) {</div><div> </div><div> ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");</div>
<div> </div><div>@@ -446,7 +464,6 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)</div><div> /* NGX_RESOLVE_A answer */</div><div> </div><div> if (naddrs != 1) {</div>
<div>- addr = 0;</div><div> addrs = ngx_resolver_rotate(r, rn->u.addrs, naddrs);</div><div> if (addrs == NULL) {</div><div> return NGX_ERROR;</div>
<div>@@ -506,6 +523,8 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)</div><div> } while (ctx);</div><div> </div><div> return NGX_OK;</div><div>+ } else {</div><div>+ rn->qtype = ctx->type;</div>
<div> }</div><div> </div><div> if (rn->waiting) {</div><div>@@ -552,6 +571,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)</div><div> rn->node.key = hash;</div><div> rn->nlen = (u_short) ctx->name.len;</div>
<div> rn->query = NULL;</div><div>+ rn->qtype = ctx->type;</div><div> </div><div> ngx_rbtree_insert(&r->name_rbtree, &rn->node);</div><div> }</div><div>@@ -629,17 +649,40 @@ failed:</div>
<div> ngx_int_t</div><div> ngx_resolve_addr(ngx_resolver_ctx_t *ctx)</div><div> {</div><div>+ uint32_t hash;</div><div> u_char *name;</div><div> ngx_resolver_t *r;</div><div> ngx_resolver_node_t *rn;</div>
<div> </div><div> r = ctx->resolver;</div><div>+ rn = NULL;</div><div>+</div><div>+ hash = ctx->addr.family;</div><div> </div><div>- ctx->addr = ntohl(ctx->addr);</div><div>+ switch(ctx->addr.family) {</div>
<div>+</div><div>+ case AF_INET:</div><div>+ ctx->addr.u.v4 = ntohl(ctx->addr.u.v4);</div><div>+ ngx_crc32_update(&hash, (u_char *)&ctx->addr.u.v4, sizeof(in_addr_t));</div><div>+ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,</div>
<div>+ "resolve addr hash: %xd, addr:%xd, family: %d", hash, ctx->addr.u.v4, ctx->addr.family);</div><div>+ break;</div><div>+</div><div>+#if (NGX_HAVE_INET6)</div><div>+ case AF_INET6:</div>
<div>+ ngx_crc32_update(&hash, (u_char *)&ctx->addr.u.v6, sizeof(struct in6_addr));</div><div>+ break;</div><div>+#endif</div><div>+</div><div>+ default:</div><div>+ goto failed;</div><div>
+ }</div><div> </div><div> /* lock addr mutex */</div><div> </div><div>- rn = ngx_resolver_lookup_addr(r, ctx->addr);</div><div>+ rn = ngx_resolver_lookup_addr(r, ctx->addr, hash);</div><div>+ ngx_log_error(r->log_level, r->log, 0,</div>
<div>+ "resolve: in resolve_addr searching, hash = %xd, rn = %p", hash, rn);</div><div> </div><div> if (rn) {</div><div> </div><div>@@ -694,8 +737,10 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)</div>
<div> goto failed;</div><div> }</div><div> </div><div>- rn->node.key = ctx->addr;</div><div>+ rn->node.key = hash;</div><div> rn->query = NULL;</div><div>+ rn->qtype = ctx->type;</div>
<div>+ rn->u.addr = ctx->addr;</div><div> </div><div> ngx_rbtree_insert(&r->addr_rbtree, &rn->node);</div><div> }</div><div>@@ -768,10 +813,11 @@ failed:</div><div> void</div><div> ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)</div>
<div> {</div><div>- in_addr_t addr;</div><div>+ uint32_t hash;</div><div> ngx_resolver_t *r;</div><div> ngx_resolver_ctx_t *w, **p;</div><div> ngx_resolver_node_t *rn;</div>
<div>+ char text[NGX_SOCKADDR_STRLEN];</div><div> </div><div> r = ctx->resolver;</div><div> </div><div>@@ -786,7 +832,25 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)</div><div> </div><div> if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {</div>
<div> </div><div>- rn = ngx_resolver_lookup_addr(r, ctx->addr);</div><div>+ hash = ctx->addr.family;</div><div>+</div><div>+ switch(ctx->addr.family) {</div><div>+</div><div>+ case AF_INET:</div>
<div>+ ngx_crc32_update(&hash, (u_char *)&ctx->addr.u.v4, sizeof(in_addr_t));</div><div>+ break;</div><div>+</div><div>+#if (NGX_HAVE_INET6)</div><div>+ case AF_INET6:</div><div>+ ngx_crc32_update(&hash, (u_char *)&ctx->addr.u.v6, sizeof(struct in6_addr));</div>
<div>+ break;</div><div>+#endif</div><div>+</div><div>+ default:</div><div>+ goto failed;</div><div>+ }</div><div>+</div><div>+ rn = ngx_resolver_lookup_addr(r, ctx->addr, hash);</div>
<div> </div><div> if (rn) {</div><div> p = &rn->waiting;</div><div>@@ -804,12 +868,13 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)</div><div> }</div><div> }</div><div> </div>
<div>- addr = ntohl(ctx->addr);</div><div>+failed:</div><div>+</div><div>+ //addr = ntohl(ctx->addr);</div><div>+ inet_ntop(ctx->addr.family, &ctx->addr.u, text, NGX_SOCKADDR_STRLEN);</div>
<div> </div><div> ngx_log_error(NGX_LOG_ALERT, r->log, 0,</div><div>- "could not cancel %ud.%ud.%ud.%ud resolving",</div><div>- (addr >> 24) & 0xff, (addr >> 16) & 0xff,</div>
<div>- (addr >> 8) & 0xff, addr & 0xff);</div><div>+ "could not cancel %s resolving", text);</div><div> }</div><div> </div><div> done:</div><div>@@ -1130,6 +1195,9 @@ found:</div>
<div> switch (qtype) {</div><div> </div><div> case NGX_RESOLVE_A:</div><div>+#if (NGX_HAVE_INET6)</div><div>+ case NGX_RESOLVE_AAAA:</div><div>+#endif</div><div> </div><div> ngx_resolver_process_a(r, buf, n, ident, code, nan,</div>
<div> i + sizeof(ngx_resolver_qs_t));</div><div>@@ -1178,7 +1246,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,</div><div> size_t len;</div><div>
int32_t ttl;</div><div> uint32_t hash;</div><div>- in_addr_t addr, *addrs;</div><div>+ ngx_ipaddr_t addr, *addrs;</div><div> ngx_str_t name;</div>
<div> ngx_uint_t qtype, qident, naddrs, a, i, n, start;</div><div> ngx_resolver_an_t *an;</div><div>@@ -1212,12 +1280,55 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,</div><div>
goto failed;</div><div> }</div><div> </div><div>- ngx_resolver_free(r, name.data);</div><div>-</div><div> if (code == 0 && nan == 0) {</div><div>+</div><div>+#if (NGX_HAVE_INET6)</div><div>+<span class="" style="white-space:pre"> </span>// If it was required dual type v4|v6 resolv create one more request</div>
<div>+<span class="" style="white-space:pre"> </span>if (rn->qtype == NGX_RESOLVE_A_AAAA</div><div>+<span class="" style="white-space:pre"> </span>|| rn->qtype == NGX_RESOLVE_AAAA_A) {</div><div>+</div><div>+ ngx_queue_remove(&rn->queue);</div>
<div>+</div><div>+ rn->valid = ngx_time() + (r->valid ? r->valid : ttl);</div><div>+ rn->expire = ngx_time() + r->expire;</div><div>+</div><div>+ ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);</div>
<div>+</div><div>+ ctx = rn->waiting;</div><div>+ rn->waiting = NULL;</div><div>+</div><div>+ if (ctx) {</div><div>+ ctx->name = name;</div><div>+</div><div>+ switch (rn->qtype) {</div>
<div>+</div><div>+ case NGX_RESOLVE_A_AAAA:</div><div>+ ctx->type = NGX_RESOLVE_AAAA;</div><div>+ break;</div><div>+</div><div>+ case NGX_RESOLVE_AAAA_A:</div>
<div>+ ctx->type = NGX_RESOLVE_A;</div><div>+ break;</div><div>+ }</div><div>+</div><div>+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,</div><div>
+ "restarting request for name %V, with type %ud",</div><div>+ &name, ctx->type);</div><div>+</div><div>+ rn->qtype = NGX_RESOLVE_RETRY;</div>
<div>+</div><div>+ (void) ngx_resolve_name_locked(r, ctx);</div><div>+ }</div><div>+</div><div>+ return;</div><div>+ }</div><div>+#endif</div><div>+</div><div> code = 3; /* NXDOMAIN */</div>
<div> }</div><div> </div><div>+ ngx_resolver_free(r, name.data);</div><div>+</div><div> if (code) {</div><div> next = rn->waiting;</div><div> rn->waiting = NULL;</div><div>@@ -1243,7 +1354,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,</div>
<div> </div><div> i = ans;</div><div> naddrs = 0;</div><div>- addr = 0;</div><div>+ addr.family = 0;</div><div> addrs = NULL;</div><div> cname = NULL;</div><div> qtype = 0;</div><div>@@ -1302,13 +1413,30 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,</div>
<div> goto short_response;</div><div> }</div><div> </div><div>- addr = htonl((buf[i] << 24) + (buf[i + 1] << 16)</div><div>+ addr.family = AF_INET;</div><div>+ addr.u.v4 = htonl((buf[i] << 24) + (buf[i + 1] << 16)</div>
<div> + (buf[i + 2] << 8) + (buf[i + 3]));</div><div> </div><div> naddrs++;</div><div> </div><div> i += len;</div><div> </div><div>+#if (NGX_HAVE_INET6)</div><div>+ } else if (qtype == NGX_RESOLVE_AAAA) {</div>
<div>+</div><div>+ i += sizeof(ngx_resolver_an_t);</div><div>+</div><div>+ if (i + len > last) {</div><div>+ goto short_response;</div><div>+ }</div><div>+</div><div>+ addr.family = AF_INET6;</div>
<div>+ ngx_memcpy(&addr.u.v6.s6_addr, &buf[i], 16);</div><div>+</div><div>+ naddrs++;</div><div>+</div><div>+ i += len;</div><div>+#endif</div><div> } else if (qtype == NGX_RESOLVE_CNAME) {</div>
<div> cname = &buf[i] + sizeof(ngx_resolver_an_t);</div><div> i += sizeof(ngx_resolver_an_t) + len;</div><div>@@ -1333,7 +1461,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,</div>
<div> </div><div> } else {</div><div> </div><div>- addrs = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));</div><div>+ addrs = ngx_resolver_alloc(r, naddrs * sizeof(ngx_ipaddr_t));</div><div>
if (addrs == NULL) {</div><div> return;</div><div> }</div><div>@@ -1369,12 +1497,23 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,</div><div> </div><div> if (qtype == NGX_RESOLVE_A) {</div>
<div> </div><div>- addrs[n++] = htonl((buf[i] << 24) + (buf[i + 1] << 16)</div><div>+ addrs[n].family = AF_INET;</div><div>+ addrs[n++].u.v4 = htonl((buf[i] << 24) + (buf[i + 1] << 16)</div>
<div> + (buf[i + 2] << 8) + (buf[i + 3]));</div><div> </div><div> if (n == naddrs) {</div><div> break;</div><div> }</div>
<div>+#if (NGX_HAVE_INET6)</div><div>+ } else if (qtype == NGX_RESOLVE_AAAA) {</div><div>+</div><div>+ addrs[n].family = AF_INET6;</div><div>+ ngx_memcpy(&addrs[n++].u.v6.s6_addr, &buf[i], 16);</div>
<div>+</div><div>+ if (n == naddrs) {</div><div>+ break;</div><div>+ }</div><div>+#endif</div><div> }</div><div> </div><div> i += len;</div>
<div>@@ -1383,7 +1522,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,</div><div> rn->u.addrs = addrs;</div><div> </div><div> addrs = ngx_resolver_dup(r, rn->u.addrs,</div>
<div>- naddrs * sizeof(in_addr_t));</div><div>+ naddrs * sizeof(ngx_ipaddr_t));</div><div> if (addrs == NULL) {</div><div> return;</div>
<div> }</div><div>@@ -1486,13 +1625,14 @@ failed:</div><div> }</div><div> </div><div> </div><div>-static void</div><div>+void</div><div> ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,</div>
<div> ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan)</div><div> {</div><div>- char *err;</div><div>+ char *err = NULL;</div><div>+ uint32_t hash = 0;</div><div>
size_t len;</div><div>- in_addr_t addr;</div><div>+ ngx_ipaddr_t addr;</div><div> int32_t ttl;</div><div> ngx_int_t digit;</div><div> ngx_str_t name;</div>
<div>@@ -1500,12 +1640,16 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,</div><div> ngx_resolver_an_t *an;</div><div> ngx_resolver_ctx_t *ctx, *next;</div><div> ngx_resolver_node_t *rn;</div>
<div>+ char text[NGX_SOCKADDR_STRLEN];</div><div> </div><div> if (ngx_resolver_copy(r, NULL, buf, &buf[12], &buf[n]) != NGX_OK) {</div><div> goto invalid_in_addr_arpa;</div><div> }</div>
<div> </div><div>- addr = 0;</div><div>+ ngx_memzero(&addr, sizeof(ngx_ipaddr_t));</div><div>+</div><div>+ /* Try to parse request as in-addr.arpa */</div><div>+ addr.family = AF_INET;</div><div> i = 12;</div>
<div> </div><div> for (mask = 0; mask < 32; mask += 8) {</div><div>@@ -1516,7 +1660,7 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,</div><div> goto invalid_in_addr_arpa;</div><div>
}</div><div> </div><div>- addr += digit << mask;</div><div>+ addr.u.v4 += digit << mask;</div><div> i += len;</div><div> }</div><div> </div><div>@@ -1524,15 +1668,79 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,</div>
<div> goto invalid_in_addr_arpa;</div><div> }</div><div> </div><div>+ i += sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t);</div><div>+</div><div>+ goto found;</div><div>+</div><div>+invalid_in_addr_arpa:</div>
<div>+</div><div>+#if (NGX_HAVE_INET6)</div><div>+ /* Try to parse request as ip6.arpa */</div><div>+ addr.family = AF_INET6;</div><div>+ i = 12;</div><div>+</div><div>+ for (len = 15; len < 16; len--) {</div>
<div>+ if (buf[i++] != 1)</div><div>+ goto invalid_arpa;</div><div>+</div><div>+ digit = ngx_hextoi(&buf[i++], 1);</div><div>+ if (digit == NGX_ERROR || digit > 16) {</div><div>+ goto invalid_arpa;</div>
<div>+ }</div><div>+</div><div>+ addr.u.v6.s6_addr[len] = digit;</div><div>+</div><div>+ if (buf[i++] != 1)</div><div>+ goto invalid_arpa;</div><div>+</div><div>+</div><div>+ digit = ngx_hextoi(&buf[i++], 1);</div>
<div>+ if (digit == NGX_ERROR || digit > 16) {</div><div>+ goto invalid_arpa;</div><div>+ }</div><div>+</div><div>+ addr.u.v6.s6_addr[len] += digit << 4;</div><div>+ }</div><div>
+</div><div>+ if (ngx_strcmp(&buf[i], "\3ip6\4arpa") != 0) {</div><div>+ goto invalid_arpa;</div><div>+ }</div><div>+</div><div>+ i += sizeof("\3ip6\4arpa") + sizeof(ngx_resolver_qs_t);</div>
<div>+</div><div>+#else /* NGX_HAVE_INET6 */</div><div>+ goto invalid_arpa;</div><div>+#endif</div><div>+</div><div>+found:</div><div>+</div><div> /* lock addr mutex */</div><div> </div><div>- rn = ngx_resolver_lookup_addr(r, addr);</div>
<div>+ hash = addr.family;</div><div>+</div><div>+ switch(addr.family) {</div><div>+</div><div>+ case AF_INET:</div><div>+ ngx_crc32_update(&hash, (u_char *)&addr.u.v4, sizeof(in_addr_t));</div><div>
+ break;</div><div>+</div><div>+#if (NGX_HAVE_INET6)</div><div>+ case AF_INET6:</div><div>+ ngx_crc32_update(&hash, (u_char *)&addr.u.v6, sizeof(struct in6_addr));</div><div>+ break;</div><div>
+#endif</div><div>+</div><div>+ default:</div><div>+ goto invalid;</div><div>+ }</div><div>+</div><div>+ rn = ngx_resolver_lookup_addr(r, addr, hash);</div><div>+</div><div>+ inet_ntop(addr.family, &addr.u, text, NGX_SOCKADDR_STRLEN);</div>
<div> </div><div> if (rn == NULL || rn->query == NULL) {</div><div> ngx_log_error(r->log_level, r->log, 0,</div><div>- "unexpected response for %ud.%ud.%ud.%ud",</div><div>
- (addr >> 24) & 0xff, (addr >> 16) & 0xff,</div><div>- (addr >> 8) & 0xff, addr & 0xff);</div><div>+ "unexpected response for %s", text);</div>
<div> goto failed;</div><div> }</div><div> </div><div>@@ -1540,12 +1748,15 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,</div><div> </div><div> if (ident != qident) {</div><div> ngx_log_error(r->log_level, r->log, 0,</div>
<div>- "wrong ident %ui response for %ud.%ud.%ud.%ud, expect %ui",</div><div>- ident, (addr >> 24) & 0xff, (addr >> 16) & 0xff,</div><div>- (addr >> 8) & 0xff, addr & 0xff, qident);</div>
<div>+ "wrong ident %ui response for %s, expect %ui",</div><div>+ ident, text, qident);</div><div> goto failed;</div><div> }</div><div> </div><div>+ ngx_log_error(r->log_level, r->log, 0,</div>
<div>+ "code: %d, nan: %d",</div><div>+ code, nan);</div><div>+</div><div> if (code == 0 && nan == 0) {</div><div> code = 3; /* NXDOMAIN */</div><div> }</div>
<div>@@ -1573,8 +1784,6 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,</div><div> return;</div><div> }</div><div> </div><div>- i += sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t);</div>
<div>-</div><div> if (i + 2 + sizeof(ngx_resolver_an_t) > (ngx_uint_t) n) {</div><div> goto short_response;</div><div> }</div><div>@@ -1654,10 +1863,10 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,</div>
<div> </div><div> return;</div><div> </div><div>-invalid_in_addr_arpa:</div><div>+invalid_arpa:</div><div> </div><div> ngx_log_error(r->log_level, r->log, 0,</div><div>- "invalid in-addr.arpa name in DNS response");</div>
<div>+ "invalid in-addr.arpa or ip6.arpa name in DNS response");</div><div> return;</div><div> </div><div> short_response:</div><div>@@ -1722,28 +1931,54 @@ ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)</div>
<div> </div><div> </div><div> static ngx_resolver_node_t *</div><div>-ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr)</div><div>+ngx_resolver_lookup_addr(ngx_resolver_t *r, ngx_ipaddr_t addr, uint32_t hash)</div>
<div> {</div><div>+ ngx_int_t rc;</div><div> ngx_rbtree_node_t *node, *sentinel;</div><div>+ ngx_resolver_node_t *rn;</div><div> </div><div> node = r->addr_rbtree.root;</div><div> sentinel = r->addr_rbtree.sentinel;</div>
<div> </div><div> while (node != sentinel) {</div><div> </div><div>- if (addr < node->key) {</div><div>+ if (hash < node->key) {</div><div> node = node->left;</div><div> continue;</div>
<div> }</div><div> </div><div>- if (addr > node->key) {</div><div>+ if (hash > node->key) {</div><div> node = node->right;</div><div> continue;</div><div> }</div>
<div> </div><div>- /* addr == node->key */</div><div>+ /* hash == node->key */</div><div>+</div><div>+ rn = (ngx_resolver_node_t *) node;</div><div>+</div><div>+ rc = addr.family - rn->u.addr.family;</div>
<div>+</div><div>+ if (rc == 0) {</div><div>+</div><div>+ switch (addr.family) {</div><div>+ case AF_INET:</div><div>+ rc = ngx_memn2cmp((u_char *)&addr.u.v4, (u_char *)&rn->u.addr.u.v4, sizeof(in_addr_t), sizeof(in_addr_t));</div>
<div>+ break;</div><div>+</div><div>+#if (NGX_HAVE_INET6)</div><div>+ case AF_INET6:</div><div>+ rc = ngx_memn2cmp((u_char *)&addr.u.v6, (u_char *)&rn->u.addr.u.v6, sizeof(struct in6_addr), sizeof(struct in6_addr));</div>
<div>+ break;</div><div>+#endif</div><div>+ }</div><div>+</div><div>+ if (rc == 0) {</div><div>+ return rn;</div><div>+ }</div><div>+</div><div>+ }</div>
<div> </div><div>- return (ngx_resolver_node_t *) node;</div><div>+ node = (rc < 0) ? node->left : node->right;</div><div> }</div><div> </div><div> /* not found */</div><div>@@ -1758,6 +1993,7 @@ ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,</div>
<div> {</div><div> ngx_rbtree_node_t **p;</div><div> ngx_resolver_node_t *rn, *rn_temp;</div><div>+ ngx_int_t rc;</div><div> </div><div> for ( ;; ) {</div><div> </div><div>@@ -1774,8 +2010,29 @@ ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,</div>
<div> rn = (ngx_resolver_node_t *) node;</div><div> rn_temp = (ngx_resolver_node_t *) temp;</div><div> </div><div>- p = (ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen, rn_temp->nlen)</div>
<div>- < 0) ? &temp->left : &temp->right;</div><div>+ if (rn->qtype == NGX_RESOLVE_PTR) {</div><div>+ rc = rn->u.addr.family - rn_temp->u.addr.family;</div>
<div>+</div><div>+ if (rc == 0) {</div><div>+</div><div>+ switch (rn->u.addr.family) {</div><div>+ case AF_INET:</div><div>+ 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));</div>
<div>+ break;</div><div>+</div><div>+ #if (NGX_HAVE_INET6)</div><div>+ case AF_INET6:</div><div>+ 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));</div>
<div>+ break;</div><div>+ #endif</div><div>+ }</div><div>+ }</div><div>+</div><div>+ } else {</div><div>+ rc = ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen, rn_temp->nlen);</div>
<div>+ }</div><div>+</div><div>+ p = (rc < 0) ? &temp->left : &temp->right;</div><div> }</div><div> </div><div> if (*p == sentinel) {</div><div>@@ -1838,7 +2095,20 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)</div>
<div> qs = (ngx_resolver_qs_t *) p;</div><div> </div><div> /* query type */</div><div>- qs->type_hi = 0; qs->type_lo = (u_char) ctx->type;</div><div>+ qs->type_hi = 0; qs->type_lo = (u_char) rn->qtype;</div>
<div>+</div><div>+#if (NGX_HAVE_INET6)</div><div>+ switch (rn->qtype) {</div><div>+</div><div>+ case NGX_RESOLVE_A_AAAA:</div><div>+ qs->type_lo = NGX_RESOLVE_A;</div><div>+ break;</div><div>+</div>
<div>+ case NGX_RESOLVE_AAAA_A:</div><div>+ qs->type_lo = NGX_RESOLVE_AAAA;</div><div>+ break;</div><div>+ }</div><div>+#endif</div><div> </div><div> /* IP query class */</div><div> qs->class_hi = 0; qs->class_lo = 1;</div>
<div>@@ -1880,8 +2150,6 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)</div><div> }</div><div> </div><div> </div><div>-/* AF_INET only */</div><div>-</div><div> static ngx_int_t</div><div>
ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)</div><div> {</div><div>@@ -1892,7 +2160,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)</div><div> ngx_resolver_query_t *query;</div>
<div> </div><div> len = sizeof(ngx_resolver_query_t)</div><div>- + sizeof(".255.255.255.255.in-addr.arpa.") - 1</div><div>+ + NGX_PTR_QUERY_LEN</div><div> + sizeof(ngx_resolver_qs_t);</div>
<div> </div><div> p = ngx_resolver_alloc(ctx->resolver, len);</div><div>@@ -1919,18 +2187,50 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)</div><div> </div><div> p += sizeof(ngx_resolver_query_t);</div>
<div> </div><div>- for (n = 0; n < 32; n += 8) {</div><div>- d = ngx_sprintf(&p[1], "%ud", (ctx->addr >> n) & 0xff);</div><div>- *p = (u_char) (d - &p[1]);</div><div>- p = d;</div>
<div>+ switch (ctx->addr.family) {</div><div>+</div><div>+ case AF_INET:</div><div>+ for (n = 0; n < 32; n += 8) {</div><div>+ d = ngx_sprintf(&p[1], "%ud", (ctx->addr.u.v4 >> n) & 0xff);</div>
<div>+ *p = (u_char) (d - &p[1]);</div><div>+ p = d;</div><div>+ }</div><div>+</div><div>+ /* query type "PTR", IP query class */</div><div>+ ngx_memcpy(p, "\7in-addr\4arpa\0\0\14\0\1", 18);</div>
<div>+</div><div>+ rn->qlen = (u_short)</div><div>+ (p + sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t)</div><div>+ - rn->query);</div><div>+</div><div>
+ break;</div><div>+</div><div>+#if (NGX_HAVE_INET6)</div><div>+ case AF_INET6:</div><div>+ for (n = 15; n >= 0; n--) {</div><div>+ p = ngx_sprintf(p, "\1%xd\1%xd", </div><div>+ (ctx->addr.u.v6.s6_addr[n]) & 0xf,</div>
<div>+ (ctx->addr.u.v6.s6_addr[n] >> 4) & 0xf);</div><div>+</div><div>+ }</div><div>+</div><div>+ /* query type "PTR", IP query class */</div><div>+ ngx_memcpy(p, "\3ip6\4arpa\0\0\14\0\1", 18);</div>
<div>+</div><div>+ rn->qlen = (u_short)</div><div>+ (p + sizeof("\3ip6\4arpa") + sizeof(ngx_resolver_qs_t)</div><div>+ - rn->query);</div><div>+</div><div>
+ break;</div><div>+#endif</div><div>+</div><div>+ default:</div><div>+ return NGX_ERROR;</div><div> }</div><div> </div><div>- /* query type "PTR", IP query class */</div><div>- ngx_memcpy(p, "\7in-addr\4arpa\0\0\14\0\1", 18);</div>
<div>+ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,</div><div>+ "resolve: query %s, ident %i", (rn->query+12), ident & 0xffff);</div><div> </div><div>- rn->qlen = (u_short)</div>
<div>- (p + sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t)</div><div>- - rn->query);</div><div> </div><div> return NGX_OK;</div><div> }</div><div>@@ -2136,13 +2436,13 @@ ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size)</div>
<div> }</div><div> </div><div> </div><div>-static in_addr_t *</div><div>-ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src, ngx_uint_t n)</div><div>+static ngx_ipaddr_t *</div><div>+ngx_resolver_rotate(ngx_resolver_t *r, ngx_ipaddr_t *src, ngx_uint_t n)</div>
<div> {</div><div> void *dst, *p;</div><div> ngx_uint_t j;</div><div> </div><div>- dst = ngx_resolver_alloc(r, n * sizeof(in_addr_t));</div><div>+ dst = ngx_resolver_alloc(r, n * sizeof(ngx_ipaddr_t));</div>
<div> </div><div> if (dst == NULL) {</div><div> return dst;</div><div>@@ -2151,12 +2451,12 @@ ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src, ngx_uint_t n)</div><div> j = ngx_random() % n;</div><div>
</div><div> if (j == 0) {</div><div>- ngx_memcpy(dst, src, n * sizeof(in_addr_t));</div><div>+ ngx_memcpy(dst, src, n * sizeof(ngx_ipaddr_t));</div><div> return dst;</div><div> }</div><div> </div>
<div>- p = ngx_cpymem(dst, &src[j], (n - j) * sizeof(in_addr_t));</div><div>- ngx_memcpy(p, src, j * sizeof(in_addr_t));</div><div>+ p = ngx_cpymem(dst, &src[j], (n - j) * sizeof(ngx_ipaddr_t));</div><div>
+ ngx_memcpy(p, src, j * sizeof(ngx_ipaddr_t));</div><div> </div><div> return dst;</div><div> }</div><div>diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h</div><div>index ae34ca5..a45b244 100644</div>
<div>--- a/src/core/ngx_resolver.h</div><div>+++ b/src/core/ngx_resolver.h</div><div>@@ -20,6 +20,15 @@</div><div> #define NGX_RESOLVE_TXT 16</div><div> #define NGX_RESOLVE_DNAME 39</div><div> </div><div>+#if (NGX_HAVE_INET6)</div>
<div>+</div><div>+#define NGX_RESOLVE_AAAA 28</div><div>+#define NGX_RESOLVE_A_AAAA 1000</div><div>+#define NGX_RESOLVE_AAAA_A 1001</div><div>+#define NGX_RESOLVE_RETRY 1002</div><div>+</div><div>+#endif</div>
<div>+</div><div> #define NGX_RESOLVE_FORMERR 1</div><div> #define NGX_RESOLVE_SERVFAIL 2</div><div> #define NGX_RESOLVE_NXDOMAIN 3</div><div>@@ -32,6 +41,11 @@</div><div> </div><div> #define NGX_RESOLVER_MAX_RECURSION 50</div>
<div> </div><div>+#if (NGX_HAVE_INET6)</div><div>+#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)</div><div>+#else</div><div>+#define NGX_PTR_QUERY_LEN (sizeof(".255.255.255.255.in-addr.arpa.") - 1)</div>
<div>+#endif</div><div> </div><div> typedef struct {</div><div> ngx_connection_t *connection;</div><div>@@ -58,10 +72,11 @@ typedef struct {</div><div> u_short qlen;</div><div> </div><div>
u_char *query;</div><div>+ ngx_int_t qtype;</div><div> </div><div> union {</div><div>- in_addr_t addr;</div><div>- in_addr_t *addrs;</div>
<div>+ ngx_ipaddr_t addr;</div><div>+ ngx_ipaddr_t *addrs;</div><div> u_char *cname;</div><div> } u;</div><div> </div><div>@@ -121,8 +136,8 @@ struct ngx_resolver_ctx_s {</div>
<div> ngx_str_t name;</div><div> </div><div> ngx_uint_t naddrs;</div><div>- in_addr_t *addrs;</div><div>- in_addr_t addr;</div><div>+ ngx_ipaddr_t *addrs;</div>
<div>+ ngx_ipaddr_t addr;</div><div> </div><div> ngx_resolver_handler_pt handler;</div><div> void *data;</div><div>diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c</div>
<div>index 16e6602..7a8035c 100644</div><div>--- a/src/http/ngx_http_upstream.c</div><div>+++ b/src/http/ngx_http_upstream.c</div><div>@@ -638,7 +638,11 @@ ngx_http_upstream_init_request(ngx_http_request_t *r)</div><div> }</div>
<div> </div><div> ctx->name = *host;</div><div>+#if (NGX_HAVE_INET6)</div><div>+ ctx->type = NGX_RESOLVE_A_AAAA;</div><div>+#else</div><div> ctx->type = NGX_RESOLVE_A;</div><div>+#endif</div>
<div> ctx->handler = ngx_http_upstream_resolve_handler;</div><div> ctx->data = r;</div><div> ctx->timeout = clcf->resolver_timeout;</div><div>@@ -912,16 +916,14 @@ ngx_http_upstream_resolve_handler(ngx_resolver_ctx_t *ctx)</div>
<div> </div><div> #if (NGX_DEBUG)</div><div> {</div><div>- in_addr_t addr;</div><div>+ char text[NGX_SOCKADDR_STRLEN];</div><div> ngx_uint_t i;</div><div> </div><div>- for (i = 0; i < ctx->naddrs; i++) {</div>
<div>- addr = ntohl(ur->addrs[i]);</div><div>+ for (i = 0; i < ur->naddrs; i++) {</div><div>+ inet_ntop(ur->addrs[i].family, &ur->addrs[i].u, text, NGX_SOCKADDR_STRLEN);</div><div> </div>
<div>- ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,</div><div>- "name was resolved to %ud.%ud.%ud.%ud",</div><div>- (addr >> 24) & 0xff, (addr >> 16) & 0xff,</div>
<div>- (addr >> 8) & 0xff, addr & 0xff);</div><div>+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,</div><div>+ "name was resolved to %s", text);</div>
<div> }</div><div> }</div><div> #endif</div><div>diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h</div><div>index fd4e36b..9e88a9a 100644</div><div>--- a/src/http/ngx_http_upstream.h</div><div>
+++ b/src/http/ngx_http_upstream.h</div><div>@@ -254,7 +254,7 @@ typedef struct {</div><div> ngx_uint_t no_port; /* unsigned no_port:1 */</div><div> </div><div> ngx_uint_t naddrs;</div>
<div>- in_addr_t *addrs;</div><div>+ ngx_ipaddr_t *addrs;</div><div> </div><div> struct sockaddr *sockaddr;</div><div> socklen_t socklen;</div>
<div>diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c</div><div>index e0c6c58..92fa825 100644</div><div>--- a/src/http/ngx_http_upstream_round_robin.c</div><div>+++ b/src/http/ngx_http_upstream_round_robin.c</div>
<div>@@ -268,6 +268,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,</div><div> size_t len;</div><div> ngx_uint_t i, n;</div><div> struct sockaddr_in *sin;</div>
<div>+#if (NGX_HAVE_INET6)</div><div>+ struct sockaddr_in6 *sin6;</div><div>+#endif</div><div> ngx_http_upstream_rr_peers_t *peers;</div><div> ngx_http_upstream_rr_peer_data_t *rrp;</div><div>
</div><div>@@ -306,27 +309,52 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,</div><div> </div><div> for (i = 0; i < ur->naddrs; i++) {</div><div> </div><div>- len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1;</div>
<div>+ len = NGX_SOCKADDR_STRLEN;</div><div> </div><div> p = ngx_pnalloc(r->pool, len);</div><div> if (p == NULL) {</div><div> return NGX_ERROR;</div><div> }</div>
<div> </div><div>- len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN);</div><div>+ len = ngx_inet_ntop(ur->addrs[i].family, &ur->addrs[i].u, p, NGX_SOCKADDR_STRLEN - sizeof(":65535") + 1);</div>
<div> len = ngx_sprintf(&p[len], ":%d", ur->port) - p;</div><div> </div><div>- sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));</div><div>- if (sin == NULL) {</div>
<div>+ switch (ur->addrs[i].family) {</div><div>+</div><div>+ case AF_INET:</div><div>+ sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in));</div><div>+ if (sin == NULL) {</div>
<div>+ return NGX_ERROR;</div><div>+ }</div><div>+</div><div>+ sin->sin_family = AF_INET;</div><div>+ sin->sin_port = htons(ur->port);</div><div>+ sin->sin_addr.s_addr = ur->addrs[i].u.v4;</div>
<div>+</div><div>+ peers->peer[i].sockaddr = (struct sockaddr *) sin;</div><div>+ peers->peer[i].socklen = sizeof(struct sockaddr_in);</div><div>+ break;</div><div>+</div>
<div>+#if (NGX_HAVE_INET6)</div><div>+ case AF_INET6:</div><div>+ sin6 = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in6));</div><div>+ if (sin6 == NULL) {</div><div>+ return NGX_ERROR;</div>
<div>+ }</div><div>+</div><div>+ sin6->sin6_family = AF_INET6;</div><div>+ sin6->sin6_port = htons(ur->port);</div><div>+ sin6->sin6_addr = ur->addrs[i].u.v6;</div>
<div>+</div><div>+ peers->peer[i].sockaddr = (struct sockaddr *) sin6;</div><div>+ peers->peer[i].socklen = sizeof(struct sockaddr_in6);</div><div>+ break;</div><div>+#endif</div>
<div>+</div><div>+ default:</div><div> return NGX_ERROR;</div><div> }</div><div> </div><div>- sin->sin_family = AF_INET;</div><div>- sin->sin_port = htons(ur->port);</div>
<div>- sin->sin_addr.s_addr = ur->addrs[i];</div><div>-</div><div>- peers->peer[i].sockaddr = (struct sockaddr *) sin;</div><div>- peers->peer[i].socklen = sizeof(struct sockaddr_in);</div>
<div> peers->peer[i].name.len = len;</div><div> peers->peer[i].name.data = p;</div><div> peers->peer[i].weight = 1;</div><div>@@ -334,6 +362,7 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,</div>
<div> peers->peer[i].current_weight = 0;</div><div> peers->peer[i].max_fails = 1;</div><div> peers->peer[i].fail_timeout = 10;</div><div>+</div><div> }</div><div> }</div>
<div> </div><div>diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c</div><div>index 2171423..668424e 100644</div><div>--- a/src/mail/ngx_mail_smtp_handler.c</div><div>+++ b/src/mail/ngx_mail_smtp_handler.c</div>
<div>@@ -56,6 +56,9 @@ void</div><div> ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)</div><div> {</div><div> struct sockaddr_in *sin;</div><div>+#if (NGX_HAVE_INET6)</div><div>+ struct sockaddr_in6 *sin6;</div>
<div>+#endif</div><div> ngx_resolver_ctx_t *ctx;</div><div> ngx_mail_core_srv_conf_t *cscf;</div><div> </div><div>@@ -67,7 +70,11 @@ ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)</div>
<div> return;</div><div> }</div><div> </div><div>- if (c->sockaddr->sa_family != AF_INET) {</div><div>+ if (c->sockaddr->sa_family != AF_INET</div><div>+#if (NGX_HAVE_INET6)</div><div>+ && c->sockaddr->sa_family != AF_INET6</div>
<div>+#endif</div><div>+ ) {</div><div> s->host = smtp_tempunavail;</div><div> ngx_mail_smtp_greeting(s, c);</div><div> return;</div><div>@@ -81,11 +88,23 @@ ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)</div>
<div> return;</div><div> }</div><div> </div><div>- /* AF_INET only */</div><div>+ ctx->addr.family = c->sockaddr->sa_family;</div><div> </div><div>- sin = (struct sockaddr_in *) c->sockaddr;</div>
<div>+ switch (c->sockaddr->sa_family) {</div><div>+</div><div>+ case AF_INET:</div><div>+ sin = (struct sockaddr_in *) c->sockaddr;</div><div>+ ctx->addr.u.v4 = sin->sin_addr.s_addr;</div>
<div>+ break;</div><div>+</div><div>+#if (NGX_HAVE_INET6)</div><div>+ case AF_INET6:</div><div>+ sin6 = (struct sockaddr_in6 *) c->sockaddr;</div><div>+ ctx->addr.u.v6 = sin6->sin6_addr;</div>
<div>+ break;</div><div>+#endif</div><div>+ }</div><div> </div><div>- ctx->addr = sin->sin_addr.s_addr;</div><div> ctx->handler = ngx_mail_smtp_resolve_addr_handler;</div><div> ctx->data = s;</div>
<div> ctx->timeout = cscf->resolver_timeout;</div><div>@@ -167,11 +186,23 @@ ngx_mail_smtp_resolve_name(ngx_event_t *rev)</div><div> }</div><div> </div><div> ctx->name = s->host;</div><div>- ctx->type = NGX_RESOLVE_A;</div>
<div> ctx->handler = ngx_mail_smtp_resolve_name_handler;</div><div> ctx->data = s;</div><div> ctx->timeout = cscf->resolver_timeout;</div><div> </div><div>+ switch (c->sockaddr->sa_family) {</div>
<div>+</div><div>+ case AF_INET:</div><div>+ ctx->type = NGX_RESOLVE_A;</div><div>+ break;</div><div>+</div><div>+#if (NGX_HAVE_INET6)</div><div>+ case AF_INET6:</div><div>+ ctx->type = NGX_RESOLVE_AAAA_A;</div>
<div>+ break;</div><div>+#endif</div><div>+ }</div><div>+</div><div> if (ngx_resolve_name(ctx) != NGX_OK) {</div><div> ngx_mail_close_connection(c);</div><div> }</div><div>@@ -181,11 +212,15 @@ ngx_mail_smtp_resolve_name(ngx_event_t *rev)</div>
<div> static void</div><div> ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx)</div><div> {</div><div>- in_addr_t addr;</div><div>+ ngx_ipaddr_t addr;</div><div> ngx_uint_t i;</div>
<div> ngx_connection_t *c;</div><div> struct sockaddr_in *sin;</div><div>+#if (NGX_HAVE_INET6)</div><div>+ struct sockaddr_in6 *sin6;</div><div>+#endif</div><div> ngx_mail_session_t *s;</div><div>+ char text[NGX_SOCKADDR_STRLEN];</div>
<div> </div><div> s = ctx->data;</div><div> c = s->connection;</div><div>@@ -205,23 +240,49 @@ ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx)</div><div> </div><div> } else {</div><div> </div>
<div>- /* AF_INET only */</div><div>+ addr.family = c->sockaddr->sa_family;</div><div> </div><div>- sin = (struct sockaddr_in *) c->sockaddr;</div><div>+ switch (c->sockaddr->sa_family) {</div>
<div>+</div><div>+ case AF_INET:</div><div>+ sin = (struct sockaddr_in *) c->sockaddr;</div><div>+ addr.u.v4 = sin->sin_addr.s_addr;</div><div>+ break;</div><div>+</div><div>+#if (NGX_HAVE_INET6)</div>
<div>+ case AF_INET6:</div><div>+ sin6 = (struct sockaddr_in6 *) c->sockaddr;</div><div>+ addr.u.v6 = sin6->sin6_addr;</div><div>+ break;</div><div>+#endif</div><div>+ }</div>
<div> </div><div> for (i = 0; i < ctx->naddrs; i++) {</div><div> </div><div>- addr = ctx->addrs[i];</div><div>+ inet_ntop(ctx->addrs[i].family, &ctx->addrs[i].u, text, NGX_SOCKADDR_STRLEN);</div>
<div> </div><div>- ngx_log_debug4(NGX_LOG_DEBUG_MAIL, c->log, 0,</div><div>- "name was resolved to %ud.%ud.%ud.%ud",</div><div>- (ntohl(addr) >> 24) & 0xff,</div>
<div>- (ntohl(addr) >> 16) & 0xff,</div><div>- (ntohl(addr) >> 8) & 0xff,</div><div>- ntohl(addr) & 0xff);</div><div>+ ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,</div>
<div>+ "name was resolved to %s", text);</div><div> </div><div>- if (addr == sin->sin_addr.s_addr) {</div><div>- goto found;</div><div>+ if (addr.family != ctx->addrs[i].family) {</div>
<div>+ continue;</div><div>+ }</div><div>+</div><div>+ switch (addr.family) {</div><div>+</div><div>+ case AF_INET:</div><div>+ if (addr.u.v4 == ctx->addrs[i].u.v4) {</div>
<div>+ goto found;</div><div>+ }</div><div>+ break;</div><div>+</div><div>+#if (NGX_HAVE_INET6)</div><div>+ case AF_INET6:</div><div>+ if (!ngx_memcmp(&addr.u.v6, &ctx->addrs[i].u.v6, sizeof(addr.u.v6))) {</div>
<div>+ goto found;</div><div>+ }</div><div>+ break;</div><div>+#endif</div><div> }</div><div> }</div><div> </div><div>-- </div><div>1.7.0.4</div><div><br>
</div></div></div>