blob: e00fe229abe36f05b10efa5793306052ffda043f [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);
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +030077static ngx_int_t ngx_resolver_create_srv_query(ngx_resolver_t *r,
78 ngx_resolver_node_t *rn, ngx_str_t *name);
Roman Arutyunyan9b914de2016-01-26 16:46:48 +030079static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r,
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +030080 ngx_resolver_node_t *rn, ngx_resolver_addr_t *addr);
Igor Sysoevcb4d5382007-11-23 17:13:26 +000081static void ngx_resolver_resend_handler(ngx_event_t *ev);
82static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree,
83 ngx_queue_t *queue);
Sergey Kandaurove6fdd2f2015-06-17 17:57:34 +030084static ngx_uint_t ngx_resolver_resend_empty(ngx_resolver_t *r);
Roman Arutyunyan910445b2016-01-28 15:28:20 +030085static void ngx_resolver_udp_read(ngx_event_t *rev);
86static void ngx_resolver_tcp_write(ngx_event_t *wev);
87static void ngx_resolver_tcp_read(ngx_event_t *rev);
Igor Sysoevcb4d5382007-11-23 17:13:26 +000088static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf,
Roman Arutyunyan910445b2016-01-28 15:28:20 +030089 size_t n, ngx_uint_t tcp);
Igor Sysoevcb4d5382007-11-23 17:13:26 +000090static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
Ruslan Ermilov769eded2013-12-09 10:53:28 +040091 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
Roman Arutyunyan910445b2016-01-28 15:28:20 +030092 ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans);
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +030093static void ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n,
94 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan,
95 ngx_uint_t trunc, ngx_uint_t ans);
Igor Sysoevcb4d5382007-11-23 17:13:26 +000096static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
Igor Sysoevc0cadf12007-12-16 20:47:55 +000097 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan);
Igor Sysoevcb4d5382007-11-23 17:13:26 +000098static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
99 ngx_str_t *name, uint32_t hash);
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300100static ngx_resolver_node_t *ngx_resolver_lookup_srv(ngx_resolver_t *r,
101 ngx_str_t *name, uint32_t hash);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000102static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r,
103 in_addr_t addr);
104static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
105 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
106static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name,
107 u_char *buf, u_char *src, u_char *last);
108static void ngx_resolver_timeout_handler(ngx_event_t *ev);
109static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn);
110static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size);
Igor Sysoev8ee01f52008-02-28 15:34:53 +0000111static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000112static void ngx_resolver_free(ngx_resolver_t *r, void *p);
113static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
114static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300115static ngx_resolver_addr_t *ngx_resolver_export(ngx_resolver_t *r,
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400116 ngx_resolver_node_t *rn, ngx_uint_t rotate);
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300117static void ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx);
Igor Sysoev089b2fd2010-01-11 11:01:02 +0000118static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len);
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300119static void ngx_resolver_resolve_srv_names(ngx_resolver_ctx_t *ctx,
120 ngx_resolver_node_t *rn);
121static void ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *ctx);
122static ngx_int_t ngx_resolver_cmp_srvs(const void *one, const void *two);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000123
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400124#if (NGX_HAVE_INET6)
125static void ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
126 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
127static ngx_resolver_node_t *ngx_resolver_lookup_addr6(ngx_resolver_t *r,
128 struct in6_addr *addr, uint32_t hash);
129#endif
130
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000131
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000132ngx_resolver_t *
Igor Sysoev62071812011-10-24 16:09:05 +0000133ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000134{
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300135 ngx_str_t s;
136 ngx_url_t u;
137 ngx_uint_t i, j;
138 ngx_resolver_t *r;
139 ngx_pool_cleanup_t *cln;
140 ngx_resolver_connection_t *rec;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000141
Igor Sysoevdfd55112008-03-04 10:42:05 +0000142 cln = ngx_pool_cleanup_add(cf->pool, 0);
Igor Sysoev4491dae2008-02-28 20:38:34 +0000143 if (cln == NULL) {
144 return NULL;
145 }
146
147 cln->handler = ngx_resolver_cleanup;
148
Igor Sysoevdfd55112008-03-04 10:42:05 +0000149 r = ngx_calloc(sizeof(ngx_resolver_t), cf->log);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000150 if (r == NULL) {
151 return NULL;
152 }
153
Igor Sysoev4491dae2008-02-28 20:38:34 +0000154 cln->data = r;
155
Igor Sysoevdfd55112008-03-04 10:42:05 +0000156 r->event = ngx_calloc(sizeof(ngx_event_t), cf->log);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000157 if (r->event == NULL) {
158 return NULL;
159 }
160
Igor Sysoev826c02e2007-12-03 12:17:26 +0000161 ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel,
162 ngx_resolver_rbtree_insert_value);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000163
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300164 ngx_rbtree_init(&r->srv_rbtree, &r->srv_sentinel,
165 ngx_resolver_rbtree_insert_value);
166
Igor Sysoev826c02e2007-12-03 12:17:26 +0000167 ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel,
168 ngx_rbtree_insert_value);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000169
Igor Sysoeva9d3a0d2007-12-03 11:21:19 +0000170 ngx_queue_init(&r->name_resend_queue);
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300171 ngx_queue_init(&r->srv_resend_queue);
Igor Sysoeva9d3a0d2007-12-03 11:21:19 +0000172 ngx_queue_init(&r->addr_resend_queue);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000173
Igor Sysoeva9d3a0d2007-12-03 11:21:19 +0000174 ngx_queue_init(&r->name_expire_queue);
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300175 ngx_queue_init(&r->srv_expire_queue);
Igor Sysoeva9d3a0d2007-12-03 11:21:19 +0000176 ngx_queue_init(&r->addr_expire_queue);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000177
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400178#if (NGX_HAVE_INET6)
Ruslan Ermilove0caf512013-12-09 10:53:30 +0400179 r->ipv6 = 1;
180
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400181 ngx_rbtree_init(&r->addr6_rbtree, &r->addr6_sentinel,
182 ngx_resolver_rbtree_insert_addr6_value);
183
184 ngx_queue_init(&r->addr6_resend_queue);
185
186 ngx_queue_init(&r->addr6_expire_queue);
187#endif
188
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000189 r->event->handler = ngx_resolver_resend_handler;
190 r->event->data = r;
Igor Sysoev0cd76ea2009-04-30 13:53:42 +0000191 r->event->log = &cf->cycle->new_log;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000192 r->ident = -1;
193
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000194 r->resend_timeout = 5;
Roman Arutyunyan910445b2016-01-28 15:28:20 +0300195 r->tcp_timeout = 5;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000196 r->expire = 30;
Ruslan Ermilovbec516b2011-11-16 13:11:39 +0000197 r->valid = 0;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000198
Igor Sysoev0cd76ea2009-04-30 13:53:42 +0000199 r->log = &cf->cycle->new_log;
Igor Sysoev49ac2b22010-09-27 11:23:45 +0000200 r->log_level = NGX_LOG_ERR;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000201
Maxim Dounin42a75bb2012-08-06 10:48:09 +0000202 if (n) {
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300203 if (ngx_array_init(&r->connections, cf->pool, n,
204 sizeof(ngx_resolver_connection_t))
Maxim Dounin42a75bb2012-08-06 10:48:09 +0000205 != NGX_OK)
206 {
207 return NULL;
208 }
209 }
210
Igor Sysoev62071812011-10-24 16:09:05 +0000211 for (i = 0; i < n; i++) {
Ruslan Ermilovbec516b2011-11-16 13:11:39 +0000212 if (ngx_strncmp(names[i].data, "valid=", 6) == 0) {
213 s.len = names[i].len - 6;
214 s.data = names[i].data + 6;
215
216 r->valid = ngx_parse_time(&s, 1);
217
Maxim Dounin9f38b202012-02-13 15:41:11 +0000218 if (r->valid == (time_t) NGX_ERROR) {
Ruslan Ermilovbec516b2011-11-16 13:11:39 +0000219 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
220 "invalid parameter: %V", &names[i]);
221 return NULL;
222 }
223
224 continue;
225 }
226
Ruslan Ermilove0caf512013-12-09 10:53:30 +0400227#if (NGX_HAVE_INET6)
228 if (ngx_strncmp(names[i].data, "ipv6=", 5) == 0) {
229
230 if (ngx_strcmp(&names[i].data[5], "on") == 0) {
231 r->ipv6 = 1;
232
233 } else if (ngx_strcmp(&names[i].data[5], "off") == 0) {
234 r->ipv6 = 0;
235
236 } else {
237 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
238 "invalid parameter: %V", &names[i]);
239 return NULL;
240 }
241
242 continue;
243 }
244#endif
245
Igor Sysoev62071812011-10-24 16:09:05 +0000246 ngx_memzero(&u, sizeof(ngx_url_t));
247
Ruslan Ermilovac7f7042012-06-04 14:23:27 +0000248 u.url = names[i];
249 u.default_port = 53;
Igor Sysoev62071812011-10-24 16:09:05 +0000250
Ruslan Ermilovac7f7042012-06-04 14:23:27 +0000251 if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
Ruslan Ermilovd2e005c2012-05-22 13:12:14 +0000252 if (u.err) {
253 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
254 "%s in resolver \"%V\"",
Ruslan Ermilovac7f7042012-06-04 14:23:27 +0000255 u.err, &u.url);
Ruslan Ermilovd2e005c2012-05-22 13:12:14 +0000256 }
257
Igor Sysoev62071812011-10-24 16:09:05 +0000258 return NULL;
259 }
260
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300261 rec = ngx_array_push_n(&r->connections, u.naddrs);
262 if (rec == NULL) {
Igor Sysoev6b2fce42007-12-03 10:05:19 +0000263 return NULL;
264 }
265
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300266 ngx_memzero(rec, u.naddrs * sizeof(ngx_resolver_connection_t));
Igor Sysoev6b2fce42007-12-03 10:05:19 +0000267
Ruslan Ermilov2c49af82012-06-18 12:46:05 +0000268 for (j = 0; j < u.naddrs; j++) {
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300269 rec[j].sockaddr = u.addrs[j].sockaddr;
270 rec[j].socklen = u.addrs[j].socklen;
271 rec[j].server = u.addrs[j].name;
Roman Arutyunyan910445b2016-01-28 15:28:20 +0300272 rec[j].resolver = r;
Ruslan Ermilov2c49af82012-06-18 12:46:05 +0000273 }
Igor Sysoev6b2fce42007-12-03 10:05:19 +0000274 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000275
276 return r;
277}
278
279
Igor Sysoev4491dae2008-02-28 20:38:34 +0000280static void
281ngx_resolver_cleanup(void *data)
282{
283 ngx_resolver_t *r = data;
284
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300285 ngx_uint_t i;
286 ngx_resolver_connection_t *rec;
Igor Sysoev62071812011-10-24 16:09:05 +0000287
Igor Sysoev4491dae2008-02-28 20:38:34 +0000288 if (r) {
289 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
290 "cleanup resolver");
291
292 ngx_resolver_cleanup_tree(r, &r->name_rbtree);
293
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300294 ngx_resolver_cleanup_tree(r, &r->srv_rbtree);
295
Igor Sysoev4491dae2008-02-28 20:38:34 +0000296 ngx_resolver_cleanup_tree(r, &r->addr_rbtree);
297
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400298#if (NGX_HAVE_INET6)
299 ngx_resolver_cleanup_tree(r, &r->addr6_rbtree);
300#endif
301
Igor Sysoev4491dae2008-02-28 20:38:34 +0000302 if (r->event) {
303 ngx_free(r->event);
304 }
305
Igor Sysoev4491dae2008-02-28 20:38:34 +0000306
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300307 rec = r->connections.elts;
Igor Sysoev62071812011-10-24 16:09:05 +0000308
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300309 for (i = 0; i < r->connections.nelts; i++) {
310 if (rec[i].udp) {
311 ngx_close_connection(rec[i].udp);
Igor Sysoev62071812011-10-24 16:09:05 +0000312 }
Roman Arutyunyan910445b2016-01-28 15:28:20 +0300313
314 if (rec[i].tcp) {
315 ngx_close_connection(rec[i].tcp);
316 }
Roman Arutyunyan1ee5b132016-02-02 13:42:55 +0300317
318 if (rec[i].read_buf) {
319 ngx_resolver_free(r, rec[i].read_buf->start);
320 ngx_resolver_free(r, rec[i].read_buf);
321 }
322
323 if (rec[i].write_buf) {
324 ngx_resolver_free(r, rec[i].write_buf->start);
325 ngx_resolver_free(r, rec[i].write_buf);
326 }
Igor Sysoev4491dae2008-02-28 20:38:34 +0000327 }
328
329 ngx_free(r);
330 }
331}
332
333
334static void
335ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree)
336{
337 ngx_resolver_ctx_t *ctx, *next;
338 ngx_resolver_node_t *rn;
339
340 while (tree->root != tree->sentinel) {
341
Ruslan Ermilovef563de2014-11-20 15:24:42 +0300342 rn = ngx_resolver_node(ngx_rbtree_min(tree->root, tree->sentinel));
Igor Sysoev4491dae2008-02-28 20:38:34 +0000343
344 ngx_queue_remove(&rn->queue);
345
346 for (ctx = rn->waiting; ctx; ctx = next) {
Igor Sysoev433608c2008-05-14 07:54:52 +0000347 next = ctx->next;
Igor Sysoev4491dae2008-02-28 20:38:34 +0000348
349 if (ctx->event) {
350 ngx_resolver_free(r, ctx->event);
351 }
352
353 ngx_resolver_free(r, ctx);
354 }
355
356 ngx_rbtree_delete(tree, &rn->node);
357
358 ngx_resolver_free_node(r, rn);
359 }
360}
361
362
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000363ngx_resolver_ctx_t *
364ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
365{
366 in_addr_t addr;
367 ngx_resolver_ctx_t *ctx;
368
369 if (temp) {
370 addr = ngx_inet_addr(temp->name.data, temp->name.len);
371
372 if (addr != INADDR_NONE) {
373 temp->resolver = r;
374 temp->state = NGX_OK;
375 temp->naddrs = 1;
376 temp->addrs = &temp->addr;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400377 temp->addr.sockaddr = (struct sockaddr *) &temp->sin;
378 temp->addr.socklen = sizeof(struct sockaddr_in);
379 ngx_memzero(&temp->sin, sizeof(struct sockaddr_in));
380 temp->sin.sin_family = AF_INET;
381 temp->sin.sin_addr.s_addr = addr;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000382 temp->quick = 1;
383
384 return temp;
385 }
386 }
387
Roman Arutyunyanec16a602016-01-28 15:28:20 +0300388 if (r->connections.nelts == 0) {
Igor Sysoev6b2fce42007-12-03 10:05:19 +0000389 return NGX_NO_RESOLVER;
390 }
391
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000392 ctx = ngx_resolver_calloc(r, sizeof(ngx_resolver_ctx_t));
393
394 if (ctx) {
395 ctx->resolver = r;
396 }
397
398 return ctx;
399}
Igor Sysoevd3283ff2005-12-05 13:18:09 +0000400
401
402ngx_int_t
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000403ngx_resolve_name(ngx_resolver_ctx_t *ctx)
Igor Sysoevd3283ff2005-12-05 13:18:09 +0000404{
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300405 size_t slen;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000406 ngx_int_t rc;
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300407 ngx_str_t name;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000408 ngx_resolver_t *r;
Igor Sysoevd3283ff2005-12-05 13:18:09 +0000409
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000410 r = ctx->resolver;
411
Yichun Zhang2e2c9db2014-01-10 11:22:14 -0800412 if (ctx->name.len > 0 && ctx->name.data[ctx->name.len - 1] == '.') {
413 ctx->name.len--;
414 }
415
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000416 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
417 "resolve: \"%V\"", &ctx->name);
418
419 if (ctx->quick) {
420 ctx->handler(ctx);
Igor Sysoevd3283ff2005-12-05 13:18:09 +0000421 return NGX_OK;
422 }
423
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300424 if (ctx->service.len) {
425 slen = ctx->service.len;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000426
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300427 if (ngx_strlchr(ctx->service.data,
428 ctx->service.data + ctx->service.len, '.')
429 == NULL)
430 {
431 slen += sizeof("_._tcp") - 1;
432 }
433
434 name.len = slen + 1 + ctx->name.len;
435
436 name.data = ngx_resolver_alloc(r, name.len);
437 if (name.data == NULL) {
438 return NGX_ERROR;
439 }
440
441 if (slen == ctx->service.len) {
442 ngx_sprintf(name.data, "%V.%V", &ctx->service, &ctx->name);
443
444 } else {
445 ngx_sprintf(name.data, "_%V._tcp.%V", &ctx->service, &ctx->name);
446 }
447
448 /* lock name mutex */
449
450 rc = ngx_resolve_name_locked(r, ctx, &name);
451
452 ngx_resolver_free(r, name.data);
453
454 } else {
455 /* lock name mutex */
456
457 rc = ngx_resolve_name_locked(r, ctx, &ctx->name);
458 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000459
460 if (rc == NGX_OK) {
461 return NGX_OK;
462 }
463
464 /* unlock name mutex */
465
466 if (rc == NGX_AGAIN) {
467 return NGX_OK;
468 }
469
Igor Sysoev7c4cf272008-02-28 20:09:39 +0000470 /* NGX_ERROR */
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000471
472 if (ctx->event) {
Igor Sysoev7c4cf272008-02-28 20:09:39 +0000473 ngx_resolver_free(r, ctx->event);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000474 }
475
Igor Sysoev7c4cf272008-02-28 20:09:39 +0000476 ngx_resolver_free(r, ctx);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000477
478 return NGX_ERROR;
479}
480
481
482void
483ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
484{
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300485 ngx_uint_t i;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000486 ngx_resolver_t *r;
487 ngx_resolver_ctx_t *w, **p;
488 ngx_resolver_node_t *rn;
489
490 r = ctx->resolver;
491
492 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
493 "resolve name done: %i", ctx->state);
494
495 if (ctx->quick) {
496 return;
497 }
498
499 if (ctx->event && ctx->event->timer_set) {
500 ngx_del_timer(ctx->event);
501 }
502
503 /* lock name mutex */
504
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300505 if (ctx->nsrvs) {
506 for (i = 0; i < ctx->nsrvs; i++) {
507 if (ctx->srvs[i].ctx) {
508 ngx_resolve_name_done(ctx->srvs[i].ctx);
509 }
510
511 if (ctx->srvs[i].addrs) {
512 ngx_resolver_free(r, ctx->srvs[i].addrs->sockaddr);
513 ngx_resolver_free(r, ctx->srvs[i].addrs);
514 }
515
516 ngx_resolver_free(r, ctx->srvs[i].name.data);
517 }
518
519 ngx_resolver_free(r, ctx->srvs);
520 }
521
Ruslan Ermilov5f509b52016-01-26 16:46:31 +0300522 if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000523
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300524 rn = ctx->node;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000525
526 if (rn) {
527 p = &rn->waiting;
528 w = rn->waiting;
529
530 while (w) {
531 if (w == ctx) {
532 *p = w->next;
533
534 goto done;
535 }
536
537 p = &w->next;
538 w = w->next;
539 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000540
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300541 ngx_log_error(NGX_LOG_ALERT, r->log, 0,
542 "could not cancel %V resolving", &ctx->name);
543 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000544 }
545
546done:
547
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300548 if (ctx->service.len) {
549 ngx_resolver_expire(r, &r->srv_rbtree, &r->srv_expire_queue);
550
551 } else {
552 ngx_resolver_expire(r, &r->name_rbtree, &r->name_expire_queue);
553 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000554
555 /* unlock name mutex */
556
Igor Sysoev7c4cf272008-02-28 20:09:39 +0000557 /* lock alloc mutex */
558
559 if (ctx->event) {
560 ngx_resolver_free_locked(r, ctx->event);
561 }
562
563 ngx_resolver_free_locked(r, ctx);
564
565 /* unlock alloc mutex */
Sergey Kandaurove6fdd2f2015-06-17 17:57:34 +0300566
567 if (r->event->timer_set && ngx_resolver_resend_empty(r)) {
568 ngx_del_timer(r->event);
569 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000570}
571
572
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000573static ngx_int_t
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300574ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx,
575 ngx_str_t *name)
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000576{
577 uint32_t hash;
Igor Sysoev09b199c2008-04-09 14:45:39 +0000578 ngx_int_t rc;
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300579 ngx_str_t cname;
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300580 ngx_uint_t i, naddrs;
581 ngx_queue_t *resend_queue, *expire_queue;
582 ngx_rbtree_t *tree;
Ruslan Ermilovec4da932016-01-26 16:46:38 +0300583 ngx_resolver_ctx_t *next, *last;
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300584 ngx_resolver_addr_t *addrs;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000585 ngx_resolver_node_t *rn;
586
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300587 ngx_strlow(name->data, name->data, name->len);
Ruslan Ermilov3fd72752013-12-13 20:49:52 +0400588
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300589 hash = ngx_crc32_short(name->data, name->len);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000590
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300591 if (ctx->service.len) {
592 rn = ngx_resolver_lookup_srv(r, name, hash);
593
594 tree = &r->srv_rbtree;
595 resend_queue = &r->srv_resend_queue;
596 expire_queue = &r->srv_expire_queue;
597
598 } else {
599 rn = ngx_resolver_lookup_name(r, name, hash);
600
601 tree = &r->name_rbtree;
602 resend_queue = &r->name_resend_queue;
603 expire_queue = &r->name_expire_queue;
604 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000605
606 if (rn) {
607
Ruslan Ermilovec4da932016-01-26 16:46:38 +0300608 /* ctx can be a list after NGX_RESOLVE_CNAME */
609 for (last = ctx; last->next; last = last->next);
610
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000611 if (rn->valid >= ngx_time()) {
612
613 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
614
615 ngx_queue_remove(&rn->queue);
616
617 rn->expire = ngx_time() + r->expire;
618
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300619 ngx_queue_insert_head(expire_queue, &rn->queue);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000620
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400621 naddrs = (rn->naddrs == (u_short) -1) ? 0 : rn->naddrs;
622#if (NGX_HAVE_INET6)
623 naddrs += (rn->naddrs6 == (u_short) -1) ? 0 : rn->naddrs6;
624#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000625
626 if (naddrs) {
627
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400628 if (naddrs == 1 && rn->naddrs == 1) {
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400629 addrs = NULL;
630
631 } else {
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400632 addrs = ngx_resolver_export(r, rn, 1);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000633 if (addrs == NULL) {
634 return NGX_ERROR;
635 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000636 }
637
Ruslan Ermilovec4da932016-01-26 16:46:38 +0300638 last->next = rn->waiting;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000639 rn->waiting = NULL;
640
641 /* unlock name mutex */
642
643 do {
644 ctx->state = NGX_OK;
Dmitry Volyntsev6f418a32016-03-23 17:44:36 +0300645 ctx->valid = rn->valid;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000646 ctx->naddrs = naddrs;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400647
648 if (addrs == NULL) {
649 ctx->addrs = &ctx->addr;
650 ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
651 ctx->addr.socklen = sizeof(struct sockaddr_in);
652 ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
653 ctx->sin.sin_family = AF_INET;
654 ctx->sin.sin_addr.s_addr = rn->u.addr;
655
656 } else {
657 ctx->addrs = addrs;
658 }
659
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000660 next = ctx->next;
661
662 ctx->handler(ctx);
663
664 ctx = next;
665 } while (ctx);
666
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400667 if (addrs != NULL) {
668 ngx_resolver_free(r, addrs->sockaddr);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000669 ngx_resolver_free(r, addrs);
670 }
671
672 return NGX_OK;
673 }
674
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300675 if (rn->nsrvs) {
676 last->next = rn->waiting;
677 rn->waiting = NULL;
678
679 /* unlock name mutex */
680
681 do {
682 next = ctx->next;
683
684 ngx_resolver_resolve_srv_names(ctx, rn);
685
686 ctx = next;
687 } while (ctx);
688
689 return NGX_OK;
690 }
691
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000692 /* NGX_RESOLVE_CNAME */
693
Igor Sysoeva8372d82008-04-12 07:29:20 +0000694 if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000695
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300696 cname.len = rn->cnlen;
697 cname.data = rn->u.cname;
Igor Sysoeva8372d82008-04-12 07:29:20 +0000698
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300699 return ngx_resolve_name_locked(r, ctx, &cname);
Igor Sysoeva8372d82008-04-12 07:29:20 +0000700 }
701
Ruslan Ermilovec4da932016-01-26 16:46:38 +0300702 last->next = rn->waiting;
Igor Sysoeva8372d82008-04-12 07:29:20 +0000703 rn->waiting = NULL;
704
705 /* unlock name mutex */
706
707 do {
708 ctx->state = NGX_RESOLVE_NXDOMAIN;
Dmitry Volyntsev6f418a32016-03-23 17:44:36 +0300709 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
Igor Sysoeva8372d82008-04-12 07:29:20 +0000710 next = ctx->next;
711
712 ctx->handler(ctx);
713
714 ctx = next;
715 } while (ctx);
716
717 return NGX_OK;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000718 }
719
720 if (rn->waiting) {
721
Dmitry Volyntsev0eb806a2016-03-23 17:44:36 +0300722 if (ctx->event == NULL && ctx->timeout) {
Ruslan Ermilov5f509b52016-01-26 16:46:31 +0300723 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
724 if (ctx->event == NULL) {
725 return NGX_ERROR;
726 }
727
728 ctx->event->handler = ngx_resolver_timeout_handler;
729 ctx->event->data = ctx;
730 ctx->event->log = r->log;
731 ctx->ident = -1;
732
733 ngx_add_timer(ctx->event, ctx->timeout);
734 }
735
Ruslan Ermilovec4da932016-01-26 16:46:38 +0300736 last->next = rn->waiting;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000737 rn->waiting = ctx;
Igor Sysoev64bfa872009-11-09 17:45:56 +0000738 ctx->state = NGX_AGAIN;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000739
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300740 do {
741 ctx->node = rn;
742 ctx = ctx->next;
743 } while (ctx);
744
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000745 return NGX_AGAIN;
746 }
747
748 ngx_queue_remove(&rn->queue);
749
750 /* lock alloc mutex */
751
Maxim Dounin7d863c02012-05-14 09:13:45 +0000752 if (rn->query) {
753 ngx_resolver_free_locked(r, rn->query);
754 rn->query = NULL;
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400755#if (NGX_HAVE_INET6)
756 rn->query6 = NULL;
757#endif
Maxim Dounin7d863c02012-05-14 09:13:45 +0000758 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000759
760 if (rn->cnlen) {
761 ngx_resolver_free_locked(r, rn->u.cname);
762 }
763
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400764 if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000765 ngx_resolver_free_locked(r, rn->u.addrs);
766 }
767
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400768#if (NGX_HAVE_INET6)
769 if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
770 ngx_resolver_free_locked(r, rn->u6.addrs6);
771 }
772#endif
773
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300774 if (rn->nsrvs) {
775 for (i = 0; i < rn->nsrvs; i++) {
776 if (rn->u.srvs[i].name.data) {
777 ngx_resolver_free_locked(r, rn->u.srvs[i].name.data);
778 }
779 }
780
781 ngx_resolver_free_locked(r, rn->u.srvs);
782 }
783
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000784 /* unlock alloc mutex */
785
786 } else {
787
788 rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
789 if (rn == NULL) {
790 return NGX_ERROR;
791 }
792
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300793 rn->name = ngx_resolver_dup(r, name->data, name->len);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000794 if (rn->name == NULL) {
795 ngx_resolver_free(r, rn);
796 return NGX_ERROR;
797 }
798
799 rn->node.key = hash;
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300800 rn->nlen = (u_short) name->len;
Igor Sysoev949aea42008-04-09 14:26:08 +0000801 rn->query = NULL;
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400802#if (NGX_HAVE_INET6)
803 rn->query6 = NULL;
804#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000805
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300806 ngx_rbtree_insert(tree, &rn->node);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000807 }
808
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300809 if (ctx->service.len) {
810 rc = ngx_resolver_create_srv_query(r, rn, name);
811
812 } else {
813 rc = ngx_resolver_create_name_query(r, rn, name);
814 }
Igor Sysoev09b199c2008-04-09 14:45:39 +0000815
816 if (rc == NGX_ERROR) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000817 goto failed;
818 }
819
Igor Sysoev09b199c2008-04-09 14:45:39 +0000820 if (rc == NGX_DECLINED) {
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300821 ngx_rbtree_delete(tree, &rn->node);
Igor Sysoev09b199c2008-04-09 14:45:39 +0000822
823 ngx_resolver_free(r, rn->query);
824 ngx_resolver_free(r, rn->name);
825 ngx_resolver_free(r, rn);
826
Ruslan Ermilovec4da932016-01-26 16:46:38 +0300827 do {
828 ctx->state = NGX_RESOLVE_NXDOMAIN;
829 next = ctx->next;
830
831 ctx->handler(ctx);
832
833 ctx = next;
834 } while (ctx);
Igor Sysoev09b199c2008-04-09 14:45:39 +0000835
836 return NGX_OK;
837 }
838
Roman Arutyunyanb6a8f8c2016-01-28 15:28:20 +0300839 rn->last_connection = r->last_connection++;
840 if (r->last_connection == r->connections.nelts) {
841 r->last_connection = 0;
842 }
843
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400844 rn->naddrs = (u_short) -1;
Roman Arutyunyan910445b2016-01-28 15:28:20 +0300845 rn->tcp = 0;
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400846#if (NGX_HAVE_INET6)
Ruslan Ermilove0caf512013-12-09 10:53:30 +0400847 rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0;
Roman Arutyunyan910445b2016-01-28 15:28:20 +0300848 rn->tcp6 = 0;
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400849#endif
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300850 rn->nsrvs = 0;
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400851
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000852 if (ngx_resolver_send_query(r, rn) != NGX_OK) {
853 goto failed;
854 }
855
Dmitry Volyntsev0eb806a2016-03-23 17:44:36 +0300856 if (ctx->event == NULL && ctx->timeout) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000857 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
858 if (ctx->event == NULL) {
859 goto failed;
860 }
861
862 ctx->event->handler = ngx_resolver_timeout_handler;
Ruslan Ermilov5f509b52016-01-26 16:46:31 +0300863 ctx->event->data = ctx;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000864 ctx->event->log = r->log;
Ruslan Ermilov5f509b52016-01-26 16:46:31 +0300865 ctx->ident = -1;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000866
867 ngx_add_timer(ctx->event, ctx->timeout);
868 }
869
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300870 if (ngx_queue_empty(resend_queue)) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000871 ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
872 }
873
874 rn->expire = ngx_time() + r->resend_timeout;
875
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300876 ngx_queue_insert_head(resend_queue, &rn->queue);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000877
Ruslan Ermilov769eded2013-12-09 10:53:28 +0400878 rn->code = 0;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000879 rn->cnlen = 0;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000880 rn->valid = 0;
Ruslan Ermilov85e6d212013-12-16 19:12:23 +0400881 rn->ttl = NGX_MAX_UINT32_VALUE;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000882 rn->waiting = ctx;
883
884 ctx->state = NGX_AGAIN;
885
Roman Arutyunyan38a72e92016-01-26 16:46:59 +0300886 do {
887 ctx->node = rn;
888 ctx = ctx->next;
889 } while (ctx);
890
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000891 return NGX_AGAIN;
892
893failed:
894
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +0300895 ngx_rbtree_delete(tree, &rn->node);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000896
Igor Sysoev949aea42008-04-09 14:26:08 +0000897 if (rn->query) {
898 ngx_resolver_free(r, rn->query);
899 }
900
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000901 ngx_resolver_free(r, rn->name);
902
903 ngx_resolver_free(r, rn);
904
905 return NGX_ERROR;
906}
907
908
909ngx_int_t
910ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
911{
Igor Sysoev92588722009-01-29 14:35:23 +0000912 u_char *name;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400913 in_addr_t addr;
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400914 ngx_queue_t *resend_queue, *expire_queue;
915 ngx_rbtree_t *tree;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000916 ngx_resolver_t *r;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400917 struct sockaddr_in *sin;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000918 ngx_resolver_node_t *rn;
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400919#if (NGX_HAVE_INET6)
920 uint32_t hash;
921 struct sockaddr_in6 *sin6;
922#endif
923
924#if (NGX_SUPPRESS_WARN)
925 addr = 0;
926#if (NGX_HAVE_INET6)
927 hash = 0;
928 sin6 = NULL;
929#endif
930#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000931
932 r = ctx->resolver;
933
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400934 switch (ctx->addr.sockaddr->sa_family) {
935
936#if (NGX_HAVE_INET6)
937 case AF_INET6:
938 sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
939 hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16);
940
941 /* lock addr mutex */
942
943 rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash);
944
945 tree = &r->addr6_rbtree;
946 resend_queue = &r->addr6_resend_queue;
947 expire_queue = &r->addr6_expire_queue;
948
949 break;
950#endif
951
952 default: /* AF_INET */
953 sin = (struct sockaddr_in *) ctx->addr.sockaddr;
954 addr = ntohl(sin->sin_addr.s_addr);
955
956 /* lock addr mutex */
957
958 rn = ngx_resolver_lookup_addr(r, addr);
959
960 tree = &r->addr_rbtree;
961 resend_queue = &r->addr_resend_queue;
962 expire_queue = &r->addr_expire_queue;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +0400963 }
964
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000965 if (rn) {
966
967 if (rn->valid >= ngx_time()) {
968
969 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
970
971 ngx_queue_remove(&rn->queue);
972
973 rn->expire = ngx_time() + r->expire;
974
Ruslan Ermilov809bee32013-12-06 14:30:28 +0400975 ngx_queue_insert_head(expire_queue, &rn->queue);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000976
Igor Sysoev92588722009-01-29 14:35:23 +0000977 name = ngx_resolver_dup(r, rn->name, rn->nlen);
978 if (name == NULL) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000979 goto failed;
980 }
981
Igor Sysoev92588722009-01-29 14:35:23 +0000982 ctx->name.len = rn->nlen;
983 ctx->name.data = name;
984
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000985 /* unlock addr mutex */
986
987 ctx->state = NGX_OK;
Dmitry Volyntsev6f418a32016-03-23 17:44:36 +0300988 ctx->valid = rn->valid;
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000989
990 ctx->handler(ctx);
991
Igor Sysoev92588722009-01-29 14:35:23 +0000992 ngx_resolver_free(r, name);
Igor Sysoevcb4d5382007-11-23 17:13:26 +0000993
994 return NGX_OK;
995 }
996
997 if (rn->waiting) {
998
Dmitry Volyntsev0eb806a2016-03-23 17:44:36 +0300999 if (ctx->event == NULL && ctx->timeout) {
1000 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
1001 if (ctx->event == NULL) {
1002 return NGX_ERROR;
1003 }
1004
1005 ctx->event->handler = ngx_resolver_timeout_handler;
1006 ctx->event->data = ctx;
1007 ctx->event->log = r->log;
1008 ctx->ident = -1;
1009
1010 ngx_add_timer(ctx->event, ctx->timeout);
Ruslan Ermilov5f509b52016-01-26 16:46:31 +03001011 }
1012
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001013 ctx->next = rn->waiting;
1014 rn->waiting = ctx;
Igor Sysoev64bfa872009-11-09 17:45:56 +00001015 ctx->state = NGX_AGAIN;
Roman Arutyunyan38a72e92016-01-26 16:46:59 +03001016 ctx->node = rn;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001017
Igor Sysoev8ef386e2009-01-31 20:33:01 +00001018 /* unlock addr mutex */
1019
1020 return NGX_OK;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001021 }
1022
1023 ngx_queue_remove(&rn->queue);
1024
1025 ngx_resolver_free(r, rn->query);
Igor Sysoev949aea42008-04-09 14:26:08 +00001026 rn->query = NULL;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001027#if (NGX_HAVE_INET6)
1028 rn->query6 = NULL;
1029#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001030
1031 } else {
1032 rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
1033 if (rn == NULL) {
1034 goto failed;
1035 }
1036
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001037 switch (ctx->addr.sockaddr->sa_family) {
1038
1039#if (NGX_HAVE_INET6)
1040 case AF_INET6:
1041 rn->addr6 = sin6->sin6_addr;
1042 rn->node.key = hash;
1043 break;
1044#endif
1045
1046 default: /* AF_INET */
1047 rn->node.key = addr;
1048 }
1049
Igor Sysoev949aea42008-04-09 14:26:08 +00001050 rn->query = NULL;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001051#if (NGX_HAVE_INET6)
1052 rn->query6 = NULL;
1053#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001054
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001055 ngx_rbtree_insert(tree, &rn->node);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001056 }
1057
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03001058 if (ngx_resolver_create_addr_query(r, rn, &ctx->addr) != NGX_OK) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001059 goto failed;
1060 }
1061
Roman Arutyunyanb6a8f8c2016-01-28 15:28:20 +03001062 rn->last_connection = r->last_connection++;
1063 if (r->last_connection == r->connections.nelts) {
1064 r->last_connection = 0;
1065 }
1066
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001067 rn->naddrs = (u_short) -1;
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001068 rn->tcp = 0;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001069#if (NGX_HAVE_INET6)
1070 rn->naddrs6 = (u_short) -1;
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001071 rn->tcp6 = 0;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001072#endif
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03001073 rn->nsrvs = 0;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001074
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001075 if (ngx_resolver_send_query(r, rn) != NGX_OK) {
1076 goto failed;
1077 }
1078
Dmitry Volyntsev0eb806a2016-03-23 17:44:36 +03001079 if (ctx->event == NULL && ctx->timeout) {
1080 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
1081 if (ctx->event == NULL) {
1082 goto failed;
1083 }
1084
1085 ctx->event->handler = ngx_resolver_timeout_handler;
1086 ctx->event->data = ctx;
1087 ctx->event->log = r->log;
1088 ctx->ident = -1;
1089
1090 ngx_add_timer(ctx->event, ctx->timeout);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001091 }
1092
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001093 if (ngx_queue_empty(resend_queue)) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001094 ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
1095 }
1096
1097 rn->expire = ngx_time() + r->resend_timeout;
1098
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001099 ngx_queue_insert_head(resend_queue, &rn->queue);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001100
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001101 rn->code = 0;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001102 rn->cnlen = 0;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001103 rn->name = NULL;
1104 rn->nlen = 0;
1105 rn->valid = 0;
Ruslan Ermilov85e6d212013-12-16 19:12:23 +04001106 rn->ttl = NGX_MAX_UINT32_VALUE;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001107 rn->waiting = ctx;
1108
1109 /* unlock addr mutex */
1110
1111 ctx->state = NGX_AGAIN;
Roman Arutyunyan38a72e92016-01-26 16:46:59 +03001112 ctx->node = rn;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001113
1114 return NGX_OK;
1115
1116failed:
1117
1118 if (rn) {
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001119 ngx_rbtree_delete(tree, &rn->node);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001120
Igor Sysoev949aea42008-04-09 14:26:08 +00001121 if (rn->query) {
1122 ngx_resolver_free(r, rn->query);
1123 }
1124
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001125 ngx_resolver_free(r, rn);
1126 }
1127
1128 /* unlock addr mutex */
1129
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001130 if (ctx->event) {
Igor Sysoev7c4cf272008-02-28 20:09:39 +00001131 ngx_resolver_free(r, ctx->event);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001132 }
1133
Igor Sysoev7c4cf272008-02-28 20:09:39 +00001134 ngx_resolver_free(r, ctx);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001135
1136 return NGX_ERROR;
1137}
1138
1139
1140void
1141ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
1142{
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001143 ngx_queue_t *expire_queue;
1144 ngx_rbtree_t *tree;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001145 ngx_resolver_t *r;
1146 ngx_resolver_ctx_t *w, **p;
1147 ngx_resolver_node_t *rn;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04001148
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001149 r = ctx->resolver;
1150
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001151 switch (ctx->addr.sockaddr->sa_family) {
1152
1153#if (NGX_HAVE_INET6)
1154 case AF_INET6:
1155 tree = &r->addr6_rbtree;
1156 expire_queue = &r->addr6_expire_queue;
1157 break;
1158#endif
1159
1160 default: /* AF_INET */
1161 tree = &r->addr_rbtree;
1162 expire_queue = &r->addr_expire_queue;
1163 }
1164
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001165 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
1166 "resolve addr done: %i", ctx->state);
1167
1168 if (ctx->event && ctx->event->timer_set) {
1169 ngx_del_timer(ctx->event);
1170 }
1171
1172 /* lock addr mutex */
1173
Ruslan Ermilov5f509b52016-01-26 16:46:31 +03001174 if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001175
Roman Arutyunyan38a72e92016-01-26 16:46:59 +03001176 rn = ctx->node;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001177
1178 if (rn) {
1179 p = &rn->waiting;
1180 w = rn->waiting;
1181
1182 while (w) {
1183 if (w == ctx) {
1184 *p = w->next;
1185
1186 goto done;
1187 }
1188
1189 p = &w->next;
1190 w = w->next;
1191 }
1192 }
1193
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001194 {
1195 u_char text[NGX_SOCKADDR_STRLEN];
1196 ngx_str_t addrtext;
1197
1198 addrtext.data = text;
1199 addrtext.len = ngx_sock_ntop(ctx->addr.sockaddr, ctx->addr.socklen,
1200 text, NGX_SOCKADDR_STRLEN, 0);
1201
1202 ngx_log_error(NGX_LOG_ALERT, r->log, 0,
1203 "could not cancel %V resolving", &addrtext);
1204 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001205 }
1206
1207done:
1208
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001209 ngx_resolver_expire(r, tree, expire_queue);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001210
1211 /* unlock addr mutex */
1212
Igor Sysoev7c4cf272008-02-28 20:09:39 +00001213 /* lock alloc mutex */
1214
1215 if (ctx->event) {
1216 ngx_resolver_free_locked(r, ctx->event);
1217 }
1218
1219 ngx_resolver_free_locked(r, ctx);
1220
1221 /* unlock alloc mutex */
Sergey Kandaurove6fdd2f2015-06-17 17:57:34 +03001222
1223 if (r->event->timer_set && ngx_resolver_resend_empty(r)) {
1224 ngx_del_timer(r->event);
1225 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001226}
1227
1228
1229static void
1230ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
1231{
1232 time_t now;
1233 ngx_uint_t i;
1234 ngx_queue_t *q;
1235 ngx_resolver_node_t *rn;
1236
1237 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver expire");
1238
1239 now = ngx_time();
1240
1241 for (i = 0; i < 2; i++) {
1242 if (ngx_queue_empty(queue)) {
1243 return;
1244 }
1245
1246 q = ngx_queue_last(queue);
1247
1248 rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
1249
1250 if (now <= rn->expire) {
1251 return;
1252 }
1253
Igor Sysoevd02661a2007-12-24 17:05:31 +00001254 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
1255 "resolver expire \"%*s\"", (size_t) rn->nlen, rn->name);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001256
1257 ngx_queue_remove(q);
1258
1259 ngx_rbtree_delete(tree, &rn->node);
1260
1261 ngx_resolver_free_node(r, rn);
1262 }
1263}
1264
1265
1266static ngx_int_t
1267ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn)
1268{
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001269 ngx_int_t rc;
Roman Arutyunyanec16a602016-01-28 15:28:20 +03001270 ngx_resolver_connection_t *rec;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001271
Roman Arutyunyanec16a602016-01-28 15:28:20 +03001272 rec = r->connections.elts;
Roman Arutyunyanb6a8f8c2016-01-28 15:28:20 +03001273 rec = &rec[rn->last_connection];
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001274
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001275 if (rec->log.handler == NULL) {
Roman Arutyunyanec16a602016-01-28 15:28:20 +03001276 rec->log = *r->log;
1277 rec->log.handler = ngx_resolver_log_error;
1278 rec->log.data = rec;
1279 rec->log.action = "resolving";
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001280 }
1281
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001282 if (rn->naddrs == (u_short) -1) {
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001283 rc = rn->tcp ? ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen)
1284 : ngx_resolver_send_udp_query(r, rec, rn->query, rn->qlen);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001285
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001286 if (rc != NGX_OK) {
1287 return rc;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001288 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001289 }
1290
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001291#if (NGX_HAVE_INET6)
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001292
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001293 if (rn->query6 && rn->naddrs6 == (u_short) -1) {
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001294 rc = rn->tcp6
1295 ? ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen)
1296 : ngx_resolver_send_udp_query(r, rec, rn->query6, rn->qlen);
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001297
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001298 if (rc != NGX_OK) {
1299 return rc;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001300 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001301 }
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001302
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001303#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001304
1305 return NGX_OK;
1306}
1307
1308
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001309static ngx_int_t
1310ngx_resolver_send_udp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec,
1311 u_char *query, u_short qlen)
1312{
1313 ssize_t n;
1314
1315 if (rec->udp == NULL) {
1316 if (ngx_udp_connect(rec) != NGX_OK) {
1317 return NGX_ERROR;
1318 }
1319
1320 rec->udp->data = rec;
1321 rec->udp->read->handler = ngx_resolver_udp_read;
1322 rec->udp->read->resolver = 1;
1323 }
1324
1325 n = ngx_send(rec->udp, query, qlen);
1326
1327 if (n == -1) {
1328 return NGX_ERROR;
1329 }
1330
1331 if ((size_t) n != (size_t) qlen) {
1332 ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete");
1333 return NGX_ERROR;
1334 }
1335
1336 return NGX_OK;
1337}
1338
1339
1340static ngx_int_t
1341ngx_resolver_send_tcp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec,
1342 u_char *query, u_short qlen)
1343{
1344 ngx_buf_t *b;
1345 ngx_int_t rc;
1346
1347 rc = NGX_OK;
1348
1349 if (rec->tcp == NULL) {
1350 b = rec->read_buf;
1351
1352 if (b == NULL) {
1353 b = ngx_resolver_calloc(r, sizeof(ngx_buf_t));
1354 if (b == NULL) {
1355 return NGX_ERROR;
1356 }
1357
1358 b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_RSIZE);
1359 if (b->start == NULL) {
Ruslan Ermilov0b6f2562016-02-02 11:35:19 +03001360 ngx_resolver_free(r, b);
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001361 return NGX_ERROR;
1362 }
1363
1364 b->end = b->start + NGX_RESOLVER_TCP_RSIZE;
1365
1366 rec->read_buf = b;
1367 }
1368
1369 b->pos = b->start;
1370 b->last = b->start;
1371
1372 b = rec->write_buf;
1373
1374 if (b == NULL) {
1375 b = ngx_resolver_calloc(r, sizeof(ngx_buf_t));
1376 if (b == NULL) {
1377 return NGX_ERROR;
1378 }
1379
1380 b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_WSIZE);
1381 if (b->start == NULL) {
Ruslan Ermilov0b6f2562016-02-02 11:35:19 +03001382 ngx_resolver_free(r, b);
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001383 return NGX_ERROR;
1384 }
1385
1386 b->end = b->start + NGX_RESOLVER_TCP_WSIZE;
1387
1388 rec->write_buf = b;
1389 }
1390
1391 b->pos = b->start;
1392 b->last = b->start;
1393
1394 rc = ngx_tcp_connect(rec);
1395 if (rc == NGX_ERROR) {
1396 return NGX_ERROR;
1397 }
1398
1399 rec->tcp->data = rec;
1400 rec->tcp->write->handler = ngx_resolver_tcp_write;
1401 rec->tcp->read->handler = ngx_resolver_tcp_read;
1402 rec->tcp->read->resolver = 1;
1403
1404 ngx_add_timer(rec->tcp->write, (ngx_msec_t) (r->tcp_timeout * 1000));
1405 }
1406
1407 b = rec->write_buf;
1408
1409 if (b->end - b->last < 2 + qlen) {
1410 ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "buffer overflow");
1411 return NGX_ERROR;
1412 }
1413
1414 *b->last++ = (u_char) (qlen >> 8);
1415 *b->last++ = (u_char) qlen;
1416 b->last = ngx_cpymem(b->last, query, qlen);
1417
1418 if (rc == NGX_OK) {
1419 ngx_resolver_tcp_write(rec->tcp->write);
1420 }
1421
1422 return NGX_OK;
1423}
1424
1425
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001426static void
1427ngx_resolver_resend_handler(ngx_event_t *ev)
1428{
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03001429 time_t timer, atimer, stimer, ntimer;
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001430#if (NGX_HAVE_INET6)
1431 time_t a6timer;
1432#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001433 ngx_resolver_t *r;
1434
1435 r = ev->data;
1436
1437 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0,
1438 "resolver resend handler");
1439
1440 /* lock name mutex */
1441
1442 ntimer = ngx_resolver_resend(r, &r->name_rbtree, &r->name_resend_queue);
1443
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03001444 stimer = ngx_resolver_resend(r, &r->srv_rbtree, &r->srv_resend_queue);
1445
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001446 /* unlock name mutex */
1447
1448 /* lock addr mutex */
1449
1450 atimer = ngx_resolver_resend(r, &r->addr_rbtree, &r->addr_resend_queue);
Igor Sysoevb4e5b4c2007-12-01 19:57:37 +00001451
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001452 /* unlock addr mutex */
1453
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001454#if (NGX_HAVE_INET6)
1455
1456 /* lock addr6 mutex */
1457
1458 a6timer = ngx_resolver_resend(r, &r->addr6_rbtree, &r->addr6_resend_queue);
1459
1460 /* unlock addr6 mutex */
1461
1462#endif
1463
1464 timer = ntimer;
1465
1466 if (timer == 0) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001467 timer = atimer;
1468
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001469 } else if (atimer) {
1470 timer = ngx_min(timer, atimer);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001471 }
1472
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03001473 if (timer == 0) {
1474 timer = stimer;
1475
1476 } else if (stimer) {
1477 timer = ngx_min(timer, stimer);
1478 }
1479
Ruslan Ermilov809bee32013-12-06 14:30:28 +04001480#if (NGX_HAVE_INET6)
1481
1482 if (timer == 0) {
1483 timer = a6timer;
1484
1485 } else if (a6timer) {
1486 timer = ngx_min(timer, a6timer);
1487 }
1488
1489#endif
1490
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001491 if (timer) {
1492 ngx_add_timer(r->event, (ngx_msec_t) (timer * 1000));
1493 }
1494}
1495
1496
1497static time_t
1498ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
1499{
1500 time_t now;
1501 ngx_queue_t *q;
1502 ngx_resolver_node_t *rn;
1503
1504 now = ngx_time();
1505
1506 for ( ;; ) {
1507 if (ngx_queue_empty(queue)) {
1508 return 0;
1509 }
1510
1511 q = ngx_queue_last(queue);
1512
1513 rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
1514
1515 if (now < rn->expire) {
1516 return rn->expire - now;
1517 }
1518
Igor Sysoevd02661a2007-12-24 17:05:31 +00001519 ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
1520 "resolver resend \"%*s\" %p",
1521 (size_t) rn->nlen, rn->name, rn->waiting);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001522
1523 ngx_queue_remove(q);
1524
1525 if (rn->waiting) {
1526
Roman Arutyunyanb6a8f8c2016-01-28 15:28:20 +03001527 if (++rn->last_connection == r->connections.nelts) {
1528 rn->last_connection = 0;
1529 }
1530
Ruslan Ermilovda8bb222012-06-18 12:30:45 +00001531 (void) ngx_resolver_send_query(r, rn);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001532
Ruslan Ermilovda8bb222012-06-18 12:30:45 +00001533 rn->expire = now + r->resend_timeout;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001534
Ruslan Ermilovda8bb222012-06-18 12:30:45 +00001535 ngx_queue_insert_head(queue, q);
Igor Sysoev61adfb22008-02-06 16:08:52 +00001536
1537 continue;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001538 }
1539
1540 ngx_rbtree_delete(tree, &rn->node);
1541
1542 ngx_resolver_free_node(r, rn);
1543 }
1544}
1545
1546
Sergey Kandaurove6fdd2f2015-06-17 17:57:34 +03001547static ngx_uint_t
1548ngx_resolver_resend_empty(ngx_resolver_t *r)
1549{
1550 return ngx_queue_empty(&r->name_resend_queue)
1551#if (NGX_HAVE_INET6)
1552 && ngx_queue_empty(&r->addr6_resend_queue)
1553#endif
1554 && ngx_queue_empty(&r->addr_resend_queue);
1555}
1556
1557
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001558static void
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001559ngx_resolver_udp_read(ngx_event_t *rev)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001560{
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001561 ssize_t n;
1562 ngx_connection_t *c;
1563 ngx_resolver_connection_t *rec;
1564 u_char buf[NGX_RESOLVER_UDP_SIZE];
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001565
1566 c = rev->data;
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001567 rec = c->data;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001568
1569 do {
Igor Sysoeve67d4612007-12-03 16:46:46 +00001570 n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001571
Igor Sysoeve67d4612007-12-03 16:46:46 +00001572 if (n < 0) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001573 return;
1574 }
1575
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001576 ngx_resolver_process_response(rec->resolver, buf, n, 0);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001577
1578 } while (rev->ready);
1579}
1580
1581
1582static void
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001583ngx_resolver_tcp_write(ngx_event_t *wev)
1584{
1585 off_t sent;
1586 ssize_t n;
1587 ngx_buf_t *b;
1588 ngx_resolver_t *r;
1589 ngx_connection_t *c;
1590 ngx_resolver_connection_t *rec;
1591
1592 c = wev->data;
1593 rec = c->data;
1594 b = rec->write_buf;
1595 r = rec->resolver;
1596
1597 if (wev->timedout) {
1598 goto failed;
1599 }
1600
1601 sent = c->sent;
1602
1603 while (wev->ready && b->pos < b->last) {
1604 n = ngx_send(c, b->pos, b->last - b->pos);
1605
1606 if (n == NGX_AGAIN) {
1607 break;
1608 }
1609
1610 if (n == NGX_ERROR) {
1611 goto failed;
1612 }
1613
1614 b->pos += n;
1615 }
1616
1617 if (b->pos != b->start) {
1618 b->last = ngx_movemem(b->start, b->pos, b->last - b->pos);
1619 b->pos = b->start;
1620 }
1621
1622 if (c->sent != sent) {
1623 ngx_add_timer(wev, (ngx_msec_t) (r->tcp_timeout * 1000));
1624 }
1625
1626 if (ngx_handle_write_event(wev, 0) != NGX_OK) {
1627 goto failed;
1628 }
1629
1630 return;
1631
1632failed:
1633
1634 ngx_close_connection(c);
1635 rec->tcp = NULL;
1636}
1637
1638
1639static void
1640ngx_resolver_tcp_read(ngx_event_t *rev)
1641{
1642 u_char *p;
1643 size_t size;
1644 ssize_t n;
1645 u_short qlen;
1646 ngx_buf_t *b;
1647 ngx_resolver_t *r;
1648 ngx_connection_t *c;
1649 ngx_resolver_connection_t *rec;
1650
1651 c = rev->data;
1652 rec = c->data;
1653 b = rec->read_buf;
1654 r = rec->resolver;
1655
1656 while (rev->ready) {
1657 n = ngx_recv(c, b->last, b->end - b->last);
1658
1659 if (n == NGX_AGAIN) {
1660 break;
1661 }
1662
1663 if (n == NGX_ERROR || n == 0) {
1664 goto failed;
1665 }
1666
1667 b->last += n;
1668
1669 for ( ;; ) {
1670 p = b->pos;
1671 size = b->last - p;
1672
1673 if (size < 2) {
1674 break;
1675 }
1676
1677 qlen = (u_short) *p++ << 8;
1678 qlen += *p++;
1679
1680 if (size < (size_t) (2 + qlen)) {
1681 break;
1682 }
1683
1684 ngx_resolver_process_response(r, p, qlen, 1);
1685
1686 b->pos += 2 + qlen;
1687 }
1688
1689 if (b->pos != b->start) {
1690 b->last = ngx_movemem(b->start, b->pos, b->last - b->pos);
1691 b->pos = b->start;
1692 }
1693 }
1694
1695 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
1696 goto failed;
1697 }
1698
1699 return;
1700
1701failed:
1702
1703 ngx_close_connection(c);
1704 rec->tcp = NULL;
1705}
1706
1707
1708static void
1709ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n,
1710 ngx_uint_t tcp)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001711{
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001712 char *err;
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001713 ngx_uint_t i, times, ident, qident, flags, code, nqs, nan, trunc,
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001714 qtype, qclass;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001715#if (NGX_HAVE_INET6)
1716 ngx_uint_t qident6;
1717#endif
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001718 ngx_queue_t *q;
1719 ngx_resolver_qs_t *qs;
1720 ngx_resolver_hdr_t *response;
1721 ngx_resolver_node_t *rn;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001722
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001723 if (n < sizeof(ngx_resolver_hdr_t)) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001724 goto short_response;
1725 }
1726
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001727 response = (ngx_resolver_hdr_t *) buf;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001728
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001729 ident = (response->ident_hi << 8) + response->ident_lo;
1730 flags = (response->flags_hi << 8) + response->flags_lo;
1731 nqs = (response->nqs_hi << 8) + response->nqs_lo;
1732 nan = (response->nan_hi << 8) + response->nan_lo;
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001733 trunc = flags & 0x0200;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001734
1735 ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0,
Ruslan Ermilov2ef6b3a2016-04-08 15:03:38 +03001736 "resolver DNS response %ui fl:%04Xi %ui/%ui/%ud/%ud",
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001737 ident, flags, nqs, nan,
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001738 (response->nns_hi << 8) + response->nns_lo,
1739 (response->nar_hi << 8) + response->nar_lo);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001740
Ruslan Ermilovf3a271f2013-12-06 14:30:27 +04001741 /* response to a standard query */
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001742 if ((flags & 0xf870) != 0x8000 || (trunc && tcp)) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001743 ngx_log_error(r->log_level, r->log, 0,
Ruslan Ermilov2ef6b3a2016-04-08 15:03:38 +03001744 "invalid %s DNS response %ui fl:%04Xi",
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001745 tcp ? "TCP" : "UDP", ident, flags);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001746 return;
1747 }
1748
Ruslan Ermilovf3a271f2013-12-06 14:30:27 +04001749 code = flags & 0xf;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001750
Igor Sysoev571a5e12008-10-24 14:38:09 +00001751 if (code == NGX_RESOLVE_FORMERR) {
1752
1753 times = 0;
1754
1755 for (q = ngx_queue_head(&r->name_resend_queue);
Roman Arutyunyan4f84c8d2016-01-26 16:46:18 +03001756 q != ngx_queue_sentinel(&r->name_resend_queue) && times++ < 100;
Igor Sysoev571a5e12008-10-24 14:38:09 +00001757 q = ngx_queue_next(q))
1758 {
1759 rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
1760 qident = (rn->query[0] << 8) + rn->query[1];
1761
1762 if (qident == ident) {
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001763 goto dns_error_name;
Igor Sysoev571a5e12008-10-24 14:38:09 +00001764 }
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001765
1766#if (NGX_HAVE_INET6)
1767 if (rn->query6) {
1768 qident6 = (rn->query6[0] << 8) + rn->query6[1];
1769
1770 if (qident6 == ident) {
1771 goto dns_error_name;
1772 }
1773 }
1774#endif
Igor Sysoev571a5e12008-10-24 14:38:09 +00001775 }
1776
1777 goto dns_error;
1778 }
1779
1780 if (code > NGX_RESOLVE_REFUSED) {
1781 goto dns_error;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001782 }
1783
1784 if (nqs != 1) {
1785 err = "invalid number of questions in DNS response";
1786 goto done;
1787 }
1788
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001789 i = sizeof(ngx_resolver_hdr_t);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001790
1791 while (i < (ngx_uint_t) n) {
1792 if (buf[i] == '\0') {
1793 goto found;
1794 }
1795
Ruslan Ermilovf3a271f2013-12-06 14:30:27 +04001796 i += 1 + buf[i];
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001797 }
1798
1799 goto short_response;
1800
1801found:
1802
Ruslan Ermilovf3a271f2013-12-06 14:30:27 +04001803 if (i++ == sizeof(ngx_resolver_hdr_t)) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001804 err = "zero-length domain name in DNS response";
1805 goto done;
1806 }
1807
1808 if (i + sizeof(ngx_resolver_qs_t) + nan * (2 + sizeof(ngx_resolver_an_t))
1809 > (ngx_uint_t) n)
1810 {
1811 goto short_response;
1812 }
1813
1814 qs = (ngx_resolver_qs_t *) &buf[i];
1815
1816 qtype = (qs->type_hi << 8) + qs->type_lo;
1817 qclass = (qs->class_hi << 8) + qs->class_lo;
1818
1819 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
Igor Sysoev7c5c1dc2008-04-10 17:27:07 +00001820 "resolver DNS response qt:%ui cl:%ui", qtype, qclass);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001821
1822 if (qclass != 1) {
1823 ngx_log_error(r->log_level, r->log, 0,
Igor Sysoev7c5c1dc2008-04-10 17:27:07 +00001824 "unknown query class %ui in DNS response", qclass);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001825 return;
1826 }
1827
1828 switch (qtype) {
1829
1830 case NGX_RESOLVE_A:
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001831#if (NGX_HAVE_INET6)
1832 case NGX_RESOLVE_AAAA:
1833#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001834
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001835 ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan, trunc,
Igor Sysoevc0cadf12007-12-16 20:47:55 +00001836 i + sizeof(ngx_resolver_qs_t));
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001837
1838 break;
1839
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03001840 case NGX_RESOLVE_SRV:
1841
1842 ngx_resolver_process_srv(r, buf, n, ident, code, nan, trunc,
1843 i + sizeof(ngx_resolver_qs_t));
1844
1845 break;
1846
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001847 case NGX_RESOLVE_PTR:
1848
Igor Sysoevc0cadf12007-12-16 20:47:55 +00001849 ngx_resolver_process_ptr(r, buf, n, ident, code, nan);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001850
1851 break;
1852
1853 default:
1854 ngx_log_error(r->log_level, r->log, 0,
Igor Sysoev7c5c1dc2008-04-10 17:27:07 +00001855 "unknown query type %ui in DNS response", qtype);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001856 return;
1857 }
1858
1859 return;
1860
1861short_response:
1862
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001863 err = "short DNS response";
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001864
1865done:
1866
1867 ngx_log_error(r->log_level, r->log, 0, err);
1868
1869 return;
Igor Sysoev571a5e12008-10-24 14:38:09 +00001870
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001871dns_error_name:
1872
1873 ngx_log_error(r->log_level, r->log, 0,
1874 "DNS error (%ui: %s), query id:%ui, name:\"%*s\"",
1875 code, ngx_resolver_strerror(code), ident,
Sergey Kandaurovacddce62016-03-31 02:33:53 +03001876 (size_t) rn->nlen, rn->name);
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001877 return;
1878
Igor Sysoev571a5e12008-10-24 14:38:09 +00001879dns_error:
1880
1881 ngx_log_error(r->log_level, r->log, 0,
1882 "DNS error (%ui: %s), query id:%ui",
1883 code, ngx_resolver_strerror(code), ident);
1884 return;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001885}
1886
1887
1888static void
Ruslan Ermilov441e93b2015-12-17 17:21:12 +03001889ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001890 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001891 ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001892{
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001893 char *err;
1894 u_char *cname;
1895 size_t len;
1896 int32_t ttl;
1897 uint32_t hash;
1898 in_addr_t *addr;
1899 ngx_str_t name;
Ruslan Ermilov441e93b2015-12-17 17:21:12 +03001900 ngx_uint_t type, class, qident, naddrs, a, i, j, start;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001901#if (NGX_HAVE_INET6)
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001902 struct in6_addr *addr6;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001903#endif
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001904 ngx_resolver_an_t *an;
1905 ngx_resolver_ctx_t *ctx, *next;
1906 ngx_resolver_node_t *rn;
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03001907 ngx_resolver_addr_t *addrs;
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001908 ngx_resolver_connection_t *rec;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001909
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001910 if (ngx_resolver_copy(r, &name, buf,
Ruslan Ermilov441e93b2015-12-17 17:21:12 +03001911 buf + sizeof(ngx_resolver_hdr_t), buf + n)
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04001912 != NGX_OK)
1913 {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001914 return;
1915 }
1916
1917 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
1918
1919 hash = ngx_crc32_short(name.data, name.len);
1920
1921 /* lock name mutex */
1922
1923 rn = ngx_resolver_lookup_name(r, &name, hash);
1924
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001925 if (rn == NULL) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001926 ngx_log_error(r->log_level, r->log, 0,
1927 "unexpected response for %V", &name);
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04001928 ngx_resolver_free(r, name.data);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001929 goto failed;
1930 }
1931
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001932 switch (qtype) {
1933
1934#if (NGX_HAVE_INET6)
1935 case NGX_RESOLVE_AAAA:
1936
1937 if (rn->query6 == NULL || rn->naddrs6 != (u_short) -1) {
1938 ngx_log_error(r->log_level, r->log, 0,
1939 "unexpected response for %V", &name);
1940 ngx_resolver_free(r, name.data);
1941 goto failed;
1942 }
1943
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001944 if (trunc && rn->tcp6) {
1945 ngx_resolver_free(r, name.data);
1946 goto failed;
1947 }
1948
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001949 qident = (rn->query6[0] << 8) + rn->query6[1];
1950
1951 break;
1952#endif
1953
1954 default: /* NGX_RESOLVE_A */
1955
1956 if (rn->query == NULL || rn->naddrs != (u_short) -1) {
1957 ngx_log_error(r->log_level, r->log, 0,
1958 "unexpected response for %V", &name);
1959 ngx_resolver_free(r, name.data);
1960 goto failed;
1961 }
1962
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001963 if (trunc && rn->tcp) {
1964 ngx_resolver_free(r, name.data);
1965 goto failed;
1966 }
1967
Ruslan Ermilov769eded2013-12-09 10:53:28 +04001968 qident = (rn->query[0] << 8) + rn->query[1];
1969 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001970
1971 if (ident != qident) {
1972 ngx_log_error(r->log_level, r->log, 0,
Igor Sysoev7c5c1dc2008-04-10 17:27:07 +00001973 "wrong ident %ui response for %V, expect %ui",
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001974 ident, &name, qident);
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04001975 ngx_resolver_free(r, name.data);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00001976 goto failed;
1977 }
1978
Igor Sysoev99651522009-09-16 13:48:11 +00001979 ngx_resolver_free(r, name.data);
1980
Roman Arutyunyan910445b2016-01-28 15:28:20 +03001981 if (trunc) {
1982
1983 ngx_queue_remove(&rn->queue);
1984
1985 if (rn->waiting == NULL) {
1986 ngx_rbtree_delete(&r->name_rbtree, &rn->node);
1987 ngx_resolver_free_node(r, rn);
1988 goto next;
1989 }
1990
1991 rec = r->connections.elts;
1992 rec = &rec[rn->last_connection];
1993
1994 switch (qtype) {
1995
1996#if (NGX_HAVE_INET6)
1997 case NGX_RESOLVE_AAAA:
1998
1999 rn->tcp6 = 1;
2000
2001 (void) ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen);
2002
2003 break;
2004#endif
2005
2006 default: /* NGX_RESOLVE_A */
2007
2008 rn->tcp = 1;
2009
2010 (void) ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen);
2011 }
2012
2013 rn->expire = ngx_time() + r->resend_timeout;
2014
2015 ngx_queue_insert_head(&r->name_resend_queue, &rn->queue);
2016
2017 goto next;
2018 }
2019
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002020 if (code == 0 && rn->code) {
2021 code = rn->code;
2022 }
2023
Igor Sysoevc0cadf12007-12-16 20:47:55 +00002024 if (code == 0 && nan == 0) {
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002025
2026#if (NGX_HAVE_INET6)
2027 switch (qtype) {
2028
2029 case NGX_RESOLVE_AAAA:
2030
Ruslan Ermilov7e524322014-07-16 10:21:28 +04002031 rn->naddrs6 = 0;
2032
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002033 if (rn->naddrs == (u_short) -1) {
2034 goto next;
2035 }
2036
2037 if (rn->naddrs) {
2038 goto export;
2039 }
2040
2041 break;
2042
2043 default: /* NGX_RESOLVE_A */
2044
Ruslan Ermilov7e524322014-07-16 10:21:28 +04002045 rn->naddrs = 0;
2046
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002047 if (rn->naddrs6 == (u_short) -1) {
2048 goto next;
2049 }
2050
2051 if (rn->naddrs6) {
2052 goto export;
2053 }
2054 }
2055#endif
2056
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002057 code = NGX_RESOLVE_NXDOMAIN;
Igor Sysoevc0cadf12007-12-16 20:47:55 +00002058 }
2059
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002060 if (code) {
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002061
2062#if (NGX_HAVE_INET6)
2063 switch (qtype) {
2064
2065 case NGX_RESOLVE_AAAA:
2066
Ruslan Ermilov7e524322014-07-16 10:21:28 +04002067 rn->naddrs6 = 0;
2068
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002069 if (rn->naddrs == (u_short) -1) {
2070 rn->code = (u_char) code;
2071 goto next;
2072 }
2073
2074 break;
2075
2076 default: /* NGX_RESOLVE_A */
2077
Ruslan Ermilov7e524322014-07-16 10:21:28 +04002078 rn->naddrs = 0;
2079
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002080 if (rn->naddrs6 == (u_short) -1) {
2081 rn->code = (u_char) code;
2082 goto next;
2083 }
2084 }
2085#endif
2086
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002087 next = rn->waiting;
2088 rn->waiting = NULL;
2089
2090 ngx_queue_remove(&rn->queue);
2091
2092 ngx_rbtree_delete(&r->name_rbtree, &rn->node);
2093
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002094 /* unlock name mutex */
2095
2096 while (next) {
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04002097 ctx = next;
2098 ctx->state = code;
Dmitry Volyntsev6f418a32016-03-23 17:44:36 +03002099 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04002100 next = ctx->next;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002101
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04002102 ctx->handler(ctx);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002103 }
2104
Ruslan Ermilovd4b7b742014-11-20 15:24:40 +03002105 ngx_resolver_free_node(r, rn);
2106
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002107 return;
2108 }
2109
2110 i = ans;
2111 naddrs = 0;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002112 cname = NULL;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002113
2114 for (a = 0; a < nan; a++) {
2115
2116 start = i;
2117
Ruslan Ermilov441e93b2015-12-17 17:21:12 +03002118 while (i < n) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002119
2120 if (buf[i] & 0xc0) {
2121 i += 2;
2122 goto found;
2123 }
2124
2125 if (buf[i] == 0) {
2126 i++;
2127 goto test_length;
2128 }
2129
2130 i += 1 + buf[i];
2131 }
2132
2133 goto short_response;
2134
2135 test_length:
2136
2137 if (i - start < 2) {
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002138 err = "invalid name in DNS response";
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002139 goto invalid;
2140 }
2141
2142 found:
2143
Ruslan Ermilov441e93b2015-12-17 17:21:12 +03002144 if (i + sizeof(ngx_resolver_an_t) >= n) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002145 goto short_response;
2146 }
2147
2148 an = (ngx_resolver_an_t *) &buf[i];
2149
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002150 type = (an->type_hi << 8) + an->type_lo;
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002151 class = (an->class_hi << 8) + an->class_lo;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002152 len = (an->len_hi << 8) + an->len_lo;
Ruslan Ermilovbec516b2011-11-16 13:11:39 +00002153 ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
2154 + (an->ttl[2] << 8) + (an->ttl[3]);
2155
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002156 if (class != 1) {
2157 ngx_log_error(r->log_level, r->log, 0,
2158 "unexpected RR class %ui", class);
2159 goto failed;
2160 }
2161
Ruslan Ermilovbec516b2011-11-16 13:11:39 +00002162 if (ttl < 0) {
2163 ttl = 0;
2164 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002165
Ruslan Ermilov85e6d212013-12-16 19:12:23 +04002166 rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl);
2167
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002168 i += sizeof(ngx_resolver_an_t);
2169
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002170 switch (type) {
2171
2172 case NGX_RESOLVE_A:
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002173
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002174 if (qtype != NGX_RESOLVE_A) {
2175 err = "unexpected A record in DNS response";
2176 goto invalid;
2177 }
2178
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002179 if (len != 4) {
2180 err = "invalid A record in DNS response";
2181 goto invalid;
2182 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002183
Ruslan Ermilov441e93b2015-12-17 17:21:12 +03002184 if (i + 4 > n) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002185 goto short_response;
2186 }
2187
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002188 naddrs++;
2189
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002190 break;
2191
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002192#if (NGX_HAVE_INET6)
2193 case NGX_RESOLVE_AAAA:
2194
2195 if (qtype != NGX_RESOLVE_AAAA) {
2196 err = "unexpected AAAA record in DNS response";
2197 goto invalid;
2198 }
2199
2200 if (len != 16) {
2201 err = "invalid AAAA record in DNS response";
2202 goto invalid;
2203 }
2204
Ruslan Ermilov441e93b2015-12-17 17:21:12 +03002205 if (i + 16 > n) {
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002206 goto short_response;
2207 }
2208
2209 naddrs++;
2210
2211 break;
2212#endif
2213
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002214 case NGX_RESOLVE_CNAME:
2215
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002216 cname = &buf[i];
Igor Sysoev19540cd2008-04-10 17:12:21 +00002217
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002218 break;
2219
2220 case NGX_RESOLVE_DNAME:
2221
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002222 break;
2223
2224 default:
2225
Igor Sysoev4ad5be62008-04-10 17:26:14 +00002226 ngx_log_error(r->log_level, r->log, 0,
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002227 "unexpected RR type %ui", type);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002228 }
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002229
2230 i += len;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002231 }
2232
Ruslan Ermilovbec516b2011-11-16 13:11:39 +00002233 ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
Ruslan Ermilov85e6d212013-12-16 19:12:23 +04002234 "resolver naddrs:%ui cname:%p ttl:%uD",
2235 naddrs, cname, rn->ttl);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002236
2237 if (naddrs) {
2238
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002239 switch (qtype) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002240
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002241#if (NGX_HAVE_INET6)
2242 case NGX_RESOLVE_AAAA:
2243
2244 if (naddrs == 1) {
2245 addr6 = &rn->u6.addr6;
2246 rn->naddrs6 = 1;
2247
2248 } else {
2249 addr6 = ngx_resolver_alloc(r, naddrs * sizeof(struct in6_addr));
2250 if (addr6 == NULL) {
2251 goto failed;
2252 }
2253
2254 rn->u6.addrs6 = addr6;
2255 rn->naddrs6 = (u_short) naddrs;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002256 }
2257
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002258#if (NGX_SUPPRESS_WARN)
2259 addr = NULL;
2260#endif
2261
2262 break;
2263#endif
2264
2265 default: /* NGX_RESOLVE_A */
2266
2267 if (naddrs == 1) {
2268 addr = &rn->u.addr;
2269 rn->naddrs = 1;
2270
2271 } else {
2272 addr = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
2273 if (addr == NULL) {
2274 goto failed;
2275 }
2276
2277 rn->u.addrs = addr;
2278 rn->naddrs = (u_short) naddrs;
2279 }
2280
2281#if (NGX_HAVE_INET6 && NGX_SUPPRESS_WARN)
2282 addr6 = NULL;
2283#endif
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002284 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002285
Ruslan Ermilov441e93b2015-12-17 17:21:12 +03002286 j = 0;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002287 i = ans;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002288
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002289 for (a = 0; a < nan; a++) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002290
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002291 for ( ;; ) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002292
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002293 if (buf[i] & 0xc0) {
2294 i += 2;
2295 break;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002296 }
2297
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002298 if (buf[i] == 0) {
2299 i++;
2300 break;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002301 }
2302
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002303 i += 1 + buf[i];
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002304 }
2305
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002306 an = (ngx_resolver_an_t *) &buf[i];
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002307
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002308 type = (an->type_hi << 8) + an->type_lo;
2309 len = (an->len_hi << 8) + an->len_lo;
2310
2311 i += sizeof(ngx_resolver_an_t);
2312
2313 if (type == NGX_RESOLVE_A) {
2314
Ruslan Ermilov441e93b2015-12-17 17:21:12 +03002315 addr[j] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002316 + (buf[i + 2] << 8) + (buf[i + 3]));
2317
Ruslan Ermilov441e93b2015-12-17 17:21:12 +03002318 if (++j == naddrs) {
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002319
2320#if (NGX_HAVE_INET6)
2321 if (rn->naddrs6 == (u_short) -1) {
2322 goto next;
2323 }
2324#endif
2325
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002326 break;
2327 }
2328 }
2329
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002330#if (NGX_HAVE_INET6)
2331 else if (type == NGX_RESOLVE_AAAA) {
2332
Ruslan Ermilov441e93b2015-12-17 17:21:12 +03002333 ngx_memcpy(addr6[j].s6_addr, &buf[i], 16);
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002334
Ruslan Ermilov441e93b2015-12-17 17:21:12 +03002335 if (++j == naddrs) {
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002336
2337 if (rn->naddrs == (u_short) -1) {
2338 goto next;
2339 }
2340
2341 break;
2342 }
2343 }
2344#endif
2345
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002346 i += len;
2347 }
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002348 }
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002349
Ruslan Ermilov7e524322014-07-16 10:21:28 +04002350 switch (qtype) {
2351
2352#if (NGX_HAVE_INET6)
2353 case NGX_RESOLVE_AAAA:
2354
2355 if (rn->naddrs6 == (u_short) -1) {
2356 rn->naddrs6 = 0;
2357 }
2358
2359 break;
2360#endif
2361
2362 default: /* NGX_RESOLVE_A */
2363
2364 if (rn->naddrs == (u_short) -1) {
2365 rn->naddrs = 0;
2366 }
2367 }
2368
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002369 if (rn->naddrs != (u_short) -1
2370#if (NGX_HAVE_INET6)
2371 && rn->naddrs6 != (u_short) -1
2372#endif
2373 && rn->naddrs
2374#if (NGX_HAVE_INET6)
2375 + rn->naddrs6
2376#endif
2377 > 0)
2378 {
2379
2380#if (NGX_HAVE_INET6)
2381 export:
2382#endif
2383
2384 naddrs = rn->naddrs;
2385#if (NGX_HAVE_INET6)
2386 naddrs += rn->naddrs6;
2387#endif
2388
2389 if (naddrs == 1 && rn->naddrs == 1) {
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002390 addrs = NULL;
2391
2392 } else {
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002393 addrs = ngx_resolver_export(r, rn, 0);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002394 if (addrs == NULL) {
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002395 goto failed;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002396 }
2397 }
2398
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002399 ngx_queue_remove(&rn->queue);
2400
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002401 rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002402 rn->expire = ngx_time() + r->expire;
2403
2404 ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
2405
2406 next = rn->waiting;
2407 rn->waiting = NULL;
2408
2409 /* unlock name mutex */
2410
2411 while (next) {
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04002412 ctx = next;
2413 ctx->state = NGX_OK;
Dmitry Volyntsev6f418a32016-03-23 17:44:36 +03002414 ctx->valid = rn->valid;
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04002415 ctx->naddrs = naddrs;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002416
2417 if (addrs == NULL) {
2418 ctx->addrs = &ctx->addr;
2419 ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
2420 ctx->addr.socklen = sizeof(struct sockaddr_in);
2421 ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
2422 ctx->sin.sin_family = AF_INET;
2423 ctx->sin.sin_addr.s_addr = rn->u.addr;
2424
2425 } else {
2426 ctx->addrs = addrs;
2427 }
2428
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04002429 next = ctx->next;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002430
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04002431 ctx->handler(ctx);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002432 }
2433
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04002434 if (addrs != NULL) {
2435 ngx_resolver_free(r, addrs->sockaddr);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002436 ngx_resolver_free(r, addrs);
2437 }
2438
Maxim Dounin7d863c02012-05-14 09:13:45 +00002439 ngx_resolver_free(r, rn->query);
2440 rn->query = NULL;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002441#if (NGX_HAVE_INET6)
2442 rn->query6 = NULL;
2443#endif
Maxim Dounin7d863c02012-05-14 09:13:45 +00002444
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002445 return;
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002446 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002447
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002448 if (cname) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002449
2450 /* CNAME only */
2451
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002452 if (rn->naddrs == (u_short) -1
2453#if (NGX_HAVE_INET6)
2454 || rn->naddrs6 == (u_short) -1
2455#endif
2456 )
2457 {
2458 goto next;
2459 }
2460
Ruslan Ermilov441e93b2015-12-17 17:21:12 +03002461 if (ngx_resolver_copy(r, &name, buf, cname, buf + n) != NGX_OK) {
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002462 goto failed;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002463 }
2464
2465 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
2466 "resolver cname:\"%V\"", &name);
2467
Igor Sysoev28bca1b2007-12-16 20:00:15 +00002468 ngx_queue_remove(&rn->queue);
2469
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002470 rn->cnlen = (u_short) name.len;
2471 rn->u.cname = name.data;
Ruslan Ermilovbec516b2011-11-16 13:11:39 +00002472
Ruslan Ermilov85e6d212013-12-16 19:12:23 +04002473 rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002474 rn->expire = ngx_time() + r->expire;
2475
2476 ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
2477
Ruslan Ermilov65a043f2016-01-26 16:47:14 +03002478 ngx_resolver_free(r, rn->query);
2479 rn->query = NULL;
2480#if (NGX_HAVE_INET6)
2481 rn->query6 = NULL;
2482#endif
2483
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002484 ctx = rn->waiting;
2485 rn->waiting = NULL;
2486
2487 if (ctx) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002488
Ruslan Ermilov65a043f2016-01-26 16:47:14 +03002489 if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) {
2490
2491 /* unlock name mutex */
2492
2493 do {
2494 ctx->state = NGX_RESOLVE_NXDOMAIN;
2495 next = ctx->next;
2496
2497 ctx->handler(ctx);
2498
2499 ctx = next;
2500 } while (ctx);
2501
2502 return;
2503 }
2504
Roman Arutyunyan38a72e92016-01-26 16:46:59 +03002505 for (next = ctx; next; next = next->next) {
2506 next->node = NULL;
2507 }
2508
2509 (void) ngx_resolve_name_locked(r, ctx, &name);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002510 }
2511
Ruslan Ermilovf57350c2013-12-06 14:30:27 +04002512 /* unlock name mutex */
2513
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002514 return;
2515 }
2516
2517 ngx_log_error(r->log_level, r->log, 0,
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002518 "no A or CNAME types in DNS response");
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002519 return;
2520
2521short_response:
2522
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04002523 err = "short DNS response";
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002524
2525invalid:
2526
2527 /* unlock name mutex */
2528
2529 ngx_log_error(r->log_level, r->log, 0, err);
2530
2531 return;
2532
2533failed:
2534
Ruslan Ermilov769eded2013-12-09 10:53:28 +04002535next:
2536
Igor Sysoevcb4d5382007-11-23 17:13:26 +00002537 /* unlock name mutex */
2538
2539 return;
2540}
2541
2542
2543static void
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03002544ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n,
2545 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan,
2546 ngx_uint_t trunc, ngx_uint_t ans)
2547{
2548 char *err;
2549 u_char *cname;
2550 size_t len;
2551 int32_t ttl;
2552 uint32_t hash;
2553 ngx_str_t name;
2554 ngx_uint_t type, qident, class, start, nsrvs, a, i, j;
2555 ngx_resolver_an_t *an;
2556 ngx_resolver_ctx_t *ctx, *next;
2557 ngx_resolver_srv_t *srvs;
2558 ngx_resolver_node_t *rn;
2559 ngx_resolver_connection_t *rec;
2560
2561 if (ngx_resolver_copy(r, &name, buf,
2562 buf + sizeof(ngx_resolver_hdr_t), buf + n)
2563 != NGX_OK)
2564 {
2565 return;
2566 }
2567
2568 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
2569
2570 hash = ngx_crc32_short(name.data, name.len);
2571
2572 rn = ngx_resolver_lookup_srv(r, &name, hash);
2573
2574 if (rn == NULL || rn->query == NULL) {
2575 ngx_log_error(r->log_level, r->log, 0,
2576 "unexpected response for %V", &name);
2577 ngx_resolver_free(r, name.data);
2578 goto failed;
2579 }
2580
2581 if (trunc && rn->tcp) {
2582 ngx_resolver_free(r, name.data);
2583 goto failed;
2584 }
2585
2586 qident = (rn->query[0] << 8) + rn->query[1];
2587
2588 if (ident != qident) {
2589 ngx_log_error(r->log_level, r->log, 0,
2590 "wrong ident %ui response for %V, expect %ui",
2591 ident, &name, qident);
2592 ngx_resolver_free(r, name.data);
2593 goto failed;
2594 }
2595
2596 ngx_resolver_free(r, name.data);
2597
2598 if (trunc) {
2599
2600 ngx_queue_remove(&rn->queue);
2601
2602 if (rn->waiting == NULL) {
2603 ngx_rbtree_delete(&r->srv_rbtree, &rn->node);
2604 ngx_resolver_free_node(r, rn);
2605 return;
2606 }
2607
2608 rec = r->connections.elts;
2609 rec = &rec[rn->last_connection];
2610
2611 rn->tcp = 1;
2612
2613 (void) ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen);
2614
2615 rn->expire = ngx_time() + r->resend_timeout;
2616
2617 ngx_queue_insert_head(&r->srv_resend_queue, &rn->queue);
2618
2619 return;
2620 }
2621
2622 if (code == 0 && rn->code) {
2623 code = rn->code;
2624 }
2625
2626 if (code == 0 && nan == 0) {
2627 code = NGX_RESOLVE_NXDOMAIN;
2628 }
2629
2630 if (code) {
2631 next = rn->waiting;
2632 rn->waiting = NULL;
2633
2634 ngx_queue_remove(&rn->queue);
2635
2636 ngx_rbtree_delete(&r->srv_rbtree, &rn->node);
2637
2638 while (next) {
2639 ctx = next;
2640 ctx->state = code;
2641 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
2642 next = ctx->next;
2643
2644 ctx->handler(ctx);
2645 }
2646
2647 ngx_resolver_free_node(r, rn);
2648
2649 return;
2650 }
2651
2652 i = ans;
2653 nsrvs = 0;
2654 cname = NULL;
2655
2656 for (a = 0; a < nan; a++) {
2657
2658 start = i;
2659
2660 while (i < n) {
2661
2662 if (buf[i] & 0xc0) {
2663 i += 2;
2664 goto found;
2665 }
2666
2667 if (buf[i] == 0) {
2668 i++;
2669 goto test_length;
2670 }
2671
2672 i += 1 + buf[i];
2673 }
2674
2675 goto short_response;
2676
2677 test_length:
2678
2679 if (i - start < 2) {
2680 err = "invalid name DNS response";
2681 goto invalid;
2682 }
2683
2684 found:
2685
2686 if (i + sizeof(ngx_resolver_an_t) >= n) {
2687 goto short_response;
2688 }
2689
2690 an = (ngx_resolver_an_t *) &buf[i];
2691
2692 type = (an->type_hi << 8) + an->type_lo;
2693 class = (an->class_hi << 8) + an->class_lo;
2694 len = (an->len_hi << 8) + an->len_lo;
2695 ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
2696 + (an->ttl[2] << 8) + (an->ttl[3]);
2697
2698 if (class != 1) {
2699 ngx_log_error(r->log_level, r->log, 0,
2700 "unexpected RR class %ui", class);
2701 goto failed;
2702 }
2703
2704 if (ttl < 0) {
2705 ttl = 0;
2706 }
2707
2708 rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl);
2709
2710 i += sizeof(ngx_resolver_an_t);
2711
2712 switch (type) {
2713
2714 case NGX_RESOLVE_SRV:
2715
2716 if (i + 6 > n) {
2717 goto short_response;
2718 }
2719
2720 if (ngx_resolver_copy(r, NULL, buf, &buf[i + 6], buf + n)
2721 != NGX_OK)
2722 {
2723 goto failed;
2724 }
2725
2726 nsrvs++;
2727
2728 break;
2729
2730 case NGX_RESOLVE_CNAME:
2731
2732 cname = &buf[i];
2733
2734 break;
2735
2736 case NGX_RESOLVE_DNAME:
2737
2738 break;
2739
2740 default:
2741
2742 ngx_log_error(r->log_level, r->log, 0,
2743 "unexpected RR type %ui", type);
2744 }
2745
2746 i += len;
2747 }
2748
2749 ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
2750 "resolver nsrvs:%ui cname:%p ttl:%uD",
2751 nsrvs, cname, rn->ttl);
2752
2753 if (nsrvs) {
2754
2755 srvs = ngx_resolver_calloc(r, nsrvs * sizeof(ngx_resolver_srv_t));
2756 if (srvs == NULL) {
2757 goto failed;
2758 }
2759
2760 rn->u.srvs = srvs;
Dmitry Volyntsev28067ba2016-03-23 18:34:05 +03002761 rn->nsrvs = (u_short) nsrvs;
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03002762
2763 j = 0;
2764 i = ans;
2765
2766 for (a = 0; a < nan; a++) {
2767
2768 for ( ;; ) {
2769
2770 if (buf[i] & 0xc0) {
2771 i += 2;
2772 break;
2773 }
2774
2775 if (buf[i] == 0) {
2776 i++;
2777 break;
2778 }
2779
2780 i += 1 + buf[i];
2781 }
2782
2783 an = (ngx_resolver_an_t *) &buf[i];
2784
2785 type = (an->type_hi << 8) + an->type_lo;
2786 len = (an->len_hi << 8) + an->len_lo;
2787
2788 i += sizeof(ngx_resolver_an_t);
2789
2790 if (type == NGX_RESOLVE_SRV) {
2791
2792 srvs[j].priority = (buf[i] << 8) + buf[i + 1];
2793 srvs[j].weight = (buf[i + 2] << 8) + buf[i + 3];
2794
2795 if (srvs[j].weight == 0) {
2796 srvs[j].weight = 1;
2797 }
2798
2799 srvs[j].port = (buf[i + 4] << 8) + buf[i + 5];
2800
2801 if (ngx_resolver_copy(r, &srvs[j].name, buf, &buf[i + 6],
2802 buf + n)
2803 != NGX_OK)
2804 {
2805 goto failed;
2806 }
2807
2808 j++;
2809 }
2810
2811 i += len;
2812 }
2813
2814 ngx_sort(srvs, nsrvs, sizeof(ngx_resolver_srv_t),
2815 ngx_resolver_cmp_srvs);
2816
2817 ngx_resolver_free(r, rn->query);
2818 rn->query = NULL;
2819
2820 ngx_queue_remove(&rn->queue);
2821
2822 rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
2823 rn->expire = ngx_time() + r->expire;
2824
2825 ngx_queue_insert_head(&r->srv_expire_queue, &rn->queue);
2826
2827 next = rn->waiting;
2828 rn->waiting = NULL;
2829
2830 while (next) {
2831 ctx = next;
2832 next = ctx->next;
2833
2834 ngx_resolver_resolve_srv_names(ctx, rn);
2835 }
2836
2837 return;
2838 }
2839
2840 rn->nsrvs = 0;
2841
2842 if (cname) {
2843
2844 /* CNAME only */
2845
2846 if (ngx_resolver_copy(r, &name, buf, cname, buf + n) != NGX_OK) {
2847 goto failed;
2848 }
2849
2850 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
2851 "resolver cname:\"%V\"", &name);
2852
2853 ngx_queue_remove(&rn->queue);
2854
2855 rn->cnlen = (u_short) name.len;
2856 rn->u.cname = name.data;
2857
2858 rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
2859 rn->expire = ngx_time() + r->expire;
2860
2861 ngx_queue_insert_head(&r->srv_expire_queue, &rn->queue);
2862
2863 ngx_resolver_free(r, rn->query);
2864 rn->query = NULL;
2865#if (NGX_HAVE_INET6)
2866 rn->query6 = NULL;
2867#endif
2868
2869 ctx = rn->waiting;
2870 rn->waiting = NULL;
2871
2872 if (ctx) {
2873
2874 if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) {
2875
2876 /* unlock name mutex */
2877
2878 do {
2879 ctx->state = NGX_RESOLVE_NXDOMAIN;
2880 next = ctx->next;
2881
2882 ctx->handler(ctx);
2883
2884 ctx = next;
2885 } while (ctx);
2886
2887 return;
2888 }
2889
2890 for (next = ctx; next; next = next->next) {
2891 next->node = NULL;
2892 }
2893
2894 (void) ngx_resolve_name_locked(r, ctx, &name);
2895 }
2896
2897 /* unlock name mutex */
2898
2899 return;
2900 }
2901
2902 ngx_log_error(r->log_level, r->log, 0, "no SRV type in DNS response");
2903
2904 return;
2905
2906short_response:
2907
2908 err = "short DNS response";
2909
2910invalid:
2911
2912 /* unlock name mutex */
2913
2914 ngx_log_error(r->log_level, r->log, 0, err);
2915
2916 return;
2917
2918failed:
2919
2920 /* unlock name mutex */
2921
2922 return;
2923}
2924
2925
2926static void
2927ngx_resolver_resolve_srv_names(ngx_resolver_ctx_t *ctx, ngx_resolver_node_t *rn)
2928{
2929 ngx_uint_t i;
2930 ngx_resolver_t *r;
2931 ngx_resolver_ctx_t *cctx;
2932 ngx_resolver_srv_name_t *srvs;
2933
2934 r = ctx->resolver;
2935
2936 ctx->node = NULL;
2937 ctx->state = NGX_OK;
2938 ctx->valid = rn->valid;
2939 ctx->count = rn->nsrvs;
2940
2941 srvs = ngx_resolver_calloc(r, rn->nsrvs * sizeof(ngx_resolver_srv_name_t));
2942 if (srvs == NULL) {
2943 goto failed;
2944 }
2945
2946 ctx->srvs = srvs;
2947 ctx->nsrvs = rn->nsrvs;
2948
2949 for (i = 0; i < rn->nsrvs; i++) {
2950 srvs[i].name.data = ngx_resolver_alloc(r, rn->u.srvs[i].name.len);
2951 if (srvs[i].name.data == NULL) {
2952 goto failed;
2953 }
2954
2955 srvs[i].name.len = rn->u.srvs[i].name.len;
2956 ngx_memcpy(srvs[i].name.data, rn->u.srvs[i].name.data,
2957 srvs[i].name.len);
2958
2959 cctx = ngx_resolve_start(r, NULL);
2960 if (cctx == NULL) {
2961 goto failed;
2962 }
2963
2964 cctx->name = srvs[i].name;
2965 cctx->handler = ngx_resolver_srv_names_handler;
2966 cctx->data = ctx;
2967 cctx->srvs = &srvs[i];
2968 cctx->timeout = 0;
2969
2970 srvs[i].priority = rn->u.srvs[i].priority;
2971 srvs[i].weight = rn->u.srvs[i].weight;
2972 srvs[i].port = rn->u.srvs[i].port;
2973 srvs[i].ctx = cctx;
2974
2975 if (ngx_resolve_name(cctx) == NGX_ERROR) {
2976 srvs[i].ctx = NULL;
2977 goto failed;
2978 }
2979 }
2980
2981 return;
2982
2983failed:
2984
2985 ctx->state = NGX_ERROR;
2986 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
2987
2988 ctx->handler(ctx);
2989}
2990
2991
2992static void
2993ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx)
2994{
2995 ngx_uint_t i;
2996 u_char (*sockaddr)[NGX_SOCKADDRLEN];
2997 ngx_addr_t *addrs;
2998 ngx_resolver_t *r;
2999 struct sockaddr_in *sin;
3000 ngx_resolver_ctx_t *ctx;
3001 ngx_resolver_srv_name_t *srv;
3002#if (NGX_HAVE_INET6)
3003 struct sockaddr_in6 *sin6;
3004#endif
3005
3006 r = cctx->resolver;
3007 ctx = cctx->data;
3008 srv = cctx->srvs;
3009
3010 ctx->count--;
3011
3012 srv->ctx = NULL;
3013
3014 if (cctx->naddrs) {
3015
3016 ctx->valid = ngx_min(ctx->valid, cctx->valid);
3017
3018 addrs = ngx_resolver_calloc(r, cctx->naddrs * sizeof(ngx_addr_t));
3019 if (addrs == NULL) {
3020 ngx_resolve_name_done(cctx);
3021
3022 ctx->state = NGX_ERROR;
3023 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
3024
3025 ctx->handler(ctx);
3026 return;
3027 }
3028
3029 sockaddr = ngx_resolver_alloc(r, cctx->naddrs * NGX_SOCKADDRLEN);
3030 if (sockaddr == NULL) {
3031 ngx_resolver_free(r, addrs);
3032 ngx_resolve_name_done(cctx);
3033
3034 ctx->state = NGX_ERROR;
3035 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
3036
3037 ctx->handler(ctx);
3038 return;
3039 }
3040
3041 for (i = 0; i < cctx->naddrs; i++) {
3042 addrs[i].sockaddr = (struct sockaddr *) sockaddr[i];
3043 addrs[i].socklen = cctx->addrs[i].socklen;
3044
3045 ngx_memcpy(sockaddr[i], cctx->addrs[i].sockaddr,
3046 addrs[i].socklen);
3047
3048 switch (addrs[i].sockaddr->sa_family) {
3049#if (NGX_HAVE_INET6)
3050 case AF_INET6:
3051 sin6 = (struct sockaddr_in6 *) addrs[i].sockaddr;
3052 sin6->sin6_port = htons(srv->port);
3053 break;
3054#endif
3055 default: /* AF_INET */
3056 sin = (struct sockaddr_in *) addrs[i].sockaddr;
3057 sin->sin_port = htons(srv->port);
3058 }
3059 }
3060
3061 srv->addrs = addrs;
3062 srv->naddrs = cctx->naddrs;
3063 }
3064
3065 ngx_resolve_name_done(cctx);
3066
3067 if (ctx->count == 0) {
3068 ngx_resolver_report_srv(r, ctx);
3069 }
3070}
3071
3072
3073static void
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003074ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
Igor Sysoevc0cadf12007-12-16 20:47:55 +00003075 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003076{
3077 char *err;
3078 size_t len;
3079 in_addr_t addr;
Ruslan Ermilovbec516b2011-11-16 13:11:39 +00003080 int32_t ttl;
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003081 ngx_int_t octet;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003082 ngx_str_t name;
Ruslan Ermilov6a92ffb2015-12-17 17:21:16 +03003083 ngx_uint_t mask, type, class, qident, a, i, start;
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003084 ngx_queue_t *expire_queue;
3085 ngx_rbtree_t *tree;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003086 ngx_resolver_an_t *an;
3087 ngx_resolver_ctx_t *ctx, *next;
3088 ngx_resolver_node_t *rn;
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003089#if (NGX_HAVE_INET6)
3090 uint32_t hash;
3091 ngx_int_t digit;
3092 struct in6_addr addr6;
3093#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003094
Ruslan Ermilov159a8bc2015-12-17 17:30:22 +03003095 if (ngx_resolver_copy(r, &name, buf,
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003096 buf + sizeof(ngx_resolver_hdr_t), buf + n)
3097 != NGX_OK)
3098 {
Ruslan Ermilov15948622013-12-06 14:30:27 +04003099 return;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003100 }
3101
Ruslan Ermilov159a8bc2015-12-17 17:30:22 +03003102 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
3103
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003104 /* AF_INET */
3105
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003106 addr = 0;
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003107 i = sizeof(ngx_resolver_hdr_t);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003108
3109 for (mask = 0; mask < 32; mask += 8) {
3110 len = buf[i++];
3111
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003112 octet = ngx_atoi(&buf[i], len);
3113 if (octet == NGX_ERROR || octet > 255) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003114 goto invalid_in_addr_arpa;
3115 }
3116
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003117 addr += octet << mask;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003118 i += len;
3119 }
3120
Ruslan Ermilov3fd72752013-12-13 20:49:52 +04003121 if (ngx_strcasecmp(&buf[i], (u_char *) "\7in-addr\4arpa") == 0) {
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003122 i += sizeof("\7in-addr\4arpa");
3123
3124 /* lock addr mutex */
3125
3126 rn = ngx_resolver_lookup_addr(r, addr);
3127
3128 tree = &r->addr_rbtree;
3129 expire_queue = &r->addr_expire_queue;
3130
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003131 goto valid;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003132 }
3133
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003134invalid_in_addr_arpa:
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003135
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003136#if (NGX_HAVE_INET6)
3137
3138 i = sizeof(ngx_resolver_hdr_t);
3139
3140 for (octet = 15; octet >= 0; octet--) {
3141 if (buf[i++] != '\1') {
3142 goto invalid_ip6_arpa;
3143 }
3144
3145 digit = ngx_hextoi(&buf[i++], 1);
3146 if (digit == NGX_ERROR) {
3147 goto invalid_ip6_arpa;
3148 }
3149
3150 addr6.s6_addr[octet] = (u_char) digit;
3151
3152 if (buf[i++] != '\1') {
3153 goto invalid_ip6_arpa;
3154 }
3155
3156 digit = ngx_hextoi(&buf[i++], 1);
3157 if (digit == NGX_ERROR) {
3158 goto invalid_ip6_arpa;
3159 }
3160
3161 addr6.s6_addr[octet] += (u_char) (digit * 16);
3162 }
3163
Ruslan Ermilov3fd72752013-12-13 20:49:52 +04003164 if (ngx_strcasecmp(&buf[i], (u_char *) "\3ip6\4arpa") == 0) {
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003165 i += sizeof("\3ip6\4arpa");
3166
3167 /* lock addr mutex */
3168
3169 hash = ngx_crc32_short(addr6.s6_addr, 16);
3170 rn = ngx_resolver_lookup_addr6(r, &addr6, hash);
3171
3172 tree = &r->addr6_rbtree;
3173 expire_queue = &r->addr6_expire_queue;
3174
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003175 goto valid;
3176 }
3177
3178invalid_ip6_arpa:
3179#endif
3180
3181 ngx_log_error(r->log_level, r->log, 0,
3182 "invalid in-addr.arpa or ip6.arpa name in DNS response");
Ruslan Ermilov159a8bc2015-12-17 17:30:22 +03003183 ngx_resolver_free(r, name.data);
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003184 return;
3185
3186valid:
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003187
3188 if (rn == NULL || rn->query == NULL) {
3189 ngx_log_error(r->log_level, r->log, 0,
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003190 "unexpected response for %V", &name);
Ruslan Ermilov159a8bc2015-12-17 17:30:22 +03003191 ngx_resolver_free(r, name.data);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003192 goto failed;
3193 }
3194
3195 qident = (rn->query[0] << 8) + rn->query[1];
3196
3197 if (ident != qident) {
3198 ngx_log_error(r->log_level, r->log, 0,
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003199 "wrong ident %ui response for %V, expect %ui",
3200 ident, &name, qident);
Ruslan Ermilov159a8bc2015-12-17 17:30:22 +03003201 ngx_resolver_free(r, name.data);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003202 goto failed;
3203 }
3204
Ruslan Ermilov159a8bc2015-12-17 17:30:22 +03003205 ngx_resolver_free(r, name.data);
3206
Igor Sysoevc0cadf12007-12-16 20:47:55 +00003207 if (code == 0 && nan == 0) {
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003208 code = NGX_RESOLVE_NXDOMAIN;
Igor Sysoevc0cadf12007-12-16 20:47:55 +00003209 }
3210
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003211 if (code) {
3212 next = rn->waiting;
3213 rn->waiting = NULL;
3214
3215 ngx_queue_remove(&rn->queue);
3216
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003217 ngx_rbtree_delete(tree, &rn->node);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003218
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003219 /* unlock addr mutex */
3220
3221 while (next) {
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04003222 ctx = next;
3223 ctx->state = code;
Dmitry Volyntsev6f418a32016-03-23 17:44:36 +03003224 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04003225 next = ctx->next;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003226
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04003227 ctx->handler(ctx);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003228 }
3229
Ruslan Ermilovd4b7b742014-11-20 15:24:40 +03003230 ngx_resolver_free_node(r, rn);
3231
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003232 return;
3233 }
3234
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003235 i += sizeof(ngx_resolver_qs_t);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003236
Ruslan Ermilov6a92ffb2015-12-17 17:21:16 +03003237 for (a = 0; a < nan; a++) {
3238
3239 start = i;
3240
3241 while (i < n) {
3242
3243 if (buf[i] & 0xc0) {
3244 i += 2;
3245 goto found;
3246 }
3247
3248 if (buf[i] == 0) {
3249 i++;
3250 goto test_length;
3251 }
3252
3253 i += 1 + buf[i];
3254 }
3255
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003256 goto short_response;
Ruslan Ermilov6a92ffb2015-12-17 17:21:16 +03003257
3258 test_length:
3259
3260 if (i - start < 2) {
3261 err = "invalid name in DNS response";
3262 goto invalid;
3263 }
3264
3265 found:
3266
3267 if (i + sizeof(ngx_resolver_an_t) >= n) {
3268 goto short_response;
3269 }
3270
3271 an = (ngx_resolver_an_t *) &buf[i];
3272
3273 type = (an->type_hi << 8) + an->type_lo;
3274 class = (an->class_hi << 8) + an->class_lo;
3275 len = (an->len_hi << 8) + an->len_lo;
3276 ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
3277 + (an->ttl[2] << 8) + (an->ttl[3]);
3278
3279 if (class != 1) {
3280 ngx_log_error(r->log_level, r->log, 0,
3281 "unexpected RR class %ui", class);
3282 goto failed;
3283 }
3284
3285 if (ttl < 0) {
3286 ttl = 0;
3287 }
3288
3289 ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
3290 "resolver qt:%ui cl:%ui len:%uz",
3291 type, class, len);
3292
3293 i += sizeof(ngx_resolver_an_t);
3294
3295 switch (type) {
3296
3297 case NGX_RESOLVE_PTR:
3298
3299 goto ptr;
3300
3301 case NGX_RESOLVE_CNAME:
3302
3303 break;
3304
3305 default:
3306
3307 ngx_log_error(r->log_level, r->log, 0,
3308 "unexpected RR type %ui", type);
3309 }
3310
3311 i += len;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003312 }
3313
Ruslan Ermilov6a92ffb2015-12-17 17:21:16 +03003314 /* unlock addr mutex */
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003315
Ruslan Ermilov6a92ffb2015-12-17 17:21:16 +03003316 ngx_log_error(r->log_level, r->log, 0,
3317 "no PTR type in DNS response");
3318 return;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003319
Ruslan Ermilov6a92ffb2015-12-17 17:21:16 +03003320ptr:
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003321
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003322 if (ngx_resolver_copy(r, &name, buf, buf + i, buf + n) != NGX_OK) {
Ruslan Ermilov15948622013-12-06 14:30:27 +04003323 goto failed;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003324 }
3325
3326 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name);
3327
Igor Sysoev2c01fd32009-01-30 11:56:45 +00003328 if (name.len != (size_t) rn->nlen
3329 || ngx_strncmp(name.data, rn->name, name.len) != 0)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003330 {
Igor Sysoev8629b9b2009-01-29 14:29:49 +00003331 if (rn->nlen) {
3332 ngx_resolver_free(r, rn->name);
3333 }
3334
Igor Sysoev9a5f4c72009-02-02 10:17:06 +00003335 rn->nlen = (u_short) name.len;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003336 rn->name = name.data;
3337
Igor Sysoev2c01fd32009-01-30 11:56:45 +00003338 name.data = ngx_resolver_dup(r, rn->name, name.len);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003339 if (name.data == NULL) {
3340 goto failed;
3341 }
3342 }
3343
3344 ngx_queue_remove(&rn->queue);
3345
Ruslan Ermilovbec516b2011-11-16 13:11:39 +00003346 rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003347 rn->expire = ngx_time() + r->expire;
3348
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003349 ngx_queue_insert_head(expire_queue, &rn->queue);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003350
3351 next = rn->waiting;
3352 rn->waiting = NULL;
3353
3354 /* unlock addr mutex */
3355
3356 while (next) {
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04003357 ctx = next;
3358 ctx->state = NGX_OK;
Dmitry Volyntsev6f418a32016-03-23 17:44:36 +03003359 ctx->valid = rn->valid;
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04003360 ctx->name = name;
3361 next = ctx->next;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003362
Ruslan Ermilov552e15b2013-12-13 19:22:44 +04003363 ctx->handler(ctx);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003364 }
3365
3366 ngx_resolver_free(r, name.data);
3367
3368 return;
3369
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003370short_response:
3371
3372 err = "short DNS response";
3373
3374invalid:
3375
3376 /* unlock addr mutex */
3377
3378 ngx_log_error(r->log_level, r->log, 0, err);
3379
3380 return;
3381
3382failed:
3383
3384 /* unlock addr mutex */
3385
3386 return;
3387}
3388
3389
3390static ngx_resolver_node_t *
3391ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
3392{
3393 ngx_int_t rc;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003394 ngx_rbtree_node_t *node, *sentinel;
3395 ngx_resolver_node_t *rn;
3396
3397 node = r->name_rbtree.root;
3398 sentinel = r->name_rbtree.sentinel;
3399
3400 while (node != sentinel) {
3401
3402 if (hash < node->key) {
3403 node = node->left;
3404 continue;
3405 }
3406
3407 if (hash > node->key) {
3408 node = node->right;
3409 continue;
3410 }
3411
3412 /* hash == node->key */
3413
Ruslan Ermilovef563de2014-11-20 15:24:42 +03003414 rn = ngx_resolver_node(node);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003415
Maxim Dounin7ca6c1f2012-02-27 22:15:39 +00003416 rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003417
Maxim Dounin7ca6c1f2012-02-27 22:15:39 +00003418 if (rc == 0) {
3419 return rn;
3420 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003421
Maxim Dounin7ca6c1f2012-02-27 22:15:39 +00003422 node = (rc < 0) ? node->left : node->right;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003423 }
3424
3425 /* not found */
3426
3427 return NULL;
3428}
3429
3430
3431static ngx_resolver_node_t *
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03003432ngx_resolver_lookup_srv(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
3433{
3434 ngx_int_t rc;
3435 ngx_rbtree_node_t *node, *sentinel;
3436 ngx_resolver_node_t *rn;
3437
3438 node = r->srv_rbtree.root;
3439 sentinel = r->srv_rbtree.sentinel;
3440
3441 while (node != sentinel) {
3442
3443 if (hash < node->key) {
3444 node = node->left;
3445 continue;
3446 }
3447
3448 if (hash > node->key) {
3449 node = node->right;
3450 continue;
3451 }
3452
3453 /* hash == node->key */
3454
3455 rn = ngx_resolver_node(node);
3456
3457 rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen);
3458
3459 if (rc == 0) {
3460 return rn;
3461 }
3462
3463 node = (rc < 0) ? node->left : node->right;
3464 }
3465
3466 /* not found */
3467
3468 return NULL;
3469}
3470
3471
3472static ngx_resolver_node_t *
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003473ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr)
3474{
3475 ngx_rbtree_node_t *node, *sentinel;
3476
3477 node = r->addr_rbtree.root;
3478 sentinel = r->addr_rbtree.sentinel;
3479
3480 while (node != sentinel) {
3481
3482 if (addr < node->key) {
3483 node = node->left;
3484 continue;
3485 }
3486
3487 if (addr > node->key) {
3488 node = node->right;
3489 continue;
3490 }
3491
3492 /* addr == node->key */
3493
Ruslan Ermilovef563de2014-11-20 15:24:42 +03003494 return ngx_resolver_node(node);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003495 }
3496
3497 /* not found */
3498
3499 return NULL;
3500}
3501
3502
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003503#if (NGX_HAVE_INET6)
3504
3505static ngx_resolver_node_t *
3506ngx_resolver_lookup_addr6(ngx_resolver_t *r, struct in6_addr *addr,
3507 uint32_t hash)
3508{
3509 ngx_int_t rc;
3510 ngx_rbtree_node_t *node, *sentinel;
3511 ngx_resolver_node_t *rn;
3512
3513 node = r->addr6_rbtree.root;
3514 sentinel = r->addr6_rbtree.sentinel;
3515
3516 while (node != sentinel) {
3517
3518 if (hash < node->key) {
3519 node = node->left;
3520 continue;
3521 }
3522
3523 if (hash > node->key) {
3524 node = node->right;
3525 continue;
3526 }
3527
3528 /* hash == node->key */
3529
Ruslan Ermilovef563de2014-11-20 15:24:42 +03003530 rn = ngx_resolver_node(node);
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003531
3532 rc = ngx_memcmp(addr, &rn->addr6, 16);
3533
3534 if (rc == 0) {
3535 return rn;
3536 }
3537
3538 node = (rc < 0) ? node->left : node->right;
3539 }
3540
3541 /* not found */
3542
3543 return NULL;
3544}
3545
3546#endif
3547
3548
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003549static void
3550ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
3551 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
3552{
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003553 ngx_rbtree_node_t **p;
3554 ngx_resolver_node_t *rn, *rn_temp;
3555
3556 for ( ;; ) {
3557
3558 if (node->key < temp->key) {
3559
3560 p = &temp->left;
3561
3562 } else if (node->key > temp->key) {
3563
3564 p = &temp->right;
3565
3566 } else { /* node->key == temp->key */
3567
Ruslan Ermilovef563de2014-11-20 15:24:42 +03003568 rn = ngx_resolver_node(node);
3569 rn_temp = ngx_resolver_node(temp);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003570
Igor Sysoeva8d3d222009-09-19 16:15:13 +00003571 p = (ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen, rn_temp->nlen)
3572 < 0) ? &temp->left : &temp->right;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003573 }
3574
3575 if (*p == sentinel) {
3576 break;
3577 }
3578
3579 temp = *p;
3580 }
3581
3582 *p = node;
3583 node->parent = temp;
3584 node->left = sentinel;
3585 node->right = sentinel;
3586 ngx_rbt_red(node);
3587}
3588
3589
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003590#if (NGX_HAVE_INET6)
3591
3592static void
3593ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
3594 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
3595{
3596 ngx_rbtree_node_t **p;
3597 ngx_resolver_node_t *rn, *rn_temp;
3598
3599 for ( ;; ) {
3600
3601 if (node->key < temp->key) {
3602
3603 p = &temp->left;
3604
3605 } else if (node->key > temp->key) {
3606
3607 p = &temp->right;
3608
3609 } else { /* node->key == temp->key */
3610
Ruslan Ermilovef563de2014-11-20 15:24:42 +03003611 rn = ngx_resolver_node(node);
3612 rn_temp = ngx_resolver_node(temp);
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003613
3614 p = (ngx_memcmp(&rn->addr6, &rn_temp->addr6, 16)
3615 < 0) ? &temp->left : &temp->right;
3616 }
3617
3618 if (*p == sentinel) {
3619 break;
3620 }
3621
3622 temp = *p;
3623 }
3624
3625 *p = node;
3626 node->parent = temp;
3627 node->left = sentinel;
3628 node->right = sentinel;
3629 ngx_rbt_red(node);
3630}
3631
3632#endif
3633
3634
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003635static ngx_int_t
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003636ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
3637 ngx_str_t *name)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003638{
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003639 u_char *p, *s;
3640 size_t len, nlen;
3641 ngx_uint_t ident;
3642 ngx_resolver_qs_t *qs;
3643 ngx_resolver_hdr_t *query;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003644
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003645 nlen = name->len ? (1 + name->len + 1) : 1;
Igor Sysoeve79f4292009-11-11 14:27:24 +00003646
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003647 len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003648
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003649#if (NGX_HAVE_INET6)
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003650 p = ngx_resolver_alloc(r, r->ipv6 ? len * 2 : len);
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003651#else
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003652 p = ngx_resolver_alloc(r, len);
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003653#endif
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003654 if (p == NULL) {
3655 return NGX_ERROR;
3656 }
3657
3658 rn->qlen = (u_short) len;
3659 rn->query = p;
3660
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003661#if (NGX_HAVE_INET6)
Ruslan Ermilove0caf512013-12-09 10:53:30 +04003662 if (r->ipv6) {
3663 rn->query6 = p + len;
3664 }
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003665#endif
3666
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003667 query = (ngx_resolver_hdr_t *) p;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003668
3669 ident = ngx_random();
3670
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003671 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
3672 "resolve: \"%V\" A %i", name, ident & 0xffff);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003673
3674 query->ident_hi = (u_char) ((ident >> 8) & 0xff);
3675 query->ident_lo = (u_char) (ident & 0xff);
3676
3677 /* recursion query */
3678 query->flags_hi = 1; query->flags_lo = 0;
3679
3680 /* one question */
3681 query->nqs_hi = 0; query->nqs_lo = 1;
3682 query->nan_hi = 0; query->nan_lo = 0;
3683 query->nns_hi = 0; query->nns_lo = 0;
3684 query->nar_hi = 0; query->nar_lo = 0;
3685
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003686 p += sizeof(ngx_resolver_hdr_t) + nlen;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003687
3688 qs = (ngx_resolver_qs_t *) p;
3689
3690 /* query type */
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003691 qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_A;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003692
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003693 /* IN query class */
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003694 qs->class_hi = 0; qs->class_lo = 1;
3695
3696 /* convert "www.example.com" to "\3www\7example\3com\0" */
3697
3698 len = 0;
3699 p--;
3700 *p-- = '\0';
3701
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003702 if (name->len == 0) {
Ruslan Ermilov487ba702012-04-26 12:58:42 +00003703 return NGX_DECLINED;
3704 }
3705
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003706 for (s = name->data + name->len - 1; s >= name->data; s--) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003707 if (*s != '.') {
3708 *p = *s;
3709 len++;
3710
3711 } else {
Maxim Dounine34ff162012-03-22 11:57:18 +00003712 if (len == 0 || len > 255) {
Igor Sysoev09b199c2008-04-09 14:45:39 +00003713 return NGX_DECLINED;
3714 }
3715
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003716 *p = (u_char) len;
3717 len = 0;
3718 }
3719
3720 p--;
3721 }
3722
Maxim Dounine34ff162012-03-22 11:57:18 +00003723 if (len == 0 || len > 255) {
3724 return NGX_DECLINED;
3725 }
3726
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003727 *p = (u_char) len;
3728
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003729#if (NGX_HAVE_INET6)
Ruslan Ermilove0caf512013-12-09 10:53:30 +04003730 if (!r->ipv6) {
3731 return NGX_OK;
3732 }
3733
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003734 p = rn->query6;
3735
3736 ngx_memcpy(p, rn->query, rn->qlen);
3737
3738 query = (ngx_resolver_hdr_t *) p;
3739
3740 ident = ngx_random();
3741
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003742 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
3743 "resolve: \"%V\" AAAA %i", name, ident & 0xffff);
Ruslan Ermilov769eded2013-12-09 10:53:28 +04003744
3745 query->ident_hi = (u_char) ((ident >> 8) & 0xff);
3746 query->ident_lo = (u_char) (ident & 0xff);
3747
3748 p += sizeof(ngx_resolver_hdr_t) + nlen;
3749
3750 qs = (ngx_resolver_qs_t *) p;
3751
3752 qs->type_lo = NGX_RESOLVE_AAAA;
3753#endif
3754
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003755 return NGX_OK;
3756}
3757
3758
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003759static ngx_int_t
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03003760ngx_resolver_create_srv_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
3761 ngx_str_t *name)
3762{
3763 u_char *p, *s;
3764 size_t len, nlen;
3765 ngx_uint_t ident;
3766 ngx_resolver_qs_t *qs;
3767 ngx_resolver_hdr_t *query;
3768
3769 nlen = name->len ? (1 + name->len + 1) : 1;
3770
3771 len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t);
3772
3773 p = ngx_resolver_alloc(r, len);
3774 if (p == NULL) {
3775 return NGX_ERROR;
3776 }
3777
3778 rn->qlen = (u_short) len;
3779 rn->query = p;
3780
3781 query = (ngx_resolver_hdr_t *) p;
3782
3783 ident = ngx_random();
3784
3785 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
3786 "resolve: \"%V\" SRV %i", name, ident & 0xffff);
3787
3788 query->ident_hi = (u_char) ((ident >> 8) & 0xff);
3789 query->ident_lo = (u_char) (ident & 0xff);
3790
3791 /* recursion query */
3792 query->flags_hi = 1; query->flags_lo = 0;
3793
3794 /* one question */
3795 query->nqs_hi = 0; query->nqs_lo = 1;
3796 query->nan_hi = 0; query->nan_lo = 0;
3797 query->nns_hi = 0; query->nns_lo = 0;
3798 query->nar_hi = 0; query->nar_lo = 0;
3799
3800 p += sizeof(ngx_resolver_hdr_t) + nlen;
3801
3802 qs = (ngx_resolver_qs_t *) p;
3803
3804 /* query type */
3805 qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_SRV;
3806
3807 /* IN query class */
3808 qs->class_hi = 0; qs->class_lo = 1;
3809
3810 /* converts "www.example.com" to "\3www\7example\3com\0" */
3811
3812 len = 0;
3813 p--;
3814 *p-- = '\0';
3815
3816 if (name->len == 0) {
3817 return NGX_DECLINED;
3818 }
3819
3820 for (s = name->data + name->len - 1; s >= name->data; s--) {
3821 if (*s != '.') {
3822 *p = *s;
3823 len++;
3824
3825 } else {
3826 if (len == 0 || len > 255) {
3827 return NGX_DECLINED;
3828 }
3829
3830 *p = (u_char) len;
3831 len = 0;
3832 }
3833
3834 p--;
3835 }
3836
3837 if (len == 0 || len > 255) {
3838 return NGX_DECLINED;
3839 }
3840
3841 *p = (u_char) len;
3842
3843 return NGX_OK;
3844}
3845
3846
3847static ngx_int_t
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003848ngx_resolver_create_addr_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03003849 ngx_resolver_addr_t *addr)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003850{
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003851 u_char *p, *d;
3852 size_t len;
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003853 in_addr_t inaddr;
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003854 ngx_int_t n;
3855 ngx_uint_t ident;
3856 ngx_resolver_hdr_t *query;
3857 struct sockaddr_in *sin;
3858#if (NGX_HAVE_INET6)
3859 struct sockaddr_in6 *sin6;
3860#endif
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04003861
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003862 switch (addr->sockaddr->sa_family) {
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003863
3864#if (NGX_HAVE_INET6)
3865 case AF_INET6:
3866 len = sizeof(ngx_resolver_hdr_t)
3867 + 64 + sizeof(".ip6.arpa.") - 1
3868 + sizeof(ngx_resolver_qs_t);
3869
3870 break;
3871#endif
3872
3873 default: /* AF_INET */
3874 len = sizeof(ngx_resolver_hdr_t)
3875 + sizeof(".255.255.255.255.in-addr.arpa.") - 1
3876 + sizeof(ngx_resolver_qs_t);
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04003877 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003878
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003879 p = ngx_resolver_alloc(r, len);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003880 if (p == NULL) {
3881 return NGX_ERROR;
3882 }
3883
3884 rn->query = p;
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003885 query = (ngx_resolver_hdr_t *) p;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003886
3887 ident = ngx_random();
3888
3889 query->ident_hi = (u_char) ((ident >> 8) & 0xff);
3890 query->ident_lo = (u_char) (ident & 0xff);
3891
3892 /* recursion query */
3893 query->flags_hi = 1; query->flags_lo = 0;
3894
3895 /* one question */
3896 query->nqs_hi = 0; query->nqs_lo = 1;
3897 query->nan_hi = 0; query->nan_lo = 0;
3898 query->nns_hi = 0; query->nns_lo = 0;
3899 query->nar_hi = 0; query->nar_lo = 0;
3900
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003901 p += sizeof(ngx_resolver_hdr_t);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003902
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003903 switch (addr->sockaddr->sa_family) {
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04003904
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003905#if (NGX_HAVE_INET6)
3906 case AF_INET6:
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003907 sin6 = (struct sockaddr_in6 *) addr->sockaddr;
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003908
3909 for (n = 15; n >= 0; n--) {
3910 p = ngx_sprintf(p, "\1%xd\1%xd",
3911 sin6->sin6_addr.s6_addr[n] & 0xf,
3912 (sin6->sin6_addr.s6_addr[n] >> 4) & 0xf);
3913 }
3914
3915 p = ngx_cpymem(p, "\3ip6\4arpa\0", 10);
3916
3917 break;
3918#endif
3919
3920 default: /* AF_INET */
3921
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003922 sin = (struct sockaddr_in *) addr->sockaddr;
3923 inaddr = ntohl(sin->sin_addr.s_addr);
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003924
3925 for (n = 0; n < 32; n += 8) {
Roman Arutyunyan9b914de2016-01-26 16:46:48 +03003926 d = ngx_sprintf(&p[1], "%ud", (inaddr >> n) & 0xff);
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003927 *p = (u_char) (d - &p[1]);
3928 p = d;
3929 }
3930
3931 p = ngx_cpymem(p, "\7in-addr\4arpa\0", 14);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003932 }
3933
Ruslan Ermilov3d245d42013-12-06 14:30:27 +04003934 /* query type "PTR", IN query class */
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003935 p = ngx_cpymem(p, "\0\14\0\1", 4);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003936
Ruslan Ermilov809bee32013-12-06 14:30:28 +04003937 rn->qlen = (u_short) (p - rn->query);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003938
3939 return NGX_OK;
3940}
3941
3942
3943static ngx_int_t
3944ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src,
3945 u_char *last)
3946{
3947 char *err;
3948 u_char *p, *dst;
3949 ssize_t len;
3950 ngx_uint_t i, n;
3951
3952 p = src;
3953 len = -1;
3954
3955 /*
3956 * compression pointers allow to create endless loop, so we set limit;
3957 * 128 pointers should be enough to store 255-byte name
3958 */
3959
3960 for (i = 0; i < 128; i++) {
3961 n = *p++;
3962
3963 if (n == 0) {
3964 goto done;
3965 }
3966
3967 if (n & 0xc0) {
Igor Sysoevb3ac4fb2008-11-17 08:04:41 +00003968 n = ((n & 0x3f) << 8) + *p;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00003969 p = &buf[n];
3970
3971 } else {
3972 len += 1 + n;
3973 p = &p[n];
3974 }
3975
3976 if (p >= last) {
3977 err = "name is out of response";
3978 goto invalid;
3979 }
3980 }
3981
3982 err = "compression pointers loop";
3983
3984invalid:
3985
3986 ngx_log_error(r->log_level, r->log, 0, err);
3987
3988 return NGX_ERROR;
3989
3990done:
3991
3992 if (name == NULL) {
3993 return NGX_OK;
3994 }
3995
Igor Sysoev70966c12009-11-09 18:04:05 +00003996 if (len == -1) {
Tatsuhiko Kuboef2b5962014-07-09 23:22:14 +09003997 ngx_str_null(name);
Igor Sysoev70966c12009-11-09 18:04:05 +00003998 return NGX_OK;
3999 }
4000
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004001 dst = ngx_resolver_alloc(r, len);
4002 if (dst == NULL) {
4003 return NGX_ERROR;
4004 }
4005
4006 name->data = dst;
4007
4008 n = *src++;
4009
4010 for ( ;; ) {
Igor Sysoeveb499ba2011-11-09 13:54:07 +00004011 if (n & 0xc0) {
4012 n = ((n & 0x3f) << 8) + *src;
4013 src = &buf[n];
4014
4015 n = *src++;
4016
4017 } else {
Ruslan Ermilov3fd72752013-12-13 20:49:52 +04004018 ngx_strlow(dst, src, n);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004019 dst += n;
4020 src += n;
4021
4022 n = *src++;
4023
4024 if (n != 0) {
4025 *dst++ = '.';
4026 }
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004027 }
4028
4029 if (n == 0) {
4030 name->len = dst - name->data;
4031 return NGX_OK;
4032 }
4033 }
4034}
4035
4036
4037static void
4038ngx_resolver_timeout_handler(ngx_event_t *ev)
4039{
Ruslan Ermilov5f509b52016-01-26 16:46:31 +03004040 ngx_resolver_ctx_t *ctx;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004041
Ruslan Ermilov5f509b52016-01-26 16:46:31 +03004042 ctx = ev->data;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004043
Ruslan Ermilov5f509b52016-01-26 16:46:31 +03004044 ctx->state = NGX_RESOLVE_TIMEDOUT;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004045
Ruslan Ermilov5f509b52016-01-26 16:46:31 +03004046 ctx->handler(ctx);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004047}
4048
4049
4050static void
4051ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn)
4052{
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03004053 ngx_uint_t i;
4054
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004055 /* lock alloc mutex */
4056
4057 if (rn->query) {
4058 ngx_resolver_free_locked(r, rn->query);
4059 }
4060
4061 if (rn->name) {
4062 ngx_resolver_free_locked(r, rn->name);
4063 }
4064
4065 if (rn->cnlen) {
4066 ngx_resolver_free_locked(r, rn->u.cname);
4067 }
4068
Ruslan Ermilov769eded2013-12-09 10:53:28 +04004069 if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004070 ngx_resolver_free_locked(r, rn->u.addrs);
4071 }
4072
Ruslan Ermilov769eded2013-12-09 10:53:28 +04004073#if (NGX_HAVE_INET6)
4074 if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
4075 ngx_resolver_free_locked(r, rn->u6.addrs6);
4076 }
4077#endif
4078
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03004079 if (rn->nsrvs) {
4080 for (i = 0; i < rn->nsrvs; i++) {
4081 if (rn->u.srvs[i].name.data) {
4082 ngx_resolver_free_locked(r, rn->u.srvs[i].name.data);
4083 }
4084 }
4085
4086 ngx_resolver_free_locked(r, rn->u.srvs);
4087 }
4088
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004089 ngx_resolver_free_locked(r, rn);
4090
4091 /* unlock alloc mutex */
4092}
4093
4094
4095static void *
4096ngx_resolver_alloc(ngx_resolver_t *r, size_t size)
4097{
4098 u_char *p;
4099
4100 /* lock alloc mutex */
4101
4102 p = ngx_alloc(size, r->log);
4103
4104 /* unlock alloc mutex */
4105
4106 return p;
4107}
4108
4109
Igor Sysoev8ee01f52008-02-28 15:34:53 +00004110static void *
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004111ngx_resolver_calloc(ngx_resolver_t *r, size_t size)
4112{
4113 u_char *p;
4114
4115 p = ngx_resolver_alloc(r, size);
4116
4117 if (p) {
4118 ngx_memzero(p, size);
4119 }
4120
4121 return p;
4122}
4123
4124
4125static void
4126ngx_resolver_free(ngx_resolver_t *r, void *p)
4127{
4128 /* lock alloc mutex */
4129
4130 ngx_free(p);
4131
4132 /* unlock alloc mutex */
4133}
4134
4135
4136static void
4137ngx_resolver_free_locked(ngx_resolver_t *r, void *p)
4138{
4139 ngx_free(p);
4140}
4141
4142
4143static void *
4144ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size)
4145{
4146 void *dst;
4147
4148 dst = ngx_resolver_alloc(r, size);
4149
4150 if (dst == NULL) {
4151 return dst;
4152 }
4153
4154 ngx_memcpy(dst, src, size);
4155
4156 return dst;
4157}
4158
4159
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03004160static ngx_resolver_addr_t *
Ruslan Ermilov769eded2013-12-09 10:53:28 +04004161ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn,
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04004162 ngx_uint_t rotate)
Maxim Dounin6a0f47e2012-09-28 18:28:38 +00004163{
Ruslan Ermilov769eded2013-12-09 10:53:28 +04004164 ngx_uint_t d, i, j, n;
4165 u_char (*sockaddr)[NGX_SOCKADDRLEN];
4166 in_addr_t *addr;
4167 struct sockaddr_in *sin;
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03004168 ngx_resolver_addr_t *dst;
Ruslan Ermilov769eded2013-12-09 10:53:28 +04004169#if (NGX_HAVE_INET6)
4170 struct in6_addr *addr6;
4171 struct sockaddr_in6 *sin6;
4172#endif
4173
4174 n = rn->naddrs;
4175#if (NGX_HAVE_INET6)
4176 n += rn->naddrs6;
4177#endif
Maxim Dounin6a0f47e2012-09-28 18:28:38 +00004178
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03004179 dst = ngx_resolver_calloc(r, n * sizeof(ngx_resolver_addr_t));
Maxim Dounin7b373182012-10-24 14:07:08 +00004180 if (dst == NULL) {
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04004181 return NULL;
Maxim Dounin7b373182012-10-24 14:07:08 +00004182 }
4183
Ruslan Ermilov769eded2013-12-09 10:53:28 +04004184 sockaddr = ngx_resolver_calloc(r, n * NGX_SOCKADDRLEN);
4185 if (sockaddr == NULL) {
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04004186 ngx_resolver_free(r, dst);
4187 return NULL;
Maxim Dounin6a0f47e2012-09-28 18:28:38 +00004188 }
4189
Ruslan Ermilov769eded2013-12-09 10:53:28 +04004190 i = 0;
4191 d = rotate ? ngx_random() % n : 0;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04004192
Ruslan Ermilov769eded2013-12-09 10:53:28 +04004193 if (rn->naddrs) {
4194 j = rotate ? ngx_random() % rn->naddrs : 0;
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04004195
Ruslan Ermilov769eded2013-12-09 10:53:28 +04004196 addr = (rn->naddrs == 1) ? &rn->u.addr : rn->u.addrs;
4197
4198 do {
4199 sin = (struct sockaddr_in *) sockaddr[d];
4200 sin->sin_family = AF_INET;
4201 sin->sin_addr.s_addr = addr[j++];
4202 dst[d].sockaddr = (struct sockaddr *) sin;
4203 dst[d++].socklen = sizeof(struct sockaddr_in);
4204
4205 if (d == n) {
4206 d = 0;
4207 }
4208
4209 if (j == rn->naddrs) {
4210 j = 0;
4211 }
4212 } while (++i < rn->naddrs);
Ruslan Ermilov3aeefbc2013-12-06 14:30:27 +04004213 }
Maxim Dounin6a0f47e2012-09-28 18:28:38 +00004214
Ruslan Ermilov769eded2013-12-09 10:53:28 +04004215#if (NGX_HAVE_INET6)
4216 if (rn->naddrs6) {
4217 j = rotate ? ngx_random() % rn->naddrs6 : 0;
4218
4219 addr6 = (rn->naddrs6 == 1) ? &rn->u6.addr6 : rn->u6.addrs6;
4220
4221 do {
4222 sin6 = (struct sockaddr_in6 *) sockaddr[d];
4223 sin6->sin6_family = AF_INET6;
4224 ngx_memcpy(sin6->sin6_addr.s6_addr, addr6[j++].s6_addr, 16);
4225 dst[d].sockaddr = (struct sockaddr *) sin6;
4226 dst[d++].socklen = sizeof(struct sockaddr_in6);
4227
4228 if (d == n) {
4229 d = 0;
4230 }
4231
4232 if (j == rn->naddrs6) {
4233 j = 0;
4234 }
4235 } while (++i < n);
4236 }
4237#endif
4238
Maxim Dounin6a0f47e2012-09-28 18:28:38 +00004239 return dst;
4240}
4241
4242
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03004243static void
4244ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
4245{
Dmitry Volyntsev28067ba2016-03-23 18:34:05 +03004246 ngx_uint_t naddrs, nsrvs, nw, i, j, k, l, m, n, w;
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03004247 ngx_resolver_addr_t *addrs;
4248 ngx_resolver_srv_name_t *srvs;
4249
4250 naddrs = 0;
4251
4252 for (i = 0; i < ctx->nsrvs; i++) {
4253 naddrs += ctx->srvs[i].naddrs;
4254 }
4255
4256 if (naddrs == 0) {
4257 ctx->state = NGX_RESOLVE_NXDOMAIN;
4258 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
4259
4260 ctx->handler(ctx);
4261 return;
4262 }
4263
4264 addrs = ngx_resolver_calloc(r, naddrs * sizeof(ngx_resolver_addr_t));
4265 if (addrs == NULL) {
4266 ctx->state = NGX_ERROR;
4267 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
4268
4269 ctx->handler(ctx);
4270 return;
4271 }
4272
4273 srvs = ctx->srvs;
4274 nsrvs = ctx->nsrvs;
4275
4276 i = 0;
4277 n = 0;
4278
4279 do {
4280 nw = 0;
4281
4282 for (j = i; j < nsrvs; j++) {
4283 if (srvs[j].priority != srvs[i].priority) {
4284 break;
4285 }
4286
4287 nw += srvs[j].naddrs * srvs[j].weight;
4288 }
4289
4290 if (nw == 0) {
4291 goto next_srv;
4292 }
4293
4294 w = ngx_random() % nw;
4295
4296 for (k = i; k < j; k++) {
4297 if (w < srvs[k].naddrs * srvs[k].weight) {
4298 break;
4299 }
4300
4301 w -= srvs[k].naddrs * srvs[k].weight;
4302 }
4303
4304 for (l = i; l < j; l++) {
4305
4306 for (m = 0; m < srvs[k].naddrs; m++) {
4307 addrs[n].socklen = srvs[k].addrs[m].socklen;
4308 addrs[n].sockaddr = srvs[k].addrs[m].sockaddr;
4309 addrs[n].name = srvs[k].name;
4310 addrs[n].priority = srvs[k].priority;
4311 addrs[n].weight = srvs[k].weight;
4312 n++;
4313 }
4314
4315 if (++k == j) {
4316 k = i;
4317 }
4318 }
4319
4320next_srv:
4321
4322 i = j;
4323
4324 } while (i < ctx->nsrvs);
4325
4326 ctx->state = NGX_OK;
4327 ctx->addrs = addrs;
4328 ctx->naddrs = naddrs;
4329
4330 ctx->handler(ctx);
4331
4332 ngx_resolver_free(r, addrs);
4333}
4334
4335
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004336char *
4337ngx_resolver_strerror(ngx_int_t err)
4338{
4339 static char *errors[] = {
4340 "Format error", /* FORMERR */
4341 "Server failure", /* SERVFAIL */
4342 "Host not found", /* NXDOMAIN */
4343 "Unimplemented", /* NOTIMP */
4344 "Operation refused" /* REFUSED */
4345 };
4346
4347 if (err > 0 && err < 6) {
4348 return errors[err - 1];
4349 }
4350
4351 if (err == NGX_RESOLVE_TIMEDOUT) {
4352 return "Operation timed out";
4353 }
4354
4355 return "Unknown error";
4356}
4357
4358
Igor Sysoev089b2fd2010-01-11 11:01:02 +00004359static u_char *
4360ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len)
4361{
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004362 u_char *p;
4363 ngx_resolver_connection_t *rec;
Igor Sysoev089b2fd2010-01-11 11:01:02 +00004364
4365 p = buf;
4366
4367 if (log->action) {
4368 p = ngx_snprintf(buf, len, " while %s", log->action);
4369 len -= p - buf;
4370 }
4371
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004372 rec = log->data;
Igor Sysoev089b2fd2010-01-11 11:01:02 +00004373
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004374 if (rec) {
4375 p = ngx_snprintf(p, len, ", resolver: %V", &rec->server);
Igor Sysoev089b2fd2010-01-11 11:01:02 +00004376 }
4377
4378 return p;
4379}
4380
4381
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004382ngx_int_t
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004383ngx_udp_connect(ngx_resolver_connection_t *rec)
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004384{
4385 int rc;
4386 ngx_int_t event;
4387 ngx_event_t *rev, *wev;
4388 ngx_socket_t s;
4389 ngx_connection_t *c;
4390
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004391 s = ngx_socket(rec->sockaddr->sa_family, SOCK_DGRAM, 0);
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004392
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004393 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "UDP socket %d", s);
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004394
Maxim Dounin48d96ce2013-09-04 20:48:28 +04004395 if (s == (ngx_socket_t) -1) {
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004396 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004397 ngx_socket_n " failed");
4398 return NGX_ERROR;
4399 }
4400
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004401 c = ngx_get_connection(s, &rec->log);
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004402
4403 if (c == NULL) {
4404 if (ngx_close_socket(s) == -1) {
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004405 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004406 ngx_close_socket_n "failed");
4407 }
4408
4409 return NGX_ERROR;
4410 }
4411
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004412 if (ngx_nonblocking(s) == -1) {
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004413 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004414 ngx_nonblocking_n " failed");
4415
Ruslan Ermilov9ae40c52014-02-20 17:27:09 +04004416 goto failed;
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004417 }
4418
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004419 rev = c->read;
4420 wev = c->write;
4421
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004422 rev->log = &rec->log;
4423 wev->log = &rec->log;
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004424
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004425 rec->udp = c;
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004426
4427 c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
4428
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004429 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0,
4430 "connect to %V, fd:%d #%uA", &rec->server, s, c->number);
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004431
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004432 rc = connect(s, rec->sockaddr, rec->socklen);
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004433
Ruslan Ermilovd0755322015-04-22 18:57:32 +03004434 /* TODO: iocp */
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004435
4436 if (rc == -1) {
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004437 ngx_log_error(NGX_LOG_CRIT, &rec->log, ngx_socket_errno,
Igor Sysoev089b2fd2010-01-11 11:01:02 +00004438 "connect() failed");
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004439
Ruslan Ermilov9ae40c52014-02-20 17:27:09 +04004440 goto failed;
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004441 }
4442
Igor Sysoevcb4d5382007-11-23 17:13:26 +00004443 /* UDP sockets are always ready to write */
4444 wev->ready = 1;
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004445
Ruslan Ermilov8cdb4332015-04-23 14:17:40 +03004446 event = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ?
4447 /* kqueue, epoll */ NGX_CLEAR_EVENT:
4448 /* select, poll, /dev/poll */ NGX_LEVEL_EVENT;
4449 /* eventport event type has no meaning: oneshot only */
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004450
Ruslan Ermilov8cdb4332015-04-23 14:17:40 +03004451 if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
4452 goto failed;
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004453 }
4454
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004455 return NGX_OK;
Ruslan Ermilov9ae40c52014-02-20 17:27:09 +04004456
4457failed:
4458
4459 ngx_close_connection(c);
Roman Arutyunyanec16a602016-01-28 15:28:20 +03004460 rec->udp = NULL;
Ruslan Ermilov9ae40c52014-02-20 17:27:09 +04004461
4462 return NGX_ERROR;
Igor Sysoevd3283ff2005-12-05 13:18:09 +00004463}
Roman Arutyunyan910445b2016-01-28 15:28:20 +03004464
4465
4466ngx_int_t
4467ngx_tcp_connect(ngx_resolver_connection_t *rec)
4468{
4469 int rc;
4470 ngx_int_t event;
4471 ngx_err_t err;
4472 ngx_uint_t level;
4473 ngx_socket_t s;
4474 ngx_event_t *rev, *wev;
4475 ngx_connection_t *c;
4476
4477 s = ngx_socket(rec->sockaddr->sa_family, SOCK_STREAM, 0);
4478
4479 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "TCP socket %d", s);
4480
4481 if (s == (ngx_socket_t) -1) {
4482 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4483 ngx_socket_n " failed");
4484 return NGX_ERROR;
4485 }
4486
4487 c = ngx_get_connection(s, &rec->log);
4488
4489 if (c == NULL) {
4490 if (ngx_close_socket(s) == -1) {
4491 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4492 ngx_close_socket_n "failed");
4493 }
4494
4495 return NGX_ERROR;
4496 }
4497
4498 if (ngx_nonblocking(s) == -1) {
4499 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4500 ngx_nonblocking_n " failed");
4501
4502 goto failed;
4503 }
4504
4505 rev = c->read;
4506 wev = c->write;
4507
4508 rev->log = &rec->log;
4509 wev->log = &rec->log;
4510
4511 rec->tcp = c;
4512
4513 c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
4514
4515 if (ngx_add_conn) {
4516 if (ngx_add_conn(c) == NGX_ERROR) {
4517 goto failed;
4518 }
4519 }
4520
4521 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0,
4522 "connect to %V, fd:%d #%uA", &rec->server, s, c->number);
4523
4524 rc = connect(s, rec->sockaddr, rec->socklen);
4525
4526 if (rc == -1) {
4527 err = ngx_socket_errno;
4528
4529
4530 if (err != NGX_EINPROGRESS
4531#if (NGX_WIN32)
4532 /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
4533 && err != NGX_EAGAIN
4534#endif
4535 )
4536 {
4537 if (err == NGX_ECONNREFUSED
4538#if (NGX_LINUX)
4539 /*
4540 * Linux returns EAGAIN instead of ECONNREFUSED
4541 * for unix sockets if listen queue is full
4542 */
4543 || err == NGX_EAGAIN
4544#endif
4545 || err == NGX_ECONNRESET
4546 || err == NGX_ENETDOWN
4547 || err == NGX_ENETUNREACH
4548 || err == NGX_EHOSTDOWN
4549 || err == NGX_EHOSTUNREACH)
4550 {
4551 level = NGX_LOG_ERR;
4552
4553 } else {
4554 level = NGX_LOG_CRIT;
4555 }
4556
4557 ngx_log_error(level, c->log, err, "connect() to %V failed",
4558 &rec->server);
4559
4560 ngx_close_connection(c);
4561 rec->tcp = NULL;
4562
4563 return NGX_ERROR;
4564 }
4565 }
4566
4567 if (ngx_add_conn) {
4568 if (rc == -1) {
4569
4570 /* NGX_EINPROGRESS */
4571
4572 return NGX_AGAIN;
4573 }
4574
4575 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected");
4576
4577 wev->ready = 1;
4578
4579 return NGX_OK;
4580 }
4581
4582 if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
4583
4584 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, ngx_socket_errno,
4585 "connect(): %d", rc);
4586
4587 if (ngx_blocking(s) == -1) {
4588 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4589 ngx_blocking_n " failed");
4590 goto failed;
4591 }
4592
4593 /*
4594 * FreeBSD's aio allows to post an operation on non-connected socket.
4595 * NT does not support it.
4596 *
4597 * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
4598 */
4599
4600 rev->ready = 1;
4601 wev->ready = 1;
4602
4603 return NGX_OK;
4604 }
4605
4606 if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
4607
4608 /* kqueue */
4609
4610 event = NGX_CLEAR_EVENT;
4611
4612 } else {
4613
4614 /* select, poll, /dev/poll */
4615
4616 event = NGX_LEVEL_EVENT;
4617 }
4618
4619 if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
4620 goto failed;
4621 }
4622
4623 if (rc == -1) {
4624
4625 /* NGX_EINPROGRESS */
4626
4627 if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
4628 goto failed;
4629 }
4630
4631 return NGX_AGAIN;
4632 }
4633
4634 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected");
4635
4636 wev->ready = 1;
4637
4638 return NGX_OK;
4639
4640failed:
4641
4642 ngx_close_connection(c);
4643 rec->tcp = NULL;
4644
4645 return NGX_ERROR;
4646}
Dmitry Volyntsevc4bf56d2016-03-23 17:44:36 +03004647
4648
4649static ngx_int_t
4650ngx_resolver_cmp_srvs(const void *one, const void *two)
4651{
4652 ngx_int_t p1, p2;
4653 ngx_resolver_srv_t *first, *second;
4654
4655 first = (ngx_resolver_srv_t *) one;
4656 second = (ngx_resolver_srv_t *) two;
4657
4658 p1 = first->priority;
4659 p2 = second->priority;
4660
4661 return p1 - p2;
4662}