Welcome! Log In Create A New Profile

Advanced

IPv6 support in resolver

ToSHiC
June 18, 2013 10:25AM
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@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
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

IPv6 support in resolver

ToSHiC 1236 June 18, 2013 10:25AM

Re: IPv6 support in resolver

Maxim Dounin 734 June 18, 2013 10:25AM

Re: IPv6 support in resolver

ToSHiC 479 July 10, 2013 01:18PM

Re: IPv6 support in resolver

ToSHiC 506 July 10, 2013 01:18PM

Re: IPv6 support in resolver

ToSHiC 508 July 10, 2013 01:26PM

Re: IPv6 support in resolver

ToSHiC 557 July 10, 2013 01:30PM

Re: IPv6 support in resolver

ToSHiC 611 July 10, 2013 01:32PM

Re: IPv6 support in resolver

ToSHiC 598 July 10, 2013 01:34PM

Re: IPv6 support in resolver

Maxim Konovalov 489 July 15, 2013 09:04AM

Re: IPv6 support in resolver

Maxim Dounin 553 October 30, 2013 09:58AM

Re: IPv6 support in resolver

Ruslan Ermilov 556 November 11, 2013 11:24PM

Re: IPv6 support in resolver

Ruslan Ermilov 462 December 18, 2013 07:50AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 133
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready