summaryrefslogtreecommitdiffstats
path: root/usr.sbin/nginx/src/core/ngx_resolver.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/nginx/src/core/ngx_resolver.c')
-rw-r--r--usr.sbin/nginx/src/core/ngx_resolver.c1335
1 files changed, 1065 insertions, 270 deletions
diff --git a/usr.sbin/nginx/src/core/ngx_resolver.c b/usr.sbin/nginx/src/core/ngx_resolver.c
index d59d0c47162..645738ce531 100644
--- a/usr.sbin/nginx/src/core/ngx_resolver.c
+++ b/usr.sbin/nginx/src/core/ngx_resolver.c
@@ -26,7 +26,7 @@ typedef struct {
u_char nns_lo;
u_char nar_hi;
u_char nar_lo;
-} ngx_resolver_query_t;
+} ngx_resolver_hdr_t;
typedef struct {
@@ -70,7 +70,8 @@ static void ngx_resolver_read_response(ngx_event_t *rev);
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);
+ ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
+ ngx_uint_t nan, ngx_uint_t ans);
static 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,
@@ -88,10 +89,17 @@ 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,
- ngx_uint_t n);
+static ngx_addr_t *ngx_resolver_export(ngx_resolver_t *r,
+ ngx_resolver_node_t *rn, ngx_uint_t rotate);
static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len);
+#if (NGX_HAVE_INET6)
+static void ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
+static ngx_resolver_node_t *ngx_resolver_lookup_addr6(ngx_resolver_t *r,
+ struct in6_addr *addr, uint32_t hash);
+#endif
+
ngx_resolver_t *
ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
@@ -134,6 +142,17 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
ngx_queue_init(&r->name_expire_queue);
ngx_queue_init(&r->addr_expire_queue);
+#if (NGX_HAVE_INET6)
+ r->ipv6 = 1;
+
+ ngx_rbtree_init(&r->addr6_rbtree, &r->addr6_sentinel,
+ ngx_resolver_rbtree_insert_addr6_value);
+
+ ngx_queue_init(&r->addr6_resend_queue);
+
+ ngx_queue_init(&r->addr6_expire_queue);
+#endif
+
r->event->handler = ngx_resolver_resend_handler;
r->event->data = r;
r->event->log = &cf->cycle->new_log;
@@ -171,6 +190,25 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
continue;
}
+#if (NGX_HAVE_INET6)
+ if (ngx_strncmp(names[i].data, "ipv6=", 5) == 0) {
+
+ if (ngx_strcmp(&names[i].data[5], "on") == 0) {
+ r->ipv6 = 1;
+
+ } else if (ngx_strcmp(&names[i].data[5], "off") == 0) {
+ r->ipv6 = 0;
+
+ } else {
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+ "invalid parameter: %V", &names[i]);
+ return NULL;
+ }
+
+ continue;
+ }
+#endif
+
ngx_memzero(&u, sizeof(ngx_url_t));
u.url = names[i];
@@ -220,6 +258,10 @@ ngx_resolver_cleanup(void *data)
ngx_resolver_cleanup_tree(r, &r->addr_rbtree);
+#if (NGX_HAVE_INET6)
+ ngx_resolver_cleanup_tree(r, &r->addr6_rbtree);
+#endif
+
if (r->event) {
ngx_free(r->event);
}
@@ -281,7 +323,11 @@ ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
temp->state = NGX_OK;
temp->naddrs = 1;
temp->addrs = &temp->addr;
- temp->addr = addr;
+ temp->addr.sockaddr = (struct sockaddr *) &temp->sin;
+ temp->addr.socklen = sizeof(struct sockaddr_in);
+ ngx_memzero(&temp->sin, sizeof(struct sockaddr_in));
+ temp->sin.sin_family = AF_INET;
+ temp->sin.sin_addr.s_addr = addr;
temp->quick = 1;
return temp;
@@ -310,6 +356,10 @@ ngx_resolve_name(ngx_resolver_ctx_t *ctx)
r = ctx->resolver;
+ if (ctx->name.len > 0 && ctx->name.data[ctx->name.len - 1] == '.') {
+ ctx->name.len--;
+ }
+
ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
"resolve: \"%V\"", &ctx->name);
@@ -411,18 +461,18 @@ done:
}
-/* NGX_RESOLVE_A only */
-
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_int_t rc;
ngx_uint_t naddrs;
+ ngx_addr_t *addrs;
ngx_resolver_ctx_t *next;
ngx_resolver_node_t *rn;
+ ngx_strlow(ctx->name.data, ctx->name.data, ctx->name.len);
+
hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
@@ -439,22 +489,21 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
- naddrs = rn->naddrs;
+ naddrs = (rn->naddrs == (u_short) -1) ? 0 : rn->naddrs;
+#if (NGX_HAVE_INET6)
+ naddrs += (rn->naddrs6 == (u_short) -1) ? 0 : rn->naddrs6;
+#endif
if (naddrs) {
- /* NGX_RESOLVE_A answer */
+ if (naddrs == 1 && rn->naddrs == 1) {
+ addrs = NULL;
- if (naddrs != 1) {
- addr = 0;
- addrs = ngx_resolver_rotate(r, rn->u.addrs, naddrs);
+ } else {
+ addrs = ngx_resolver_export(r, rn, 1);
if (addrs == NULL) {
return NGX_ERROR;
}
-
- } else {
- addr = rn->u.addr;
- addrs = NULL;
}
ctx->next = rn->waiting;
@@ -465,8 +514,19 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
do {
ctx->state = NGX_OK;
ctx->naddrs = naddrs;
- ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs;
- ctx->addr = addr;
+
+ if (addrs == NULL) {
+ ctx->addrs = &ctx->addr;
+ ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
+ ctx->addr.socklen = sizeof(struct sockaddr_in);
+ ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
+ ctx->sin.sin_family = AF_INET;
+ ctx->sin.sin_addr.s_addr = rn->u.addr;
+
+ } else {
+ ctx->addrs = addrs;
+ }
+
next = ctx->next;
ctx->handler(ctx);
@@ -474,7 +534,8 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ctx = next;
} while (ctx);
- if (addrs) {
+ if (addrs != NULL) {
+ ngx_resolver_free(r, addrs->sockaddr);
ngx_resolver_free(r, addrs);
}
@@ -524,16 +585,25 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
if (rn->query) {
ngx_resolver_free_locked(r, rn->query);
rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
}
if (rn->cnlen) {
ngx_resolver_free_locked(r, rn->u.cname);
}
- if (rn->naddrs > 1) {
+ if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
ngx_resolver_free_locked(r, rn->u.addrs);
}
+#if (NGX_HAVE_INET6)
+ if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
+ ngx_resolver_free_locked(r, rn->u6.addrs6);
+ }
+#endif
+
/* unlock alloc mutex */
} else {
@@ -552,6 +622,9 @@ 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;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
ngx_rbtree_insert(&r->name_rbtree, &rn->node);
}
@@ -575,6 +648,11 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
return NGX_OK;
}
+ rn->naddrs = (u_short) -1;
+#if (NGX_HAVE_INET6)
+ rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0;
+#endif
+
if (ngx_resolver_send_query(r, rn) != NGX_OK) {
goto failed;
}
@@ -601,9 +679,10 @@ ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
ngx_queue_insert_head(&r->name_resend_queue, &rn->queue);
+ rn->code = 0;
rn->cnlen = 0;
- rn->naddrs = 0;
rn->valid = 0;
+ rn->ttl = NGX_MAX_UINT32_VALUE;
rn->waiting = ctx;
ctx->state = NGX_AGAIN;
@@ -630,16 +709,57 @@ ngx_int_t
ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
{
u_char *name;
+ in_addr_t addr;
+ ngx_queue_t *resend_queue, *expire_queue;
+ ngx_rbtree_t *tree;
ngx_resolver_t *r;
+ struct sockaddr_in *sin;
ngx_resolver_node_t *rn;
+#if (NGX_HAVE_INET6)
+ uint32_t hash;
+ struct sockaddr_in6 *sin6;
+#endif
+
+#if (NGX_SUPPRESS_WARN)
+ addr = 0;
+#if (NGX_HAVE_INET6)
+ hash = 0;
+ sin6 = NULL;
+#endif
+#endif
r = ctx->resolver;
- ctx->addr = ntohl(ctx->addr);
+ switch (ctx->addr.sockaddr->sa_family) {
- /* lock addr mutex */
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
+ hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16);
+
+ /* lock addr mutex */
+
+ rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash);
+
+ tree = &r->addr6_rbtree;
+ resend_queue = &r->addr6_resend_queue;
+ expire_queue = &r->addr6_expire_queue;
+
+ break;
+#endif
+
+ default: /* AF_INET */
+ sin = (struct sockaddr_in *) ctx->addr.sockaddr;
+ addr = ntohl(sin->sin_addr.s_addr);
- rn = ngx_resolver_lookup_addr(r, ctx->addr);
+ /* lock addr mutex */
+
+ rn = ngx_resolver_lookup_addr(r, addr);
+
+ tree = &r->addr_rbtree;
+ resend_queue = &r->addr_resend_queue;
+ expire_queue = &r->addr_expire_queue;
+ }
if (rn) {
@@ -651,7 +771,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
rn->expire = ngx_time() + r->expire;
- ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue);
+ ngx_queue_insert_head(expire_queue, &rn->queue);
name = ngx_resolver_dup(r, rn->name, rn->nlen);
if (name == NULL) {
@@ -687,6 +807,9 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
ngx_resolver_free(r, rn->query);
rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
} else {
rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
@@ -694,16 +817,36 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
goto failed;
}
- rn->node.key = ctx->addr;
+ switch (ctx->addr.sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ rn->addr6 = sin6->sin6_addr;
+ rn->node.key = hash;
+ break;
+#endif
+
+ default: /* AF_INET */
+ rn->node.key = addr;
+ }
+
rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
- ngx_rbtree_insert(&r->addr_rbtree, &rn->node);
+ ngx_rbtree_insert(tree, &rn->node);
}
if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) {
goto failed;
}
+ rn->naddrs = (u_short) -1;
+#if (NGX_HAVE_INET6)
+ rn->naddrs6 = (u_short) -1;
+#endif
+
if (ngx_resolver_send_query(r, rn) != NGX_OK) {
goto failed;
}
@@ -720,19 +863,20 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
ngx_add_timer(ctx->event, ctx->timeout);
- if (ngx_queue_empty(&r->addr_resend_queue)) {
+ if (ngx_queue_empty(resend_queue)) {
ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
}
rn->expire = ngx_time() + r->resend_timeout;
- ngx_queue_insert_head(&r->addr_resend_queue, &rn->queue);
+ ngx_queue_insert_head(resend_queue, &rn->queue);
+ rn->code = 0;
rn->cnlen = 0;
- rn->naddrs = 0;
rn->name = NULL;
rn->nlen = 0;
rn->valid = 0;
+ rn->ttl = NGX_MAX_UINT32_VALUE;
rn->waiting = ctx;
/* unlock addr mutex */
@@ -744,7 +888,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
failed:
if (rn) {
- ngx_rbtree_delete(&r->addr_rbtree, &rn->node);
+ ngx_rbtree_delete(tree, &rn->node);
if (rn->query) {
ngx_resolver_free(r, rn->query);
@@ -769,12 +913,33 @@ void
ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
{
in_addr_t addr;
+ ngx_queue_t *expire_queue;
+ ngx_rbtree_t *tree;
ngx_resolver_t *r;
ngx_resolver_ctx_t *w, **p;
+ struct sockaddr_in *sin;
ngx_resolver_node_t *rn;
+#if (NGX_HAVE_INET6)
+ uint32_t hash;
+ struct sockaddr_in6 *sin6;
+#endif
r = ctx->resolver;
+ switch (ctx->addr.sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ tree = &r->addr6_rbtree;
+ expire_queue = &r->addr6_expire_queue;
+ break;
+#endif
+
+ default: /* AF_INET */
+ tree = &r->addr_rbtree;
+ expire_queue = &r->addr_expire_queue;
+ }
+
ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
"resolve addr done: %i", ctx->state);
@@ -786,7 +951,21 @@ 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);
+ switch (ctx->addr.sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
+ hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16);
+ rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash);
+ break;
+#endif
+
+ default: /* AF_INET */
+ sin = (struct sockaddr_in *) ctx->addr.sockaddr;
+ addr = ntohl(sin->sin_addr.s_addr);
+ rn = ngx_resolver_lookup_addr(r, addr);
+ }
if (rn) {
p = &rn->waiting;
@@ -804,17 +983,22 @@ ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
}
}
- addr = ntohl(ctx->addr);
+ {
+ u_char text[NGX_SOCKADDR_STRLEN];
+ ngx_str_t addrtext;
- 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);
+ addrtext.data = text;
+ addrtext.len = ngx_sock_ntop(ctx->addr.sockaddr, ctx->addr.socklen,
+ text, NGX_SOCKADDR_STRLEN, 0);
+
+ ngx_log_error(NGX_LOG_ALERT, r->log, 0,
+ "could not cancel %V resolving", &addrtext);
+ }
}
done:
- ngx_resolver_expire(r, &r->addr_rbtree, &r->addr_expire_queue);
+ ngx_resolver_expire(r, tree, expire_queue);
/* unlock addr mutex */
@@ -896,16 +1080,33 @@ ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn)
uc->connection->read->resolver = 1;
}
- n = ngx_send(uc->connection, rn->query, rn->qlen);
+ if (rn->naddrs == (u_short) -1) {
+ n = ngx_send(uc->connection, rn->query, rn->qlen);
- if (n == -1) {
- return NGX_ERROR;
+ if (n == -1) {
+ return NGX_ERROR;
+ }
+
+ if ((size_t) n != (size_t) rn->qlen) {
+ ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete");
+ return NGX_ERROR;
+ }
}
- if ((size_t) n != (size_t) rn->qlen) {
- ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete");
- return NGX_ERROR;
+#if (NGX_HAVE_INET6)
+ if (rn->query6 && rn->naddrs6 == (u_short) -1) {
+ n = ngx_send(uc->connection, rn->query6, rn->qlen);
+
+ if (n == -1) {
+ return NGX_ERROR;
+ }
+
+ if ((size_t) n != (size_t) rn->qlen) {
+ ngx_log_error(NGX_LOG_CRIT, &uc->log, 0, "send() incomplete");
+ return NGX_ERROR;
+ }
}
+#endif
return NGX_OK;
}
@@ -915,6 +1116,9 @@ static void
ngx_resolver_resend_handler(ngx_event_t *ev)
{
time_t timer, atimer, ntimer;
+#if (NGX_HAVE_INET6)
+ time_t a6timer;
+#endif
ngx_resolver_t *r;
r = ev->data;
@@ -934,16 +1138,36 @@ ngx_resolver_resend_handler(ngx_event_t *ev)
/* unlock addr mutex */
- if (ntimer == 0) {
+#if (NGX_HAVE_INET6)
+
+ /* lock addr6 mutex */
+
+ a6timer = ngx_resolver_resend(r, &r->addr6_rbtree, &r->addr6_resend_queue);
+
+ /* unlock addr6 mutex */
+
+#endif
+
+ timer = ntimer;
+
+ if (timer == 0) {
timer = atimer;
- } else if (atimer == 0) {
- timer = ntimer;
+ } else if (atimer) {
+ timer = ngx_min(timer, atimer);
+ }
- } else {
- timer = (atimer < ntimer) ? atimer : ntimer;
+#if (NGX_HAVE_INET6)
+
+ if (timer == 0) {
+ timer = a6timer;
+
+ } else if (a6timer) {
+ timer = ngx_min(timer, a6timer);
}
+#endif
+
if (timer) {
ngx_add_timer(r->event, (ngx_msec_t) (timer * 1000));
}
@@ -1021,39 +1245,42 @@ ngx_resolver_read_response(ngx_event_t *rev)
static void
ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n)
{
- char *err;
- size_t len;
- ngx_uint_t i, times, ident, qident, flags, code, nqs, nan,
- qtype, qclass;
- ngx_queue_t *q;
- ngx_resolver_qs_t *qs;
- ngx_resolver_node_t *rn;
- ngx_resolver_query_t *query;
-
- if ((size_t) n < sizeof(ngx_resolver_query_t)) {
+ char *err;
+ ngx_uint_t i, times, ident, qident, flags, code, nqs, nan,
+ qtype, qclass;
+#if (NGX_HAVE_INET6)
+ ngx_uint_t qident6;
+#endif
+ ngx_queue_t *q;
+ ngx_resolver_qs_t *qs;
+ ngx_resolver_hdr_t *response;
+ ngx_resolver_node_t *rn;
+
+ if (n < sizeof(ngx_resolver_hdr_t)) {
goto short_response;
}
- query = (ngx_resolver_query_t *) buf;
+ response = (ngx_resolver_hdr_t *) buf;
- ident = (query->ident_hi << 8) + query->ident_lo;
- flags = (query->flags_hi << 8) + query->flags_lo;
- nqs = (query->nqs_hi << 8) + query->nqs_lo;
- nan = (query->nan_hi << 8) + query->nan_lo;
+ ident = (response->ident_hi << 8) + response->ident_lo;
+ flags = (response->flags_hi << 8) + response->flags_lo;
+ nqs = (response->nqs_hi << 8) + response->nqs_lo;
+ nan = (response->nan_hi << 8) + response->nan_lo;
ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0,
"resolver DNS response %ui fl:%04Xui %ui/%ui/%ud/%ud",
ident, flags, nqs, nan,
- (query->nns_hi << 8) + query->nns_lo,
- (query->nar_hi << 8) + query->nar_lo);
+ (response->nns_hi << 8) + response->nns_lo,
+ (response->nar_hi << 8) + response->nar_lo);
- if (!(flags & 0x8000)) {
+ /* response to a standard query */
+ if ((flags & 0xf870) != 0x8000) {
ngx_log_error(r->log_level, r->log, 0,
"invalid DNS response %ui fl:%04Xui", ident, flags);
return;
}
- code = flags & 0x7f;
+ code = flags & 0xf;
if (code == NGX_RESOLVE_FORMERR) {
@@ -1067,12 +1294,18 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n)
qident = (rn->query[0] << 8) + rn->query[1];
if (qident == ident) {
- ngx_log_error(r->log_level, r->log, 0,
- "DNS error (%ui: %s), query id:%ui, name:\"%*s\"",
- code, ngx_resolver_strerror(code), ident,
- rn->nlen, rn->name);
- return;
+ goto dns_error_name;
+ }
+
+#if (NGX_HAVE_INET6)
+ if (rn->query6) {
+ qident6 = (rn->query6[0] << 8) + rn->query6[1];
+
+ if (qident6 == ident) {
+ goto dns_error_name;
+ }
}
+#endif
}
goto dns_error;
@@ -1087,22 +1320,21 @@ ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n)
goto done;
}
- i = sizeof(ngx_resolver_query_t);
+ i = sizeof(ngx_resolver_hdr_t);
while (i < (ngx_uint_t) n) {
if (buf[i] == '\0') {
goto found;
}
- len = buf[i];
- i += 1 + len;
+ i += 1 + buf[i];
}
goto short_response;
found:
- if (i++ == 0) {
+ if (i++ == sizeof(ngx_resolver_hdr_t)) {
err = "zero-length domain name in DNS response";
goto done;
}
@@ -1130,8 +1362,11 @@ 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,
+ ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan,
i + sizeof(ngx_resolver_qs_t));
break;
@@ -1152,7 +1387,7 @@ found:
short_response:
- err = "short dns response";
+ err = "short DNS response";
done:
@@ -1160,6 +1395,14 @@ done:
return;
+dns_error_name:
+
+ ngx_log_error(r->log_level, r->log, 0,
+ "DNS error (%ui: %s), query id:%ui, name:\"%*s\"",
+ code, ngx_resolver_strerror(code), ident,
+ rn->nlen, rn->name);
+ return;
+
dns_error:
ngx_log_error(r->log_level, r->log, 0,
@@ -1171,21 +1414,29 @@ dns_error:
static void
ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
- ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans)
+ ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
+ ngx_uint_t nan, ngx_uint_t ans)
{
char *err;
u_char *cname;
size_t len;
int32_t ttl;
uint32_t hash;
- in_addr_t addr, *addrs;
+ in_addr_t *addr;
ngx_str_t name;
- ngx_uint_t qtype, qident, naddrs, a, i, n, start;
+ ngx_addr_t *addrs;
+ ngx_uint_t type, class, qident, naddrs, a, i, n, start;
+#if (NGX_HAVE_INET6)
+ struct in6_addr *addr6;
+#endif
ngx_resolver_an_t *an;
ngx_resolver_ctx_t *ctx, *next;
ngx_resolver_node_t *rn;
- if (ngx_resolver_copy(r, &name, buf, &buf[12], &buf[last]) != NGX_OK) {
+ if (ngx_resolver_copy(r, &name, buf,
+ buf + sizeof(ngx_resolver_hdr_t), buf + last)
+ != NGX_OK)
+ {
return;
}
@@ -1197,28 +1448,113 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
rn = ngx_resolver_lookup_name(r, &name, hash);
- if (rn == NULL || rn->query == NULL) {
+ if (rn == NULL) {
ngx_log_error(r->log_level, r->log, 0,
"unexpected response for %V", &name);
+ ngx_resolver_free(r, name.data);
goto failed;
}
- qident = (rn->query[0] << 8) + rn->query[1];
+ switch (qtype) {
+
+#if (NGX_HAVE_INET6)
+ case NGX_RESOLVE_AAAA:
+
+ if (rn->query6 == NULL || rn->naddrs6 != (u_short) -1) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected response for %V", &name);
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ rn->naddrs6 = 0;
+ qident = (rn->query6[0] << 8) + rn->query6[1];
+
+ break;
+#endif
+
+ default: /* NGX_RESOLVE_A */
+
+ if (rn->query == NULL || rn->naddrs != (u_short) -1) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected response for %V", &name);
+ ngx_resolver_free(r, name.data);
+ goto failed;
+ }
+
+ rn->naddrs = 0;
+ qident = (rn->query[0] << 8) + rn->query[1];
+ }
if (ident != qident) {
ngx_log_error(r->log_level, r->log, 0,
"wrong ident %ui response for %V, expect %ui",
ident, &name, qident);
+ ngx_resolver_free(r, name.data);
goto failed;
}
ngx_resolver_free(r, name.data);
+ if (code == 0 && rn->code) {
+ code = rn->code;
+ }
+
if (code == 0 && nan == 0) {
- code = 3; /* NXDOMAIN */
+
+#if (NGX_HAVE_INET6)
+ switch (qtype) {
+
+ case NGX_RESOLVE_AAAA:
+
+ if (rn->naddrs == (u_short) -1) {
+ goto next;
+ }
+
+ if (rn->naddrs) {
+ goto export;
+ }
+
+ break;
+
+ default: /* NGX_RESOLVE_A */
+
+ if (rn->naddrs6 == (u_short) -1) {
+ goto next;
+ }
+
+ if (rn->naddrs6) {
+ goto export;
+ }
+ }
+#endif
+
+ code = NGX_RESOLVE_NXDOMAIN;
}
if (code) {
+
+#if (NGX_HAVE_INET6)
+ switch (qtype) {
+
+ case NGX_RESOLVE_AAAA:
+
+ if (rn->naddrs == (u_short) -1) {
+ rn->code = (u_char) code;
+ goto next;
+ }
+
+ break;
+
+ default: /* NGX_RESOLVE_A */
+
+ if (rn->naddrs6 == (u_short) -1) {
+ rn->code = (u_char) code;
+ goto next;
+ }
+ }
+#endif
+
next = rn->waiting;
rn->waiting = NULL;
@@ -1231,11 +1567,11 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
/* unlock name mutex */
while (next) {
- ctx = next;
- ctx->state = code;
- next = ctx->next;
+ ctx = next;
+ ctx->state = code;
+ next = ctx->next;
- ctx->handler(ctx);
+ ctx->handler(ctx);
}
return;
@@ -1243,11 +1579,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
i = ans;
naddrs = 0;
- addr = 0;
- addrs = NULL;
cname = NULL;
- qtype = 0;
- ttl = 0;
for (a = 0; a < nan; a++) {
@@ -1273,7 +1605,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
test_length:
if (i - start < 2) {
- err = "invalid name in dns response";
+ err = "invalid name in DNS response";
goto invalid;
}
@@ -1285,115 +1617,239 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
an = (ngx_resolver_an_t *) &buf[i];
- qtype = (an->type_hi << 8) + an->type_lo;
+ type = (an->type_hi << 8) + an->type_lo;
+ class = (an->class_hi << 8) + an->class_lo;
len = (an->len_hi << 8) + an->len_lo;
ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
+ (an->ttl[2] << 8) + (an->ttl[3]);
+ if (class != 1) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected RR class %ui", class);
+ goto failed;
+ }
+
if (ttl < 0) {
ttl = 0;
}
- if (qtype == NGX_RESOLVE_A) {
+ rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl);
- i += sizeof(ngx_resolver_an_t);
+ i += sizeof(ngx_resolver_an_t);
+
+ switch (type) {
+
+ case NGX_RESOLVE_A:
+
+ if (qtype != NGX_RESOLVE_A) {
+ err = "unexpected A record in DNS response";
+ goto invalid;
+ }
- if (i + len > last) {
+ if (len != 4) {
+ err = "invalid A record in DNS response";
+ goto invalid;
+ }
+
+ if (i + 4 > last) {
goto short_response;
}
- addr = htonl((buf[i] << 24) + (buf[i + 1] << 16)
- + (buf[i + 2] << 8) + (buf[i + 3]));
+ naddrs++;
+
+ break;
+
+#if (NGX_HAVE_INET6)
+ case NGX_RESOLVE_AAAA:
+
+ if (qtype != NGX_RESOLVE_AAAA) {
+ err = "unexpected AAAA record in DNS response";
+ goto invalid;
+ }
+
+ if (len != 16) {
+ err = "invalid AAAA record in DNS response";
+ goto invalid;
+ }
+
+ if (i + 16 > last) {
+ goto short_response;
+ }
naddrs++;
- i += len;
+ break;
+#endif
- } else if (qtype == NGX_RESOLVE_CNAME) {
- cname = &buf[i] + sizeof(ngx_resolver_an_t);
- i += sizeof(ngx_resolver_an_t) + len;
+ case NGX_RESOLVE_CNAME:
- } else if (qtype == NGX_RESOLVE_DNAME) {
- i += sizeof(ngx_resolver_an_t) + len;
+ cname = &buf[i];
+
+ break;
+
+ case NGX_RESOLVE_DNAME:
+
+ break;
+
+ default:
- } else {
ngx_log_error(r->log_level, r->log, 0,
- "unexpected qtype %ui", qtype);
+ "unexpected RR type %ui", type);
}
+
+ i += len;
}
ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
- "resolver naddrs:%ui cname:%p ttl:%d",
- naddrs, cname, ttl);
+ "resolver naddrs:%ui cname:%p ttl:%uD",
+ naddrs, cname, rn->ttl);
if (naddrs) {
- if (naddrs == 1) {
- rn->u.addr = addr;
+ switch (qtype) {
- } else {
+#if (NGX_HAVE_INET6)
+ case NGX_RESOLVE_AAAA:
- addrs = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
- if (addrs == NULL) {
- return;
+ if (naddrs == 1) {
+ addr6 = &rn->u6.addr6;
+ rn->naddrs6 = 1;
+
+ } else {
+ addr6 = ngx_resolver_alloc(r, naddrs * sizeof(struct in6_addr));
+ if (addr6 == NULL) {
+ goto failed;
+ }
+
+ rn->u6.addrs6 = addr6;
+ rn->naddrs6 = (u_short) naddrs;
}
- n = 0;
- i = ans;
+#if (NGX_SUPPRESS_WARN)
+ addr = NULL;
+#endif
- for (a = 0; a < nan; a++) {
+ break;
+#endif
- for ( ;; ) {
+ default: /* NGX_RESOLVE_A */
- if (buf[i] & 0xc0) {
- i += 2;
- goto ok;
- }
+ if (naddrs == 1) {
+ addr = &rn->u.addr;
+ rn->naddrs = 1;
- if (buf[i] == 0) {
- i++;
- goto ok;
- }
+ } else {
+ addr = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
+ if (addr == NULL) {
+ goto failed;
+ }
+
+ rn->u.addrs = addr;
+ rn->naddrs = (u_short) naddrs;
+ }
+
+#if (NGX_HAVE_INET6 && NGX_SUPPRESS_WARN)
+ addr6 = NULL;
+#endif
+ }
- i += 1 + buf[i];
+ n = 0;
+ i = ans;
+
+ for (a = 0; a < nan; a++) {
+
+ for ( ;; ) {
+
+ if (buf[i] & 0xc0) {
+ i += 2;
+ break;
+ }
+
+ if (buf[i] == 0) {
+ i++;
+ break;
}
- ok:
+ i += 1 + buf[i];
+ }
+
+ an = (ngx_resolver_an_t *) &buf[i];
- an = (ngx_resolver_an_t *) &buf[i];
+ type = (an->type_hi << 8) + an->type_lo;
+ len = (an->len_hi << 8) + an->len_lo;
- qtype = (an->type_hi << 8) + an->type_lo;
- len = (an->len_hi << 8) + an->len_lo;
+ i += sizeof(ngx_resolver_an_t);
- i += sizeof(ngx_resolver_an_t);
+ if (type == NGX_RESOLVE_A) {
- if (qtype == NGX_RESOLVE_A) {
+ addr[n] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
+ + (buf[i + 2] << 8) + (buf[i + 3]));
- addrs[n++] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
- + (buf[i + 2] << 8) + (buf[i + 3]));
+ if (++n == naddrs) {
- if (n == naddrs) {
- break;
+#if (NGX_HAVE_INET6)
+ if (rn->naddrs6 == (u_short) -1) {
+ goto next;
}
+#endif
+
+ break;
}
+ }
+
+#if (NGX_HAVE_INET6)
+ else if (type == NGX_RESOLVE_AAAA) {
+
+ ngx_memcpy(addr6[n].s6_addr, &buf[i], 16);
+
+ if (++n == naddrs) {
+
+ if (rn->naddrs == (u_short) -1) {
+ goto next;
+ }
- i += len;
+ break;
+ }
}
+#endif
- rn->u.addrs = addrs;
+ i += len;
+ }
+ }
- addrs = ngx_resolver_dup(r, rn->u.addrs,
- naddrs * sizeof(in_addr_t));
+ if (rn->naddrs != (u_short) -1
+#if (NGX_HAVE_INET6)
+ && rn->naddrs6 != (u_short) -1
+#endif
+ && rn->naddrs
+#if (NGX_HAVE_INET6)
+ + rn->naddrs6
+#endif
+ > 0)
+ {
+
+#if (NGX_HAVE_INET6)
+ export:
+#endif
+
+ naddrs = rn->naddrs;
+#if (NGX_HAVE_INET6)
+ naddrs += rn->naddrs6;
+#endif
+
+ if (naddrs == 1 && rn->naddrs == 1) {
+ addrs = NULL;
+
+ } else {
+ addrs = ngx_resolver_export(r, rn, 0);
if (addrs == NULL) {
- return;
+ goto failed;
}
}
- rn->naddrs = (u_short) naddrs;
-
ngx_queue_remove(&rn->queue);
- rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
+ rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
rn->expire = ngx_time() + r->expire;
ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
@@ -1404,31 +1860,56 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
/* unlock name mutex */
while (next) {
- ctx = next;
- ctx->state = NGX_OK;
- ctx->naddrs = naddrs;
- ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs;
- ctx->addr = addr;
- next = ctx->next;
+ ctx = next;
+ ctx->state = NGX_OK;
+ ctx->naddrs = naddrs;
+
+ if (addrs == NULL) {
+ ctx->addrs = &ctx->addr;
+ ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
+ ctx->addr.socklen = sizeof(struct sockaddr_in);
+ ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
+ ctx->sin.sin_family = AF_INET;
+ ctx->sin.sin_addr.s_addr = rn->u.addr;
+
+ } else {
+ ctx->addrs = addrs;
+ }
- ctx->handler(ctx);
+ next = ctx->next;
+
+ ctx->handler(ctx);
}
- if (naddrs > 1) {
+ if (addrs != NULL) {
+ ngx_resolver_free(r, addrs->sockaddr);
ngx_resolver_free(r, addrs);
}
ngx_resolver_free(r, rn->query);
rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
return;
+ }
- } else if (cname) {
+ if (cname) {
/* CNAME only */
- if (ngx_resolver_copy(r, &name, buf, cname, &buf[last]) != NGX_OK) {
- return;
+ if (rn->naddrs == (u_short) -1
+#if (NGX_HAVE_INET6)
+ || rn->naddrs6 == (u_short) -1
+#endif
+ )
+ {
+ goto next;
+ }
+
+ if (ngx_resolver_copy(r, &name, buf, cname, buf + last) != NGX_OK) {
+ goto failed;
}
ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
@@ -1439,7 +1920,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
rn->cnlen = (u_short) name.len;
rn->u.cname = name.data;
- rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
+ rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
rn->expire = ngx_time() + r->expire;
ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
@@ -1455,18 +1936,22 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
ngx_resolver_free(r, rn->query);
rn->query = NULL;
+#if (NGX_HAVE_INET6)
+ rn->query6 = NULL;
+#endif
+
+ /* unlock name mutex */
return;
}
ngx_log_error(r->log_level, r->log, 0,
- "no A or CNAME types in DNS responses, unknown query type: %ui",
- qtype);
+ "no A or CNAME types in DNS response");
return;
short_response:
- err = "short dns response";
+ err = "short DNS response";
invalid:
@@ -1478,9 +1963,9 @@ invalid:
failed:
- /* unlock name mutex */
+next:
- ngx_resolver_free(r, name.data);
+ /* unlock name mutex */
return;
}
@@ -1492,47 +1977,123 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
{
char *err;
size_t len;
+ u_char text[NGX_SOCKADDR_STRLEN];
in_addr_t addr;
int32_t ttl;
- ngx_int_t digit;
+ ngx_int_t octet;
ngx_str_t name;
- ngx_uint_t i, mask, qident;
+ ngx_uint_t i, mask, qident, class;
+ ngx_queue_t *expire_queue;
+ ngx_rbtree_t *tree;
ngx_resolver_an_t *an;
ngx_resolver_ctx_t *ctx, *next;
ngx_resolver_node_t *rn;
+#if (NGX_HAVE_INET6)
+ uint32_t hash;
+ ngx_int_t digit;
+ struct in6_addr addr6;
+#endif
- if (ngx_resolver_copy(r, NULL, buf, &buf[12], &buf[n]) != NGX_OK) {
- goto invalid_in_addr_arpa;
+ if (ngx_resolver_copy(r, NULL, buf,
+ buf + sizeof(ngx_resolver_hdr_t), buf + n)
+ != NGX_OK)
+ {
+ return;
}
+ /* AF_INET */
+
addr = 0;
- i = 12;
+ i = sizeof(ngx_resolver_hdr_t);
for (mask = 0; mask < 32; mask += 8) {
len = buf[i++];
- digit = ngx_atoi(&buf[i], len);
- if (digit == NGX_ERROR || digit > 255) {
+ octet = ngx_atoi(&buf[i], len);
+ if (octet == NGX_ERROR || octet > 255) {
goto invalid_in_addr_arpa;
}
- addr += digit << mask;
+ addr += octet << mask;
i += len;
}
- if (ngx_strcmp(&buf[i], "\7in-addr\4arpa") != 0) {
- goto invalid_in_addr_arpa;
+ if (ngx_strcasecmp(&buf[i], (u_char *) "\7in-addr\4arpa") == 0) {
+ i += sizeof("\7in-addr\4arpa");
+
+ /* lock addr mutex */
+
+ rn = ngx_resolver_lookup_addr(r, addr);
+
+ tree = &r->addr_rbtree;
+ expire_queue = &r->addr_expire_queue;
+
+ addr = htonl(addr);
+ name.len = ngx_inet_ntop(AF_INET, &addr, text, NGX_SOCKADDR_STRLEN);
+ name.data = text;
+
+ goto valid;
}
- /* lock addr mutex */
+invalid_in_addr_arpa:
+
+#if (NGX_HAVE_INET6)
+
+ i = sizeof(ngx_resolver_hdr_t);
+
+ for (octet = 15; octet >= 0; octet--) {
+ if (buf[i++] != '\1') {
+ goto invalid_ip6_arpa;
+ }
+
+ digit = ngx_hextoi(&buf[i++], 1);
+ if (digit == NGX_ERROR) {
+ goto invalid_ip6_arpa;
+ }
+
+ addr6.s6_addr[octet] = (u_char) digit;
+
+ if (buf[i++] != '\1') {
+ goto invalid_ip6_arpa;
+ }
+
+ digit = ngx_hextoi(&buf[i++], 1);
+ if (digit == NGX_ERROR) {
+ goto invalid_ip6_arpa;
+ }
+
+ addr6.s6_addr[octet] += (u_char) (digit * 16);
+ }
+
+ if (ngx_strcasecmp(&buf[i], (u_char *) "\3ip6\4arpa") == 0) {
+ i += sizeof("\3ip6\4arpa");
+
+ /* lock addr mutex */
+
+ hash = ngx_crc32_short(addr6.s6_addr, 16);
+ rn = ngx_resolver_lookup_addr6(r, &addr6, hash);
+
+ tree = &r->addr6_rbtree;
+ expire_queue = &r->addr6_expire_queue;
+
+ name.len = ngx_inet6_ntop(addr6.s6_addr, text, NGX_SOCKADDR_STRLEN);
+ name.data = text;
+
+ goto valid;
+ }
- rn = ngx_resolver_lookup_addr(r, addr);
+invalid_ip6_arpa:
+#endif
+
+ ngx_log_error(r->log_level, r->log, 0,
+ "invalid in-addr.arpa or ip6.arpa name in DNS response");
+ return;
+
+valid:
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 %V", &name);
goto failed;
}
@@ -1540,14 +2101,13 @@ 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 %V, expect %ui",
+ ident, &name, qident);
goto failed;
}
if (code == 0 && nan == 0) {
- code = 3; /* NXDOMAIN */
+ code = NGX_RESOLVE_NXDOMAIN;
}
if (code) {
@@ -1556,42 +2116,49 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
ngx_queue_remove(&rn->queue);
- ngx_rbtree_delete(&r->addr_rbtree, &rn->node);
+ ngx_rbtree_delete(tree, &rn->node);
ngx_resolver_free_node(r, rn);
/* unlock addr mutex */
while (next) {
- ctx = next;
- ctx->state = code;
- next = ctx->next;
+ ctx = next;
+ ctx->state = code;
+ next = ctx->next;
- ctx->handler(ctx);
+ ctx->handler(ctx);
}
return;
}
- i += sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t);
+ i += sizeof(ngx_resolver_qs_t);
- if (i + 2 + sizeof(ngx_resolver_an_t) > (ngx_uint_t) n) {
+ if (i + 2 + sizeof(ngx_resolver_an_t) >= n) {
goto short_response;
}
- /* compression pointer to "XX.XX.XX.XX.in-addr.arpa */
+ /* compression pointer to *.arpa */
- if (buf[i] != 0xc0 || buf[i + 1] != 0x0c) {
- err = "invalid in-addr.arpa name in DNS response";
+ if (buf[i] != 0xc0 || buf[i + 1] != sizeof(ngx_resolver_hdr_t)) {
+ err = "invalid in-addr.arpa or ip6.arpa name in DNS response";
goto invalid;
}
an = (ngx_resolver_an_t *) &buf[i + 2];
+ class = (an->class_hi << 8) + an->class_lo;
len = (an->len_hi << 8) + an->len_lo;
ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
+ (an->ttl[2] << 8) + (an->ttl[3]);
+ if (class != 1) {
+ ngx_log_error(r->log_level, r->log, 0,
+ "unexpected RR class %ui", class);
+ goto failed;
+ }
+
if (ttl < 0) {
ttl = 0;
}
@@ -1599,16 +2166,16 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
"resolver qt:%ui cl:%ui len:%uz",
(an->type_hi << 8) + an->type_lo,
- (an->class_hi << 8) + an->class_lo, len);
+ class, len);
i += 2 + sizeof(ngx_resolver_an_t);
- if (i + len > (ngx_uint_t) n) {
+ if (i + len > n) {
goto short_response;
}
- if (ngx_resolver_copy(r, &name, buf, &buf[i], &buf[n]) != NGX_OK) {
- return;
+ if (ngx_resolver_copy(r, &name, buf, buf + i, buf + n) != NGX_OK) {
+ goto failed;
}
ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name);
@@ -1634,7 +2201,7 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
rn->expire = ngx_time() + r->expire;
- ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue);
+ ngx_queue_insert_head(expire_queue, &rn->queue);
next = rn->waiting;
rn->waiting = NULL;
@@ -1642,24 +2209,18 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
/* unlock addr mutex */
while (next) {
- ctx = next;
- ctx->state = NGX_OK;
- ctx->name = name;
- next = ctx->next;
+ ctx = next;
+ ctx->state = NGX_OK;
+ ctx->name = name;
+ next = ctx->next;
- ctx->handler(ctx);
+ ctx->handler(ctx);
}
ngx_resolver_free(r, name.data);
return;
-invalid_in_addr_arpa:
-
- ngx_log_error(r->log_level, r->log, 0,
- "invalid in-addr.arpa name in DNS response");
- return;
-
short_response:
err = "short DNS response";
@@ -1752,6 +2313,52 @@ ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr)
}
+#if (NGX_HAVE_INET6)
+
+static ngx_resolver_node_t *
+ngx_resolver_lookup_addr6(ngx_resolver_t *r, struct in6_addr *addr,
+ uint32_t hash)
+{
+ ngx_int_t rc;
+ ngx_rbtree_node_t *node, *sentinel;
+ ngx_resolver_node_t *rn;
+
+ node = r->addr6_rbtree.root;
+ sentinel = r->addr6_rbtree.sentinel;
+
+ while (node != sentinel) {
+
+ if (hash < node->key) {
+ node = node->left;
+ continue;
+ }
+
+ if (hash > node->key) {
+ node = node->right;
+ continue;
+ }
+
+ /* hash == node->key */
+
+ rn = (ngx_resolver_node_t *) node;
+
+ rc = ngx_memcmp(addr, &rn->addr6, 16);
+
+ if (rc == 0) {
+ return rn;
+ }
+
+ node = (rc < 0) ? node->left : node->right;
+ }
+
+ /* not found */
+
+ return NULL;
+}
+
+#endif
+
+
static void
ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
@@ -1793,20 +2400,74 @@ ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
}
+#if (NGX_HAVE_INET6)
+
+static void
+ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
+ ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
+{
+ ngx_rbtree_node_t **p;
+ ngx_resolver_node_t *rn, *rn_temp;
+
+ for ( ;; ) {
+
+ if (node->key < temp->key) {
+
+ p = &temp->left;
+
+ } else if (node->key > temp->key) {
+
+ p = &temp->right;
+
+ } else { /* node->key == temp->key */
+
+ rn = (ngx_resolver_node_t *) node;
+ rn_temp = (ngx_resolver_node_t *) temp;
+
+ p = (ngx_memcmp(&rn->addr6, &rn_temp->addr6, 16)
+ < 0) ? &temp->left : &temp->right;
+ }
+
+ if (*p == sentinel) {
+ break;
+ }
+
+ temp = *p;
+ }
+
+ *p = node;
+ node->parent = temp;
+ node->left = sentinel;
+ node->right = sentinel;
+ ngx_rbt_red(node);
+}
+
+#endif
+
+
static ngx_int_t
ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
{
- u_char *p, *s;
- size_t len, nlen;
- ngx_uint_t ident;
- ngx_resolver_qs_t *qs;
- ngx_resolver_query_t *query;
+ u_char *p, *s;
+ size_t len, nlen;
+ ngx_uint_t ident;
+#if (NGX_HAVE_INET6)
+ ngx_resolver_t *r;
+#endif
+ ngx_resolver_qs_t *qs;
+ ngx_resolver_hdr_t *query;
nlen = ctx->name.len ? (1 + ctx->name.len + 1) : 1;
- len = sizeof(ngx_resolver_query_t) + nlen + sizeof(ngx_resolver_qs_t);
+ len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t);
+#if (NGX_HAVE_INET6)
+ r = ctx->resolver;
+
+ p = ngx_resolver_alloc(ctx->resolver, r->ipv6 ? len * 2 : len);
+#else
p = ngx_resolver_alloc(ctx->resolver, len);
+#endif
if (p == NULL) {
return NGX_ERROR;
}
@@ -1814,12 +2475,18 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
rn->qlen = (u_short) len;
rn->query = p;
- query = (ngx_resolver_query_t *) p;
+#if (NGX_HAVE_INET6)
+ if (r->ipv6) {
+ rn->query6 = p + len;
+ }
+#endif
+
+ query = (ngx_resolver_hdr_t *) p;
ident = ngx_random();
ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
- "resolve: \"%V\" %i", &ctx->name, ident & 0xffff);
+ "resolve: \"%V\" A %i", &ctx->name, ident & 0xffff);
query->ident_hi = (u_char) ((ident >> 8) & 0xff);
query->ident_lo = (u_char) (ident & 0xff);
@@ -1833,14 +2500,14 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
query->nns_hi = 0; query->nns_lo = 0;
query->nar_hi = 0; query->nar_lo = 0;
- p += sizeof(ngx_resolver_query_t) + nlen;
+ p += sizeof(ngx_resolver_hdr_t) + nlen;
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 = NGX_RESOLVE_A;
- /* IP query class */
+ /* IN query class */
qs->class_hi = 0; qs->class_lo = 1;
/* convert "www.example.com" to "\3www\7example\3com\0" */
@@ -1876,24 +2543,66 @@ ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
*p = (u_char) len;
+#if (NGX_HAVE_INET6)
+ if (!r->ipv6) {
+ return NGX_OK;
+ }
+
+ p = rn->query6;
+
+ ngx_memcpy(p, rn->query, rn->qlen);
+
+ query = (ngx_resolver_hdr_t *) p;
+
+ ident = ngx_random();
+
+ ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
+ "resolve: \"%V\" AAAA %i", &ctx->name, ident & 0xffff);
+
+ query->ident_hi = (u_char) ((ident >> 8) & 0xff);
+ query->ident_lo = (u_char) (ident & 0xff);
+
+ p += sizeof(ngx_resolver_hdr_t) + nlen;
+
+ qs = (ngx_resolver_qs_t *) p;
+
+ qs->type_lo = NGX_RESOLVE_AAAA;
+#endif
+
return NGX_OK;
}
-/* AF_INET only */
-
static ngx_int_t
ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
{
- u_char *p, *d;
- size_t len;
- ngx_int_t n;
- ngx_uint_t ident;
- ngx_resolver_query_t *query;
+ u_char *p, *d;
+ size_t len;
+ in_addr_t addr;
+ ngx_int_t n;
+ ngx_uint_t ident;
+ ngx_resolver_hdr_t *query;
+ struct sockaddr_in *sin;
+#if (NGX_HAVE_INET6)
+ struct sockaddr_in6 *sin6;
+#endif
+
+ switch (ctx->addr.sockaddr->sa_family) {
- len = sizeof(ngx_resolver_query_t)
- + sizeof(".255.255.255.255.in-addr.arpa.") - 1
- + sizeof(ngx_resolver_qs_t);
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ len = sizeof(ngx_resolver_hdr_t)
+ + 64 + sizeof(".ip6.arpa.") - 1
+ + sizeof(ngx_resolver_qs_t);
+
+ break;
+#endif
+
+ default: /* AF_INET */
+ len = sizeof(ngx_resolver_hdr_t)
+ + sizeof(".255.255.255.255.in-addr.arpa.") - 1
+ + sizeof(ngx_resolver_qs_t);
+ }
p = ngx_resolver_alloc(ctx->resolver, len);
if (p == NULL) {
@@ -1901,7 +2610,7 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
}
rn->query = p;
- query = (ngx_resolver_query_t *) p;
+ query = (ngx_resolver_hdr_t *) p;
ident = ngx_random();
@@ -1917,20 +2626,43 @@ ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
query->nns_hi = 0; query->nns_lo = 0;
query->nar_hi = 0; query->nar_lo = 0;
- p += sizeof(ngx_resolver_query_t);
+ p += sizeof(ngx_resolver_hdr_t);
+
+ switch (ctx->addr.sockaddr->sa_family) {
+
+#if (NGX_HAVE_INET6)
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
+
+ for (n = 15; n >= 0; n--) {
+ p = ngx_sprintf(p, "\1%xd\1%xd",
+ sin6->sin6_addr.s6_addr[n] & 0xf,
+ (sin6->sin6_addr.s6_addr[n] >> 4) & 0xf);
+ }
+
+ p = ngx_cpymem(p, "\3ip6\4arpa\0", 10);
- 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;
+ break;
+#endif
+
+ default: /* AF_INET */
+
+ sin = (struct sockaddr_in *) ctx->addr.sockaddr;
+ addr = ntohl(sin->sin_addr.s_addr);
+
+ for (n = 0; n < 32; n += 8) {
+ d = ngx_sprintf(&p[1], "%ud", (addr >> n) & 0xff);
+ *p = (u_char) (d - &p[1]);
+ p = d;
+ }
+
+ p = ngx_cpymem(p, "\7in-addr\4arpa\0", 14);
}
- /* query type "PTR", IP query class */
- ngx_memcpy(p, "\7in-addr\4arpa\0\0\14\0\1", 18);
+ /* query type "PTR", IN query class */
+ p = ngx_cpymem(p, "\0\14\0\1", 4);
- rn->qlen = (u_short)
- (p + sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t)
- - rn->query);
+ rn->qlen = (u_short) (p - rn->query);
return NGX_OK;
}
@@ -2012,7 +2744,7 @@ done:
n = *src++;
} else {
- ngx_memcpy(dst, src, n);
+ ngx_strlow(dst, src, n);
dst += n;
src += n;
@@ -2061,10 +2793,16 @@ ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn)
ngx_resolver_free_locked(r, rn->u.cname);
}
- if (rn->naddrs > 1) {
+ if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
ngx_resolver_free_locked(r, rn->u.addrs);
}
+#if (NGX_HAVE_INET6)
+ if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
+ ngx_resolver_free_locked(r, rn->u6.addrs6);
+ }
+#endif
+
ngx_resolver_free_locked(r, rn);
/* unlock alloc mutex */
@@ -2136,27 +2874,84 @@ 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_addr_t *
+ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn,
+ ngx_uint_t rotate)
{
- void *dst, *p;
- ngx_uint_t j;
+ ngx_addr_t *dst;
+ ngx_uint_t d, i, j, n;
+ u_char (*sockaddr)[NGX_SOCKADDRLEN];
+ in_addr_t *addr;
+ struct sockaddr_in *sin;
+#if (NGX_HAVE_INET6)
+ struct in6_addr *addr6;
+ struct sockaddr_in6 *sin6;
+#endif
- dst = ngx_resolver_alloc(r, n * sizeof(in_addr_t));
+ n = rn->naddrs;
+#if (NGX_HAVE_INET6)
+ n += rn->naddrs6;
+#endif
+ dst = ngx_resolver_calloc(r, n * sizeof(ngx_addr_t));
if (dst == NULL) {
- return dst;
+ return NULL;
}
- j = ngx_random() % n;
+ sockaddr = ngx_resolver_calloc(r, n * NGX_SOCKADDRLEN);
+ if (sockaddr == NULL) {
+ ngx_resolver_free(r, dst);
+ return NULL;
+ }
- if (j == 0) {
- ngx_memcpy(dst, src, n * sizeof(in_addr_t));
- return dst;
+ i = 0;
+ d = rotate ? ngx_random() % n : 0;
+
+ if (rn->naddrs) {
+ j = rotate ? ngx_random() % rn->naddrs : 0;
+
+ addr = (rn->naddrs == 1) ? &rn->u.addr : rn->u.addrs;
+
+ do {
+ sin = (struct sockaddr_in *) sockaddr[d];
+ sin->sin_family = AF_INET;
+ sin->sin_addr.s_addr = addr[j++];
+ dst[d].sockaddr = (struct sockaddr *) sin;
+ dst[d++].socklen = sizeof(struct sockaddr_in);
+
+ if (d == n) {
+ d = 0;
+ }
+
+ if (j == rn->naddrs) {
+ j = 0;
+ }
+ } while (++i < rn->naddrs);
}
- p = ngx_cpymem(dst, &src[j], (n - j) * sizeof(in_addr_t));
- ngx_memcpy(p, src, j * sizeof(in_addr_t));
+#if (NGX_HAVE_INET6)
+ if (rn->naddrs6) {
+ j = rotate ? ngx_random() % rn->naddrs6 : 0;
+
+ addr6 = (rn->naddrs6 == 1) ? &rn->u6.addr6 : rn->u6.addrs6;
+
+ do {
+ sin6 = (struct sockaddr_in6 *) sockaddr[d];
+ sin6->sin6_family = AF_INET6;
+ ngx_memcpy(sin6->sin6_addr.s6_addr, addr6[j++].s6_addr, 16);
+ dst[d].sockaddr = (struct sockaddr *) sin6;
+ dst[d++].socklen = sizeof(struct sockaddr_in6);
+
+ if (d == n) {
+ d = 0;
+ }
+
+ if (j == rn->naddrs6) {
+ j = 0;
+ }
+ } while (++i < n);
+ }
+#endif
return dst;
}
@@ -2221,7 +3016,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc)
ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &uc->log, 0, "UDP socket %d", s);
- if (s == -1) {
+ if (s == (ngx_socket_t) -1) {
ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
ngx_socket_n " failed");
return NGX_ERROR;
@@ -2242,14 +3037,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc)
ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
ngx_nonblocking_n " failed");
- ngx_free_connection(c);
-
- if (ngx_close_socket(s) == -1) {
- ngx_log_error(NGX_LOG_ALERT, &uc->log, ngx_socket_errno,
- ngx_close_socket_n " failed");
- }
-
- return NGX_ERROR;
+ goto failed;
}
rev = c->read;
@@ -2274,7 +3062,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc)
#endif
ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &uc->log, 0,
- "connect to %V, fd:%d #%d", &uc->server, s, c->number);
+ "connect to %V, fd:%d #%uA", &uc->server, s, c->number);
rc = connect(s, uc->sockaddr, uc->socklen);
@@ -2284,7 +3072,7 @@ ngx_udp_connect(ngx_udp_connection_t *uc)
ngx_log_error(NGX_LOG_CRIT, &uc->log, ngx_socket_errno,
"connect() failed");
- return NGX_ERROR;
+ goto failed;
}
/* UDP sockets are always ready to write */
@@ -2298,16 +3086,23 @@ ngx_udp_connect(ngx_udp_connection_t *uc)
/* eventport event type has no meaning: oneshot only */
if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
- return NGX_ERROR;
+ goto failed;
}
} else {
/* rtsig */
if (ngx_add_conn(c) == NGX_ERROR) {
- return NGX_ERROR;
+ goto failed;
}
}
return NGX_OK;
+
+failed:
+
+ ngx_close_connection(c);
+ uc->connection = NULL;
+
+ return NGX_ERROR;
}