IPv6 support in resolver
ToSHiC
toshic.toshic at gmail.com
Wed Jul 10 17:24:03 UTC 2013
commit 8670b164784032b2911b3c34ac31ef52ddba5b60
Author: Anton Kortunov <toshic.toshic at gmail.com>
Date: Wed Jul 10 19:53:06 2013 +0400
IPv6 support in resolver for forward requests
To resolve name into IPv6 address use NGX_RESOLVE_AAAA,
NGX_RESOLVE_A_AAAA or NGX_RESOLVE_AAAA_A record type instead of
NGX_RESOLVE_A
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index d59d0c4..567368b 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -76,7 +76,7 @@ static void ngx_resolver_process_ptr(ngx_resolver_t *r,
u_char *buf, size_t n,
static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
ngx_str_t *name, uint32_t hash);
static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r,
- in_addr_t addr);
+ ngx_ipaddr_t addr, uint32_t hash);
static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name,
@@ -88,7 +88,7 @@ static void *ngx_resolver_calloc(ngx_resolver_t *r,
size_t size);
static void ngx_resolver_free(ngx_resolver_t *r, void *p);
static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
-static in_addr_t *ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src,
+static ngx_ipaddr_t *ngx_resolver_rotate(ngx_resolver_t *r, ngx_ipaddr_t
*src,
ngx_uint_t n);
static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t
len);
@@ -270,13 +270,27 @@ ngx_resolver_cleanup_tree(ngx_resolver_t *r,
ngx_rbtree_t *tree)
ngx_resolver_ctx_t *
ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
{
- in_addr_t addr;
+ ngx_ipaddr_t addr;
ngx_resolver_ctx_t *ctx;
if (temp) {
- addr = ngx_inet_addr(temp->name.data, temp->name.len);
+ addr.family = 0;
- if (addr != INADDR_NONE) {
+
+ addr.u.v4 = ngx_inet_addr(temp->name.data, temp->name.len);
+
+ if (addr.u.v4 != INADDR_NONE) {
+
+ addr.family = AF_INET;
+
+#if (NGX_HAVE_INET6)
+ } else if (ngx_inet6_addr(temp->name.data, temp->name.len,
addr.u.v6.s6_addr) == NGX_OK) {
+
+ addr.family = AF_INET6;
+#endif
+ }
+
+ if (addr.family) {
temp->resolver = r;
temp->state = NGX_OK;
temp->naddrs = 1;
@@ -417,7 +431,7 @@ static ngx_int_t
ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
{
uint32_t hash;
- in_addr_t addr, *addrs;
+ ngx_ipaddr_t addr, *addrs;
ngx_int_t rc;
ngx_uint_t naddrs;
ngx_resolver_ctx_t *next;
@@ -429,7 +443,11 @@ ngx_resolve_name_locked(ngx_resolver_t *r,
ngx_resolver_ctx_t *ctx)
if (rn) {
- if (rn->valid >= ngx_time()) {
+ if (rn->valid >= ngx_time()
+#if (NGX_HAVE_INET6)
+ && rn->qtype != NGX_RESOLVE_RETRY
+#endif
+ ) {
ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve
cached");
@@ -446,7 +464,6 @@ ngx_resolve_name_locked(ngx_resolver_t *r,
ngx_resolver_ctx_t *ctx)
/* NGX_RESOLVE_A answer */
if (naddrs != 1) {
- addr = 0;
addrs = ngx_resolver_rotate(r, rn->u.addrs, naddrs);
if (addrs == NULL) {
return NGX_ERROR;
@@ -506,6 +523,8 @@ ngx_resolve_name_locked(ngx_resolver_t *r,
ngx_resolver_ctx_t *ctx)
} while (ctx);
return NGX_OK;
+ } else {
+ rn->qtype = ctx->type;
}
if (rn->waiting) {
@@ -552,6 +571,7 @@ ngx_resolve_name_locked(ngx_resolver_t *r,
ngx_resolver_ctx_t *ctx)
rn->node.key = hash;
rn->nlen = (u_short) ctx->name.len;
rn->query = NULL;
+ rn->qtype = ctx->type;
ngx_rbtree_insert(&r->name_rbtree, &rn->node);
}
@@ -1130,6 +1150,9 @@ found:
switch (qtype) {
case NGX_RESOLVE_A:
+#if (NGX_HAVE_INET6)
+ case NGX_RESOLVE_AAAA:
+#endif
ngx_resolver_process_a(r, buf, n, ident, code, nan,
i + sizeof(ngx_resolver_qs_t));
@@ -1178,7 +1201,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
*buf, size_t last,
size_t len;
int32_t ttl;
uint32_t hash;
- in_addr_t addr, *addrs;
+ ngx_ipaddr_t addr, *addrs;
ngx_str_t name;
ngx_uint_t qtype, qident, naddrs, a, i, n, start;
ngx_resolver_an_t *an;
@@ -1212,12 +1235,57 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
*buf, size_t last,
goto failed;
}
- ngx_resolver_free(r, name.data);
-
if (code == 0 && nan == 0) {
+
+#if (NGX_HAVE_INET6)
+ /*
+ * If it was required dual type v4|v6 resolv create one more request
+ */
+ if (rn->qtype == NGX_RESOLVE_A_AAAA
+ || rn->qtype == NGX_RESOLVE_AAAA_A) {
+
+ ngx_queue_remove(&rn->queue);
+
+ rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
+ rn->expire = ngx_time() + r->expire;
+
+ ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
+
+ ctx = rn->waiting;
+ rn->waiting = NULL;
+
+ if (ctx) {
+ ctx->name = name;
+
+ switch (rn->qtype) {
+
+ case NGX_RESOLVE_A_AAAA:
+ ctx->type = NGX_RESOLVE_AAAA;
+ break;
+
+ case NGX_RESOLVE_AAAA_A:
+ ctx->type = NGX_RESOLVE_A;
+ break;
+ }
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
+ "restarting request for name %V, with type
%ud",
+ &name, ctx->type);
+
+ rn->qtype = NGX_RESOLVE_RETRY;
+
+ (void) ngx_resolve_name_locked(r, ctx);
+ }
+
+ return;
+ }
+#endif
+
code = 3; /* NXDOMAIN */
}
+ ngx_resolver_free(r, name.data);
+
if (code) {
next = rn->waiting;
rn->waiting = NULL;
@@ -1243,7 +1311,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
*buf, size_t last,
i = ans;
naddrs = 0;
- addr = 0;
+ addr.family = 0;
addrs = NULL;
cname = NULL;
qtype = 0;
@@ -1302,13 +1370,30 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
*buf, size_t last,
goto short_response;
}
- addr = htonl((buf[i] << 24) + (buf[i + 1] << 16)
+ addr.family = AF_INET;
+ addr.u.v4 = htonl((buf[i] << 24) + (buf[i + 1] << 16)
+ (buf[i + 2] << 8) + (buf[i + 3]));
naddrs++;
i += len;
+#if (NGX_HAVE_INET6)
+ } else if (qtype == NGX_RESOLVE_AAAA) {
+
+ i += sizeof(ngx_resolver_an_t);
+
+ if (i + len > last) {
+ goto short_response;
+ }
+
+ addr.family = AF_INET6;
+ ngx_memcpy(&addr.u.v6.s6_addr, &buf[i], 16);
+
+ naddrs++;
+
+ i += len;
+#endif
} else if (qtype == NGX_RESOLVE_CNAME) {
cname = &buf[i] + sizeof(ngx_resolver_an_t);
i += sizeof(ngx_resolver_an_t) + len;
@@ -1333,7 +1418,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
*buf, size_t last,
} else {
- addrs = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
+ addrs = ngx_resolver_alloc(r, naddrs * sizeof(ngx_ipaddr_t));
if (addrs == NULL) {
return;
}
@@ -1369,12 +1454,23 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
*buf, size_t last,
if (qtype == NGX_RESOLVE_A) {
- addrs[n++] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
+ addrs[n].family = AF_INET;
+ addrs[n++].u.v4 = htonl((buf[i] << 24) + (buf[i + 1]
<< 16)
+ (buf[i + 2] << 8) + (buf[i + 3]));
if (n == naddrs) {
break;
}
+#if (NGX_HAVE_INET6)
+ } else if (qtype == NGX_RESOLVE_AAAA) {
+
+ addrs[n].family = AF_INET6;
+ ngx_memcpy(&addrs[n++].u.v6.s6_addr, &buf[i], 16);
+
+ if (n == naddrs) {
+ break;
+ }
+#endif
}
i += len;
@@ -1383,7 +1479,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char
*buf, size_t last,
rn->u.addrs = addrs;
addrs = ngx_resolver_dup(r, rn->u.addrs,
- naddrs * sizeof(in_addr_t));
+ naddrs * sizeof(ngx_ipaddr_t));
if (addrs == NULL) {
return;
}
@@ -1838,7 +1934,20 @@ ngx_resolver_create_name_query(ngx_resolver_node_t
*rn, ngx_resolver_ctx_t *ctx)
qs = (ngx_resolver_qs_t *) p;
/* query type */
- qs->type_hi = 0; qs->type_lo = (u_char) ctx->type;
+ qs->type_hi = 0; qs->type_lo = (u_char) rn->qtype;
+
+#if (NGX_HAVE_INET6)
+ switch (rn->qtype) {
+
+ case NGX_RESOLVE_A_AAAA:
+ qs->type_lo = NGX_RESOLVE_A;
+ break;
+
+ case NGX_RESOLVE_AAAA_A:
+ qs->type_lo = NGX_RESOLVE_AAAA;
+ break;
+ }
+#endif
/* IP query class */
qs->class_hi = 0; qs->class_lo = 1;
@@ -2136,13 +2245,13 @@ ngx_resolver_dup(ngx_resolver_t *r, void *src,
size_t size)
}
-static in_addr_t *
-ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t *src, ngx_uint_t n)
+static ngx_ipaddr_t *
+ngx_resolver_rotate(ngx_resolver_t *r, ngx_ipaddr_t *src, ngx_uint_t n)
{
void *dst, *p;
ngx_uint_t j;
- dst = ngx_resolver_alloc(r, n * sizeof(in_addr_t));
+ dst = ngx_resolver_alloc(r, n * sizeof(ngx_ipaddr_t));
if (dst == NULL) {
return dst;
@@ -2151,12 +2260,12 @@ ngx_resolver_rotate(ngx_resolver_t *r, in_addr_t
*src, ngx_uint_t n)
j = ngx_random() % n;
if (j == 0) {
- ngx_memcpy(dst, src, n * sizeof(in_addr_t));
+ ngx_memcpy(dst, src, n * sizeof(ngx_ipaddr_t));
return dst;
}
- p = ngx_cpymem(dst, &src[j], (n - j) * sizeof(in_addr_t));
- ngx_memcpy(p, src, j * sizeof(in_addr_t));
+ p = ngx_cpymem(dst, &src[j], (n - j) * sizeof(ngx_ipaddr_t));
+ ngx_memcpy(p, src, j * sizeof(ngx_ipaddr_t));
return dst;
}
diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h
index 6fd81fe..d2a4606 100644
--- a/src/core/ngx_resolver.h
+++ b/src/core/ngx_resolver.h
@@ -67,10 +67,11 @@ typedef struct {
u_short qlen;
u_char *query;
+ ngx_int_t qtype;
union {
- in_addr_t addr;
- in_addr_t *addrs;
+ ngx_ipaddr_t addr;
+ ngx_ipaddr_t *addrs;
u_char *cname;
} u;
@@ -130,8 +131,8 @@ struct ngx_resolver_ctx_s {
ngx_str_t name;
ngx_uint_t naddrs;
- in_addr_t *addrs;
- in_addr_t addr;
+ ngx_ipaddr_t *addrs;
+ ngx_ipaddr_t addr;
ngx_resolver_handler_pt handler;
void *data;
On Wed, Jul 10, 2013 at 9:17 PM, ToSHiC <toshic.toshic at gmail.com> wrote:
> commit 482bd2a0b6240a2b26409b9c7924ad01c814f293
> Author: Anton Kortunov <toshic.toshic at gmail.com>
> Date: Wed Jul 10 13:21:27 2013 +0400
>
> Added NGX_RESOLVE_* constants
>
> Module developers can decide how to resolve hosts relating to IPv6:
>
> NGX_RESOLVE_AAAA - try to resolve only to IPv6 address
> NGX_RESOLVE_AAAA_A - IPv6 is preferred (recommended by standards)
> NGX_RESOLVE_A_AAAA - IPv4 is preferred (better strategy nowadays)
>
> diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h
> index ae34ca5..6fd81fe 100644
> --- a/src/core/ngx_resolver.h
> +++ b/src/core/ngx_resolver.h
> @@ -20,6 +20,15 @@
> #define NGX_RESOLVE_TXT 16
> #define NGX_RESOLVE_DNAME 39
>
> +#if (NGX_HAVE_INET6)
> +
> +#define NGX_RESOLVE_AAAA 28
> +#define NGX_RESOLVE_A_AAAA 1000
> +#define NGX_RESOLVE_AAAA_A 1001
> +#define NGX_RESOLVE_RETRY 1002
> +
> +#endif
> +
> #define NGX_RESOLVE_FORMERR 1
> #define NGX_RESOLVE_SERVFAIL 2
> #define NGX_RESOLVE_NXDOMAIN 3
>
>
>
> On Wed, Jul 10, 2013 at 9:17 PM, ToSHiC <toshic.toshic at gmail.com> wrote:
>
>> Hello,
>>
>> I've split this big patch into several small patches, taking into account
>> your comments. I'll send each part in separate email. Here is the first one.
>>
>> commit 597d09e7ae9247c5466b18aa2ef3f5892e61b708
>> Author: Anton Kortunov <toshic.toshic at gmail.com>
>> Date: Wed Jul 10 13:14:52 2013 +0400
>>
>> Added new structure ngx_ipaddr_t
>>
>> This structure contains family field
>> and the union of ipv4/ipv6 structures in_addr_t and in6_addr.
>>
>> diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h
>> index 6a5a368..077ed34 100644
>> --- a/src/core/ngx_inet.h
>> +++ b/src/core/ngx_inet.h
>> @@ -68,6 +68,16 @@ typedef struct {
>>
>>
>> typedef struct {
>> + ngx_uint_t family;
>> + union {
>> + in_addr_t v4;
>> +#if (NGX_HAVE_INET6)
>> + struct in6_addr v6;
>> +#endif
>> + } u;
>> +} ngx_ipaddr_t;
>> +
>> +typedef struct {
>> struct sockaddr *sockaddr;
>> socklen_t socklen;
>> ngx_str_t name;
>>
>>
>>
>> On Mon, Jun 17, 2013 at 7:30 PM, Maxim Dounin <mdounin at mdounin.ru> wrote:
>>
>>> Hello!
>>>
>>> On Fri, Jun 14, 2013 at 09:44:46PM +0400, ToSHiC wrote:
>>>
>>> > Hello,
>>> >
>>> > We needed this feature in our company, I found that it is in
>>> milestones of
>>> > version 1.5 but doesn't exist yet. So I've implemented it based in 1.3
>>> code
>>> > and merged in current 1.5 code. When I wrote this code I mostly cared
>>> about
>>> > minimum intrusion into other parts of nginx.
>>> >
>>> > IPv6 fallback logic is not a straightforward implementation of
>>> suggested by
>>> > RFC. RFC states that IPv6 resolving have priority over IPv4, and it's
>>> not
>>> > very good for Internet we have currently. With this patch you can
>>> specify
>>> > priority, and in upstream and mail modules I've set IPv4 as preferred
>>> > address family.
>>> >
>>> > Patch is pretty big and I hope it'll not break mailing list or mail
>>> clients.
>>>
>>> You may want to try to split the patch into smaller patches to
>>> simplify review. See also some hints here:
>>>
>>> http://nginx.org/en/docs/contributing_changes.html
>>>
>>> Some quick comments below.
>>>
>>> [...]
>>>
>>> > - addr = ntohl(ctx->addr);
>>> > +failed:
>>> > +
>>> > + //addr = ntohl(ctx->addr);
>>> > + inet_ntop(ctx->addr.family, &ctx->addr.u, text,
>>> > NGX_SOCKADDR_STRLEN);
>>> >
>>> > ngx_log_error(NGX_LOG_ALERT, r->log, 0,
>>> > - "could not cancel %ud.%ud.%ud.%ud resolving",
>>> > - (addr >> 24) & 0xff, (addr >> 16) & 0xff,
>>> > - (addr >> 8) & 0xff, addr & 0xff);
>>> > + "could not cancel %s resolving", text);
>>>
>>> 1. Don't use inet_ntop(), there is ngx_sock_ntop() instead.
>>>
>>> 2. Don't use C++ style ("//") comments.
>>>
>>> 3. If some data is only needed for debug logging, keep relevant
>>> calculations under #if (NGX_DEBUG).
>>>
>>> [...]
>>>
>>> > @@ -334,6 +362,7 @@
>>> > ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
>>> > peers->peer[i].current_weight = 0;
>>> > peers->peer[i].max_fails = 1;
>>> > peers->peer[i].fail_timeout = 10;
>>> > +
>>> > }
>>> > }
>>> >
>>>
>>> Please avoid unrelated changes.
>>>
>>> [...]
>>>
>>> --
>>> Maxim Dounin
>>> http://nginx.org/en/donation.html
>>>
>>> _______________________________________________
>>> nginx-devel mailing list
>>> nginx-devel at nginx.org
>>> http://mailman.nginx.org/mailman/listinfo/nginx-devel
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.nginx.org/pipermail/nginx-devel/attachments/20130710/6ea6da6c/attachment-0001.html>
More information about the nginx-devel
mailing list