blob: abc23fcbf962fe24bbf73d75c5869f009a36bc0d [file] [log] [blame]
Igor Sysoevd3283ff2005-12-05 13:18:09 +00001
2/*
3 * Copyright (C) Igor Sysoev
Maxim Konovalovf8d59e32012-01-18 15:07:43 +00004 * Copyright (C) Nginx, Inc.
Igor Sysoevd3283ff2005-12-05 13:18:09 +00005 */
6
7
8#include <ngx_config.h>
9#include <ngx_core.h>
10#include <ngx_event.h>
11
12
Igor Sysoevcb4d5382007-11-23 17:13:26 +000013#define NGX_RESOLVER_UDP_SIZE 4096
14
Roman Arutyunyan910445b2016-01-28 15:28:20 +030015#define NGX_RESOLVER_TCP_RSIZE (2 + 65535)
16#define NGX_RESOLVER_TCP_WSIZE 8192
17
Igor Sysoevcb4d5382007-11-23 17:13:26 +000018
Igor Sysoevd3283ff2005-12-05 13:18:09 +000019typedef struct {
Igor Sysoevcb4d5382007-11-23 17:13:26 +000020 u_char ident_hi;
21 u_char ident_lo;
22 u_char flags_hi;
23 u_char flags_lo;
24 u_char nqs_hi;
25 u_char nqs_lo;
26 u_char nan_hi;
27 u_char nan_lo;
28 u_char nns_hi;
29 u_char nns_lo;
30 u_char nar_hi;
31 u_char nar_lo;
Ruslan Ermilov3d245d42013-12-06 14:30:27 +040032} ngx_resolver_hdr_t;
Igor Sysoevd3283ff2005-12-05 13:18:09 +000033
Igor Sysoevd3283ff2005-12-05 13:18:09 +000034
Igor Sysoevcb4d5382007-11-23 17:13:26 +000035typedef struct {
36 u_char type_hi;
37 u_char type_lo;
38 u_char class_hi;
39 u_char class_lo;
40} ngx_resolver_qs_t;
Igor Sysoevd3283ff2005-12-05 13:18:09 +000041
Igor Sysoevd3283ff2005-12-05 13:18:09 +000042
Igor Sysoevcb4d5382007-11-23 17:13:26 +000043typedef struct {
44 u_char type_hi;
45 u_char type_lo;
46 u_char class_hi;
47 u_char class_lo;
48 u_char ttl[4];
49 u_char len_hi;
50 u_char len_lo;
51} ngx_resolver_an_t;
52
53
Ruslan Ermilovef563de2014-11-20 15:24:42 +030054#define ngx_resolver_node(n) \
55 (ngx_resolver_node_t *) \
56 ((u_char *) (n) - offsetof(ngx_resolver_node_t, node))
57
58
Roman Arutyunyanec16a602016-01-28 15:28:20 +030059ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec);
Roman Arutyunyan910445b2016-01-28 15:28:20 +030060ngx_int_t ngx_tcp_connect(ngx_resolver_connection_t *rec);
Igor Sysoevcb4d5382007-11-23 17:13:26 +000061
62
Igor Sysoev4491dae2008-02-28 20:38:34 +000063static void ngx_resolver_cleanup(void *data);
64static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree);
Igor Sysoevcb4d5382007-11-23 17:13:26 +000065static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r,
Roman Arutyunyan38a72e92016-01-26 16:46:59 +030066 ngx_resolver_ctx_t *ctx, ngx_str_t *name);
Igor Sysoevcb4d5382007-11-23 17:13:26 +000067static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree,
68 ngx_queue_t *queue);
69static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r,
70 ngx_resolver_node_t *rn);
Roman Arutyunyan910445b2016-01-28 15:28:20 +030071static ngx_int_t ngx_resolver_send_udp_query(ngx_resolver_t *r,
72 ngx_resolver_connection_t *rec, u_char *query, u_short qlen);
73static ngx_int_t ngx_resolver_send_tcp_query(ngx_resolver_t *r,
74 ngx_resolver_connection_t *rec, u_char *query, u_short qlen);
Roman Arutyunyan9b914de2016-01-26 16:46:48 +030075static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r,
76 ngx_resolver_node_t *rn, ngx_str_t *name);
77static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r,
78 ngx_resolver_node_t *rn, ngx_addr_t *addr);
Igor Sysoevcb4d5382007-11-23 17:13:26 +000079static void ngx_resolver_resend_handler(ngx_event_t *ev);
80static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree,
81 ngx_queue_t *queue);
Sergey Kandaurove6fdd2f2015-06-17 17:57:34 +030082static ngx_uint_t ngx_resolver_resend_empty(ngx_resolver_t *r);
Roman Arutyunyan910445b2016-01-28 15:28:20 +030083static void ngx_resolver_udp_read(ngx_event_t *rev);
84static void ngx_resolver_tcp_write(ngx_event_t *wev);
85static void ngx_resolver_tcp_read(ngx_event_t *rev);
Igor Sysoevcb4d5382007-11-23 17:13:26 +000086static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf,
Roman Arutyunyan910445b2016-01-28 15:28:20 +030087 size_t n, ngx_uint_t tcp);
Igor Sysoevcb4d5382007-11-23 17:13:26 +000088static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
Ruslan Ermilov769eded2013-12-09 10:53:28 +040089 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
Roman Arutyunyan910445b2016-01-28 15:28:20 +030090 ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans);
Igor Sysoevcb4d5382007-11-23 17:13:26 +000091static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
Igor Sysoevc0cadf12007-12-16 20:47:55 +000092 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan);
Igor Sysoevcb4d5382007-11-23 17:13:26 +000093static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
94 ngx_str_t *name, uint32_t hash);
95static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r,
96 in_addr_t addr);
97static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
98 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
99static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name,
100 u_char *buf, u_char *src, u_char *last);
101static void ngx_resolver_timeout_handler(ngx_event_t *ev);
102static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn);
103static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size);
Igor Sysoev8ee01f52008-02-28 15:34:53 +0000104static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000105static void ngx_resolver_free(ngx_resolver_t *r, void *p);
106static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
107static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400108static ngx_addr_t *ngx_resolver_export(ngx_resolver_t *r,
109 ngx_resolver_node_t *rn, ngx_uint_t rotate);
Igor Sysoev089b2fd2010-01-11 11:01:02 +0000110static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000111
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400112#if (NGX_HAVE_INET6)
113static void ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
114 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
115static ngx_resolver_node_t *ngx_resolver_lookup_addr6(ngx_resolver_t *r,
116 struct in6_addr *addr, uint32_t hash);
117#endif
118
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000119
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000120ngx_resolver_t *
Igor Sysoev62071812011-10-24 16:09:05 +0000121ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000122{
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300123 ngx_str_t s;
124 ngx_url_t u;
125 ngx_uint_t i, j;
126 ngx_resolver_t *r;
127 ngx_pool_cleanup_t *cln;
128 ngx_resolver_connection_t *rec;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000129
Igor Sysoevdfd55112008-03-04 10:42:05 +0000130 cln = ngx_pool_cleanup_add(cf->pool, 0);
Igor Sysoev4491dae2008-02-28 20:38:34 +0000131 if (cln == NULL) {
132 return NULL;
133 }
134
135 cln->handler = ngx_resolver_cleanup;
136
Igor Sysoevdfd55112008-03-04 10:42:05 +0000137 r = ngx_calloc(sizeof(ngx_resolver_t), cf->log);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000138 if (r == NULL) {
139 return NULL;
140 }
141
Igor Sysoev4491dae2008-02-28 20:38:34 +0000142 cln->data = r;
143
Igor Sysoevdfd55112008-03-04 10:42:05 +0000144 r->event = ngx_calloc(sizeof(ngx_event_t), cf->log);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000145 if (r->event == NULL) {
146 return NULL;
147 }
148
Igor Sysoev826c02e2007-12-03 12:17:26 +0000149 ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel,
150 ngx_resolver_rbtree_insert_value);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000151
Igor Sysoev826c02e2007-12-03 12:17:26 +0000152 ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel,
153 ngx_rbtree_insert_value);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000154
Igor Sysoeva9d3a0d2007-12-03 11:21:19 +0000155 ngx_queue_init(&r->name_resend_queue);
156 ngx_queue_init(&r->addr_resend_queue);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000157
Igor Sysoeva9d3a0d2007-12-03 11:21:19 +0000158 ngx_queue_init(&r->name_expire_queue);
159 ngx_queue_init(&r->addr_expire_queue);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000160
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400161#if (NGX_HAVE_INET6)
Ruslan Ermilove0caf512013-12-09 10:53:30 +0400162 r->ipv6 = 1;
163
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400164 ngx_rbtree_init(&r->addr6_rbtree, &r->addr6_sentinel,
165 ngx_resolver_rbtree_insert_addr6_value);
166
167 ngx_queue_init(&r->addr6_resend_queue);
168
169 ngx_queue_init(&r->addr6_expire_queue);
170#endif
171
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000172 r->event->handler = ngx_resolver_resend_handler;
173 r->event->data = r;
Igor Sysoev0cd76ea2009-04-30 13:53:42 +0000174 r->event->log = &cf->cycle->new_log;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000175 r->ident = -1;
176
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000177 r->resend_timeout = 5;
Roman Arutyunyan910445b2016-01-28 15:28:20 +0300178 r->tcp_timeout = 5;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000179 r->expire = 30;
Ruslan Ermilovbec516b2011-11-16 13:11:39 +0000180 r->valid = 0;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000181
Igor Sysoev0cd76ea2009-04-30 13:53:42 +0000182 r->log = &cf->cycle->new_log;
Igor Sysoev49ac2b22010-09-27 11:23:45 +0000183 r->log_level = NGX_LOG_ERR;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000184
Maxim Dounin42a75bb2012-08-06 10:48:09 +0000185 if (n) {
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300186 if (ngx_array_init(&r->connections, cf->pool, n,
187 sizeof(ngx_resolver_connection_t))
Maxim Dounin42a75bb2012-08-06 10:48:09 +0000188 != NGX_OK)
189 {
190 return NULL;
191 }
192 }
193
Igor Sysoev62071812011-10-24 16:09:05 +0000194 for (i = 0; i < n; i++) {
Ruslan Ermilovbec516b2011-11-16 13:11:39 +0000195 if (ngx_strncmp(names[i].data, "valid=", 6) == 0) {
196 s.len = names[i].len - 6;
197 s.data = names[i].data + 6;
198
199 r->valid = ngx_parse_time(&s, 1);
200
Maxim Dounin9f38b202012-02-13 15:41:11 +0000201 if (r->valid == (time_t) NGX_ERROR) {
Ruslan Ermilovbec516b2011-11-16 13:11:39 +0000202 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
203 "invalid parameter: %V", &names[i]);
204 return NULL;
205 }
206
207 continue;
208 }
209
Ruslan Ermilove0caf512013-12-09 10:53:30 +0400210#if (NGX_HAVE_INET6)
211 if (ngx_strncmp(names[i].data, "ipv6=", 5) == 0) {
212
213 if (ngx_strcmp(&names[i].data[5], "on") == 0) {
214 r->ipv6 = 1;
215
216 } else if (ngx_strcmp(&names[i].data[5], "off") == 0) {
217 r->ipv6 = 0;
218
219 } else {
220 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
221 "invalid parameter: %V", &names[i]);
222 return NULL;
223 }
224
225 continue;
226 }
227#endif
228
Igor Sysoev62071812011-10-24 16:09:05 +0000229 ngx_memzero(&u, sizeof(ngx_url_t));
230
Ruslan Ermilovac7f7042012-06-04 14:23:27 +0000231 u.url = names[i];
232 u.default_port = 53;
Igor Sysoev62071812011-10-24 16:09:05 +0000233
Ruslan Ermilovac7f7042012-06-04 14:23:27 +0000234 if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
Ruslan Ermilovd2e005c2012-05-22 13:12:14 +0000235 if (u.err) {
236 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
237 "%s in resolver \"%V\"",
Ruslan Ermilovac7f7042012-06-04 14:23:27 +0000238 u.err, &u.url);
Ruslan Ermilovd2e005c2012-05-22 13:12:14 +0000239 }
240
Igor Sysoev62071812011-10-24 16:09:05 +0000241 return NULL;
242 }
243
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300244 rec = ngx_array_push_n(&r->connections, u.naddrs);
245 if (rec == NULL) {
Igor Sysoev6b2fce42007-12-03 10:05:19 +0000246 return NULL;
247 }
248
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300249 ngx_memzero(rec, u.naddrs * sizeof(ngx_resolver_connection_t));
Igor Sysoev6b2fce42007-12-03 10:05:19 +0000250
Ruslan Ermilov2c49af82012-06-18 12:46:05 +0000251 for (j = 0; j < u.naddrs; j++) {
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300252 rec[j].sockaddr = u.addrs[j].sockaddr;
253 rec[j].socklen = u.addrs[j].socklen;
254 rec[j].server = u.addrs[j].name;
Roman Arutyunyan910445b2016-01-28 15:28:20 +0300255 rec[j].resolver = r;
Ruslan Ermilov2c49af82012-06-18 12:46:05 +0000256 }
Igor Sysoev6b2fce42007-12-03 10:05:19 +0000257 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000258
259 return r;
260}
261
262
Igor Sysoev4491dae2008-02-28 20:38:34 +0000263static void
264ngx_resolver_cleanup(void *data)
265{
266 ngx_resolver_t *r = data;
267
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300268 ngx_uint_t i;
269 ngx_resolver_connection_t *rec;
Igor Sysoev62071812011-10-24 16:09:05 +0000270
Igor Sysoev4491dae2008-02-28 20:38:34 +0000271 if (r) {
272 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
273 "cleanup resolver");
274
275 ngx_resolver_cleanup_tree(r, &r->name_rbtree);
276
277 ngx_resolver_cleanup_tree(r, &r->addr_rbtree);
278
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400279#if (NGX_HAVE_INET6)
280 ngx_resolver_cleanup_tree(r, &r->addr6_rbtree);
281#endif
282
Igor Sysoev4491dae2008-02-28 20:38:34 +0000283 if (r->event) {
284 ngx_free(r->event);
285 }
286
Igor Sysoev4491dae2008-02-28 20:38:34 +0000287
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300288 rec = r->connections.elts;
Igor Sysoev62071812011-10-24 16:09:05 +0000289
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300290 for (i = 0; i < r->connections.nelts; i++) {
291 if (rec[i].udp) {
292 ngx_close_connection(rec[i].udp);
Igor Sysoev62071812011-10-24 16:09:05 +0000293 }
Roman Arutyunyan910445b2016-01-28 15:28:20 +0300294
295 if (rec[i].tcp) {
296 ngx_close_connection(rec[i].tcp);
297 }
Igor Sysoev4491dae2008-02-28 20:38:34 +0000298 }
299
300 ngx_free(r);
301 }
302}
303
304
305static void
306ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree)
307{
308 ngx_resolver_ctx_t *ctx, *next;
309 ngx_resolver_node_t *rn;
310
311 while (tree->root != tree->sentinel) {
312
Ruslan Ermilovef563de2014-11-20 15:24:42 +0300313 rn = ngx_resolver_node(ngx_rbtree_min(tree->root, tree->sentinel));
Igor Sysoev4491dae2008-02-28 20:38:34 +0000314
315 ngx_queue_remove(&rn->queue);
316
317 for (ctx = rn->waiting; ctx; ctx = next) {
Igor Sysoev433608c2008-05-14 07:54:52 +0000318 next = ctx->next;
Igor Sysoev4491dae2008-02-28 20:38:34 +0000319
320 if (ctx->event) {
321 ngx_resolver_free(r, ctx->event);
322 }
323
324 ngx_resolver_free(r, ctx);
325 }
326
327 ngx_rbtree_delete(tree, &rn->node);
328
329 ngx_resolver_free_node(r, rn);
330 }
331}
332
333
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000334ngx_resolver_ctx_t *
335ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
336{
337 in_addr_t addr;
338 ngx_resolver_ctx_t *ctx;
339
340 if (temp) {
341 addr = ngx_inet_addr(temp->name.data, temp->name.len);
342
343 if (addr != INADDR_NONE) {
344 temp->resolver = r;
345 temp->state = NGX_OK;
346 temp->naddrs = 1;
347 temp->addrs = &temp->addr;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400348 temp->addr.sockaddr = (struct sockaddr *) &temp->sin;
349 temp->addr.socklen = sizeof(struct sockaddr_in);
350 ngx_memzero(&temp->sin, sizeof(struct sockaddr_in));
351 temp->sin.sin_family = AF_INET;
352 temp->sin.sin_addr.s_addr = addr;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000353 temp->quick = 1;
354
355 return temp;
356 }
357 }
358
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300359 if (r->connections.nelts == 0) {
Igor Sysoev6b2fce42007-12-03 10:05:19 +0000360 return NGX_NO_RESOLVER;
361 }
362
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000363 ctx = ngx_resolver_calloc(r, sizeof(ngx_resolver_ctx_t));
364
365 if (ctx) {
366 ctx->resolver = r;
367 }
368
369 return ctx;
370}
Igor Sysoevd3283ff2005-12-05 13:18:09 +0000371
372
373ngx_int_t
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000374ngx_resolve_name(ngx_resolver_ctx_t *ctx)
Igor Sysoevd3283ff2005-12-05 13:18:09 +0000375{
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000376 ngx_int_t rc;
377 ngx_resolver_t *r;
Igor Sysoevd3283ff2005-12-05 13:18:09 +0000378
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000379 r = ctx->resolver;
380
Yichun Zhang2e2c9db2014-01-10 11:22:14 -0800381 if (ctx->name.len > 0 && ctx->name.data[ctx->name.len - 1] == '.') {
382 ctx->name.len--;
383 }
384
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000385 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
386 "resolve: \"%V\"", &ctx->name);
387
388 if (ctx->quick) {
389 ctx->handler(ctx);
Igor Sysoevd3283ff2005-12-05 13:18:09 +0000390 return NGX_OK;
391 }
392
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000393 /* lock name mutex */
394
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300395 rc = ngx_resolve_name_locked(r, ctx, &ctx->name);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000396
397 if (rc == NGX_OK) {
398 return NGX_OK;
399 }
400
401 /* unlock name mutex */
402
403 if (rc == NGX_AGAIN) {
404 return NGX_OK;
405 }
406
Igor Sysoev7c4cf272008-02-28 20:09:39 +0000407 /* NGX_ERROR */
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000408
409 if (ctx->event) {
Igor Sysoev7c4cf272008-02-28 20:09:39 +0000410 ngx_resolver_free(r, ctx->event);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000411 }
412
Igor Sysoev7c4cf272008-02-28 20:09:39 +0000413 ngx_resolver_free(r, ctx);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000414
415 return NGX_ERROR;
416}
417
418
419void
420ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
421{
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000422 ngx_resolver_t *r;
423 ngx_resolver_ctx_t *w, **p;
424 ngx_resolver_node_t *rn;
425
426 r = ctx->resolver;
427
428 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
429 "resolve name done: %i", ctx->state);
430
431 if (ctx->quick) {
432 return;
433 }
434
435 if (ctx->event && ctx->event->timer_set) {
436 ngx_del_timer(ctx->event);
437 }
438
439 /* lock name mutex */
440
Ruslan Ermilov5f509b52016-01-26 16:46:31 +0300441 if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000442
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300443 rn = ctx->node;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000444
445 if (rn) {
446 p = &rn->waiting;
447 w = rn->waiting;
448
449 while (w) {
450 if (w == ctx) {
451 *p = w->next;
452
453 goto done;
454 }
455
456 p = &w->next;
457 w = w->next;
458 }
459 }
460
461 ngx_log_error(NGX_LOG_ALERT, r->log, 0,
462 "could not cancel %V resolving", &ctx->name);
463 }
464
465done:
466
467 ngx_resolver_expire(r, &r->name_rbtree, &r->name_expire_queue);
468
469 /* unlock name mutex */
470
Igor Sysoev7c4cf272008-02-28 20:09:39 +0000471 /* lock alloc mutex */
472
473 if (ctx->event) {
474 ngx_resolver_free_locked(r, ctx->event);
475 }
476
477 ngx_resolver_free_locked(r, ctx);
478
479 /* unlock alloc mutex */
Sergey Kandaurove6fdd2f2015-06-17 17:57:34 +0300480
481 if (r->event->timer_set && ngx_resolver_resend_empty(r)) {
482 ngx_del_timer(r->event);
483 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000484}
485
486
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000487static ngx_int_t
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300488ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx,
489 ngx_str_t *name)
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000490{
491 uint32_t hash;
Igor Sysoev09b199c2008-04-09 14:45:39 +0000492 ngx_int_t rc;
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300493 ngx_str_t cname;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000494 ngx_uint_t naddrs;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400495 ngx_addr_t *addrs;
Ruslan Ermilovec4da932016-01-26 16:46:38 +0300496 ngx_resolver_ctx_t *next, *last;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000497 ngx_resolver_node_t *rn;
498
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300499 ngx_strlow(name->data, name->data, name->len);
Ruslan Ermilov3fd72752013-12-13 20:49:52 +0400500
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300501 hash = ngx_crc32_short(name->data, name->len);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000502
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300503 rn = ngx_resolver_lookup_name(r, name, hash);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000504
505 if (rn) {
506
Ruslan Ermilovec4da932016-01-26 16:46:38 +0300507 /* ctx can be a list after NGX_RESOLVE_CNAME */
508 for (last = ctx; last->next; last = last->next);
509
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000510 if (rn->valid >= ngx_time()) {
511
512 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
513
514 ngx_queue_remove(&rn->queue);
515
516 rn->expire = ngx_time() + r->expire;
517
518 ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
519
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400520 naddrs = (rn->naddrs == (u_short) -1) ? 0 : rn->naddrs;
521#if (NGX_HAVE_INET6)
522 naddrs += (rn->naddrs6 == (u_short) -1) ? 0 : rn->naddrs6;
523#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000524
525 if (naddrs) {
526
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400527 if (naddrs == 1 && rn->naddrs == 1) {
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400528 addrs = NULL;
529
530 } else {
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400531 addrs = ngx_resolver_export(r, rn, 1);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000532 if (addrs == NULL) {
533 return NGX_ERROR;
534 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000535 }
536
Ruslan Ermilovec4da932016-01-26 16:46:38 +0300537 last->next = rn->waiting;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000538 rn->waiting = NULL;
539
540 /* unlock name mutex */
541
542 do {
543 ctx->state = NGX_OK;
544 ctx->naddrs = naddrs;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400545
546 if (addrs == NULL) {
547 ctx->addrs = &ctx->addr;
548 ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
549 ctx->addr.socklen = sizeof(struct sockaddr_in);
550 ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
551 ctx->sin.sin_family = AF_INET;
552 ctx->sin.sin_addr.s_addr = rn->u.addr;
553
554 } else {
555 ctx->addrs = addrs;
556 }
557
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000558 next = ctx->next;
559
560 ctx->handler(ctx);
561
562 ctx = next;
563 } while (ctx);
564
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400565 if (addrs != NULL) {
566 ngx_resolver_free(r, addrs->sockaddr);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000567 ngx_resolver_free(r, addrs);
568 }
569
570 return NGX_OK;
571 }
572
573 /* NGX_RESOLVE_CNAME */
574
Igor Sysoeva8372d82008-04-12 07:29:20 +0000575 if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000576
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300577 cname.len = rn->cnlen;
578 cname.data = rn->u.cname;
Igor Sysoeva8372d82008-04-12 07:29:20 +0000579
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300580 return ngx_resolve_name_locked(r, ctx, &cname);
Igor Sysoeva8372d82008-04-12 07:29:20 +0000581 }
582
Ruslan Ermilovec4da932016-01-26 16:46:38 +0300583 last->next = rn->waiting;
Igor Sysoeva8372d82008-04-12 07:29:20 +0000584 rn->waiting = NULL;
585
586 /* unlock name mutex */
587
588 do {
589 ctx->state = NGX_RESOLVE_NXDOMAIN;
590 next = ctx->next;
591
592 ctx->handler(ctx);
593
594 ctx = next;
595 } while (ctx);
596
597 return NGX_OK;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000598 }
599
600 if (rn->waiting) {
601
Ruslan Ermilov5f509b52016-01-26 16:46:31 +0300602 if (ctx->event == NULL) {
603 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
604 if (ctx->event == NULL) {
605 return NGX_ERROR;
606 }
607
608 ctx->event->handler = ngx_resolver_timeout_handler;
609 ctx->event->data = ctx;
610 ctx->event->log = r->log;
611 ctx->ident = -1;
612
613 ngx_add_timer(ctx->event, ctx->timeout);
614 }
615
Ruslan Ermilovec4da932016-01-26 16:46:38 +0300616 last->next = rn->waiting;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000617 rn->waiting = ctx;
Igor Sysoev64bfa872009-11-09 17:45:56 +0000618 ctx->state = NGX_AGAIN;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000619
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300620 do {
621 ctx->node = rn;
622 ctx = ctx->next;
623 } while (ctx);
624
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000625 return NGX_AGAIN;
626 }
627
628 ngx_queue_remove(&rn->queue);
629
630 /* lock alloc mutex */
631
Maxim Dounin7d863c02012-05-14 09:13:45 +0000632 if (rn->query) {
633 ngx_resolver_free_locked(r, rn->query);
634 rn->query = NULL;
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400635#if (NGX_HAVE_INET6)
636 rn->query6 = NULL;
637#endif
Maxim Dounin7d863c02012-05-14 09:13:45 +0000638 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000639
640 if (rn->cnlen) {
641 ngx_resolver_free_locked(r, rn->u.cname);
642 }
643
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400644 if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000645 ngx_resolver_free_locked(r, rn->u.addrs);
646 }
647
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400648#if (NGX_HAVE_INET6)
649 if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
650 ngx_resolver_free_locked(r, rn->u6.addrs6);
651 }
652#endif
653
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000654 /* unlock alloc mutex */
655
656 } else {
657
658 rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
659 if (rn == NULL) {
660 return NGX_ERROR;
661 }
662
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300663 rn->name = ngx_resolver_dup(r, name->data, name->len);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000664 if (rn->name == NULL) {
665 ngx_resolver_free(r, rn);
666 return NGX_ERROR;
667 }
668
669 rn->node.key = hash;
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300670 rn->nlen = (u_short) name->len;
Igor Sysoev949aea42008-04-09 14:26:08 +0000671 rn->query = NULL;
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400672#if (NGX_HAVE_INET6)
673 rn->query6 = NULL;
674#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000675
676 ngx_rbtree_insert(&r->name_rbtree, &rn->node);
677 }
678
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300679 rc = ngx_resolver_create_name_query(r, rn, name);
Igor Sysoev09b199c2008-04-09 14:45:39 +0000680
681 if (rc == NGX_ERROR) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000682 goto failed;
683 }
684
Igor Sysoev09b199c2008-04-09 14:45:39 +0000685 if (rc == NGX_DECLINED) {
686 ngx_rbtree_delete(&r->name_rbtree, &rn->node);
687
688 ngx_resolver_free(r, rn->query);
689 ngx_resolver_free(r, rn->name);
690 ngx_resolver_free(r, rn);
691
Ruslan Ermilovec4da932016-01-26 16:46:38 +0300692 do {
693 ctx->state = NGX_RESOLVE_NXDOMAIN;
694 next = ctx->next;
695
696 ctx->handler(ctx);
697
698 ctx = next;
699 } while (ctx);
Igor Sysoev09b199c2008-04-09 14:45:39 +0000700
701 return NGX_OK;
702 }
703
Roman Arutyunyanb6a8f8c2016-01-28 15:28:20 +0300704 rn->last_connection = r->last_connection++;
705 if (r->last_connection == r->connections.nelts) {
706 r->last_connection = 0;
707 }
708
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400709 rn->naddrs = (u_short) -1;
Roman Arutyunyan910445b2016-01-28 15:28:20 +0300710 rn->tcp = 0;
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400711#if (NGX_HAVE_INET6)
Ruslan Ermilove0caf512013-12-09 10:53:30 +0400712 rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0;
Roman Arutyunyan910445b2016-01-28 15:28:20 +0300713 rn->tcp6 = 0;
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400714#endif
715
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000716 if (ngx_resolver_send_query(r, rn) != NGX_OK) {
717 goto failed;
718 }
719
720 if (ctx->event == NULL) {
721 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
722 if (ctx->event == NULL) {
723 goto failed;
724 }
725
726 ctx->event->handler = ngx_resolver_timeout_handler;
Ruslan Ermilov5f509b52016-01-26 16:46:31 +0300727 ctx->event->data = ctx;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000728 ctx->event->log = r->log;
Ruslan Ermilov5f509b52016-01-26 16:46:31 +0300729 ctx->ident = -1;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000730
731 ngx_add_timer(ctx->event, ctx->timeout);
732 }
733
734 if (ngx_queue_empty(&r->name_resend_queue)) {
735 ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
736 }
737
738 rn->expire = ngx_time() + r->resend_timeout;
739
740 ngx_queue_insert_head(&r->name_resend_queue, &rn->queue);
741
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400742 rn->code = 0;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000743 rn->cnlen = 0;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000744 rn->valid = 0;
Ruslan Ermilov85e6d212013-12-16 19:12:23 +0400745 rn->ttl = NGX_MAX_UINT32_VALUE;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000746 rn->waiting = ctx;
747
748 ctx->state = NGX_AGAIN;
749
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300750 do {
751 ctx->node = rn;
752 ctx = ctx->next;
753 } while (ctx);
754
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000755 return NGX_AGAIN;
756
757failed:
758
759 ngx_rbtree_delete(&r->name_rbtree, &rn->node);
760
Igor Sysoev949aea42008-04-09 14:26:08 +0000761 if (rn->query) {
762 ngx_resolver_free(r, rn->query);
763 }
764
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000765 ngx_resolver_free(r, rn->name);
766
767 ngx_resolver_free(r, rn);
768
769 return NGX_ERROR;
770}
771
772
773ngx_int_t
774ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
775{
Igor Sysoev92588722009-01-29 14:35:23 +0000776 u_char *name;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400777 in_addr_t addr;
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400778 ngx_queue_t *resend_queue, *expire_queue;
779 ngx_rbtree_t *tree;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000780 ngx_resolver_t *r;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400781 struct sockaddr_in *sin;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000782 ngx_resolver_node_t *rn;
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400783#if (NGX_HAVE_INET6)
784 uint32_t hash;
785 struct sockaddr_in6 *sin6;
786#endif
787
788#if (NGX_SUPPRESS_WARN)
789 addr = 0;
790#if (NGX_HAVE_INET6)
791 hash = 0;
792 sin6 = NULL;
793#endif
794#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000795
796 r = ctx->resolver;
797
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400798 switch (ctx->addr.sockaddr->sa_family) {
799
800#if (NGX_HAVE_INET6)
801 case AF_INET6:
802 sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
803 hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16);
804
805 /* lock addr mutex */
806
807 rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash);
808
809 tree = &r->addr6_rbtree;
810 resend_queue = &r->addr6_resend_queue;
811 expire_queue = &r->addr6_expire_queue;
812
813 break;
814#endif
815
816 default: /* AF_INET */
817 sin = (struct sockaddr_in *) ctx->addr.sockaddr;
818 addr = ntohl(sin->sin_addr.s_addr);
819
820 /* lock addr mutex */
821
822 rn = ngx_resolver_lookup_addr(r, addr);
823
824 tree = &r->addr_rbtree;
825 resend_queue = &r->addr_resend_queue;
826 expire_queue = &r->addr_expire_queue;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400827 }
828
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000829 if (rn) {
830
831 if (rn->valid >= ngx_time()) {
832
833 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
834
835 ngx_queue_remove(&rn->queue);
836
837 rn->expire = ngx_time() + r->expire;
838
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400839 ngx_queue_insert_head(expire_queue, &rn->queue);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000840
Igor Sysoev92588722009-01-29 14:35:23 +0000841 name = ngx_resolver_dup(r, rn->name, rn->nlen);
842 if (name == NULL) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000843 goto failed;
844 }
845
Igor Sysoev92588722009-01-29 14:35:23 +0000846 ctx->name.len = rn->nlen;
847 ctx->name.data = name;
848
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000849 /* unlock addr mutex */
850
851 ctx->state = NGX_OK;
852
853 ctx->handler(ctx);
854
Igor Sysoev92588722009-01-29 14:35:23 +0000855 ngx_resolver_free(r, name);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000856
857 return NGX_OK;
858 }
859
860 if (rn->waiting) {
861
Ruslan Ermilov5f509b52016-01-26 16:46:31 +0300862 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
863 if (ctx->event == NULL) {
864 return NGX_ERROR;
865 }
866
867 ctx->event->handler = ngx_resolver_timeout_handler;
868 ctx->event->data = ctx;
869 ctx->event->log = r->log;
870 ctx->ident = -1;
871
872 ngx_add_timer(ctx->event, ctx->timeout);
873
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000874 ctx->next = rn->waiting;
875 rn->waiting = ctx;
Igor Sysoev64bfa872009-11-09 17:45:56 +0000876 ctx->state = NGX_AGAIN;
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300877 ctx->node = rn;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000878
Igor Sysoev8ef386e2009-01-31 20:33:01 +0000879 /* unlock addr mutex */
880
881 return NGX_OK;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000882 }
883
884 ngx_queue_remove(&rn->queue);
885
886 ngx_resolver_free(r, rn->query);
Igor Sysoev949aea42008-04-09 14:26:08 +0000887 rn->query = NULL;
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400888#if (NGX_HAVE_INET6)
889 rn->query6 = NULL;
890#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000891
892 } else {
893 rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
894 if (rn == NULL) {
895 goto failed;
896 }
897
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400898 switch (ctx->addr.sockaddr->sa_family) {
899
900#if (NGX_HAVE_INET6)
901 case AF_INET6:
902 rn->addr6 = sin6->sin6_addr;
903 rn->node.key = hash;
904 break;
905#endif
906
907 default: /* AF_INET */
908 rn->node.key = addr;
909 }
910
Igor Sysoev949aea42008-04-09 14:26:08 +0000911 rn->query = NULL;
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400912#if (NGX_HAVE_INET6)
913 rn->query6 = NULL;
914#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000915
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400916 ngx_rbtree_insert(tree, &rn->node);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000917 }
918
Roman Arutyunyan9b914de2016-01-26 16:46:48 +0300919 if (ngx_resolver_create_addr_query(r, rn, &ctx->addr) != NGX_OK) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000920 goto failed;
921 }
922
Roman Arutyunyanb6a8f8c2016-01-28 15:28:20 +0300923 rn->last_connection = r->last_connection++;
924 if (r->last_connection == r->connections.nelts) {
925 r->last_connection = 0;
926 }
927
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400928 rn->naddrs = (u_short) -1;
Roman Arutyunyan910445b2016-01-28 15:28:20 +0300929 rn->tcp = 0;
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400930#if (NGX_HAVE_INET6)
931 rn->naddrs6 = (u_short) -1;
Roman Arutyunyan910445b2016-01-28 15:28:20 +0300932 rn->tcp6 = 0;
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400933#endif
934
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000935 if (ngx_resolver_send_query(r, rn) != NGX_OK) {
936 goto failed;
937 }
938
939 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
940 if (ctx->event == NULL) {
941 goto failed;
942 }
943
944 ctx->event->handler = ngx_resolver_timeout_handler;
Ruslan Ermilov5f509b52016-01-26 16:46:31 +0300945 ctx->event->data = ctx;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000946 ctx->event->log = r->log;
Ruslan Ermilov5f509b52016-01-26 16:46:31 +0300947 ctx->ident = -1;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000948
949 ngx_add_timer(ctx->event, ctx->timeout);
950
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400951 if (ngx_queue_empty(resend_queue)) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000952 ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
953 }
954
955 rn->expire = ngx_time() + r->resend_timeout;
956
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400957 ngx_queue_insert_head(resend_queue, &rn->queue);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000958
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400959 rn->code = 0;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000960 rn->cnlen = 0;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000961 rn->name = NULL;
962 rn->nlen = 0;
963 rn->valid = 0;
Ruslan Ermilov85e6d212013-12-16 19:12:23 +0400964 rn->ttl = NGX_MAX_UINT32_VALUE;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000965 rn->waiting = ctx;
966
967 /* unlock addr mutex */
968
969 ctx->state = NGX_AGAIN;
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300970 ctx->node = rn;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000971
972 return NGX_OK;
973
974failed:
975
976 if (rn) {
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400977 ngx_rbtree_delete(tree, &rn->node);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000978
Igor Sysoev949aea42008-04-09 14:26:08 +0000979 if (rn->query) {
980 ngx_resolver_free(r, rn->query);
981 }
982
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000983 ngx_resolver_free(r, rn);
984 }
985
986 /* unlock addr mutex */
987
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000988 if (ctx->event) {
Igor Sysoev7c4cf272008-02-28 20:09:39 +0000989 ngx_resolver_free(r, ctx->event);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000990 }
991
Igor Sysoev7c4cf272008-02-28 20:09:39 +0000992 ngx_resolver_free(r, ctx);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000993
994 return NGX_ERROR;
995}
996
997
998void
999ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
1000{
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001001 ngx_queue_t *expire_queue;
1002 ngx_rbtree_t *tree;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001003 ngx_resolver_t *r;
1004 ngx_resolver_ctx_t *w, **p;
1005 ngx_resolver_node_t *rn;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04001006
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001007 r = ctx->resolver;
1008
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001009 switch (ctx->addr.sockaddr->sa_family) {
1010
1011#if (NGX_HAVE_INET6)
1012 case AF_INET6:
1013 tree = &r->addr6_rbtree;
1014 expire_queue = &r->addr6_expire_queue;
1015 break;
1016#endif
1017
1018 default: /* AF_INET */
1019 tree = &r->addr_rbtree;
1020 expire_queue = &r->addr_expire_queue;
1021 }
1022
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001023 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
1024 "resolve addr done: %i", ctx->state);
1025
1026 if (ctx->event && ctx->event->timer_set) {
1027 ngx_del_timer(ctx->event);
1028 }
1029
1030 /* lock addr mutex */
1031
Ruslan Ermilov5f509b52016-01-26 16:46:31 +03001032 if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001033
Roman Arutyunyan38a72e92016-01-26 16:46:59 +03001034 rn = ctx->node;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001035
1036 if (rn) {
1037 p = &rn->waiting;
1038 w = rn->waiting;
1039
1040 while (w) {
1041 if (w == ctx) {
1042 *p = w->next;
1043
1044 goto done;
1045 }
1046
1047 p = &w->next;
1048 w = w->next;
1049 }
1050 }
1051
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001052 {
1053 u_char text[NGX_SOCKADDR_STRLEN];
1054 ngx_str_t addrtext;
1055
1056 addrtext.data = text;
1057 addrtext.len = ngx_sock_ntop(ctx->addr.sockaddr, ctx->addr.socklen,
1058 text, NGX_SOCKADDR_STRLEN, 0);
1059
1060 ngx_log_error(NGX_LOG_ALERT, r->log, 0,
1061 "could not cancel %V resolving", &addrtext);
1062 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001063 }
1064
1065done:
1066
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001067 ngx_resolver_expire(r, tree, expire_queue);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001068
1069 /* unlock addr mutex */
1070
Igor Sysoev7c4cf272008-02-28 20:09:39 +00001071 /* lock alloc mutex */
1072
1073 if (ctx->event) {
1074 ngx_resolver_free_locked(r, ctx->event);
1075 }
1076
1077 ngx_resolver_free_locked(r, ctx);
1078
1079 /* unlock alloc mutex */
Sergey Kandaurove6fdd2f2015-06-17 17:57:34 +03001080
1081 if (r->event->timer_set && ngx_resolver_resend_empty(r)) {
1082 ngx_del_timer(r->event);
1083 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001084}
1085
1086
1087static void
1088ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
1089{
1090 time_t now;
1091 ngx_uint_t i;
1092 ngx_queue_t *q;
1093 ngx_resolver_node_t *rn;
1094
1095 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver expire");
1096
1097 now = ngx_time();
1098
1099 for (i = 0; i < 2; i++) {
1100 if (ngx_queue_empty(queue)) {
1101 return;
1102 }
1103
1104 q = ngx_queue_last(queue);
1105
1106 rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
1107
1108 if (now <= rn->expire) {
1109 return;
1110 }
1111
Igor Sysoevd02661a2007-12-24 17:05:31 +00001112 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
1113 "resolver expire \"%*s\"", (size_t) rn->nlen, rn->name);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001114
1115 ngx_queue_remove(q);
1116
1117 ngx_rbtree_delete(tree, &rn->node);
1118
1119 ngx_resolver_free_node(r, rn);
1120 }
1121}
1122
1123
1124static ngx_int_t
1125ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn)
1126{
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001127 ngx_int_t rc;
Roman Arutyunyanec16a602016-01-28 15:28:20 +03001128 ngx_resolver_connection_t *rec;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001129
Roman Arutyunyanec16a602016-01-28 15:28:20 +03001130 rec = r->connections.elts;
Roman Arutyunyanb6a8f8c2016-01-28 15:28:20 +03001131 rec = &rec[rn->last_connection];
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001132
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001133 if (rec->log.handler == NULL) {
Roman Arutyunyanec16a602016-01-28 15:28:20 +03001134 rec->log = *r->log;
1135 rec->log.handler = ngx_resolver_log_error;
1136 rec->log.data = rec;
1137 rec->log.action = "resolving";
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001138 }
1139
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001140 if (rn->naddrs == (u_short) -1) {
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001141 rc = rn->tcp ? ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen)
1142 : ngx_resolver_send_udp_query(r, rec, rn->query, rn->qlen);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001143
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001144 if (rc != NGX_OK) {
1145 return rc;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001146 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001147 }
1148
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001149#if (NGX_HAVE_INET6)
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001150
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001151 if (rn->query6 && rn->naddrs6 == (u_short) -1) {
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001152 rc = rn->tcp6
1153 ? ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen)
1154 : ngx_resolver_send_udp_query(r, rec, rn->query6, rn->qlen);
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001155
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001156 if (rc != NGX_OK) {
1157 return rc;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001158 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001159 }
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001160
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001161#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001162
1163 return NGX_OK;
1164}
1165
1166
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001167static ngx_int_t
1168ngx_resolver_send_udp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec,
1169 u_char *query, u_short qlen)
1170{
1171 ssize_t n;
1172
1173 if (rec->udp == NULL) {
1174 if (ngx_udp_connect(rec) != NGX_OK) {
1175 return NGX_ERROR;
1176 }
1177
1178 rec->udp->data = rec;
1179 rec->udp->read->handler = ngx_resolver_udp_read;
1180 rec->udp->read->resolver = 1;
1181 }
1182
1183 n = ngx_send(rec->udp, query, qlen);
1184
1185 if (n == -1) {
1186 return NGX_ERROR;
1187 }
1188
1189 if ((size_t) n != (size_t) qlen) {
1190 ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete");
1191 return NGX_ERROR;
1192 }
1193
1194 return NGX_OK;
1195}
1196
1197
1198static ngx_int_t
1199ngx_resolver_send_tcp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec,
1200 u_char *query, u_short qlen)
1201{
1202 ngx_buf_t *b;
1203 ngx_int_t rc;
1204
1205 rc = NGX_OK;
1206
1207 if (rec->tcp == NULL) {
1208 b = rec->read_buf;
1209
1210 if (b == NULL) {
1211 b = ngx_resolver_calloc(r, sizeof(ngx_buf_t));
1212 if (b == NULL) {
1213 return NGX_ERROR;
1214 }
1215
1216 b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_RSIZE);
1217 if (b->start == NULL) {
Ruslan Ermilov0b6f2562016-02-02 11:35:19 +03001218 ngx_resolver_free(r, b);
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001219 return NGX_ERROR;
1220 }
1221
1222 b->end = b->start + NGX_RESOLVER_TCP_RSIZE;
1223
1224 rec->read_buf = b;
1225 }
1226
1227 b->pos = b->start;
1228 b->last = b->start;
1229
1230 b = rec->write_buf;
1231
1232 if (b == NULL) {
1233 b = ngx_resolver_calloc(r, sizeof(ngx_buf_t));
1234 if (b == NULL) {
1235 return NGX_ERROR;
1236 }
1237
1238 b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_WSIZE);
1239 if (b->start == NULL) {
Ruslan Ermilov0b6f2562016-02-02 11:35:19 +03001240 ngx_resolver_free(r, b);
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001241 return NGX_ERROR;
1242 }
1243
1244 b->end = b->start + NGX_RESOLVER_TCP_WSIZE;
1245
1246 rec->write_buf = b;
1247 }
1248
1249 b->pos = b->start;
1250 b->last = b->start;
1251
1252 rc = ngx_tcp_connect(rec);
1253 if (rc == NGX_ERROR) {
1254 return NGX_ERROR;
1255 }
1256
1257 rec->tcp->data = rec;
1258 rec->tcp->write->handler = ngx_resolver_tcp_write;
1259 rec->tcp->read->handler = ngx_resolver_tcp_read;
1260 rec->tcp->read->resolver = 1;
1261
1262 ngx_add_timer(rec->tcp->write, (ngx_msec_t) (r->tcp_timeout * 1000));
1263 }
1264
1265 b = rec->write_buf;
1266
1267 if (b->end - b->last < 2 + qlen) {
1268 ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "buffer overflow");
1269 return NGX_ERROR;
1270 }
1271
1272 *b->last++ = (u_char) (qlen >> 8);
1273 *b->last++ = (u_char) qlen;
1274 b->last = ngx_cpymem(b->last, query, qlen);
1275
1276 if (rc == NGX_OK) {
1277 ngx_resolver_tcp_write(rec->tcp->write);
1278 }
1279
1280 return NGX_OK;
1281}
1282
1283
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001284static void
1285ngx_resolver_resend_handler(ngx_event_t *ev)
1286{
1287 time_t timer, atimer, ntimer;
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001288#if (NGX_HAVE_INET6)
1289 time_t a6timer;
1290#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001291 ngx_resolver_t *r;
1292
1293 r = ev->data;
1294
1295 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0,
1296 "resolver resend handler");
1297
1298 /* lock name mutex */
1299
1300 ntimer = ngx_resolver_resend(r, &r->name_rbtree, &r->name_resend_queue);
1301
1302 /* unlock name mutex */
1303
1304 /* lock addr mutex */
1305
1306 atimer = ngx_resolver_resend(r, &r->addr_rbtree, &r->addr_resend_queue);
Igor Sysoevb4e5b4c2007-12-01 19:57:37 +00001307
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001308 /* unlock addr mutex */
1309
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001310#if (NGX_HAVE_INET6)
1311
1312 /* lock addr6 mutex */
1313
1314 a6timer = ngx_resolver_resend(r, &r->addr6_rbtree, &r->addr6_resend_queue);
1315
1316 /* unlock addr6 mutex */
1317
1318#endif
1319
1320 timer = ntimer;
1321
1322 if (timer == 0) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001323 timer = atimer;
1324
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001325 } else if (atimer) {
1326 timer = ngx_min(timer, atimer);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001327 }
1328
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001329#if (NGX_HAVE_INET6)
1330
1331 if (timer == 0) {
1332 timer = a6timer;
1333
1334 } else if (a6timer) {
1335 timer = ngx_min(timer, a6timer);
1336 }
1337
1338#endif
1339
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001340 if (timer) {
1341 ngx_add_timer(r->event, (ngx_msec_t) (timer * 1000));
1342 }
1343}
1344
1345
1346static time_t
1347ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
1348{
1349 time_t now;
1350 ngx_queue_t *q;
1351 ngx_resolver_node_t *rn;
1352
1353 now = ngx_time();
1354
1355 for ( ;; ) {
1356 if (ngx_queue_empty(queue)) {
1357 return 0;
1358 }
1359
1360 q = ngx_queue_last(queue);
1361
1362 rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
1363
1364 if (now < rn->expire) {
1365 return rn->expire - now;
1366 }
1367
Igor Sysoevd02661a2007-12-24 17:05:31 +00001368 ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
1369 "resolver resend \"%*s\" %p",
1370 (size_t) rn->nlen, rn->name, rn->waiting);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001371
1372 ngx_queue_remove(q);
1373
1374 if (rn->waiting) {
1375
Roman Arutyunyanb6a8f8c2016-01-28 15:28:20 +03001376 if (++rn->last_connection == r->connections.nelts) {
1377 rn->last_connection = 0;
1378 }
1379
Ruslan Ermilovda8bb222012-06-18 12:30:45 +00001380 (void) ngx_resolver_send_query(r, rn);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001381
Ruslan Ermilovda8bb222012-06-18 12:30:45 +00001382 rn->expire = now + r->resend_timeout;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001383
Ruslan Ermilovda8bb222012-06-18 12:30:45 +00001384 ngx_queue_insert_head(queue, q);
Igor Sysoev61adfb22008-02-06 16:08:52 +00001385
1386 continue;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001387 }
1388
1389 ngx_rbtree_delete(tree, &rn->node);
1390
1391 ngx_resolver_free_node(r, rn);
1392 }
1393}
1394
1395
Sergey Kandaurove6fdd2f2015-06-17 17:57:34 +03001396static ngx_uint_t
1397ngx_resolver_resend_empty(ngx_resolver_t *r)
1398{
1399 return ngx_queue_empty(&r->name_resend_queue)
1400#if (NGX_HAVE_INET6)
1401 && ngx_queue_empty(&r->addr6_resend_queue)
1402#endif
1403 && ngx_queue_empty(&r->addr_resend_queue);
1404}
1405
1406
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001407static void
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001408ngx_resolver_udp_read(ngx_event_t *rev)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001409{
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001410 ssize_t n;
1411 ngx_connection_t *c;
1412 ngx_resolver_connection_t *rec;
1413 u_char buf[NGX_RESOLVER_UDP_SIZE];
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001414
1415 c = rev->data;
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001416 rec = c->data;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001417
1418 do {
Igor Sysoeve67d4612007-12-03 16:46:46 +00001419 n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001420
Igor Sysoeve67d4612007-12-03 16:46:46 +00001421 if (n < 0) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001422 return;
1423 }
1424
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001425 ngx_resolver_process_response(rec->resolver, buf, n, 0);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001426
1427 } while (rev->ready);
1428}
1429
1430
1431static void
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001432ngx_resolver_tcp_write(ngx_event_t *wev)
1433{
1434 off_t sent;
1435 ssize_t n;
1436 ngx_buf_t *b;
1437 ngx_resolver_t *r;
1438 ngx_connection_t *c;
1439 ngx_resolver_connection_t *rec;
1440
1441 c = wev->data;
1442 rec = c->data;
1443 b = rec->write_buf;
1444 r = rec->resolver;
1445
1446 if (wev->timedout) {
1447 goto failed;
1448 }
1449
1450 sent = c->sent;
1451
1452 while (wev->ready && b->pos < b->last) {
1453 n = ngx_send(c, b->pos, b->last - b->pos);
1454
1455 if (n == NGX_AGAIN) {
1456 break;
1457 }
1458
1459 if (n == NGX_ERROR) {
1460 goto failed;
1461 }
1462
1463 b->pos += n;
1464 }
1465
1466 if (b->pos != b->start) {
1467 b->last = ngx_movemem(b->start, b->pos, b->last - b->pos);
1468 b->pos = b->start;
1469 }
1470
1471 if (c->sent != sent) {
1472 ngx_add_timer(wev, (ngx_msec_t) (r->tcp_timeout * 1000));
1473 }
1474
1475 if (ngx_handle_write_event(wev, 0) != NGX_OK) {
1476 goto failed;
1477 }
1478
1479 return;
1480
1481failed:
1482
1483 ngx_close_connection(c);
1484 rec->tcp = NULL;
1485}
1486
1487
1488static void
1489ngx_resolver_tcp_read(ngx_event_t *rev)
1490{
1491 u_char *p;
1492 size_t size;
1493 ssize_t n;
1494 u_short qlen;
1495 ngx_buf_t *b;
1496 ngx_resolver_t *r;
1497 ngx_connection_t *c;
1498 ngx_resolver_connection_t *rec;
1499
1500 c = rev->data;
1501 rec = c->data;
1502 b = rec->read_buf;
1503 r = rec->resolver;
1504
1505 while (rev->ready) {
1506 n = ngx_recv(c, b->last, b->end - b->last);
1507
1508 if (n == NGX_AGAIN) {
1509 break;
1510 }
1511
1512 if (n == NGX_ERROR || n == 0) {
1513 goto failed;
1514 }
1515
1516 b->last += n;
1517
1518 for ( ;; ) {
1519 p = b->pos;
1520 size = b->last - p;
1521
1522 if (size < 2) {
1523 break;
1524 }
1525
1526 qlen = (u_short) *p++ << 8;
1527 qlen += *p++;
1528
1529 if (size < (size_t) (2 + qlen)) {
1530 break;
1531 }
1532
1533 ngx_resolver_process_response(r, p, qlen, 1);
1534
1535 b->pos += 2 + qlen;
1536 }
1537
1538 if (b->pos != b->start) {
1539 b->last = ngx_movemem(b->start, b->pos, b->last - b->pos);
1540 b->pos = b->start;
1541 }
1542 }
1543
1544 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
1545 goto failed;
1546 }
1547
1548 return;
1549
1550failed:
1551
1552 ngx_close_connection(c);
1553 rec->tcp = NULL;
1554}
1555
1556
1557static void
1558ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n,
1559 ngx_uint_t tcp)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001560{
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001561 char *err;
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001562 ngx_uint_t i, times, ident, qident, flags, code, nqs, nan, trunc,
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001563 qtype, qclass;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001564#if (NGX_HAVE_INET6)
1565 ngx_uint_t qident6;
1566#endif
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001567 ngx_queue_t *q;
1568 ngx_resolver_qs_t *qs;
1569 ngx_resolver_hdr_t *response;
1570 ngx_resolver_node_t *rn;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001571
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001572 if (n < sizeof(ngx_resolver_hdr_t)) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001573 goto short_response;
1574 }
1575
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001576 response = (ngx_resolver_hdr_t *) buf;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001577
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001578 ident = (response->ident_hi << 8) + response->ident_lo;
1579 flags = (response->flags_hi << 8) + response->flags_lo;
1580 nqs = (response->nqs_hi << 8) + response->nqs_lo;
1581 nan = (response->nan_hi << 8) + response->nan_lo;
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001582 trunc = flags & 0x0200;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001583
1584 ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0,
Maxim Dounin01f1e4d2012-06-03 23:18:24 +00001585 "resolver DNS response %ui fl:%04Xui %ui/%ui/%ud/%ud",
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001586 ident, flags, nqs, nan,
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001587 (response->nns_hi << 8) + response->nns_lo,
1588 (response->nar_hi << 8) + response->nar_lo);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001589
Ruslan Ermilovf3a271f2013-12-06 14:30:27 +04001590 /* response to a standard query */
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001591 if ((flags & 0xf870) != 0x8000 || (trunc && tcp)) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001592 ngx_log_error(r->log_level, r->log, 0,
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001593 "invalid %s DNS response %ui fl:%04Xui",
1594 tcp ? "TCP" : "UDP", ident, flags);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001595 return;
1596 }
1597
Ruslan Ermilovf3a271f2013-12-06 14:30:27 +04001598 code = flags & 0xf;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001599
Igor Sysoev571a5e12008-10-24 14:38:09 +00001600 if (code == NGX_RESOLVE_FORMERR) {
1601
1602 times = 0;
1603
1604 for (q = ngx_queue_head(&r->name_resend_queue);
Roman Arutyunyan4f84c8d2016-01-26 16:46:18 +03001605 q != ngx_queue_sentinel(&r->name_resend_queue) && times++ < 100;
Igor Sysoev571a5e12008-10-24 14:38:09 +00001606 q = ngx_queue_next(q))
1607 {
1608 rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
1609 qident = (rn->query[0] << 8) + rn->query[1];
1610
1611 if (qident == ident) {
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001612 goto dns_error_name;
Igor Sysoev571a5e12008-10-24 14:38:09 +00001613 }
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001614
1615#if (NGX_HAVE_INET6)
1616 if (rn->query6) {
1617 qident6 = (rn->query6[0] << 8) + rn->query6[1];
1618
1619 if (qident6 == ident) {
1620 goto dns_error_name;
1621 }
1622 }
1623#endif
Igor Sysoev571a5e12008-10-24 14:38:09 +00001624 }
1625
1626 goto dns_error;
1627 }
1628
1629 if (code > NGX_RESOLVE_REFUSED) {
1630 goto dns_error;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001631 }
1632
1633 if (nqs != 1) {
1634 err = "invalid number of questions in DNS response";
1635 goto done;
1636 }
1637
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001638 i = sizeof(ngx_resolver_hdr_t);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001639
1640 while (i < (ngx_uint_t) n) {
1641 if (buf[i] == '\0') {
1642 goto found;
1643 }
1644
Ruslan Ermilovf3a271f2013-12-06 14:30:27 +04001645 i += 1 + buf[i];
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001646 }
1647
1648 goto short_response;
1649
1650found:
1651
Ruslan Ermilovf3a271f2013-12-06 14:30:27 +04001652 if (i++ == sizeof(ngx_resolver_hdr_t)) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001653 err = "zero-length domain name in DNS response";
1654 goto done;
1655 }
1656
1657 if (i + sizeof(ngx_resolver_qs_t) + nan * (2 + sizeof(ngx_resolver_an_t))
1658 > (ngx_uint_t) n)
1659 {
1660 goto short_response;
1661 }
1662
1663 qs = (ngx_resolver_qs_t *) &buf[i];
1664
1665 qtype = (qs->type_hi << 8) + qs->type_lo;
1666 qclass = (qs->class_hi << 8) + qs->class_lo;
1667
1668 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
Igor Sysoev7c5c1dc2008-04-10 17:27:07 +00001669 "resolver DNS response qt:%ui cl:%ui", qtype, qclass);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001670
1671 if (qclass != 1) {
1672 ngx_log_error(r->log_level, r->log, 0,
Igor Sysoev7c5c1dc2008-04-10 17:27:07 +00001673 "unknown query class %ui in DNS response", qclass);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001674 return;
1675 }
1676
1677 switch (qtype) {
1678
1679 case NGX_RESOLVE_A:
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001680#if (NGX_HAVE_INET6)
1681 case NGX_RESOLVE_AAAA:
1682#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001683
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001684 ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan, trunc,
Igor Sysoevc0cadf12007-12-16 20:47:55 +00001685 i + sizeof(ngx_resolver_qs_t));
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001686
1687 break;
1688
1689 case NGX_RESOLVE_PTR:
1690
Igor Sysoevc0cadf12007-12-16 20:47:55 +00001691 ngx_resolver_process_ptr(r, buf, n, ident, code, nan);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001692
1693 break;
1694
1695 default:
1696 ngx_log_error(r->log_level, r->log, 0,
Igor Sysoev7c5c1dc2008-04-10 17:27:07 +00001697 "unknown query type %ui in DNS response", qtype);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001698 return;
1699 }
1700
1701 return;
1702
1703short_response:
1704
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001705 err = "short DNS response";
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001706
1707done:
1708
1709 ngx_log_error(r->log_level, r->log, 0, err);
1710
1711 return;
Igor Sysoev571a5e12008-10-24 14:38:09 +00001712
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001713dns_error_name:
1714
1715 ngx_log_error(r->log_level, r->log, 0,
1716 "DNS error (%ui: %s), query id:%ui, name:\"%*s\"",
1717 code, ngx_resolver_strerror(code), ident,
1718 rn->nlen, rn->name);
1719 return;
1720
Igor Sysoev571a5e12008-10-24 14:38:09 +00001721dns_error:
1722
1723 ngx_log_error(r->log_level, r->log, 0,
1724 "DNS error (%ui: %s), query id:%ui",
1725 code, ngx_resolver_strerror(code), ident);
1726 return;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001727}
1728
1729
1730static void
1731ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001732 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001733 ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001734{
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001735 char *err;
1736 u_char *cname;
1737 size_t len;
1738 int32_t ttl;
1739 uint32_t hash;
1740 in_addr_t *addr;
1741 ngx_str_t name;
1742 ngx_addr_t *addrs;
1743 ngx_uint_t type, class, qident, naddrs, a, i, n, start;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001744#if (NGX_HAVE_INET6)
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001745 struct in6_addr *addr6;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001746#endif
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001747 ngx_resolver_an_t *an;
1748 ngx_resolver_ctx_t *ctx, *next;
1749 ngx_resolver_node_t *rn;
1750 ngx_resolver_connection_t *rec;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001751
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001752 if (ngx_resolver_copy(r, &name, buf,
1753 buf + sizeof(ngx_resolver_hdr_t), buf + last)
1754 != NGX_OK)
1755 {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001756 return;
1757 }
1758
1759 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
1760
1761 hash = ngx_crc32_short(name.data, name.len);
1762
1763 /* lock name mutex */
1764
1765 rn = ngx_resolver_lookup_name(r, &name, hash);
1766
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001767 if (rn == NULL) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001768 ngx_log_error(r->log_level, r->log, 0,
1769 "unexpected response for %V", &name);
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04001770 ngx_resolver_free(r, name.data);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001771 goto failed;
1772 }
1773
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001774 switch (qtype) {
1775
1776#if (NGX_HAVE_INET6)
1777 case NGX_RESOLVE_AAAA:
1778
1779 if (rn->query6 == NULL || rn->naddrs6 != (u_short) -1) {
1780 ngx_log_error(r->log_level, r->log, 0,
1781 "unexpected response for %V", &name);
1782 ngx_resolver_free(r, name.data);
1783 goto failed;
1784 }
1785
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001786 if (trunc && rn->tcp6) {
1787 ngx_resolver_free(r, name.data);
1788 goto failed;
1789 }
1790
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001791 qident = (rn->query6[0] << 8) + rn->query6[1];
1792
1793 break;
1794#endif
1795
1796 default: /* NGX_RESOLVE_A */
1797
1798 if (rn->query == NULL || rn->naddrs != (u_short) -1) {
1799 ngx_log_error(r->log_level, r->log, 0,
1800 "unexpected response for %V", &name);
1801 ngx_resolver_free(r, name.data);
1802 goto failed;
1803 }
1804
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001805 if (trunc && rn->tcp) {
1806 ngx_resolver_free(r, name.data);
1807 goto failed;
1808 }
1809
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001810 qident = (rn->query[0] << 8) + rn->query[1];
1811 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001812
1813 if (ident != qident) {
1814 ngx_log_error(r->log_level, r->log, 0,
Igor Sysoev7c5c1dc2008-04-10 17:27:07 +00001815 "wrong ident %ui response for %V, expect %ui",
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001816 ident, &name, qident);
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04001817 ngx_resolver_free(r, name.data);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001818 goto failed;
1819 }
1820
Igor Sysoev99651522009-09-16 13:48:11 +00001821 ngx_resolver_free(r, name.data);
1822
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001823 if (trunc) {
1824
1825 ngx_queue_remove(&rn->queue);
1826
1827 if (rn->waiting == NULL) {
1828 ngx_rbtree_delete(&r->name_rbtree, &rn->node);
1829 ngx_resolver_free_node(r, rn);
1830 goto next;
1831 }
1832
1833 rec = r->connections.elts;
1834 rec = &rec[rn->last_connection];
1835
1836 switch (qtype) {
1837
1838#if (NGX_HAVE_INET6)
1839 case NGX_RESOLVE_AAAA:
1840
1841 rn->tcp6 = 1;
1842
1843 (void) ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen);
1844
1845 break;
1846#endif
1847
1848 default: /* NGX_RESOLVE_A */
1849
1850 rn->tcp = 1;
1851
1852 (void) ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen);
1853 }
1854
1855 rn->expire = ngx_time() + r->resend_timeout;
1856
1857 ngx_queue_insert_head(&r->name_resend_queue, &rn->queue);
1858
1859 goto next;
1860 }
1861
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001862 if (code == 0 && rn->code) {
1863 code = rn->code;
1864 }
1865
Igor Sysoevc0cadf12007-12-16 20:47:55 +00001866 if (code == 0 && nan == 0) {
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001867
1868#if (NGX_HAVE_INET6)
1869 switch (qtype) {
1870
1871 case NGX_RESOLVE_AAAA:
1872
Ruslan Ermilov7e524322014-07-16 10:21:28 +04001873 rn->naddrs6 = 0;
1874
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001875 if (rn->naddrs == (u_short) -1) {
1876 goto next;
1877 }
1878
1879 if (rn->naddrs) {
1880 goto export;
1881 }
1882
1883 break;
1884
1885 default: /* NGX_RESOLVE_A */
1886
Ruslan Ermilov7e524322014-07-16 10:21:28 +04001887 rn->naddrs = 0;
1888
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001889 if (rn->naddrs6 == (u_short) -1) {
1890 goto next;
1891 }
1892
1893 if (rn->naddrs6) {
1894 goto export;
1895 }
1896 }
1897#endif
1898
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001899 code = NGX_RESOLVE_NXDOMAIN;
Igor Sysoevc0cadf12007-12-16 20:47:55 +00001900 }
1901
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001902 if (code) {
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001903
1904#if (NGX_HAVE_INET6)
1905 switch (qtype) {
1906
1907 case NGX_RESOLVE_AAAA:
1908
Ruslan Ermilov7e524322014-07-16 10:21:28 +04001909 rn->naddrs6 = 0;
1910
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001911 if (rn->naddrs == (u_short) -1) {
1912 rn->code = (u_char) code;
1913 goto next;
1914 }
1915
1916 break;
1917
1918 default: /* NGX_RESOLVE_A */
1919
Ruslan Ermilov7e524322014-07-16 10:21:28 +04001920 rn->naddrs = 0;
1921
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001922 if (rn->naddrs6 == (u_short) -1) {
1923 rn->code = (u_char) code;
1924 goto next;
1925 }
1926 }
1927#endif
1928
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001929 next = rn->waiting;
1930 rn->waiting = NULL;
1931
1932 ngx_queue_remove(&rn->queue);
1933
1934 ngx_rbtree_delete(&r->name_rbtree, &rn->node);
1935
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001936 /* unlock name mutex */
1937
1938 while (next) {
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04001939 ctx = next;
1940 ctx->state = code;
1941 next = ctx->next;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001942
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04001943 ctx->handler(ctx);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001944 }
1945
Ruslan Ermilovd4b7b742014-11-20 15:24:40 +03001946 ngx_resolver_free_node(r, rn);
1947
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001948 return;
1949 }
1950
1951 i = ans;
1952 naddrs = 0;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001953 cname = NULL;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001954
1955 for (a = 0; a < nan; a++) {
1956
1957 start = i;
1958
1959 while (i < last) {
1960
1961 if (buf[i] & 0xc0) {
1962 i += 2;
1963 goto found;
1964 }
1965
1966 if (buf[i] == 0) {
1967 i++;
1968 goto test_length;
1969 }
1970
1971 i += 1 + buf[i];
1972 }
1973
1974 goto short_response;
1975
1976 test_length:
1977
1978 if (i - start < 2) {
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001979 err = "invalid name in DNS response";
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001980 goto invalid;
1981 }
1982
1983 found:
1984
1985 if (i + sizeof(ngx_resolver_an_t) >= last) {
1986 goto short_response;
1987 }
1988
1989 an = (ngx_resolver_an_t *) &buf[i];
1990
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001991 type = (an->type_hi << 8) + an->type_lo;
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04001992 class = (an->class_hi << 8) + an->class_lo;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001993 len = (an->len_hi << 8) + an->len_lo;
Ruslan Ermilovbec516b2011-11-16 13:11:39 +00001994 ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
1995 + (an->ttl[2] << 8) + (an->ttl[3]);
1996
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04001997 if (class != 1) {
1998 ngx_log_error(r->log_level, r->log, 0,
1999 "unexpected RR class %ui", class);
2000 goto failed;
2001 }
2002
Ruslan Ermilovbec516b2011-11-16 13:11:39 +00002003 if (ttl < 0) {
2004 ttl = 0;
2005 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002006
Ruslan Ermilov85e6d212013-12-16 19:12:23 +04002007 rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl);
2008
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002009 i += sizeof(ngx_resolver_an_t);
2010
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002011 switch (type) {
2012
2013 case NGX_RESOLVE_A:
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002014
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002015 if (qtype != NGX_RESOLVE_A) {
2016 err = "unexpected A record in DNS response";
2017 goto invalid;
2018 }
2019
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002020 if (len != 4) {
2021 err = "invalid A record in DNS response";
2022 goto invalid;
2023 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002024
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002025 if (i + 4 > last) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002026 goto short_response;
2027 }
2028
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002029 naddrs++;
2030
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002031 break;
2032
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002033#if (NGX_HAVE_INET6)
2034 case NGX_RESOLVE_AAAA:
2035
2036 if (qtype != NGX_RESOLVE_AAAA) {
2037 err = "unexpected AAAA record in DNS response";
2038 goto invalid;
2039 }
2040
2041 if (len != 16) {
2042 err = "invalid AAAA record in DNS response";
2043 goto invalid;
2044 }
2045
2046 if (i + 16 > last) {
2047 goto short_response;
2048 }
2049
2050 naddrs++;
2051
2052 break;
2053#endif
2054
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002055 case NGX_RESOLVE_CNAME:
2056
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002057 cname = &buf[i];
Igor Sysoev19540cd2008-04-10 17:12:21 +00002058
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002059 break;
2060
2061 case NGX_RESOLVE_DNAME:
2062
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002063 break;
2064
2065 default:
2066
Igor Sysoev4ad5be62008-04-10 17:26:14 +00002067 ngx_log_error(r->log_level, r->log, 0,
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002068 "unexpected RR type %ui", type);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002069 }
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002070
2071 i += len;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002072 }
2073
Ruslan Ermilovbec516b2011-11-16 13:11:39 +00002074 ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
Ruslan Ermilov85e6d212013-12-16 19:12:23 +04002075 "resolver naddrs:%ui cname:%p ttl:%uD",
2076 naddrs, cname, rn->ttl);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002077
2078 if (naddrs) {
2079
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002080 switch (qtype) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002081
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002082#if (NGX_HAVE_INET6)
2083 case NGX_RESOLVE_AAAA:
2084
2085 if (naddrs == 1) {
2086 addr6 = &rn->u6.addr6;
2087 rn->naddrs6 = 1;
2088
2089 } else {
2090 addr6 = ngx_resolver_alloc(r, naddrs * sizeof(struct in6_addr));
2091 if (addr6 == NULL) {
2092 goto failed;
2093 }
2094
2095 rn->u6.addrs6 = addr6;
2096 rn->naddrs6 = (u_short) naddrs;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002097 }
2098
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002099#if (NGX_SUPPRESS_WARN)
2100 addr = NULL;
2101#endif
2102
2103 break;
2104#endif
2105
2106 default: /* NGX_RESOLVE_A */
2107
2108 if (naddrs == 1) {
2109 addr = &rn->u.addr;
2110 rn->naddrs = 1;
2111
2112 } else {
2113 addr = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
2114 if (addr == NULL) {
2115 goto failed;
2116 }
2117
2118 rn->u.addrs = addr;
2119 rn->naddrs = (u_short) naddrs;
2120 }
2121
2122#if (NGX_HAVE_INET6 && NGX_SUPPRESS_WARN)
2123 addr6 = NULL;
2124#endif
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002125 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002126
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002127 n = 0;
2128 i = ans;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002129
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002130 for (a = 0; a < nan; a++) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002131
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002132 for ( ;; ) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002133
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002134 if (buf[i] & 0xc0) {
2135 i += 2;
2136 break;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002137 }
2138
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002139 if (buf[i] == 0) {
2140 i++;
2141 break;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002142 }
2143
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002144 i += 1 + buf[i];
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002145 }
2146
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002147 an = (ngx_resolver_an_t *) &buf[i];
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002148
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002149 type = (an->type_hi << 8) + an->type_lo;
2150 len = (an->len_hi << 8) + an->len_lo;
2151
2152 i += sizeof(ngx_resolver_an_t);
2153
2154 if (type == NGX_RESOLVE_A) {
2155
2156 addr[n] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
2157 + (buf[i + 2] << 8) + (buf[i + 3]));
2158
2159 if (++n == naddrs) {
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002160
2161#if (NGX_HAVE_INET6)
2162 if (rn->naddrs6 == (u_short) -1) {
2163 goto next;
2164 }
2165#endif
2166
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002167 break;
2168 }
2169 }
2170
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002171#if (NGX_HAVE_INET6)
2172 else if (type == NGX_RESOLVE_AAAA) {
2173
2174 ngx_memcpy(addr6[n].s6_addr, &buf[i], 16);
2175
2176 if (++n == naddrs) {
2177
2178 if (rn->naddrs == (u_short) -1) {
2179 goto next;
2180 }
2181
2182 break;
2183 }
2184 }
2185#endif
2186
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002187 i += len;
2188 }
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002189 }
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002190
Ruslan Ermilov7e524322014-07-16 10:21:28 +04002191 switch (qtype) {
2192
2193#if (NGX_HAVE_INET6)
2194 case NGX_RESOLVE_AAAA:
2195
2196 if (rn->naddrs6 == (u_short) -1) {
2197 rn->naddrs6 = 0;
2198 }
2199
2200 break;
2201#endif
2202
2203 default: /* NGX_RESOLVE_A */
2204
2205 if (rn->naddrs == (u_short) -1) {
2206 rn->naddrs = 0;
2207 }
2208 }
2209
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002210 if (rn->naddrs != (u_short) -1
2211#if (NGX_HAVE_INET6)
2212 && rn->naddrs6 != (u_short) -1
2213#endif
2214 && rn->naddrs
2215#if (NGX_HAVE_INET6)
2216 + rn->naddrs6
2217#endif
2218 > 0)
2219 {
2220
2221#if (NGX_HAVE_INET6)
2222 export:
2223#endif
2224
2225 naddrs = rn->naddrs;
2226#if (NGX_HAVE_INET6)
2227 naddrs += rn->naddrs6;
2228#endif
2229
2230 if (naddrs == 1 && rn->naddrs == 1) {
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002231 addrs = NULL;
2232
2233 } else {
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002234 addrs = ngx_resolver_export(r, rn, 0);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002235 if (addrs == NULL) {
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002236 goto failed;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002237 }
2238 }
2239
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002240 ngx_queue_remove(&rn->queue);
2241
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002242 rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002243 rn->expire = ngx_time() + r->expire;
2244
2245 ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
2246
2247 next = rn->waiting;
2248 rn->waiting = NULL;
2249
2250 /* unlock name mutex */
2251
2252 while (next) {
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04002253 ctx = next;
2254 ctx->state = NGX_OK;
2255 ctx->naddrs = naddrs;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002256
2257 if (addrs == NULL) {
2258 ctx->addrs = &ctx->addr;
2259 ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
2260 ctx->addr.socklen = sizeof(struct sockaddr_in);
2261 ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
2262 ctx->sin.sin_family = AF_INET;
2263 ctx->sin.sin_addr.s_addr = rn->u.addr;
2264
2265 } else {
2266 ctx->addrs = addrs;
2267 }
2268
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04002269 next = ctx->next;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002270
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04002271 ctx->handler(ctx);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002272 }
2273
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002274 if (addrs != NULL) {
2275 ngx_resolver_free(r, addrs->sockaddr);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002276 ngx_resolver_free(r, addrs);
2277 }
2278
Maxim Dounin7d863c02012-05-14 09:13:45 +00002279 ngx_resolver_free(r, rn->query);
2280 rn->query = NULL;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002281#if (NGX_HAVE_INET6)
2282 rn->query6 = NULL;
2283#endif
Maxim Dounin7d863c02012-05-14 09:13:45 +00002284
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002285 return;
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002286 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002287
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002288 if (cname) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002289
2290 /* CNAME only */
2291
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002292 if (rn->naddrs == (u_short) -1
2293#if (NGX_HAVE_INET6)
2294 || rn->naddrs6 == (u_short) -1
2295#endif
2296 )
2297 {
2298 goto next;
2299 }
2300
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002301 if (ngx_resolver_copy(r, &name, buf, cname, buf + last) != NGX_OK) {
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002302 goto failed;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002303 }
2304
2305 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
2306 "resolver cname:\"%V\"", &name);
2307
Igor Sysoev28bca1b2007-12-16 20:00:15 +00002308 ngx_queue_remove(&rn->queue);
2309
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002310 rn->cnlen = (u_short) name.len;
2311 rn->u.cname = name.data;
Ruslan Ermilovbec516b2011-11-16 13:11:39 +00002312
Ruslan Ermilov85e6d212013-12-16 19:12:23 +04002313 rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002314 rn->expire = ngx_time() + r->expire;
2315
2316 ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
2317
Ruslan Ermilov65a043f2016-01-26 16:47:14 +03002318 ngx_resolver_free(r, rn->query);
2319 rn->query = NULL;
2320#if (NGX_HAVE_INET6)
2321 rn->query6 = NULL;
2322#endif
2323
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002324 ctx = rn->waiting;
2325 rn->waiting = NULL;
2326
2327 if (ctx) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002328
Ruslan Ermilov65a043f2016-01-26 16:47:14 +03002329 if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) {
2330
2331 /* unlock name mutex */
2332
2333 do {
2334 ctx->state = NGX_RESOLVE_NXDOMAIN;
2335 next = ctx->next;
2336
2337 ctx->handler(ctx);
2338
2339 ctx = next;
2340 } while (ctx);
2341
2342 return;
2343 }
2344
Roman Arutyunyan38a72e92016-01-26 16:46:59 +03002345 for (next = ctx; next; next = next->next) {
2346 next->node = NULL;
2347 }
2348
2349 (void) ngx_resolve_name_locked(r, ctx, &name);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002350 }
2351
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002352 /* unlock name mutex */
2353
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002354 return;
2355 }
2356
2357 ngx_log_error(r->log_level, r->log, 0,
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002358 "no A or CNAME types in DNS response");
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002359 return;
2360
2361short_response:
2362
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002363 err = "short DNS response";
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002364
2365invalid:
2366
2367 /* unlock name mutex */
2368
2369 ngx_log_error(r->log_level, r->log, 0, err);
2370
2371 return;
2372
2373failed:
2374
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002375next:
2376
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002377 /* unlock name mutex */
2378
2379 return;
2380}
2381
2382
2383static void
2384ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
Igor Sysoevc0cadf12007-12-16 20:47:55 +00002385 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002386{
2387 char *err;
2388 size_t len;
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002389 u_char text[NGX_SOCKADDR_STRLEN];
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002390 in_addr_t addr;
Ruslan Ermilovbec516b2011-11-16 13:11:39 +00002391 int32_t ttl;
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002392 ngx_int_t octet;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002393 ngx_str_t name;
Ruslan Ermilov15948622013-12-06 14:30:27 +04002394 ngx_uint_t i, mask, qident, class;
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002395 ngx_queue_t *expire_queue;
2396 ngx_rbtree_t *tree;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002397 ngx_resolver_an_t *an;
2398 ngx_resolver_ctx_t *ctx, *next;
2399 ngx_resolver_node_t *rn;
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002400#if (NGX_HAVE_INET6)
2401 uint32_t hash;
2402 ngx_int_t digit;
2403 struct in6_addr addr6;
2404#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002405
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002406 if (ngx_resolver_copy(r, NULL, buf,
2407 buf + sizeof(ngx_resolver_hdr_t), buf + n)
2408 != NGX_OK)
2409 {
Ruslan Ermilov15948622013-12-06 14:30:27 +04002410 return;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002411 }
2412
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002413 /* AF_INET */
2414
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002415 addr = 0;
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002416 i = sizeof(ngx_resolver_hdr_t);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002417
2418 for (mask = 0; mask < 32; mask += 8) {
2419 len = buf[i++];
2420
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002421 octet = ngx_atoi(&buf[i], len);
2422 if (octet == NGX_ERROR || octet > 255) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002423 goto invalid_in_addr_arpa;
2424 }
2425
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002426 addr += octet << mask;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002427 i += len;
2428 }
2429
Ruslan Ermilov3fd72752013-12-13 20:49:52 +04002430 if (ngx_strcasecmp(&buf[i], (u_char *) "\7in-addr\4arpa") == 0) {
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002431 i += sizeof("\7in-addr\4arpa");
2432
2433 /* lock addr mutex */
2434
2435 rn = ngx_resolver_lookup_addr(r, addr);
2436
2437 tree = &r->addr_rbtree;
2438 expire_queue = &r->addr_expire_queue;
2439
2440 addr = htonl(addr);
2441 name.len = ngx_inet_ntop(AF_INET, &addr, text, NGX_SOCKADDR_STRLEN);
2442 name.data = text;
2443
2444 goto valid;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002445 }
2446
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002447invalid_in_addr_arpa:
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002448
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002449#if (NGX_HAVE_INET6)
2450
2451 i = sizeof(ngx_resolver_hdr_t);
2452
2453 for (octet = 15; octet >= 0; octet--) {
2454 if (buf[i++] != '\1') {
2455 goto invalid_ip6_arpa;
2456 }
2457
2458 digit = ngx_hextoi(&buf[i++], 1);
2459 if (digit == NGX_ERROR) {
2460 goto invalid_ip6_arpa;
2461 }
2462
2463 addr6.s6_addr[octet] = (u_char) digit;
2464
2465 if (buf[i++] != '\1') {
2466 goto invalid_ip6_arpa;
2467 }
2468
2469 digit = ngx_hextoi(&buf[i++], 1);
2470 if (digit == NGX_ERROR) {
2471 goto invalid_ip6_arpa;
2472 }
2473
2474 addr6.s6_addr[octet] += (u_char) (digit * 16);
2475 }
2476
Ruslan Ermilov3fd72752013-12-13 20:49:52 +04002477 if (ngx_strcasecmp(&buf[i], (u_char *) "\3ip6\4arpa") == 0) {
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002478 i += sizeof("\3ip6\4arpa");
2479
2480 /* lock addr mutex */
2481
2482 hash = ngx_crc32_short(addr6.s6_addr, 16);
2483 rn = ngx_resolver_lookup_addr6(r, &addr6, hash);
2484
2485 tree = &r->addr6_rbtree;
2486 expire_queue = &r->addr6_expire_queue;
2487
2488 name.len = ngx_inet6_ntop(addr6.s6_addr, text, NGX_SOCKADDR_STRLEN);
2489 name.data = text;
2490
2491 goto valid;
2492 }
2493
2494invalid_ip6_arpa:
2495#endif
2496
2497 ngx_log_error(r->log_level, r->log, 0,
2498 "invalid in-addr.arpa or ip6.arpa name in DNS response");
2499 return;
2500
2501valid:
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002502
2503 if (rn == NULL || rn->query == NULL) {
2504 ngx_log_error(r->log_level, r->log, 0,
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002505 "unexpected response for %V", &name);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002506 goto failed;
2507 }
2508
2509 qident = (rn->query[0] << 8) + rn->query[1];
2510
2511 if (ident != qident) {
2512 ngx_log_error(r->log_level, r->log, 0,
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002513 "wrong ident %ui response for %V, expect %ui",
2514 ident, &name, qident);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002515 goto failed;
2516 }
2517
Igor Sysoevc0cadf12007-12-16 20:47:55 +00002518 if (code == 0 && nan == 0) {
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002519 code = NGX_RESOLVE_NXDOMAIN;
Igor Sysoevc0cadf12007-12-16 20:47:55 +00002520 }
2521
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002522 if (code) {
2523 next = rn->waiting;
2524 rn->waiting = NULL;
2525
2526 ngx_queue_remove(&rn->queue);
2527
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002528 ngx_rbtree_delete(tree, &rn->node);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002529
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002530 /* unlock addr mutex */
2531
2532 while (next) {
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04002533 ctx = next;
2534 ctx->state = code;
2535 next = ctx->next;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002536
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04002537 ctx->handler(ctx);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002538 }
2539
Ruslan Ermilovd4b7b742014-11-20 15:24:40 +03002540 ngx_resolver_free_node(r, rn);
2541
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002542 return;
2543 }
2544
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002545 i += sizeof(ngx_resolver_qs_t);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002546
Ruslan Ermilov15948622013-12-06 14:30:27 +04002547 if (i + 2 + sizeof(ngx_resolver_an_t) >= n) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002548 goto short_response;
2549 }
2550
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002551 /* compression pointer to *.arpa */
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002552
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002553 if (buf[i] != 0xc0 || buf[i + 1] != sizeof(ngx_resolver_hdr_t)) {
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002554 err = "invalid in-addr.arpa or ip6.arpa name in DNS response";
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002555 goto invalid;
2556 }
2557
2558 an = (ngx_resolver_an_t *) &buf[i + 2];
2559
Ruslan Ermilov15948622013-12-06 14:30:27 +04002560 class = (an->class_hi << 8) + an->class_lo;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002561 len = (an->len_hi << 8) + an->len_lo;
Ruslan Ermilovbec516b2011-11-16 13:11:39 +00002562 ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
2563 + (an->ttl[2] << 8) + (an->ttl[3]);
2564
Ruslan Ermilov15948622013-12-06 14:30:27 +04002565 if (class != 1) {
2566 ngx_log_error(r->log_level, r->log, 0,
2567 "unexpected RR class %ui", class);
2568 goto failed;
2569 }
2570
Ruslan Ermilovbec516b2011-11-16 13:11:39 +00002571 if (ttl < 0) {
2572 ttl = 0;
2573 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002574
2575 ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
Igor Sysoevefde3eb2011-04-23 17:25:06 +00002576 "resolver qt:%ui cl:%ui len:%uz",
2577 (an->type_hi << 8) + an->type_lo,
Ruslan Ermilov15948622013-12-06 14:30:27 +04002578 class, len);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002579
2580 i += 2 + sizeof(ngx_resolver_an_t);
2581
Ruslan Ermilov23071832013-12-06 14:30:27 +04002582 if (i + len > n) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002583 goto short_response;
2584 }
2585
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002586 if (ngx_resolver_copy(r, &name, buf, buf + i, buf + n) != NGX_OK) {
Ruslan Ermilov15948622013-12-06 14:30:27 +04002587 goto failed;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002588 }
2589
2590 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name);
2591
Igor Sysoev2c01fd32009-01-30 11:56:45 +00002592 if (name.len != (size_t) rn->nlen
2593 || ngx_strncmp(name.data, rn->name, name.len) != 0)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002594 {
Igor Sysoev8629b9b2009-01-29 14:29:49 +00002595 if (rn->nlen) {
2596 ngx_resolver_free(r, rn->name);
2597 }
2598
Igor Sysoev9a5f4c72009-02-02 10:17:06 +00002599 rn->nlen = (u_short) name.len;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002600 rn->name = name.data;
2601
Igor Sysoev2c01fd32009-01-30 11:56:45 +00002602 name.data = ngx_resolver_dup(r, rn->name, name.len);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002603 if (name.data == NULL) {
2604 goto failed;
2605 }
2606 }
2607
2608 ngx_queue_remove(&rn->queue);
2609
Ruslan Ermilovbec516b2011-11-16 13:11:39 +00002610 rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002611 rn->expire = ngx_time() + r->expire;
2612
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002613 ngx_queue_insert_head(expire_queue, &rn->queue);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002614
2615 next = rn->waiting;
2616 rn->waiting = NULL;
2617
2618 /* unlock addr mutex */
2619
2620 while (next) {
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04002621 ctx = next;
2622 ctx->state = NGX_OK;
2623 ctx->name = name;
2624 next = ctx->next;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002625
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04002626 ctx->handler(ctx);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002627 }
2628
2629 ngx_resolver_free(r, name.data);
2630
2631 return;
2632
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002633short_response:
2634
2635 err = "short DNS response";
2636
2637invalid:
2638
2639 /* unlock addr mutex */
2640
2641 ngx_log_error(r->log_level, r->log, 0, err);
2642
2643 return;
2644
2645failed:
2646
2647 /* unlock addr mutex */
2648
2649 return;
2650}
2651
2652
2653static ngx_resolver_node_t *
2654ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
2655{
2656 ngx_int_t rc;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002657 ngx_rbtree_node_t *node, *sentinel;
2658 ngx_resolver_node_t *rn;
2659
2660 node = r->name_rbtree.root;
2661 sentinel = r->name_rbtree.sentinel;
2662
2663 while (node != sentinel) {
2664
2665 if (hash < node->key) {
2666 node = node->left;
2667 continue;
2668 }
2669
2670 if (hash > node->key) {
2671 node = node->right;
2672 continue;
2673 }
2674
2675 /* hash == node->key */
2676
Ruslan Ermilovef563de2014-11-20 15:24:42 +03002677 rn = ngx_resolver_node(node);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002678
Maxim Dounin7ca6c1f2012-02-27 22:15:39 +00002679 rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002680
Maxim Dounin7ca6c1f2012-02-27 22:15:39 +00002681 if (rc == 0) {
2682 return rn;
2683 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002684
Maxim Dounin7ca6c1f2012-02-27 22:15:39 +00002685 node = (rc < 0) ? node->left : node->right;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002686 }
2687
2688 /* not found */
2689
2690 return NULL;
2691}
2692
2693
2694static ngx_resolver_node_t *
2695ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr)
2696{
2697 ngx_rbtree_node_t *node, *sentinel;
2698
2699 node = r->addr_rbtree.root;
2700 sentinel = r->addr_rbtree.sentinel;
2701
2702 while (node != sentinel) {
2703
2704 if (addr < node->key) {
2705 node = node->left;
2706 continue;
2707 }
2708
2709 if (addr > node->key) {
2710 node = node->right;
2711 continue;
2712 }
2713
2714 /* addr == node->key */
2715
Ruslan Ermilovef563de2014-11-20 15:24:42 +03002716 return ngx_resolver_node(node);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002717 }
2718
2719 /* not found */
2720
2721 return NULL;
2722}
2723
2724
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002725#if (NGX_HAVE_INET6)
2726
2727static ngx_resolver_node_t *
2728ngx_resolver_lookup_addr6(ngx_resolver_t *r, struct in6_addr *addr,
2729 uint32_t hash)
2730{
2731 ngx_int_t rc;
2732 ngx_rbtree_node_t *node, *sentinel;
2733 ngx_resolver_node_t *rn;
2734
2735 node = r->addr6_rbtree.root;
2736 sentinel = r->addr6_rbtree.sentinel;
2737
2738 while (node != sentinel) {
2739
2740 if (hash < node->key) {
2741 node = node->left;
2742 continue;
2743 }
2744
2745 if (hash > node->key) {
2746 node = node->right;
2747 continue;
2748 }
2749
2750 /* hash == node->key */
2751
Ruslan Ermilovef563de2014-11-20 15:24:42 +03002752 rn = ngx_resolver_node(node);
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002753
2754 rc = ngx_memcmp(addr, &rn->addr6, 16);
2755
2756 if (rc == 0) {
2757 return rn;
2758 }
2759
2760 node = (rc < 0) ? node->left : node->right;
2761 }
2762
2763 /* not found */
2764
2765 return NULL;
2766}
2767
2768#endif
2769
2770
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002771static void
2772ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
2773 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
2774{
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002775 ngx_rbtree_node_t **p;
2776 ngx_resolver_node_t *rn, *rn_temp;
2777
2778 for ( ;; ) {
2779
2780 if (node->key < temp->key) {
2781
2782 p = &temp->left;
2783
2784 } else if (node->key > temp->key) {
2785
2786 p = &temp->right;
2787
2788 } else { /* node->key == temp->key */
2789
Ruslan Ermilovef563de2014-11-20 15:24:42 +03002790 rn = ngx_resolver_node(node);
2791 rn_temp = ngx_resolver_node(temp);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002792
Igor Sysoeva8d3d222009-09-19 16:15:13 +00002793 p = (ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen, rn_temp->nlen)
2794 < 0) ? &temp->left : &temp->right;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002795 }
2796
2797 if (*p == sentinel) {
2798 break;
2799 }
2800
2801 temp = *p;
2802 }
2803
2804 *p = node;
2805 node->parent = temp;
2806 node->left = sentinel;
2807 node->right = sentinel;
2808 ngx_rbt_red(node);
2809}
2810
2811
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002812#if (NGX_HAVE_INET6)
2813
2814static void
2815ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
2816 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
2817{
2818 ngx_rbtree_node_t **p;
2819 ngx_resolver_node_t *rn, *rn_temp;
2820
2821 for ( ;; ) {
2822
2823 if (node->key < temp->key) {
2824
2825 p = &temp->left;
2826
2827 } else if (node->key > temp->key) {
2828
2829 p = &temp->right;
2830
2831 } else { /* node->key == temp->key */
2832
Ruslan Ermilovef563de2014-11-20 15:24:42 +03002833 rn = ngx_resolver_node(node);
2834 rn_temp = ngx_resolver_node(temp);
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002835
2836 p = (ngx_memcmp(&rn->addr6, &rn_temp->addr6, 16)
2837 < 0) ? &temp->left : &temp->right;
2838 }
2839
2840 if (*p == sentinel) {
2841 break;
2842 }
2843
2844 temp = *p;
2845 }
2846
2847 *p = node;
2848 node->parent = temp;
2849 node->left = sentinel;
2850 node->right = sentinel;
2851 ngx_rbt_red(node);
2852}
2853
2854#endif
2855
2856
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002857static ngx_int_t
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03002858ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
2859 ngx_str_t *name)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002860{
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002861 u_char *p, *s;
2862 size_t len, nlen;
2863 ngx_uint_t ident;
2864 ngx_resolver_qs_t *qs;
2865 ngx_resolver_hdr_t *query;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002866
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03002867 nlen = name->len ? (1 + name->len + 1) : 1;
Igor Sysoeve79f4292009-11-11 14:27:24 +00002868
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002869 len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002870
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002871#if (NGX_HAVE_INET6)
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03002872 p = ngx_resolver_alloc(r, r->ipv6 ? len * 2 : len);
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002873#else
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03002874 p = ngx_resolver_alloc(r, len);
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002875#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002876 if (p == NULL) {
2877 return NGX_ERROR;
2878 }
2879
2880 rn->qlen = (u_short) len;
2881 rn->query = p;
2882
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002883#if (NGX_HAVE_INET6)
Ruslan Ermilove0caf512013-12-09 10:53:30 +04002884 if (r->ipv6) {
2885 rn->query6 = p + len;
2886 }
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002887#endif
2888
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002889 query = (ngx_resolver_hdr_t *) p;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002890
2891 ident = ngx_random();
2892
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03002893 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
2894 "resolve: \"%V\" A %i", name, ident & 0xffff);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002895
2896 query->ident_hi = (u_char) ((ident >> 8) & 0xff);
2897 query->ident_lo = (u_char) (ident & 0xff);
2898
2899 /* recursion query */
2900 query->flags_hi = 1; query->flags_lo = 0;
2901
2902 /* one question */
2903 query->nqs_hi = 0; query->nqs_lo = 1;
2904 query->nan_hi = 0; query->nan_lo = 0;
2905 query->nns_hi = 0; query->nns_lo = 0;
2906 query->nar_hi = 0; query->nar_lo = 0;
2907
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002908 p += sizeof(ngx_resolver_hdr_t) + nlen;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002909
2910 qs = (ngx_resolver_qs_t *) p;
2911
2912 /* query type */
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002913 qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_A;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002914
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002915 /* IN query class */
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002916 qs->class_hi = 0; qs->class_lo = 1;
2917
2918 /* convert "www.example.com" to "\3www\7example\3com\0" */
2919
2920 len = 0;
2921 p--;
2922 *p-- = '\0';
2923
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03002924 if (name->len == 0) {
Ruslan Ermilov487ba702012-04-26 12:58:42 +00002925 return NGX_DECLINED;
2926 }
2927
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03002928 for (s = name->data + name->len - 1; s >= name->data; s--) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002929 if (*s != '.') {
2930 *p = *s;
2931 len++;
2932
2933 } else {
Maxim Dounine34ff162012-03-22 11:57:18 +00002934 if (len == 0 || len > 255) {
Igor Sysoev09b199c2008-04-09 14:45:39 +00002935 return NGX_DECLINED;
2936 }
2937
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002938 *p = (u_char) len;
2939 len = 0;
2940 }
2941
2942 p--;
2943 }
2944
Maxim Dounine34ff162012-03-22 11:57:18 +00002945 if (len == 0 || len > 255) {
2946 return NGX_DECLINED;
2947 }
2948
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002949 *p = (u_char) len;
2950
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002951#if (NGX_HAVE_INET6)
Ruslan Ermilove0caf512013-12-09 10:53:30 +04002952 if (!r->ipv6) {
2953 return NGX_OK;
2954 }
2955
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002956 p = rn->query6;
2957
2958 ngx_memcpy(p, rn->query, rn->qlen);
2959
2960 query = (ngx_resolver_hdr_t *) p;
2961
2962 ident = ngx_random();
2963
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03002964 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
2965 "resolve: \"%V\" AAAA %i", name, ident & 0xffff);
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002966
2967 query->ident_hi = (u_char) ((ident >> 8) & 0xff);
2968 query->ident_lo = (u_char) (ident & 0xff);
2969
2970 p += sizeof(ngx_resolver_hdr_t) + nlen;
2971
2972 qs = (ngx_resolver_qs_t *) p;
2973
2974 qs->type_lo = NGX_RESOLVE_AAAA;
2975#endif
2976
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002977 return NGX_OK;
2978}
2979
2980
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002981static ngx_int_t
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03002982ngx_resolver_create_addr_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
2983 ngx_addr_t *addr)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002984{
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002985 u_char *p, *d;
2986 size_t len;
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03002987 in_addr_t inaddr;
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002988 ngx_int_t n;
2989 ngx_uint_t ident;
2990 ngx_resolver_hdr_t *query;
2991 struct sockaddr_in *sin;
2992#if (NGX_HAVE_INET6)
2993 struct sockaddr_in6 *sin6;
2994#endif
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002995
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03002996 switch (addr->sockaddr->sa_family) {
Ruslan Ermilov809bee32013-12-06 14:30:28 +04002997
2998#if (NGX_HAVE_INET6)
2999 case AF_INET6:
3000 len = sizeof(ngx_resolver_hdr_t)
3001 + 64 + sizeof(".ip6.arpa.") - 1
3002 + sizeof(ngx_resolver_qs_t);
3003
3004 break;
3005#endif
3006
3007 default: /* AF_INET */
3008 len = sizeof(ngx_resolver_hdr_t)
3009 + sizeof(".255.255.255.255.in-addr.arpa.") - 1
3010 + sizeof(ngx_resolver_qs_t);
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04003011 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003012
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003013 p = ngx_resolver_alloc(r, len);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003014 if (p == NULL) {
3015 return NGX_ERROR;
3016 }
3017
3018 rn->query = p;
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003019 query = (ngx_resolver_hdr_t *) p;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003020
3021 ident = ngx_random();
3022
3023 query->ident_hi = (u_char) ((ident >> 8) & 0xff);
3024 query->ident_lo = (u_char) (ident & 0xff);
3025
3026 /* recursion query */
3027 query->flags_hi = 1; query->flags_lo = 0;
3028
3029 /* one question */
3030 query->nqs_hi = 0; query->nqs_lo = 1;
3031 query->nan_hi = 0; query->nan_lo = 0;
3032 query->nns_hi = 0; query->nns_lo = 0;
3033 query->nar_hi = 0; query->nar_lo = 0;
3034
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003035 p += sizeof(ngx_resolver_hdr_t);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003036
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003037 switch (addr->sockaddr->sa_family) {
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04003038
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003039#if (NGX_HAVE_INET6)
3040 case AF_INET6:
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003041 sin6 = (struct sockaddr_in6 *) addr->sockaddr;
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003042
3043 for (n = 15; n >= 0; n--) {
3044 p = ngx_sprintf(p, "\1%xd\1%xd",
3045 sin6->sin6_addr.s6_addr[n] & 0xf,
3046 (sin6->sin6_addr.s6_addr[n] >> 4) & 0xf);
3047 }
3048
3049 p = ngx_cpymem(p, "\3ip6\4arpa\0", 10);
3050
3051 break;
3052#endif
3053
3054 default: /* AF_INET */
3055
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003056 sin = (struct sockaddr_in *) addr->sockaddr;
3057 inaddr = ntohl(sin->sin_addr.s_addr);
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003058
3059 for (n = 0; n < 32; n += 8) {
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003060 d = ngx_sprintf(&p[1], "%ud", (inaddr >> n) & 0xff);
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003061 *p = (u_char) (d - &p[1]);
3062 p = d;
3063 }
3064
3065 p = ngx_cpymem(p, "\7in-addr\4arpa\0", 14);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003066 }
3067
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003068 /* query type "PTR", IN query class */
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003069 p = ngx_cpymem(p, "\0\14\0\1", 4);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003070
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003071 rn->qlen = (u_short) (p - rn->query);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003072
3073 return NGX_OK;
3074}
3075
3076
3077static ngx_int_t
3078ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src,
3079 u_char *last)
3080{
3081 char *err;
3082 u_char *p, *dst;
3083 ssize_t len;
3084 ngx_uint_t i, n;
3085
3086 p = src;
3087 len = -1;
3088
3089 /*
3090 * compression pointers allow to create endless loop, so we set limit;
3091 * 128 pointers should be enough to store 255-byte name
3092 */
3093
3094 for (i = 0; i < 128; i++) {
3095 n = *p++;
3096
3097 if (n == 0) {
3098 goto done;
3099 }
3100
3101 if (n & 0xc0) {
Igor Sysoevb3ac4fb2008-11-17 08:04:41 +00003102 n = ((n & 0x3f) << 8) + *p;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003103 p = &buf[n];
3104
3105 } else {
3106 len += 1 + n;
3107 p = &p[n];
3108 }
3109
3110 if (p >= last) {
3111 err = "name is out of response";
3112 goto invalid;
3113 }
3114 }
3115
3116 err = "compression pointers loop";
3117
3118invalid:
3119
3120 ngx_log_error(r->log_level, r->log, 0, err);
3121
3122 return NGX_ERROR;
3123
3124done:
3125
3126 if (name == NULL) {
3127 return NGX_OK;
3128 }
3129
Igor Sysoev70966c12009-11-09 18:04:05 +00003130 if (len == -1) {
Tatsuhiko Kuboef2b5962014-07-09 23:22:14 +09003131 ngx_str_null(name);
Igor Sysoev70966c12009-11-09 18:04:05 +00003132 return NGX_OK;
3133 }
3134
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003135 dst = ngx_resolver_alloc(r, len);
3136 if (dst == NULL) {
3137 return NGX_ERROR;
3138 }
3139
3140 name->data = dst;
3141
3142 n = *src++;
3143
3144 for ( ;; ) {
Igor Sysoeveb499ba2011-11-09 13:54:07 +00003145 if (n & 0xc0) {
3146 n = ((n & 0x3f) << 8) + *src;
3147 src = &buf[n];
3148
3149 n = *src++;
3150
3151 } else {
Ruslan Ermilov3fd72752013-12-13 20:49:52 +04003152 ngx_strlow(dst, src, n);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003153 dst += n;
3154 src += n;
3155
3156 n = *src++;
3157
3158 if (n != 0) {
3159 *dst++ = '.';
3160 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003161 }
3162
3163 if (n == 0) {
3164 name->len = dst - name->data;
3165 return NGX_OK;
3166 }
3167 }
3168}
3169
3170
3171static void
3172ngx_resolver_timeout_handler(ngx_event_t *ev)
3173{
Ruslan Ermilov5f509b52016-01-26 16:46:31 +03003174 ngx_resolver_ctx_t *ctx;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003175
Ruslan Ermilov5f509b52016-01-26 16:46:31 +03003176 ctx = ev->data;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003177
Ruslan Ermilov5f509b52016-01-26 16:46:31 +03003178 ctx->state = NGX_RESOLVE_TIMEDOUT;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003179
Ruslan Ermilov5f509b52016-01-26 16:46:31 +03003180 ctx->handler(ctx);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003181}
3182
3183
3184static void
3185ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn)
3186{
3187 /* lock alloc mutex */
3188
3189 if (rn->query) {
3190 ngx_resolver_free_locked(r, rn->query);
3191 }
3192
3193 if (rn->name) {
3194 ngx_resolver_free_locked(r, rn->name);
3195 }
3196
3197 if (rn->cnlen) {
3198 ngx_resolver_free_locked(r, rn->u.cname);
3199 }
3200
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003201 if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003202 ngx_resolver_free_locked(r, rn->u.addrs);
3203 }
3204
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003205#if (NGX_HAVE_INET6)
3206 if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
3207 ngx_resolver_free_locked(r, rn->u6.addrs6);
3208 }
3209#endif
3210
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003211 ngx_resolver_free_locked(r, rn);
3212
3213 /* unlock alloc mutex */
3214}
3215
3216
3217static void *
3218ngx_resolver_alloc(ngx_resolver_t *r, size_t size)
3219{
3220 u_char *p;
3221
3222 /* lock alloc mutex */
3223
3224 p = ngx_alloc(size, r->log);
3225
3226 /* unlock alloc mutex */
3227
3228 return p;
3229}
3230
3231
Igor Sysoev8ee01f52008-02-28 15:34:53 +00003232static void *
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003233ngx_resolver_calloc(ngx_resolver_t *r, size_t size)
3234{
3235 u_char *p;
3236
3237 p = ngx_resolver_alloc(r, size);
3238
3239 if (p) {
3240 ngx_memzero(p, size);
3241 }
3242
3243 return p;
3244}
3245
3246
3247static void
3248ngx_resolver_free(ngx_resolver_t *r, void *p)
3249{
3250 /* lock alloc mutex */
3251
3252 ngx_free(p);
3253
3254 /* unlock alloc mutex */
3255}
3256
3257
3258static void
3259ngx_resolver_free_locked(ngx_resolver_t *r, void *p)
3260{
3261 ngx_free(p);
3262}
3263
3264
3265static void *
3266ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size)
3267{
3268 void *dst;
3269
3270 dst = ngx_resolver_alloc(r, size);
3271
3272 if (dst == NULL) {
3273 return dst;
3274 }
3275
3276 ngx_memcpy(dst, src, size);
3277
3278 return dst;
3279}
3280
3281
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04003282static ngx_addr_t *
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003283ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn,
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04003284 ngx_uint_t rotate)
Maxim Dounin6a0f47e2012-09-28 18:28:38 +00003285{
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003286 ngx_addr_t *dst;
3287 ngx_uint_t d, i, j, n;
3288 u_char (*sockaddr)[NGX_SOCKADDRLEN];
3289 in_addr_t *addr;
3290 struct sockaddr_in *sin;
3291#if (NGX_HAVE_INET6)
3292 struct in6_addr *addr6;
3293 struct sockaddr_in6 *sin6;
3294#endif
3295
3296 n = rn->naddrs;
3297#if (NGX_HAVE_INET6)
3298 n += rn->naddrs6;
3299#endif
Maxim Dounin6a0f47e2012-09-28 18:28:38 +00003300
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04003301 dst = ngx_resolver_calloc(r, n * sizeof(ngx_addr_t));
Maxim Dounin7b373182012-10-24 14:07:08 +00003302 if (dst == NULL) {
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04003303 return NULL;
Maxim Dounin7b373182012-10-24 14:07:08 +00003304 }
3305
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003306 sockaddr = ngx_resolver_calloc(r, n * NGX_SOCKADDRLEN);
3307 if (sockaddr == NULL) {
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04003308 ngx_resolver_free(r, dst);
3309 return NULL;
Maxim Dounin6a0f47e2012-09-28 18:28:38 +00003310 }
3311
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003312 i = 0;
3313 d = rotate ? ngx_random() % n : 0;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04003314
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003315 if (rn->naddrs) {
3316 j = rotate ? ngx_random() % rn->naddrs : 0;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04003317
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003318 addr = (rn->naddrs == 1) ? &rn->u.addr : rn->u.addrs;
3319
3320 do {
3321 sin = (struct sockaddr_in *) sockaddr[d];
3322 sin->sin_family = AF_INET;
3323 sin->sin_addr.s_addr = addr[j++];
3324 dst[d].sockaddr = (struct sockaddr *) sin;
3325 dst[d++].socklen = sizeof(struct sockaddr_in);
3326
3327 if (d == n) {
3328 d = 0;
3329 }
3330
3331 if (j == rn->naddrs) {
3332 j = 0;
3333 }
3334 } while (++i < rn->naddrs);
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04003335 }
Maxim Dounin6a0f47e2012-09-28 18:28:38 +00003336
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003337#if (NGX_HAVE_INET6)
3338 if (rn->naddrs6) {
3339 j = rotate ? ngx_random() % rn->naddrs6 : 0;
3340
3341 addr6 = (rn->naddrs6 == 1) ? &rn->u6.addr6 : rn->u6.addrs6;
3342
3343 do {
3344 sin6 = (struct sockaddr_in6 *) sockaddr[d];
3345 sin6->sin6_family = AF_INET6;
3346 ngx_memcpy(sin6->sin6_addr.s6_addr, addr6[j++].s6_addr, 16);
3347 dst[d].sockaddr = (struct sockaddr *) sin6;
3348 dst[d++].socklen = sizeof(struct sockaddr_in6);
3349
3350 if (d == n) {
3351 d = 0;
3352 }
3353
3354 if (j == rn->naddrs6) {
3355 j = 0;
3356 }
3357 } while (++i < n);
3358 }
3359#endif
3360
Maxim Dounin6a0f47e2012-09-28 18:28:38 +00003361 return dst;
3362}
3363
3364
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003365char *
3366ngx_resolver_strerror(ngx_int_t err)
3367{
3368 static char *errors[] = {
3369 "Format error", /* FORMERR */
3370 "Server failure", /* SERVFAIL */
3371 "Host not found", /* NXDOMAIN */
3372 "Unimplemented", /* NOTIMP */
3373 "Operation refused" /* REFUSED */
3374 };
3375
3376 if (err > 0 && err < 6) {
3377 return errors[err - 1];
3378 }
3379
3380 if (err == NGX_RESOLVE_TIMEDOUT) {
3381 return "Operation timed out";
3382 }
3383
3384 return "Unknown error";
3385}
3386
3387
Igor Sysoev089b2fd2010-01-11 11:01:02 +00003388static u_char *
3389ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len)
3390{
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003391 u_char *p;
3392 ngx_resolver_connection_t *rec;
Igor Sysoev089b2fd2010-01-11 11:01:02 +00003393
3394 p = buf;
3395
3396 if (log->action) {
3397 p = ngx_snprintf(buf, len, " while %s", log->action);
3398 len -= p - buf;
3399 }
3400
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003401 rec = log->data;
Igor Sysoev089b2fd2010-01-11 11:01:02 +00003402
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003403 if (rec) {
3404 p = ngx_snprintf(p, len, ", resolver: %V", &rec->server);
Igor Sysoev089b2fd2010-01-11 11:01:02 +00003405 }
3406
3407 return p;
3408}
3409
3410
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003411ngx_int_t
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003412ngx_udp_connect(ngx_resolver_connection_t *rec)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003413{
3414 int rc;
3415 ngx_int_t event;
3416 ngx_event_t *rev, *wev;
3417 ngx_socket_t s;
3418 ngx_connection_t *c;
3419
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003420 s = ngx_socket(rec->sockaddr->sa_family, SOCK_DGRAM, 0);
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003421
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003422 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "UDP socket %d", s);
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003423
Maxim Dounin48d96ce2013-09-04 20:48:28 +04003424 if (s == (ngx_socket_t) -1) {
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003425 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003426 ngx_socket_n " failed");
3427 return NGX_ERROR;
3428 }
3429
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003430 c = ngx_get_connection(s, &rec->log);
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003431
3432 if (c == NULL) {
3433 if (ngx_close_socket(s) == -1) {
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003434 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003435 ngx_close_socket_n "failed");
3436 }
3437
3438 return NGX_ERROR;
3439 }
3440
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003441 if (ngx_nonblocking(s) == -1) {
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003442 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003443 ngx_nonblocking_n " failed");
3444
Ruslan Ermilov9ae40c52014-02-20 17:27:09 +04003445 goto failed;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003446 }
3447
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003448 rev = c->read;
3449 wev = c->write;
3450
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003451 rev->log = &rec->log;
3452 wev->log = &rec->log;
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003453
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003454 rec->udp = c;
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003455
3456 c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
3457
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003458 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0,
3459 "connect to %V, fd:%d #%uA", &rec->server, s, c->number);
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003460
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003461 rc = connect(s, rec->sockaddr, rec->socklen);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003462
Ruslan Ermilovd0755322015-04-22 18:57:32 +03003463 /* TODO: iocp */
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003464
3465 if (rc == -1) {
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003466 ngx_log_error(NGX_LOG_CRIT, &rec->log, ngx_socket_errno,
Igor Sysoev089b2fd2010-01-11 11:01:02 +00003467 "connect() failed");
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003468
Ruslan Ermilov9ae40c52014-02-20 17:27:09 +04003469 goto failed;
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003470 }
3471
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003472 /* UDP sockets are always ready to write */
3473 wev->ready = 1;
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003474
Ruslan Ermilov8cdb4332015-04-23 14:17:40 +03003475 event = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ?
3476 /* kqueue, epoll */ NGX_CLEAR_EVENT:
3477 /* select, poll, /dev/poll */ NGX_LEVEL_EVENT;
3478 /* eventport event type has no meaning: oneshot only */
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003479
Ruslan Ermilov8cdb4332015-04-23 14:17:40 +03003480 if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
3481 goto failed;
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003482 }
3483
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003484 return NGX_OK;
Ruslan Ermilov9ae40c52014-02-20 17:27:09 +04003485
3486failed:
3487
3488 ngx_close_connection(c);
Roman Arutyunyanec16a602016-01-28 15:28:20 +03003489 rec->udp = NULL;
Ruslan Ermilov9ae40c52014-02-20 17:27:09 +04003490
3491 return NGX_ERROR;
Igor Sysoevd3283ff2005-12-05 13:18:09 +00003492}
Roman Arutyunyan910445b2016-01-28 15:28:20 +03003493
3494
3495ngx_int_t
3496ngx_tcp_connect(ngx_resolver_connection_t *rec)
3497{
3498 int rc;
3499 ngx_int_t event;
3500 ngx_err_t err;
3501 ngx_uint_t level;
3502 ngx_socket_t s;
3503 ngx_event_t *rev, *wev;
3504 ngx_connection_t *c;
3505
3506 s = ngx_socket(rec->sockaddr->sa_family, SOCK_STREAM, 0);
3507
3508 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "TCP socket %d", s);
3509
3510 if (s == (ngx_socket_t) -1) {
3511 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
3512 ngx_socket_n " failed");
3513 return NGX_ERROR;
3514 }
3515
3516 c = ngx_get_connection(s, &rec->log);
3517
3518 if (c == NULL) {
3519 if (ngx_close_socket(s) == -1) {
3520 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
3521 ngx_close_socket_n "failed");
3522 }
3523
3524 return NGX_ERROR;
3525 }
3526
3527 if (ngx_nonblocking(s) == -1) {
3528 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
3529 ngx_nonblocking_n " failed");
3530
3531 goto failed;
3532 }
3533
3534 rev = c->read;
3535 wev = c->write;
3536
3537 rev->log = &rec->log;
3538 wev->log = &rec->log;
3539
3540 rec->tcp = c;
3541
3542 c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
3543
3544 if (ngx_add_conn) {
3545 if (ngx_add_conn(c) == NGX_ERROR) {
3546 goto failed;
3547 }
3548 }
3549
3550 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0,
3551 "connect to %V, fd:%d #%uA", &rec->server, s, c->number);
3552
3553 rc = connect(s, rec->sockaddr, rec->socklen);
3554
3555 if (rc == -1) {
3556 err = ngx_socket_errno;
3557
3558
3559 if (err != NGX_EINPROGRESS
3560#if (NGX_WIN32)
3561 /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
3562 && err != NGX_EAGAIN
3563#endif
3564 )
3565 {
3566 if (err == NGX_ECONNREFUSED
3567#if (NGX_LINUX)
3568 /*
3569 * Linux returns EAGAIN instead of ECONNREFUSED
3570 * for unix sockets if listen queue is full
3571 */
3572 || err == NGX_EAGAIN
3573#endif
3574 || err == NGX_ECONNRESET
3575 || err == NGX_ENETDOWN
3576 || err == NGX_ENETUNREACH
3577 || err == NGX_EHOSTDOWN
3578 || err == NGX_EHOSTUNREACH)
3579 {
3580 level = NGX_LOG_ERR;
3581
3582 } else {
3583 level = NGX_LOG_CRIT;
3584 }
3585
3586 ngx_log_error(level, c->log, err, "connect() to %V failed",
3587 &rec->server);
3588
3589 ngx_close_connection(c);
3590 rec->tcp = NULL;
3591
3592 return NGX_ERROR;
3593 }
3594 }
3595
3596 if (ngx_add_conn) {
3597 if (rc == -1) {
3598
3599 /* NGX_EINPROGRESS */
3600
3601 return NGX_AGAIN;
3602 }
3603
3604 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected");
3605
3606 wev->ready = 1;
3607
3608 return NGX_OK;
3609 }
3610
3611 if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
3612
3613 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, ngx_socket_errno,
3614 "connect(): %d", rc);
3615
3616 if (ngx_blocking(s) == -1) {
3617 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
3618 ngx_blocking_n " failed");
3619 goto failed;
3620 }
3621
3622 /*
3623 * FreeBSD's aio allows to post an operation on non-connected socket.
3624 * NT does not support it.
3625 *
3626 * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
3627 */
3628
3629 rev->ready = 1;
3630 wev->ready = 1;
3631
3632 return NGX_OK;
3633 }
3634
3635 if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
3636
3637 /* kqueue */
3638
3639 event = NGX_CLEAR_EVENT;
3640
3641 } else {
3642
3643 /* select, poll, /dev/poll */
3644
3645 event = NGX_LEVEL_EVENT;
3646 }
3647
3648 if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
3649 goto failed;
3650 }
3651
3652 if (rc == -1) {
3653
3654 /* NGX_EINPROGRESS */
3655
3656 if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
3657 goto failed;
3658 }
3659
3660 return NGX_AGAIN;
3661 }
3662
3663 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected");
3664
3665 wev->ready = 1;
3666
3667 return NGX_OK;
3668
3669failed:
3670
3671 ngx_close_connection(c);
3672 rec->tcp = NULL;
3673
3674 return NGX_ERROR;
3675}