1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_event.h>
11
12
13 #define NGX_RESOLVER_UDP_SIZE 4096
14
15 #define NGX_RESOLVER_TCP_RSIZE (2 + 65535)
16 #define NGX_RESOLVER_TCP_WSIZE 8192
17
18
19 typedef struct {
20 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;
32 } ngx_resolver_hdr_t;
33
34
35 typedef 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;
41
42
43 typedef 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
54 #define ngx_resolver_node(n) \
55 (ngx_resolver_node_t *) \
56 ((u_char *) (n) - offsetof(ngx_resolver_node_t, node))
57
58
59 static ngx_int_t ngx_udp_connect(ngx_resolver_connection_t *rec);
60 static ngx_int_t ngx_tcp_connect(ngx_resolver_connection_t *rec);
61
62
63 static void ngx_resolver_cleanup(void *data);
64 static void ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree);
65 static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r,
66 ngx_resolver_ctx_t *ctx, ngx_str_t *name);
67 static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree,
68 ngx_queue_t *queue);
69 static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r,
70 ngx_resolver_node_t *rn);
71 static ngx_int_t ngx_resolver_send_udp_query(ngx_resolver_t *r,
72 ngx_resolver_connection_t *rec, u_char *query, u_short qlen);
73 static ngx_int_t ngx_resolver_send_tcp_query(ngx_resolver_t *r,
74 ngx_resolver_connection_t *rec, u_char *query, u_short qlen);
75 static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_t *r,
76 ngx_resolver_node_t *rn, ngx_str_t *name);
77 static ngx_int_t ngx_resolver_create_srv_query(ngx_resolver_t *r,
78 ngx_resolver_node_t *rn, ngx_str_t *name);
79 static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_t *r,
80 ngx_resolver_node_t *rn, ngx_resolver_addr_t *addr);
81 static void ngx_resolver_resend_handler(ngx_event_t *ev);
82 static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree,
83 ngx_queue_t *queue);
84 static ngx_uint_t ngx_resolver_resend_empty(ngx_resolver_t *r);
85 static void ngx_resolver_udp_read(ngx_event_t *rev);
86 static void ngx_resolver_tcp_write(ngx_event_t *wev);
87 static void ngx_resolver_tcp_read(ngx_event_t *rev);
88 static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf,
89 size_t n, ngx_uint_t tcp);
90 static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
91 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
92 ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans);
93 static 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);
96 static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
97 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan);
98 static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
99 ngx_str_t *name, uint32_t hash);
100 static ngx_resolver_node_t *ngx_resolver_lookup_srv(ngx_resolver_t *r,
101 ngx_str_t *name, uint32_t hash);
102 static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r,
103 in_addr_t addr);
104 static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
105 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
106 static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name,
107 u_char *buf, u_char *src, u_char *last);
108 static ngx_int_t ngx_resolver_set_timeout(ngx_resolver_t *r,
109 ngx_resolver_ctx_t *ctx);
110 static void ngx_resolver_timeout_handler(ngx_event_t *ev);
111 static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn);
112 static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size);
113 static void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size);
114 static void ngx_resolver_free(ngx_resolver_t *r, void *p);
115 static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
116 static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
117 static ngx_resolver_addr_t *ngx_resolver_export(ngx_resolver_t *r,
118 ngx_resolver_node_t *rn, ngx_uint_t rotate);
119 static void ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx);
120 static u_char *ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len);
121 static void ngx_resolver_resolve_srv_names(ngx_resolver_ctx_t *ctx,
122 ngx_resolver_node_t *rn);
123 static void ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *ctx);
124 static ngx_int_t ngx_resolver_cmp_srvs(const void *one, const void *two);
125
126 #if (NGX_HAVE_INET6)
127 static void ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
128 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
129 static ngx_resolver_node_t *ngx_resolver_lookup_addr6(ngx_resolver_t *r,
130 struct in6_addr *addr, uint32_t hash);
131 #endif
132
133
134 ngx_resolver_t *
ngx_resolver_create(ngx_conf_t * cf,ngx_str_t * names,ngx_uint_t n)135 ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
136 {
137 ngx_str_t s;
138 ngx_url_t u;
139 ngx_uint_t i, j;
140 ngx_resolver_t *r;
141 ngx_pool_cleanup_t *cln;
142 ngx_resolver_connection_t *rec;
143
144 r = ngx_pcalloc(cf->pool, sizeof(ngx_resolver_t));
145 if (r == NULL) {
146 return NULL;
147 }
148
149 r->event = ngx_pcalloc(cf->pool, sizeof(ngx_event_t));
150 if (r->event == NULL) {
151 return NULL;
152 }
153
154 cln = ngx_pool_cleanup_add(cf->pool, 0);
155 if (cln == NULL) {
156 return NULL;
157 }
158
159 cln->handler = ngx_resolver_cleanup;
160 cln->data = r;
161
162 ngx_rbtree_init(&r->name_rbtree, &r->name_sentinel,
163 ngx_resolver_rbtree_insert_value);
164
165 ngx_rbtree_init(&r->srv_rbtree, &r->srv_sentinel,
166 ngx_resolver_rbtree_insert_value);
167
168 ngx_rbtree_init(&r->addr_rbtree, &r->addr_sentinel,
169 ngx_rbtree_insert_value);
170
171 ngx_queue_init(&r->name_resend_queue);
172 ngx_queue_init(&r->srv_resend_queue);
173 ngx_queue_init(&r->addr_resend_queue);
174
175 ngx_queue_init(&r->name_expire_queue);
176 ngx_queue_init(&r->srv_expire_queue);
177 ngx_queue_init(&r->addr_expire_queue);
178
179 #if (NGX_HAVE_INET6)
180 r->ipv6 = 1;
181
182 ngx_rbtree_init(&r->addr6_rbtree, &r->addr6_sentinel,
183 ngx_resolver_rbtree_insert_addr6_value);
184
185 ngx_queue_init(&r->addr6_resend_queue);
186
187 ngx_queue_init(&r->addr6_expire_queue);
188 #endif
189
190 r->event->handler = ngx_resolver_resend_handler;
191 r->event->data = r;
192 r->event->log = &cf->cycle->new_log;
193 r->event->cancelable = 1;
194 r->ident = -1;
195
196 r->resend_timeout = 5;
197 r->tcp_timeout = 5;
198 r->expire = 30;
199 r->valid = 0;
200
201 r->log = &cf->cycle->new_log;
202 r->log_level = NGX_LOG_ERR;
203
204 if (n) {
205 if (ngx_array_init(&r->connections, cf->pool, n,
206 sizeof(ngx_resolver_connection_t))
207 != NGX_OK)
208 {
209 return NULL;
210 }
211 }
212
213 for (i = 0; i < n; i++) {
214 if (ngx_strncmp(names[i].data, "valid=", 6) == 0) {
215 s.len = names[i].len - 6;
216 s.data = names[i].data + 6;
217
218 r->valid = ngx_parse_time(&s, 1);
219
220 if (r->valid == (time_t) NGX_ERROR) {
221 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
222 "invalid parameter: %V", &names[i]);
223 return NULL;
224 }
225
226 continue;
227 }
228
229 #if (NGX_HAVE_INET6)
230 if (ngx_strncmp(names[i].data, "ipv6=", 5) == 0) {
231
232 if (ngx_strcmp(&names[i].data[5], "on") == 0) {
233 r->ipv6 = 1;
234
235 } else if (ngx_strcmp(&names[i].data[5], "off") == 0) {
236 r->ipv6 = 0;
237
238 } else {
239 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
240 "invalid parameter: %V", &names[i]);
241 return NULL;
242 }
243
244 continue;
245 }
246 #endif
247
248 ngx_memzero(&u, sizeof(ngx_url_t));
249
250 u.url = names[i];
251 u.default_port = 53;
252
253 if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
254 if (u.err) {
255 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
256 "%s in resolver \"%V\"",
257 u.err, &u.url);
258 }
259
260 return NULL;
261 }
262
263 rec = ngx_array_push_n(&r->connections, u.naddrs);
264 if (rec == NULL) {
265 return NULL;
266 }
267
268 ngx_memzero(rec, u.naddrs * sizeof(ngx_resolver_connection_t));
269
270 for (j = 0; j < u.naddrs; j++) {
271 rec[j].sockaddr = u.addrs[j].sockaddr;
272 rec[j].socklen = u.addrs[j].socklen;
273 rec[j].server = u.addrs[j].name;
274 rec[j].resolver = r;
275 }
276 }
277
278 if (n && r->connections.nelts == 0) {
279 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "no name servers defined");
280 return NULL;
281 }
282
283 return r;
284 }
285
286
287 static void
ngx_resolver_cleanup(void * data)288 ngx_resolver_cleanup(void *data)
289 {
290 ngx_resolver_t *r = data;
291
292 ngx_uint_t i;
293 ngx_resolver_connection_t *rec;
294
295 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "cleanup resolver");
296
297 ngx_resolver_cleanup_tree(r, &r->name_rbtree);
298
299 ngx_resolver_cleanup_tree(r, &r->srv_rbtree);
300
301 ngx_resolver_cleanup_tree(r, &r->addr_rbtree);
302
303 #if (NGX_HAVE_INET6)
304 ngx_resolver_cleanup_tree(r, &r->addr6_rbtree);
305 #endif
306
307 if (r->event->timer_set) {
308 ngx_del_timer(r->event);
309 }
310
311 rec = r->connections.elts;
312
313 for (i = 0; i < r->connections.nelts; i++) {
314 if (rec[i].udp) {
315 ngx_close_connection(rec[i].udp);
316 }
317
318 if (rec[i].tcp) {
319 ngx_close_connection(rec[i].tcp);
320 }
321
322 if (rec[i].read_buf) {
323 ngx_resolver_free(r, rec[i].read_buf->start);
324 ngx_resolver_free(r, rec[i].read_buf);
325 }
326
327 if (rec[i].write_buf) {
328 ngx_resolver_free(r, rec[i].write_buf->start);
329 ngx_resolver_free(r, rec[i].write_buf);
330 }
331 }
332 }
333
334
335 static void
ngx_resolver_cleanup_tree(ngx_resolver_t * r,ngx_rbtree_t * tree)336 ngx_resolver_cleanup_tree(ngx_resolver_t *r, ngx_rbtree_t *tree)
337 {
338 ngx_resolver_ctx_t *ctx, *next;
339 ngx_resolver_node_t *rn;
340
341 while (tree->root != tree->sentinel) {
342
343 rn = ngx_resolver_node(ngx_rbtree_min(tree->root, tree->sentinel));
344
345 ngx_queue_remove(&rn->queue);
346
347 for (ctx = rn->waiting; ctx; ctx = next) {
348 next = ctx->next;
349
350 if (ctx->event) {
351 if (ctx->event->timer_set) {
352 ngx_del_timer(ctx->event);
353 }
354
355 ngx_resolver_free(r, ctx->event);
356 }
357
358 ngx_resolver_free(r, ctx);
359 }
360
361 ngx_rbtree_delete(tree, &rn->node);
362
363 ngx_resolver_free_node(r, rn);
364 }
365 }
366
367
368 ngx_resolver_ctx_t *
ngx_resolve_start(ngx_resolver_t * r,ngx_resolver_ctx_t * temp)369 ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
370 {
371 in_addr_t addr;
372 ngx_resolver_ctx_t *ctx;
373
374 if (temp) {
375 addr = ngx_inet_addr(temp->name.data, temp->name.len);
376
377 if (addr != INADDR_NONE) {
378 temp->resolver = r;
379 temp->state = NGX_OK;
380 temp->naddrs = 1;
381 temp->addrs = &temp->addr;
382 temp->addr.sockaddr = (struct sockaddr *) &temp->sin;
383 temp->addr.socklen = sizeof(struct sockaddr_in);
384 ngx_memzero(&temp->sin, sizeof(struct sockaddr_in));
385 temp->sin.sin_family = AF_INET;
386 temp->sin.sin_addr.s_addr = addr;
387 temp->quick = 1;
388
389 return temp;
390 }
391 }
392
393 if (r->connections.nelts == 0) {
394 return NGX_NO_RESOLVER;
395 }
396
397 ctx = ngx_resolver_calloc(r, sizeof(ngx_resolver_ctx_t));
398
399 if (ctx) {
400 ctx->resolver = r;
401 }
402
403 return ctx;
404 }
405
406
407 ngx_int_t
ngx_resolve_name(ngx_resolver_ctx_t * ctx)408 ngx_resolve_name(ngx_resolver_ctx_t *ctx)
409 {
410 size_t slen;
411 ngx_int_t rc;
412 ngx_str_t name;
413 ngx_resolver_t *r;
414
415 r = ctx->resolver;
416
417 if (ctx->name.len > 0 && ctx->name.data[ctx->name.len - 1] == '.') {
418 ctx->name.len--;
419 }
420
421 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
422 "resolve: \"%V\"", &ctx->name);
423
424 if (ctx->quick) {
425 ctx->handler(ctx);
426 return NGX_OK;
427 }
428
429 if (ctx->service.len) {
430 slen = ctx->service.len;
431
432 if (ngx_strlchr(ctx->service.data,
433 ctx->service.data + ctx->service.len, '.')
434 == NULL)
435 {
436 slen += sizeof("_._tcp") - 1;
437 }
438
439 name.len = slen + 1 + ctx->name.len;
440
441 name.data = ngx_resolver_alloc(r, name.len);
442 if (name.data == NULL) {
443 goto failed;
444 }
445
446 if (slen == ctx->service.len) {
447 ngx_sprintf(name.data, "%V.%V", &ctx->service, &ctx->name);
448
449 } else {
450 ngx_sprintf(name.data, "_%V._tcp.%V", &ctx->service, &ctx->name);
451 }
452
453 /* lock name mutex */
454
455 rc = ngx_resolve_name_locked(r, ctx, &name);
456
457 ngx_resolver_free(r, name.data);
458
459 } else {
460 /* lock name mutex */
461
462 rc = ngx_resolve_name_locked(r, ctx, &ctx->name);
463 }
464
465 if (rc == NGX_OK) {
466 return NGX_OK;
467 }
468
469 /* unlock name mutex */
470
471 if (rc == NGX_AGAIN) {
472 return NGX_OK;
473 }
474
475 /* NGX_ERROR */
476
477 if (ctx->event) {
478 ngx_resolver_free(r, ctx->event);
479 }
480
481 failed:
482
483 ngx_resolver_free(r, ctx);
484
485 return NGX_ERROR;
486 }
487
488
489 void
ngx_resolve_name_done(ngx_resolver_ctx_t * ctx)490 ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
491 {
492 ngx_uint_t i;
493 ngx_resolver_t *r;
494 ngx_resolver_ctx_t *w, **p;
495 ngx_resolver_node_t *rn;
496
497 r = ctx->resolver;
498
499 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
500 "resolve name done: %i", ctx->state);
501
502 if (ctx->quick) {
503 return;
504 }
505
506 if (ctx->event && ctx->event->timer_set) {
507 ngx_del_timer(ctx->event);
508 }
509
510 /* lock name mutex */
511
512 if (ctx->nsrvs) {
513 for (i = 0; i < ctx->nsrvs; i++) {
514 if (ctx->srvs[i].ctx) {
515 ngx_resolve_name_done(ctx->srvs[i].ctx);
516 }
517
518 if (ctx->srvs[i].addrs) {
519 ngx_resolver_free(r, ctx->srvs[i].addrs->sockaddr);
520 ngx_resolver_free(r, ctx->srvs[i].addrs);
521 }
522
523 ngx_resolver_free(r, ctx->srvs[i].name.data);
524 }
525
526 ngx_resolver_free(r, ctx->srvs);
527 }
528
529 if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
530
531 rn = ctx->node;
532
533 if (rn) {
534 p = &rn->waiting;
535 w = rn->waiting;
536
537 while (w) {
538 if (w == ctx) {
539 *p = w->next;
540
541 goto done;
542 }
543
544 p = &w->next;
545 w = w->next;
546 }
547
548 ngx_log_error(NGX_LOG_ALERT, r->log, 0,
549 "could not cancel %V resolving", &ctx->name);
550 }
551 }
552
553 done:
554
555 if (ctx->service.len) {
556 ngx_resolver_expire(r, &r->srv_rbtree, &r->srv_expire_queue);
557
558 } else {
559 ngx_resolver_expire(r, &r->name_rbtree, &r->name_expire_queue);
560 }
561
562 /* unlock name mutex */
563
564 /* lock alloc mutex */
565
566 if (ctx->event) {
567 ngx_resolver_free_locked(r, ctx->event);
568 }
569
570 ngx_resolver_free_locked(r, ctx);
571
572 /* unlock alloc mutex */
573
574 if (r->event->timer_set && ngx_resolver_resend_empty(r)) {
575 ngx_del_timer(r->event);
576 }
577 }
578
579
580 static ngx_int_t
ngx_resolve_name_locked(ngx_resolver_t * r,ngx_resolver_ctx_t * ctx,ngx_str_t * name)581 ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx,
582 ngx_str_t *name)
583 {
584 uint32_t hash;
585 ngx_int_t rc;
586 ngx_str_t cname;
587 ngx_uint_t i, naddrs;
588 ngx_queue_t *resend_queue, *expire_queue;
589 ngx_rbtree_t *tree;
590 ngx_resolver_ctx_t *next, *last;
591 ngx_resolver_addr_t *addrs;
592 ngx_resolver_node_t *rn;
593
594 ngx_strlow(name->data, name->data, name->len);
595
596 hash = ngx_crc32_short(name->data, name->len);
597
598 if (ctx->service.len) {
599 rn = ngx_resolver_lookup_srv(r, name, hash);
600
601 tree = &r->srv_rbtree;
602 resend_queue = &r->srv_resend_queue;
603 expire_queue = &r->srv_expire_queue;
604
605 } else {
606 rn = ngx_resolver_lookup_name(r, name, hash);
607
608 tree = &r->name_rbtree;
609 resend_queue = &r->name_resend_queue;
610 expire_queue = &r->name_expire_queue;
611 }
612
613 if (rn) {
614
615 /* ctx can be a list after NGX_RESOLVE_CNAME */
616 for (last = ctx; last->next; last = last->next);
617
618 if (rn->valid >= ngx_time()) {
619
620 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
621
622 ngx_queue_remove(&rn->queue);
623
624 rn->expire = ngx_time() + r->expire;
625
626 ngx_queue_insert_head(expire_queue, &rn->queue);
627
628 naddrs = (rn->naddrs == (u_short) -1) ? 0 : rn->naddrs;
629 #if (NGX_HAVE_INET6)
630 naddrs += (rn->naddrs6 == (u_short) -1) ? 0 : rn->naddrs6;
631 #endif
632
633 if (naddrs) {
634
635 if (naddrs == 1 && rn->naddrs == 1) {
636 addrs = NULL;
637
638 } else {
639 addrs = ngx_resolver_export(r, rn, 1);
640 if (addrs == NULL) {
641 return NGX_ERROR;
642 }
643 }
644
645 last->next = rn->waiting;
646 rn->waiting = NULL;
647
648 /* unlock name mutex */
649
650 do {
651 ctx->state = NGX_OK;
652 ctx->valid = rn->valid;
653 ctx->naddrs = naddrs;
654
655 if (addrs == NULL) {
656 ctx->addrs = &ctx->addr;
657 ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
658 ctx->addr.socklen = sizeof(struct sockaddr_in);
659 ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
660 ctx->sin.sin_family = AF_INET;
661 ctx->sin.sin_addr.s_addr = rn->u.addr;
662
663 } else {
664 ctx->addrs = addrs;
665 }
666
667 next = ctx->next;
668
669 ctx->handler(ctx);
670
671 ctx = next;
672 } while (ctx);
673
674 if (addrs != NULL) {
675 ngx_resolver_free(r, addrs->sockaddr);
676 ngx_resolver_free(r, addrs);
677 }
678
679 return NGX_OK;
680 }
681
682 if (rn->nsrvs) {
683 last->next = rn->waiting;
684 rn->waiting = NULL;
685
686 /* unlock name mutex */
687
688 do {
689 next = ctx->next;
690
691 ngx_resolver_resolve_srv_names(ctx, rn);
692
693 ctx = next;
694 } while (ctx);
695
696 return NGX_OK;
697 }
698
699 /* NGX_RESOLVE_CNAME */
700
701 if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) {
702
703 cname.len = rn->cnlen;
704 cname.data = rn->u.cname;
705
706 return ngx_resolve_name_locked(r, ctx, &cname);
707 }
708
709 last->next = rn->waiting;
710 rn->waiting = NULL;
711
712 /* unlock name mutex */
713
714 do {
715 ctx->state = NGX_RESOLVE_NXDOMAIN;
716 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
717 next = ctx->next;
718
719 ctx->handler(ctx);
720
721 ctx = next;
722 } while (ctx);
723
724 return NGX_OK;
725 }
726
727 if (rn->waiting) {
728 if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) {
729 return NGX_ERROR;
730 }
731
732 last->next = rn->waiting;
733 rn->waiting = ctx;
734 ctx->state = NGX_AGAIN;
735 ctx->async = 1;
736
737 do {
738 ctx->node = rn;
739 ctx = ctx->next;
740 } while (ctx);
741
742 return NGX_AGAIN;
743 }
744
745 ngx_queue_remove(&rn->queue);
746
747 /* lock alloc mutex */
748
749 if (rn->query) {
750 ngx_resolver_free_locked(r, rn->query);
751 rn->query = NULL;
752 #if (NGX_HAVE_INET6)
753 rn->query6 = NULL;
754 #endif
755 }
756
757 if (rn->cnlen) {
758 ngx_resolver_free_locked(r, rn->u.cname);
759 }
760
761 if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
762 ngx_resolver_free_locked(r, rn->u.addrs);
763 }
764
765 #if (NGX_HAVE_INET6)
766 if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
767 ngx_resolver_free_locked(r, rn->u6.addrs6);
768 }
769 #endif
770
771 if (rn->nsrvs) {
772 for (i = 0; i < (ngx_uint_t) rn->nsrvs; i++) {
773 if (rn->u.srvs[i].name.data) {
774 ngx_resolver_free_locked(r, rn->u.srvs[i].name.data);
775 }
776 }
777
778 ngx_resolver_free_locked(r, rn->u.srvs);
779 }
780
781 /* unlock alloc mutex */
782
783 } else {
784
785 rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
786 if (rn == NULL) {
787 return NGX_ERROR;
788 }
789
790 rn->name = ngx_resolver_dup(r, name->data, name->len);
791 if (rn->name == NULL) {
792 ngx_resolver_free(r, rn);
793 return NGX_ERROR;
794 }
795
796 rn->node.key = hash;
797 rn->nlen = (u_short) name->len;
798 rn->query = NULL;
799 #if (NGX_HAVE_INET6)
800 rn->query6 = NULL;
801 #endif
802
803 ngx_rbtree_insert(tree, &rn->node);
804 }
805
806 if (ctx->service.len) {
807 rc = ngx_resolver_create_srv_query(r, rn, name);
808
809 } else {
810 rc = ngx_resolver_create_name_query(r, rn, name);
811 }
812
813 if (rc == NGX_ERROR) {
814 goto failed;
815 }
816
817 if (rc == NGX_DECLINED) {
818 ngx_rbtree_delete(tree, &rn->node);
819
820 ngx_resolver_free(r, rn->query);
821 ngx_resolver_free(r, rn->name);
822 ngx_resolver_free(r, rn);
823
824 do {
825 ctx->state = NGX_RESOLVE_NXDOMAIN;
826 next = ctx->next;
827
828 ctx->handler(ctx);
829
830 ctx = next;
831 } while (ctx);
832
833 return NGX_OK;
834 }
835
836 rn->last_connection = r->last_connection++;
837 if (r->last_connection == r->connections.nelts) {
838 r->last_connection = 0;
839 }
840
841 rn->naddrs = (u_short) -1;
842 rn->tcp = 0;
843 #if (NGX_HAVE_INET6)
844 rn->naddrs6 = r->ipv6 ? (u_short) -1 : 0;
845 rn->tcp6 = 0;
846 #endif
847 rn->nsrvs = 0;
848
849 if (ngx_resolver_send_query(r, rn) != NGX_OK) {
850
851 /* immediately retry once on failure */
852
853 rn->last_connection++;
854 if (rn->last_connection == r->connections.nelts) {
855 rn->last_connection = 0;
856 }
857
858 (void) ngx_resolver_send_query(r, rn);
859 }
860
861 if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) {
862 goto failed;
863 }
864
865 if (ngx_resolver_resend_empty(r)) {
866 ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
867 }
868
869 rn->expire = ngx_time() + r->resend_timeout;
870
871 ngx_queue_insert_head(resend_queue, &rn->queue);
872
873 rn->code = 0;
874 rn->cnlen = 0;
875 rn->valid = 0;
876 rn->ttl = NGX_MAX_UINT32_VALUE;
877 rn->waiting = ctx;
878
879 ctx->state = NGX_AGAIN;
880 ctx->async = 1;
881
882 do {
883 ctx->node = rn;
884 ctx = ctx->next;
885 } while (ctx);
886
887 return NGX_AGAIN;
888
889 failed:
890
891 ngx_rbtree_delete(tree, &rn->node);
892
893 if (rn->query) {
894 ngx_resolver_free(r, rn->query);
895 }
896
897 ngx_resolver_free(r, rn->name);
898
899 ngx_resolver_free(r, rn);
900
901 return NGX_ERROR;
902 }
903
904
905 ngx_int_t
ngx_resolve_addr(ngx_resolver_ctx_t * ctx)906 ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
907 {
908 u_char *name;
909 in_addr_t addr;
910 ngx_queue_t *resend_queue, *expire_queue;
911 ngx_rbtree_t *tree;
912 ngx_resolver_t *r;
913 struct sockaddr_in *sin;
914 ngx_resolver_node_t *rn;
915 #if (NGX_HAVE_INET6)
916 uint32_t hash;
917 struct sockaddr_in6 *sin6;
918 #endif
919
920 #if (NGX_SUPPRESS_WARN)
921 addr = 0;
922 #if (NGX_HAVE_INET6)
923 hash = 0;
924 sin6 = NULL;
925 #endif
926 #endif
927
928 r = ctx->resolver;
929
930 switch (ctx->addr.sockaddr->sa_family) {
931
932 #if (NGX_HAVE_INET6)
933 case AF_INET6:
934 sin6 = (struct sockaddr_in6 *) ctx->addr.sockaddr;
935 hash = ngx_crc32_short(sin6->sin6_addr.s6_addr, 16);
936
937 /* lock addr mutex */
938
939 rn = ngx_resolver_lookup_addr6(r, &sin6->sin6_addr, hash);
940
941 tree = &r->addr6_rbtree;
942 resend_queue = &r->addr6_resend_queue;
943 expire_queue = &r->addr6_expire_queue;
944
945 break;
946 #endif
947
948 default: /* AF_INET */
949 sin = (struct sockaddr_in *) ctx->addr.sockaddr;
950 addr = ntohl(sin->sin_addr.s_addr);
951
952 /* lock addr mutex */
953
954 rn = ngx_resolver_lookup_addr(r, addr);
955
956 tree = &r->addr_rbtree;
957 resend_queue = &r->addr_resend_queue;
958 expire_queue = &r->addr_expire_queue;
959 }
960
961 if (rn) {
962
963 if (rn->valid >= ngx_time()) {
964
965 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
966
967 ngx_queue_remove(&rn->queue);
968
969 rn->expire = ngx_time() + r->expire;
970
971 ngx_queue_insert_head(expire_queue, &rn->queue);
972
973 name = ngx_resolver_dup(r, rn->name, rn->nlen);
974 if (name == NULL) {
975 goto failed;
976 }
977
978 ctx->name.len = rn->nlen;
979 ctx->name.data = name;
980
981 /* unlock addr mutex */
982
983 ctx->state = NGX_OK;
984 ctx->valid = rn->valid;
985
986 ctx->handler(ctx);
987
988 ngx_resolver_free(r, name);
989
990 return NGX_OK;
991 }
992
993 if (rn->waiting) {
994 if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) {
995 return NGX_ERROR;
996 }
997
998 ctx->next = rn->waiting;
999 rn->waiting = ctx;
1000 ctx->state = NGX_AGAIN;
1001 ctx->async = 1;
1002 ctx->node = rn;
1003
1004 /* unlock addr mutex */
1005
1006 return NGX_OK;
1007 }
1008
1009 ngx_queue_remove(&rn->queue);
1010
1011 ngx_resolver_free(r, rn->query);
1012 rn->query = NULL;
1013 #if (NGX_HAVE_INET6)
1014 rn->query6 = NULL;
1015 #endif
1016
1017 } else {
1018 rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
1019 if (rn == NULL) {
1020 goto failed;
1021 }
1022
1023 switch (ctx->addr.sockaddr->sa_family) {
1024
1025 #if (NGX_HAVE_INET6)
1026 case AF_INET6:
1027 rn->addr6 = sin6->sin6_addr;
1028 rn->node.key = hash;
1029 break;
1030 #endif
1031
1032 default: /* AF_INET */
1033 rn->node.key = addr;
1034 }
1035
1036 rn->query = NULL;
1037 #if (NGX_HAVE_INET6)
1038 rn->query6 = NULL;
1039 #endif
1040
1041 ngx_rbtree_insert(tree, &rn->node);
1042 }
1043
1044 if (ngx_resolver_create_addr_query(r, rn, &ctx->addr) != NGX_OK) {
1045 goto failed;
1046 }
1047
1048 rn->last_connection = r->last_connection++;
1049 if (r->last_connection == r->connections.nelts) {
1050 r->last_connection = 0;
1051 }
1052
1053 rn->naddrs = (u_short) -1;
1054 rn->tcp = 0;
1055 #if (NGX_HAVE_INET6)
1056 rn->naddrs6 = (u_short) -1;
1057 rn->tcp6 = 0;
1058 #endif
1059 rn->nsrvs = 0;
1060
1061 if (ngx_resolver_send_query(r, rn) != NGX_OK) {
1062
1063 /* immediately retry once on failure */
1064
1065 rn->last_connection++;
1066 if (rn->last_connection == r->connections.nelts) {
1067 rn->last_connection = 0;
1068 }
1069
1070 (void) ngx_resolver_send_query(r, rn);
1071 }
1072
1073 if (ngx_resolver_set_timeout(r, ctx) != NGX_OK) {
1074 goto failed;
1075 }
1076
1077 if (ngx_resolver_resend_empty(r)) {
1078 ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
1079 }
1080
1081 rn->expire = ngx_time() + r->resend_timeout;
1082
1083 ngx_queue_insert_head(resend_queue, &rn->queue);
1084
1085 rn->code = 0;
1086 rn->cnlen = 0;
1087 rn->name = NULL;
1088 rn->nlen = 0;
1089 rn->valid = 0;
1090 rn->ttl = NGX_MAX_UINT32_VALUE;
1091 rn->waiting = ctx;
1092
1093 /* unlock addr mutex */
1094
1095 ctx->state = NGX_AGAIN;
1096 ctx->async = 1;
1097 ctx->node = rn;
1098
1099 return NGX_OK;
1100
1101 failed:
1102
1103 if (rn) {
1104 ngx_rbtree_delete(tree, &rn->node);
1105
1106 if (rn->query) {
1107 ngx_resolver_free(r, rn->query);
1108 }
1109
1110 ngx_resolver_free(r, rn);
1111 }
1112
1113 /* unlock addr mutex */
1114
1115 if (ctx->event) {
1116 ngx_resolver_free(r, ctx->event);
1117 }
1118
1119 ngx_resolver_free(r, ctx);
1120
1121 return NGX_ERROR;
1122 }
1123
1124
1125 void
ngx_resolve_addr_done(ngx_resolver_ctx_t * ctx)1126 ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
1127 {
1128 ngx_queue_t *expire_queue;
1129 ngx_rbtree_t *tree;
1130 ngx_resolver_t *r;
1131 ngx_resolver_ctx_t *w, **p;
1132 ngx_resolver_node_t *rn;
1133
1134 r = ctx->resolver;
1135
1136 switch (ctx->addr.sockaddr->sa_family) {
1137
1138 #if (NGX_HAVE_INET6)
1139 case AF_INET6:
1140 tree = &r->addr6_rbtree;
1141 expire_queue = &r->addr6_expire_queue;
1142 break;
1143 #endif
1144
1145 default: /* AF_INET */
1146 tree = &r->addr_rbtree;
1147 expire_queue = &r->addr_expire_queue;
1148 }
1149
1150 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
1151 "resolve addr done: %i", ctx->state);
1152
1153 if (ctx->event && ctx->event->timer_set) {
1154 ngx_del_timer(ctx->event);
1155 }
1156
1157 /* lock addr mutex */
1158
1159 if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
1160
1161 rn = ctx->node;
1162
1163 if (rn) {
1164 p = &rn->waiting;
1165 w = rn->waiting;
1166
1167 while (w) {
1168 if (w == ctx) {
1169 *p = w->next;
1170
1171 goto done;
1172 }
1173
1174 p = &w->next;
1175 w = w->next;
1176 }
1177 }
1178
1179 {
1180 u_char text[NGX_SOCKADDR_STRLEN];
1181 ngx_str_t addrtext;
1182
1183 addrtext.data = text;
1184 addrtext.len = ngx_sock_ntop(ctx->addr.sockaddr, ctx->addr.socklen,
1185 text, NGX_SOCKADDR_STRLEN, 0);
1186
1187 ngx_log_error(NGX_LOG_ALERT, r->log, 0,
1188 "could not cancel %V resolving", &addrtext);
1189 }
1190 }
1191
1192 done:
1193
1194 ngx_resolver_expire(r, tree, expire_queue);
1195
1196 /* unlock addr mutex */
1197
1198 /* lock alloc mutex */
1199
1200 if (ctx->event) {
1201 ngx_resolver_free_locked(r, ctx->event);
1202 }
1203
1204 ngx_resolver_free_locked(r, ctx);
1205
1206 /* unlock alloc mutex */
1207
1208 if (r->event->timer_set && ngx_resolver_resend_empty(r)) {
1209 ngx_del_timer(r->event);
1210 }
1211 }
1212
1213
1214 static void
ngx_resolver_expire(ngx_resolver_t * r,ngx_rbtree_t * tree,ngx_queue_t * queue)1215 ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
1216 {
1217 time_t now;
1218 ngx_uint_t i;
1219 ngx_queue_t *q;
1220 ngx_resolver_node_t *rn;
1221
1222 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver expire");
1223
1224 now = ngx_time();
1225
1226 for (i = 0; i < 2; i++) {
1227 if (ngx_queue_empty(queue)) {
1228 return;
1229 }
1230
1231 q = ngx_queue_last(queue);
1232
1233 rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
1234
1235 if (now <= rn->expire) {
1236 return;
1237 }
1238
1239 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
1240 "resolver expire \"%*s\"", (size_t) rn->nlen, rn->name);
1241
1242 ngx_queue_remove(q);
1243
1244 ngx_rbtree_delete(tree, &rn->node);
1245
1246 ngx_resolver_free_node(r, rn);
1247 }
1248 }
1249
1250
1251 static ngx_int_t
ngx_resolver_send_query(ngx_resolver_t * r,ngx_resolver_node_t * rn)1252 ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn)
1253 {
1254 ngx_int_t rc;
1255 ngx_resolver_connection_t *rec;
1256
1257 rec = r->connections.elts;
1258 rec = &rec[rn->last_connection];
1259
1260 if (rec->log.handler == NULL) {
1261 rec->log = *r->log;
1262 rec->log.handler = ngx_resolver_log_error;
1263 rec->log.data = rec;
1264 rec->log.action = "resolving";
1265 }
1266
1267 if (rn->naddrs == (u_short) -1) {
1268 rc = rn->tcp ? ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen)
1269 : ngx_resolver_send_udp_query(r, rec, rn->query, rn->qlen);
1270
1271 if (rc != NGX_OK) {
1272 return rc;
1273 }
1274 }
1275
1276 #if (NGX_HAVE_INET6)
1277
1278 if (rn->query6 && rn->naddrs6 == (u_short) -1) {
1279 rc = rn->tcp6
1280 ? ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen)
1281 : ngx_resolver_send_udp_query(r, rec, rn->query6, rn->qlen);
1282
1283 if (rc != NGX_OK) {
1284 return rc;
1285 }
1286 }
1287
1288 #endif
1289
1290 return NGX_OK;
1291 }
1292
1293
1294 static ngx_int_t
ngx_resolver_send_udp_query(ngx_resolver_t * r,ngx_resolver_connection_t * rec,u_char * query,u_short qlen)1295 ngx_resolver_send_udp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec,
1296 u_char *query, u_short qlen)
1297 {
1298 ssize_t n;
1299
1300 if (rec->udp == NULL) {
1301 if (ngx_udp_connect(rec) != NGX_OK) {
1302 return NGX_ERROR;
1303 }
1304
1305 rec->udp->data = rec;
1306 rec->udp->read->handler = ngx_resolver_udp_read;
1307 rec->udp->read->resolver = 1;
1308 }
1309
1310 n = ngx_send(rec->udp, query, qlen);
1311
1312 if (n == NGX_ERROR) {
1313 goto failed;
1314 }
1315
1316 if ((size_t) n != (size_t) qlen) {
1317 ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "send() incomplete");
1318 goto failed;
1319 }
1320
1321 return NGX_OK;
1322
1323 failed:
1324
1325 ngx_close_connection(rec->udp);
1326 rec->udp = NULL;
1327
1328 return NGX_ERROR;
1329 }
1330
1331
1332 static ngx_int_t
ngx_resolver_send_tcp_query(ngx_resolver_t * r,ngx_resolver_connection_t * rec,u_char * query,u_short qlen)1333 ngx_resolver_send_tcp_query(ngx_resolver_t *r, ngx_resolver_connection_t *rec,
1334 u_char *query, u_short qlen)
1335 {
1336 ngx_buf_t *b;
1337 ngx_int_t rc;
1338
1339 rc = NGX_OK;
1340
1341 if (rec->tcp == NULL) {
1342 b = rec->read_buf;
1343
1344 if (b == NULL) {
1345 b = ngx_resolver_calloc(r, sizeof(ngx_buf_t));
1346 if (b == NULL) {
1347 return NGX_ERROR;
1348 }
1349
1350 b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_RSIZE);
1351 if (b->start == NULL) {
1352 ngx_resolver_free(r, b);
1353 return NGX_ERROR;
1354 }
1355
1356 b->end = b->start + NGX_RESOLVER_TCP_RSIZE;
1357
1358 rec->read_buf = b;
1359 }
1360
1361 b->pos = b->start;
1362 b->last = b->start;
1363
1364 b = rec->write_buf;
1365
1366 if (b == NULL) {
1367 b = ngx_resolver_calloc(r, sizeof(ngx_buf_t));
1368 if (b == NULL) {
1369 return NGX_ERROR;
1370 }
1371
1372 b->start = ngx_resolver_alloc(r, NGX_RESOLVER_TCP_WSIZE);
1373 if (b->start == NULL) {
1374 ngx_resolver_free(r, b);
1375 return NGX_ERROR;
1376 }
1377
1378 b->end = b->start + NGX_RESOLVER_TCP_WSIZE;
1379
1380 rec->write_buf = b;
1381 }
1382
1383 b->pos = b->start;
1384 b->last = b->start;
1385
1386 rc = ngx_tcp_connect(rec);
1387 if (rc == NGX_ERROR) {
1388 return NGX_ERROR;
1389 }
1390
1391 rec->tcp->data = rec;
1392 rec->tcp->write->handler = ngx_resolver_tcp_write;
1393 rec->tcp->read->handler = ngx_resolver_tcp_read;
1394 rec->tcp->read->resolver = 1;
1395
1396 ngx_add_timer(rec->tcp->write, (ngx_msec_t) (r->tcp_timeout * 1000));
1397 }
1398
1399 b = rec->write_buf;
1400
1401 if (b->end - b->last < 2 + qlen) {
1402 ngx_log_error(NGX_LOG_CRIT, &rec->log, 0, "buffer overflow");
1403 return NGX_ERROR;
1404 }
1405
1406 *b->last++ = (u_char) (qlen >> 8);
1407 *b->last++ = (u_char) qlen;
1408 b->last = ngx_cpymem(b->last, query, qlen);
1409
1410 if (rc == NGX_OK) {
1411 ngx_resolver_tcp_write(rec->tcp->write);
1412 }
1413
1414 return NGX_OK;
1415 }
1416
1417
1418 static void
ngx_resolver_resend_handler(ngx_event_t * ev)1419 ngx_resolver_resend_handler(ngx_event_t *ev)
1420 {
1421 time_t timer, atimer, stimer, ntimer;
1422 #if (NGX_HAVE_INET6)
1423 time_t a6timer;
1424 #endif
1425 ngx_resolver_t *r;
1426
1427 r = ev->data;
1428
1429 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0,
1430 "resolver resend handler");
1431
1432 /* lock name mutex */
1433
1434 ntimer = ngx_resolver_resend(r, &r->name_rbtree, &r->name_resend_queue);
1435
1436 stimer = ngx_resolver_resend(r, &r->srv_rbtree, &r->srv_resend_queue);
1437
1438 /* unlock name mutex */
1439
1440 /* lock addr mutex */
1441
1442 atimer = ngx_resolver_resend(r, &r->addr_rbtree, &r->addr_resend_queue);
1443
1444 /* unlock addr mutex */
1445
1446 #if (NGX_HAVE_INET6)
1447
1448 /* lock addr6 mutex */
1449
1450 a6timer = ngx_resolver_resend(r, &r->addr6_rbtree, &r->addr6_resend_queue);
1451
1452 /* unlock addr6 mutex */
1453
1454 #endif
1455
1456 timer = ntimer;
1457
1458 if (timer == 0) {
1459 timer = atimer;
1460
1461 } else if (atimer) {
1462 timer = ngx_min(timer, atimer);
1463 }
1464
1465 if (timer == 0) {
1466 timer = stimer;
1467
1468 } else if (stimer) {
1469 timer = ngx_min(timer, stimer);
1470 }
1471
1472 #if (NGX_HAVE_INET6)
1473
1474 if (timer == 0) {
1475 timer = a6timer;
1476
1477 } else if (a6timer) {
1478 timer = ngx_min(timer, a6timer);
1479 }
1480
1481 #endif
1482
1483 if (timer) {
1484 ngx_add_timer(r->event, (ngx_msec_t) (timer * 1000));
1485 }
1486 }
1487
1488
1489 static time_t
ngx_resolver_resend(ngx_resolver_t * r,ngx_rbtree_t * tree,ngx_queue_t * queue)1490 ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
1491 {
1492 time_t now;
1493 ngx_queue_t *q;
1494 ngx_resolver_node_t *rn;
1495
1496 now = ngx_time();
1497
1498 for ( ;; ) {
1499 if (ngx_queue_empty(queue)) {
1500 return 0;
1501 }
1502
1503 q = ngx_queue_last(queue);
1504
1505 rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
1506
1507 if (now < rn->expire) {
1508 return rn->expire - now;
1509 }
1510
1511 ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
1512 "resolver resend \"%*s\" %p",
1513 (size_t) rn->nlen, rn->name, rn->waiting);
1514
1515 ngx_queue_remove(q);
1516
1517 if (rn->waiting) {
1518
1519 if (++rn->last_connection == r->connections.nelts) {
1520 rn->last_connection = 0;
1521 }
1522
1523 (void) ngx_resolver_send_query(r, rn);
1524
1525 rn->expire = now + r->resend_timeout;
1526
1527 ngx_queue_insert_head(queue, q);
1528
1529 continue;
1530 }
1531
1532 ngx_rbtree_delete(tree, &rn->node);
1533
1534 ngx_resolver_free_node(r, rn);
1535 }
1536 }
1537
1538
1539 static ngx_uint_t
ngx_resolver_resend_empty(ngx_resolver_t * r)1540 ngx_resolver_resend_empty(ngx_resolver_t *r)
1541 {
1542 return ngx_queue_empty(&r->name_resend_queue)
1543 && ngx_queue_empty(&r->srv_resend_queue)
1544 #if (NGX_HAVE_INET6)
1545 && ngx_queue_empty(&r->addr6_resend_queue)
1546 #endif
1547 && ngx_queue_empty(&r->addr_resend_queue);
1548 }
1549
1550
1551 static void
ngx_resolver_udp_read(ngx_event_t * rev)1552 ngx_resolver_udp_read(ngx_event_t *rev)
1553 {
1554 ssize_t n;
1555 ngx_connection_t *c;
1556 ngx_resolver_connection_t *rec;
1557 u_char buf[NGX_RESOLVER_UDP_SIZE];
1558
1559 c = rev->data;
1560 rec = c->data;
1561
1562 do {
1563 n = ngx_udp_recv(c, buf, NGX_RESOLVER_UDP_SIZE);
1564
1565 if (n < 0) {
1566 return;
1567 }
1568
1569 ngx_resolver_process_response(rec->resolver, buf, n, 0);
1570
1571 } while (rev->ready);
1572 }
1573
1574
1575 static void
ngx_resolver_tcp_write(ngx_event_t * wev)1576 ngx_resolver_tcp_write(ngx_event_t *wev)
1577 {
1578 off_t sent;
1579 ssize_t n;
1580 ngx_buf_t *b;
1581 ngx_resolver_t *r;
1582 ngx_connection_t *c;
1583 ngx_resolver_connection_t *rec;
1584
1585 c = wev->data;
1586 rec = c->data;
1587 b = rec->write_buf;
1588 r = rec->resolver;
1589
1590 if (wev->timedout) {
1591 goto failed;
1592 }
1593
1594 sent = c->sent;
1595
1596 while (wev->ready && b->pos < b->last) {
1597 n = ngx_send(c, b->pos, b->last - b->pos);
1598
1599 if (n == NGX_AGAIN) {
1600 break;
1601 }
1602
1603 if (n == NGX_ERROR) {
1604 goto failed;
1605 }
1606
1607 b->pos += n;
1608 }
1609
1610 if (b->pos != b->start) {
1611 b->last = ngx_movemem(b->start, b->pos, b->last - b->pos);
1612 b->pos = b->start;
1613 }
1614
1615 if (c->sent != sent) {
1616 ngx_add_timer(wev, (ngx_msec_t) (r->tcp_timeout * 1000));
1617 }
1618
1619 if (ngx_handle_write_event(wev, 0) != NGX_OK) {
1620 goto failed;
1621 }
1622
1623 return;
1624
1625 failed:
1626
1627 ngx_close_connection(c);
1628 rec->tcp = NULL;
1629 }
1630
1631
1632 static void
ngx_resolver_tcp_read(ngx_event_t * rev)1633 ngx_resolver_tcp_read(ngx_event_t *rev)
1634 {
1635 u_char *p;
1636 size_t size;
1637 ssize_t n;
1638 u_short qlen;
1639 ngx_buf_t *b;
1640 ngx_resolver_t *r;
1641 ngx_connection_t *c;
1642 ngx_resolver_connection_t *rec;
1643
1644 c = rev->data;
1645 rec = c->data;
1646 b = rec->read_buf;
1647 r = rec->resolver;
1648
1649 while (rev->ready) {
1650 n = ngx_recv(c, b->last, b->end - b->last);
1651
1652 if (n == NGX_AGAIN) {
1653 break;
1654 }
1655
1656 if (n == NGX_ERROR || n == 0) {
1657 goto failed;
1658 }
1659
1660 b->last += n;
1661
1662 for ( ;; ) {
1663 p = b->pos;
1664 size = b->last - p;
1665
1666 if (size < 2) {
1667 break;
1668 }
1669
1670 qlen = (u_short) *p++ << 8;
1671 qlen += *p++;
1672
1673 if (size < (size_t) (2 + qlen)) {
1674 break;
1675 }
1676
1677 ngx_resolver_process_response(r, p, qlen, 1);
1678
1679 b->pos += 2 + qlen;
1680 }
1681
1682 if (b->pos != b->start) {
1683 b->last = ngx_movemem(b->start, b->pos, b->last - b->pos);
1684 b->pos = b->start;
1685 }
1686 }
1687
1688 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
1689 goto failed;
1690 }
1691
1692 return;
1693
1694 failed:
1695
1696 ngx_close_connection(c);
1697 rec->tcp = NULL;
1698 }
1699
1700
1701 static void
ngx_resolver_process_response(ngx_resolver_t * r,u_char * buf,size_t n,ngx_uint_t tcp)1702 ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n,
1703 ngx_uint_t tcp)
1704 {
1705 char *err;
1706 ngx_uint_t i, times, ident, qident, flags, code, nqs, nan, trunc,
1707 qtype, qclass;
1708 #if (NGX_HAVE_INET6)
1709 ngx_uint_t qident6;
1710 #endif
1711 ngx_queue_t *q;
1712 ngx_resolver_qs_t *qs;
1713 ngx_resolver_hdr_t *response;
1714 ngx_resolver_node_t *rn;
1715
1716 if (n < sizeof(ngx_resolver_hdr_t)) {
1717 goto short_response;
1718 }
1719
1720 response = (ngx_resolver_hdr_t *) buf;
1721
1722 ident = (response->ident_hi << 8) + response->ident_lo;
1723 flags = (response->flags_hi << 8) + response->flags_lo;
1724 nqs = (response->nqs_hi << 8) + response->nqs_lo;
1725 nan = (response->nan_hi << 8) + response->nan_lo;
1726 trunc = flags & 0x0200;
1727
1728 ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0,
1729 "resolver DNS response %ui fl:%04Xi %ui/%ui/%ud/%ud",
1730 ident, flags, nqs, nan,
1731 (response->nns_hi << 8) + response->nns_lo,
1732 (response->nar_hi << 8) + response->nar_lo);
1733
1734 /* response to a standard query */
1735 if ((flags & 0xf870) != 0x8000 || (trunc && tcp)) {
1736 ngx_log_error(r->log_level, r->log, 0,
1737 "invalid %s DNS response %ui fl:%04Xi",
1738 tcp ? "TCP" : "UDP", ident, flags);
1739 return;
1740 }
1741
1742 code = flags & 0xf;
1743
1744 if (code == NGX_RESOLVE_FORMERR) {
1745
1746 times = 0;
1747
1748 for (q = ngx_queue_head(&r->name_resend_queue);
1749 q != ngx_queue_sentinel(&r->name_resend_queue) && times++ < 100;
1750 q = ngx_queue_next(q))
1751 {
1752 rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
1753 qident = (rn->query[0] << 8) + rn->query[1];
1754
1755 if (qident == ident) {
1756 goto dns_error_name;
1757 }
1758
1759 #if (NGX_HAVE_INET6)
1760 if (rn->query6) {
1761 qident6 = (rn->query6[0] << 8) + rn->query6[1];
1762
1763 if (qident6 == ident) {
1764 goto dns_error_name;
1765 }
1766 }
1767 #endif
1768 }
1769
1770 goto dns_error;
1771 }
1772
1773 if (code > NGX_RESOLVE_REFUSED) {
1774 goto dns_error;
1775 }
1776
1777 if (nqs != 1) {
1778 err = "invalid number of questions in DNS response";
1779 goto done;
1780 }
1781
1782 i = sizeof(ngx_resolver_hdr_t);
1783
1784 while (i < (ngx_uint_t) n) {
1785 if (buf[i] == '\0') {
1786 goto found;
1787 }
1788
1789 i += 1 + buf[i];
1790 }
1791
1792 goto short_response;
1793
1794 found:
1795
1796 if (i++ == sizeof(ngx_resolver_hdr_t)) {
1797 err = "zero-length domain name in DNS response";
1798 goto done;
1799 }
1800
1801 if (i + sizeof(ngx_resolver_qs_t) + nan * (2 + sizeof(ngx_resolver_an_t))
1802 > (ngx_uint_t) n)
1803 {
1804 goto short_response;
1805 }
1806
1807 qs = (ngx_resolver_qs_t *) &buf[i];
1808
1809 qtype = (qs->type_hi << 8) + qs->type_lo;
1810 qclass = (qs->class_hi << 8) + qs->class_lo;
1811
1812 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
1813 "resolver DNS response qt:%ui cl:%ui", qtype, qclass);
1814
1815 if (qclass != 1) {
1816 ngx_log_error(r->log_level, r->log, 0,
1817 "unknown query class %ui in DNS response", qclass);
1818 return;
1819 }
1820
1821 switch (qtype) {
1822
1823 case NGX_RESOLVE_A:
1824 #if (NGX_HAVE_INET6)
1825 case NGX_RESOLVE_AAAA:
1826 #endif
1827
1828 ngx_resolver_process_a(r, buf, n, ident, code, qtype, nan, trunc,
1829 i + sizeof(ngx_resolver_qs_t));
1830
1831 break;
1832
1833 case NGX_RESOLVE_SRV:
1834
1835 ngx_resolver_process_srv(r, buf, n, ident, code, nan, trunc,
1836 i + sizeof(ngx_resolver_qs_t));
1837
1838 break;
1839
1840 case NGX_RESOLVE_PTR:
1841
1842 ngx_resolver_process_ptr(r, buf, n, ident, code, nan);
1843
1844 break;
1845
1846 default:
1847 ngx_log_error(r->log_level, r->log, 0,
1848 "unknown query type %ui in DNS response", qtype);
1849 return;
1850 }
1851
1852 return;
1853
1854 short_response:
1855
1856 err = "short DNS response";
1857
1858 done:
1859
1860 ngx_log_error(r->log_level, r->log, 0, err);
1861
1862 return;
1863
1864 dns_error_name:
1865
1866 ngx_log_error(r->log_level, r->log, 0,
1867 "DNS error (%ui: %s), query id:%ui, name:\"%*s\"",
1868 code, ngx_resolver_strerror(code), ident,
1869 (size_t) rn->nlen, rn->name);
1870 return;
1871
1872 dns_error:
1873
1874 ngx_log_error(r->log_level, r->log, 0,
1875 "DNS error (%ui: %s), query id:%ui",
1876 code, ngx_resolver_strerror(code), ident);
1877 return;
1878 }
1879
1880
1881 static void
ngx_resolver_process_a(ngx_resolver_t * r,u_char * buf,size_t n,ngx_uint_t ident,ngx_uint_t code,ngx_uint_t qtype,ngx_uint_t nan,ngx_uint_t trunc,ngx_uint_t ans)1882 ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
1883 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t qtype,
1884 ngx_uint_t nan, ngx_uint_t trunc, ngx_uint_t ans)
1885 {
1886 char *err;
1887 u_char *cname;
1888 size_t len;
1889 int32_t ttl;
1890 uint32_t hash;
1891 in_addr_t *addr;
1892 ngx_str_t name;
1893 ngx_uint_t type, class, qident, naddrs, a, i, j, start;
1894 #if (NGX_HAVE_INET6)
1895 struct in6_addr *addr6;
1896 #endif
1897 ngx_resolver_an_t *an;
1898 ngx_resolver_ctx_t *ctx, *next;
1899 ngx_resolver_node_t *rn;
1900 ngx_resolver_addr_t *addrs;
1901 ngx_resolver_connection_t *rec;
1902
1903 if (ngx_resolver_copy(r, &name, buf,
1904 buf + sizeof(ngx_resolver_hdr_t), buf + n)
1905 != NGX_OK)
1906 {
1907 return;
1908 }
1909
1910 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
1911
1912 hash = ngx_crc32_short(name.data, name.len);
1913
1914 /* lock name mutex */
1915
1916 rn = ngx_resolver_lookup_name(r, &name, hash);
1917
1918 if (rn == NULL) {
1919 ngx_log_error(r->log_level, r->log, 0,
1920 "unexpected response for %V", &name);
1921 ngx_resolver_free(r, name.data);
1922 goto failed;
1923 }
1924
1925 switch (qtype) {
1926
1927 #if (NGX_HAVE_INET6)
1928 case NGX_RESOLVE_AAAA:
1929
1930 if (rn->query6 == NULL || rn->naddrs6 != (u_short) -1) {
1931 ngx_log_error(r->log_level, r->log, 0,
1932 "unexpected response for %V", &name);
1933 ngx_resolver_free(r, name.data);
1934 goto failed;
1935 }
1936
1937 if (trunc && rn->tcp6) {
1938 ngx_resolver_free(r, name.data);
1939 goto failed;
1940 }
1941
1942 qident = (rn->query6[0] << 8) + rn->query6[1];
1943
1944 break;
1945 #endif
1946
1947 default: /* NGX_RESOLVE_A */
1948
1949 if (rn->query == NULL || rn->naddrs != (u_short) -1) {
1950 ngx_log_error(r->log_level, r->log, 0,
1951 "unexpected response for %V", &name);
1952 ngx_resolver_free(r, name.data);
1953 goto failed;
1954 }
1955
1956 if (trunc && rn->tcp) {
1957 ngx_resolver_free(r, name.data);
1958 goto failed;
1959 }
1960
1961 qident = (rn->query[0] << 8) + rn->query[1];
1962 }
1963
1964 if (ident != qident) {
1965 ngx_log_error(r->log_level, r->log, 0,
1966 "wrong ident %ui response for %V, expect %ui",
1967 ident, &name, qident);
1968 ngx_resolver_free(r, name.data);
1969 goto failed;
1970 }
1971
1972 ngx_resolver_free(r, name.data);
1973
1974 if (trunc) {
1975
1976 ngx_queue_remove(&rn->queue);
1977
1978 if (rn->waiting == NULL) {
1979 ngx_rbtree_delete(&r->name_rbtree, &rn->node);
1980 ngx_resolver_free_node(r, rn);
1981 goto next;
1982 }
1983
1984 rec = r->connections.elts;
1985 rec = &rec[rn->last_connection];
1986
1987 switch (qtype) {
1988
1989 #if (NGX_HAVE_INET6)
1990 case NGX_RESOLVE_AAAA:
1991
1992 rn->tcp6 = 1;
1993
1994 (void) ngx_resolver_send_tcp_query(r, rec, rn->query6, rn->qlen);
1995
1996 break;
1997 #endif
1998
1999 default: /* NGX_RESOLVE_A */
2000
2001 rn->tcp = 1;
2002
2003 (void) ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen);
2004 }
2005
2006 rn->expire = ngx_time() + r->resend_timeout;
2007
2008 ngx_queue_insert_head(&r->name_resend_queue, &rn->queue);
2009
2010 goto next;
2011 }
2012
2013 if (code == 0 && rn->code) {
2014 code = rn->code;
2015 }
2016
2017 if (code == 0 && nan == 0) {
2018
2019 #if (NGX_HAVE_INET6)
2020 switch (qtype) {
2021
2022 case NGX_RESOLVE_AAAA:
2023
2024 rn->naddrs6 = 0;
2025
2026 if (rn->naddrs == (u_short) -1) {
2027 goto next;
2028 }
2029
2030 if (rn->naddrs) {
2031 goto export;
2032 }
2033
2034 break;
2035
2036 default: /* NGX_RESOLVE_A */
2037
2038 rn->naddrs = 0;
2039
2040 if (rn->naddrs6 == (u_short) -1) {
2041 goto next;
2042 }
2043
2044 if (rn->naddrs6) {
2045 goto export;
2046 }
2047 }
2048 #endif
2049
2050 code = NGX_RESOLVE_NXDOMAIN;
2051 }
2052
2053 if (code) {
2054
2055 #if (NGX_HAVE_INET6)
2056 switch (qtype) {
2057
2058 case NGX_RESOLVE_AAAA:
2059
2060 rn->naddrs6 = 0;
2061
2062 if (rn->naddrs == (u_short) -1) {
2063 rn->code = (u_char) code;
2064 goto next;
2065 }
2066
2067 break;
2068
2069 default: /* NGX_RESOLVE_A */
2070
2071 rn->naddrs = 0;
2072
2073 if (rn->naddrs6 == (u_short) -1) {
2074 rn->code = (u_char) code;
2075 goto next;
2076 }
2077 }
2078 #endif
2079
2080 next = rn->waiting;
2081 rn->waiting = NULL;
2082
2083 ngx_queue_remove(&rn->queue);
2084
2085 ngx_rbtree_delete(&r->name_rbtree, &rn->node);
2086
2087 /* unlock name mutex */
2088
2089 while (next) {
2090 ctx = next;
2091 ctx->state = code;
2092 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
2093 next = ctx->next;
2094
2095 ctx->handler(ctx);
2096 }
2097
2098 ngx_resolver_free_node(r, rn);
2099
2100 return;
2101 }
2102
2103 i = ans;
2104 naddrs = 0;
2105 cname = NULL;
2106
2107 for (a = 0; a < nan; a++) {
2108
2109 start = i;
2110
2111 while (i < n) {
2112
2113 if (buf[i] & 0xc0) {
2114 i += 2;
2115 goto found;
2116 }
2117
2118 if (buf[i] == 0) {
2119 i++;
2120 goto test_length;
2121 }
2122
2123 i += 1 + buf[i];
2124 }
2125
2126 goto short_response;
2127
2128 test_length:
2129
2130 if (i - start < 2) {
2131 err = "invalid name in DNS response";
2132 goto invalid;
2133 }
2134
2135 found:
2136
2137 if (i + sizeof(ngx_resolver_an_t) >= n) {
2138 goto short_response;
2139 }
2140
2141 an = (ngx_resolver_an_t *) &buf[i];
2142
2143 type = (an->type_hi << 8) + an->type_lo;
2144 class = (an->class_hi << 8) + an->class_lo;
2145 len = (an->len_hi << 8) + an->len_lo;
2146 ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
2147 + (an->ttl[2] << 8) + (an->ttl[3]);
2148
2149 if (class != 1) {
2150 ngx_log_error(r->log_level, r->log, 0,
2151 "unexpected RR class %ui", class);
2152 goto failed;
2153 }
2154
2155 if (ttl < 0) {
2156 ttl = 0;
2157 }
2158
2159 rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl);
2160
2161 i += sizeof(ngx_resolver_an_t);
2162
2163 switch (type) {
2164
2165 case NGX_RESOLVE_A:
2166
2167 if (qtype != NGX_RESOLVE_A) {
2168 err = "unexpected A record in DNS response";
2169 goto invalid;
2170 }
2171
2172 if (len != 4) {
2173 err = "invalid A record in DNS response";
2174 goto invalid;
2175 }
2176
2177 if (i + 4 > n) {
2178 goto short_response;
2179 }
2180
2181 naddrs++;
2182
2183 break;
2184
2185 #if (NGX_HAVE_INET6)
2186 case NGX_RESOLVE_AAAA:
2187
2188 if (qtype != NGX_RESOLVE_AAAA) {
2189 err = "unexpected AAAA record in DNS response";
2190 goto invalid;
2191 }
2192
2193 if (len != 16) {
2194 err = "invalid AAAA record in DNS response";
2195 goto invalid;
2196 }
2197
2198 if (i + 16 > n) {
2199 goto short_response;
2200 }
2201
2202 naddrs++;
2203
2204 break;
2205 #endif
2206
2207 case NGX_RESOLVE_CNAME:
2208
2209 cname = &buf[i];
2210
2211 break;
2212
2213 case NGX_RESOLVE_DNAME:
2214
2215 break;
2216
2217 default:
2218
2219 ngx_log_error(r->log_level, r->log, 0,
2220 "unexpected RR type %ui", type);
2221 }
2222
2223 i += len;
2224 }
2225
2226 ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
2227 "resolver naddrs:%ui cname:%p ttl:%uD",
2228 naddrs, cname, rn->ttl);
2229
2230 if (naddrs) {
2231
2232 switch (qtype) {
2233
2234 #if (NGX_HAVE_INET6)
2235 case NGX_RESOLVE_AAAA:
2236
2237 if (naddrs == 1) {
2238 addr6 = &rn->u6.addr6;
2239 rn->naddrs6 = 1;
2240
2241 } else {
2242 addr6 = ngx_resolver_alloc(r, naddrs * sizeof(struct in6_addr));
2243 if (addr6 == NULL) {
2244 goto failed;
2245 }
2246
2247 rn->u6.addrs6 = addr6;
2248 rn->naddrs6 = (u_short) naddrs;
2249 }
2250
2251 #if (NGX_SUPPRESS_WARN)
2252 addr = NULL;
2253 #endif
2254
2255 break;
2256 #endif
2257
2258 default: /* NGX_RESOLVE_A */
2259
2260 if (naddrs == 1) {
2261 addr = &rn->u.addr;
2262 rn->naddrs = 1;
2263
2264 } else {
2265 addr = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
2266 if (addr == NULL) {
2267 goto failed;
2268 }
2269
2270 rn->u.addrs = addr;
2271 rn->naddrs = (u_short) naddrs;
2272 }
2273
2274 #if (NGX_HAVE_INET6 && NGX_SUPPRESS_WARN)
2275 addr6 = NULL;
2276 #endif
2277 }
2278
2279 j = 0;
2280 i = ans;
2281
2282 for (a = 0; a < nan; a++) {
2283
2284 for ( ;; ) {
2285
2286 if (buf[i] & 0xc0) {
2287 i += 2;
2288 break;
2289 }
2290
2291 if (buf[i] == 0) {
2292 i++;
2293 break;
2294 }
2295
2296 i += 1 + buf[i];
2297 }
2298
2299 an = (ngx_resolver_an_t *) &buf[i];
2300
2301 type = (an->type_hi << 8) + an->type_lo;
2302 len = (an->len_hi << 8) + an->len_lo;
2303
2304 i += sizeof(ngx_resolver_an_t);
2305
2306 if (type == NGX_RESOLVE_A) {
2307
2308 addr[j] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
2309 + (buf[i + 2] << 8) + (buf[i + 3]));
2310
2311 if (++j == naddrs) {
2312
2313 #if (NGX_HAVE_INET6)
2314 if (rn->naddrs6 == (u_short) -1) {
2315 goto next;
2316 }
2317 #endif
2318
2319 break;
2320 }
2321 }
2322
2323 #if (NGX_HAVE_INET6)
2324 else if (type == NGX_RESOLVE_AAAA) {
2325
2326 ngx_memcpy(addr6[j].s6_addr, &buf[i], 16);
2327
2328 if (++j == naddrs) {
2329
2330 if (rn->naddrs == (u_short) -1) {
2331 goto next;
2332 }
2333
2334 break;
2335 }
2336 }
2337 #endif
2338
2339 i += len;
2340 }
2341 }
2342
2343 switch (qtype) {
2344
2345 #if (NGX_HAVE_INET6)
2346 case NGX_RESOLVE_AAAA:
2347
2348 if (rn->naddrs6 == (u_short) -1) {
2349 rn->naddrs6 = 0;
2350 }
2351
2352 break;
2353 #endif
2354
2355 default: /* NGX_RESOLVE_A */
2356
2357 if (rn->naddrs == (u_short) -1) {
2358 rn->naddrs = 0;
2359 }
2360 }
2361
2362 if (rn->naddrs != (u_short) -1
2363 #if (NGX_HAVE_INET6)
2364 && rn->naddrs6 != (u_short) -1
2365 #endif
2366 && rn->naddrs
2367 #if (NGX_HAVE_INET6)
2368 + rn->naddrs6
2369 #endif
2370 > 0)
2371 {
2372
2373 #if (NGX_HAVE_INET6)
2374 export:
2375 #endif
2376
2377 naddrs = rn->naddrs;
2378 #if (NGX_HAVE_INET6)
2379 naddrs += rn->naddrs6;
2380 #endif
2381
2382 if (naddrs == 1 && rn->naddrs == 1) {
2383 addrs = NULL;
2384
2385 } else {
2386 addrs = ngx_resolver_export(r, rn, 0);
2387 if (addrs == NULL) {
2388 goto failed;
2389 }
2390 }
2391
2392 ngx_queue_remove(&rn->queue);
2393
2394 rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
2395 rn->expire = ngx_time() + r->expire;
2396
2397 ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
2398
2399 next = rn->waiting;
2400 rn->waiting = NULL;
2401
2402 /* unlock name mutex */
2403
2404 while (next) {
2405 ctx = next;
2406 ctx->state = NGX_OK;
2407 ctx->valid = rn->valid;
2408 ctx->naddrs = naddrs;
2409
2410 if (addrs == NULL) {
2411 ctx->addrs = &ctx->addr;
2412 ctx->addr.sockaddr = (struct sockaddr *) &ctx->sin;
2413 ctx->addr.socklen = sizeof(struct sockaddr_in);
2414 ngx_memzero(&ctx->sin, sizeof(struct sockaddr_in));
2415 ctx->sin.sin_family = AF_INET;
2416 ctx->sin.sin_addr.s_addr = rn->u.addr;
2417
2418 } else {
2419 ctx->addrs = addrs;
2420 }
2421
2422 next = ctx->next;
2423
2424 ctx->handler(ctx);
2425 }
2426
2427 if (addrs != NULL) {
2428 ngx_resolver_free(r, addrs->sockaddr);
2429 ngx_resolver_free(r, addrs);
2430 }
2431
2432 ngx_resolver_free(r, rn->query);
2433 rn->query = NULL;
2434 #if (NGX_HAVE_INET6)
2435 rn->query6 = NULL;
2436 #endif
2437
2438 return;
2439 }
2440
2441 if (cname) {
2442
2443 /* CNAME only */
2444
2445 if (rn->naddrs == (u_short) -1
2446 #if (NGX_HAVE_INET6)
2447 || rn->naddrs6 == (u_short) -1
2448 #endif
2449 )
2450 {
2451 goto next;
2452 }
2453
2454 if (ngx_resolver_copy(r, &name, buf, cname, buf + n) != NGX_OK) {
2455 goto failed;
2456 }
2457
2458 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
2459 "resolver cname:\"%V\"", &name);
2460
2461 ngx_queue_remove(&rn->queue);
2462
2463 rn->cnlen = (u_short) name.len;
2464 rn->u.cname = name.data;
2465
2466 rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
2467 rn->expire = ngx_time() + r->expire;
2468
2469 ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
2470
2471 ngx_resolver_free(r, rn->query);
2472 rn->query = NULL;
2473 #if (NGX_HAVE_INET6)
2474 rn->query6 = NULL;
2475 #endif
2476
2477 ctx = rn->waiting;
2478 rn->waiting = NULL;
2479
2480 if (ctx) {
2481
2482 if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) {
2483
2484 /* unlock name mutex */
2485
2486 do {
2487 ctx->state = NGX_RESOLVE_NXDOMAIN;
2488 next = ctx->next;
2489
2490 ctx->handler(ctx);
2491
2492 ctx = next;
2493 } while (ctx);
2494
2495 return;
2496 }
2497
2498 for (next = ctx; next; next = next->next) {
2499 next->node = NULL;
2500 }
2501
2502 (void) ngx_resolve_name_locked(r, ctx, &name);
2503 }
2504
2505 /* unlock name mutex */
2506
2507 return;
2508 }
2509
2510 ngx_log_error(r->log_level, r->log, 0,
2511 "no A or CNAME types in DNS response");
2512 return;
2513
2514 short_response:
2515
2516 err = "short DNS response";
2517
2518 invalid:
2519
2520 /* unlock name mutex */
2521
2522 ngx_log_error(r->log_level, r->log, 0, err);
2523
2524 return;
2525
2526 failed:
2527
2528 next:
2529
2530 /* unlock name mutex */
2531
2532 return;
2533 }
2534
2535
2536 static void
ngx_resolver_process_srv(ngx_resolver_t * r,u_char * buf,size_t n,ngx_uint_t ident,ngx_uint_t code,ngx_uint_t nan,ngx_uint_t trunc,ngx_uint_t ans)2537 ngx_resolver_process_srv(ngx_resolver_t *r, u_char *buf, size_t n,
2538 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan,
2539 ngx_uint_t trunc, ngx_uint_t ans)
2540 {
2541 char *err;
2542 u_char *cname;
2543 size_t len;
2544 int32_t ttl;
2545 uint32_t hash;
2546 ngx_str_t name;
2547 ngx_uint_t type, qident, class, start, nsrvs, a, i, j;
2548 ngx_resolver_an_t *an;
2549 ngx_resolver_ctx_t *ctx, *next;
2550 ngx_resolver_srv_t *srvs;
2551 ngx_resolver_node_t *rn;
2552 ngx_resolver_connection_t *rec;
2553
2554 if (ngx_resolver_copy(r, &name, buf,
2555 buf + sizeof(ngx_resolver_hdr_t), buf + n)
2556 != NGX_OK)
2557 {
2558 return;
2559 }
2560
2561 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
2562
2563 hash = ngx_crc32_short(name.data, name.len);
2564
2565 rn = ngx_resolver_lookup_srv(r, &name, hash);
2566
2567 if (rn == NULL || rn->query == NULL) {
2568 ngx_log_error(r->log_level, r->log, 0,
2569 "unexpected response for %V", &name);
2570 ngx_resolver_free(r, name.data);
2571 goto failed;
2572 }
2573
2574 if (trunc && rn->tcp) {
2575 ngx_resolver_free(r, name.data);
2576 goto failed;
2577 }
2578
2579 qident = (rn->query[0] << 8) + rn->query[1];
2580
2581 if (ident != qident) {
2582 ngx_log_error(r->log_level, r->log, 0,
2583 "wrong ident %ui response for %V, expect %ui",
2584 ident, &name, qident);
2585 ngx_resolver_free(r, name.data);
2586 goto failed;
2587 }
2588
2589 ngx_resolver_free(r, name.data);
2590
2591 if (trunc) {
2592
2593 ngx_queue_remove(&rn->queue);
2594
2595 if (rn->waiting == NULL) {
2596 ngx_rbtree_delete(&r->srv_rbtree, &rn->node);
2597 ngx_resolver_free_node(r, rn);
2598 return;
2599 }
2600
2601 rec = r->connections.elts;
2602 rec = &rec[rn->last_connection];
2603
2604 rn->tcp = 1;
2605
2606 (void) ngx_resolver_send_tcp_query(r, rec, rn->query, rn->qlen);
2607
2608 rn->expire = ngx_time() + r->resend_timeout;
2609
2610 ngx_queue_insert_head(&r->srv_resend_queue, &rn->queue);
2611
2612 return;
2613 }
2614
2615 if (code == 0 && rn->code) {
2616 code = rn->code;
2617 }
2618
2619 if (code == 0 && nan == 0) {
2620 code = NGX_RESOLVE_NXDOMAIN;
2621 }
2622
2623 if (code) {
2624 next = rn->waiting;
2625 rn->waiting = NULL;
2626
2627 ngx_queue_remove(&rn->queue);
2628
2629 ngx_rbtree_delete(&r->srv_rbtree, &rn->node);
2630
2631 while (next) {
2632 ctx = next;
2633 ctx->state = code;
2634 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
2635 next = ctx->next;
2636
2637 ctx->handler(ctx);
2638 }
2639
2640 ngx_resolver_free_node(r, rn);
2641
2642 return;
2643 }
2644
2645 i = ans;
2646 nsrvs = 0;
2647 cname = NULL;
2648
2649 for (a = 0; a < nan; a++) {
2650
2651 start = i;
2652
2653 while (i < n) {
2654
2655 if (buf[i] & 0xc0) {
2656 i += 2;
2657 goto found;
2658 }
2659
2660 if (buf[i] == 0) {
2661 i++;
2662 goto test_length;
2663 }
2664
2665 i += 1 + buf[i];
2666 }
2667
2668 goto short_response;
2669
2670 test_length:
2671
2672 if (i - start < 2) {
2673 err = "invalid name DNS response";
2674 goto invalid;
2675 }
2676
2677 found:
2678
2679 if (i + sizeof(ngx_resolver_an_t) >= n) {
2680 goto short_response;
2681 }
2682
2683 an = (ngx_resolver_an_t *) &buf[i];
2684
2685 type = (an->type_hi << 8) + an->type_lo;
2686 class = (an->class_hi << 8) + an->class_lo;
2687 len = (an->len_hi << 8) + an->len_lo;
2688 ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
2689 + (an->ttl[2] << 8) + (an->ttl[3]);
2690
2691 if (class != 1) {
2692 ngx_log_error(r->log_level, r->log, 0,
2693 "unexpected RR class %ui", class);
2694 goto failed;
2695 }
2696
2697 if (ttl < 0) {
2698 ttl = 0;
2699 }
2700
2701 rn->ttl = ngx_min(rn->ttl, (uint32_t) ttl);
2702
2703 i += sizeof(ngx_resolver_an_t);
2704
2705 switch (type) {
2706
2707 case NGX_RESOLVE_SRV:
2708
2709 if (i + 6 > n) {
2710 goto short_response;
2711 }
2712
2713 if (ngx_resolver_copy(r, NULL, buf, &buf[i + 6], buf + n)
2714 != NGX_OK)
2715 {
2716 goto failed;
2717 }
2718
2719 nsrvs++;
2720
2721 break;
2722
2723 case NGX_RESOLVE_CNAME:
2724
2725 cname = &buf[i];
2726
2727 break;
2728
2729 case NGX_RESOLVE_DNAME:
2730
2731 break;
2732
2733 default:
2734
2735 ngx_log_error(r->log_level, r->log, 0,
2736 "unexpected RR type %ui", type);
2737 }
2738
2739 i += len;
2740 }
2741
2742 ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
2743 "resolver nsrvs:%ui cname:%p ttl:%uD",
2744 nsrvs, cname, rn->ttl);
2745
2746 if (nsrvs) {
2747
2748 srvs = ngx_resolver_calloc(r, nsrvs * sizeof(ngx_resolver_srv_t));
2749 if (srvs == NULL) {
2750 goto failed;
2751 }
2752
2753 rn->u.srvs = srvs;
2754 rn->nsrvs = (u_short) nsrvs;
2755
2756 j = 0;
2757 i = ans;
2758
2759 for (a = 0; a < nan; a++) {
2760
2761 for ( ;; ) {
2762
2763 if (buf[i] & 0xc0) {
2764 i += 2;
2765 break;
2766 }
2767
2768 if (buf[i] == 0) {
2769 i++;
2770 break;
2771 }
2772
2773 i += 1 + buf[i];
2774 }
2775
2776 an = (ngx_resolver_an_t *) &buf[i];
2777
2778 type = (an->type_hi << 8) + an->type_lo;
2779 len = (an->len_hi << 8) + an->len_lo;
2780
2781 i += sizeof(ngx_resolver_an_t);
2782
2783 if (type == NGX_RESOLVE_SRV) {
2784
2785 srvs[j].priority = (buf[i] << 8) + buf[i + 1];
2786 srvs[j].weight = (buf[i + 2] << 8) + buf[i + 3];
2787
2788 if (srvs[j].weight == 0) {
2789 srvs[j].weight = 1;
2790 }
2791
2792 srvs[j].port = (buf[i + 4] << 8) + buf[i + 5];
2793
2794 if (ngx_resolver_copy(r, &srvs[j].name, buf, &buf[i + 6],
2795 buf + n)
2796 != NGX_OK)
2797 {
2798 goto failed;
2799 }
2800
2801 j++;
2802 }
2803
2804 i += len;
2805 }
2806
2807 ngx_sort(srvs, nsrvs, sizeof(ngx_resolver_srv_t),
2808 ngx_resolver_cmp_srvs);
2809
2810 ngx_resolver_free(r, rn->query);
2811 rn->query = NULL;
2812
2813 ngx_queue_remove(&rn->queue);
2814
2815 rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
2816 rn->expire = ngx_time() + r->expire;
2817
2818 ngx_queue_insert_head(&r->srv_expire_queue, &rn->queue);
2819
2820 next = rn->waiting;
2821 rn->waiting = NULL;
2822
2823 while (next) {
2824 ctx = next;
2825 next = ctx->next;
2826
2827 ngx_resolver_resolve_srv_names(ctx, rn);
2828 }
2829
2830 return;
2831 }
2832
2833 rn->nsrvs = 0;
2834
2835 if (cname) {
2836
2837 /* CNAME only */
2838
2839 if (ngx_resolver_copy(r, &name, buf, cname, buf + n) != NGX_OK) {
2840 goto failed;
2841 }
2842
2843 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
2844 "resolver cname:\"%V\"", &name);
2845
2846 ngx_queue_remove(&rn->queue);
2847
2848 rn->cnlen = (u_short) name.len;
2849 rn->u.cname = name.data;
2850
2851 rn->valid = ngx_time() + (r->valid ? r->valid : (time_t) rn->ttl);
2852 rn->expire = ngx_time() + r->expire;
2853
2854 ngx_queue_insert_head(&r->srv_expire_queue, &rn->queue);
2855
2856 ngx_resolver_free(r, rn->query);
2857 rn->query = NULL;
2858 #if (NGX_HAVE_INET6)
2859 rn->query6 = NULL;
2860 #endif
2861
2862 ctx = rn->waiting;
2863 rn->waiting = NULL;
2864
2865 if (ctx) {
2866
2867 if (ctx->recursion++ >= NGX_RESOLVER_MAX_RECURSION) {
2868
2869 /* unlock name mutex */
2870
2871 do {
2872 ctx->state = NGX_RESOLVE_NXDOMAIN;
2873 next = ctx->next;
2874
2875 ctx->handler(ctx);
2876
2877 ctx = next;
2878 } while (ctx);
2879
2880 return;
2881 }
2882
2883 for (next = ctx; next; next = next->next) {
2884 next->node = NULL;
2885 }
2886
2887 (void) ngx_resolve_name_locked(r, ctx, &name);
2888 }
2889
2890 /* unlock name mutex */
2891
2892 return;
2893 }
2894
2895 ngx_log_error(r->log_level, r->log, 0, "no SRV type in DNS response");
2896
2897 return;
2898
2899 short_response:
2900
2901 err = "short DNS response";
2902
2903 invalid:
2904
2905 /* unlock name mutex */
2906
2907 ngx_log_error(r->log_level, r->log, 0, err);
2908
2909 return;
2910
2911 failed:
2912
2913 /* unlock name mutex */
2914
2915 return;
2916 }
2917
2918
2919 static void
ngx_resolver_resolve_srv_names(ngx_resolver_ctx_t * ctx,ngx_resolver_node_t * rn)2920 ngx_resolver_resolve_srv_names(ngx_resolver_ctx_t *ctx, ngx_resolver_node_t *rn)
2921 {
2922 ngx_uint_t i;
2923 ngx_resolver_t *r;
2924 ngx_resolver_ctx_t *cctx;
2925 ngx_resolver_srv_name_t *srvs;
2926
2927 r = ctx->resolver;
2928
2929 ctx->node = NULL;
2930 ctx->state = NGX_OK;
2931 ctx->valid = rn->valid;
2932 ctx->count = rn->nsrvs;
2933
2934 srvs = ngx_resolver_calloc(r, rn->nsrvs * sizeof(ngx_resolver_srv_name_t));
2935 if (srvs == NULL) {
2936 goto failed;
2937 }
2938
2939 ctx->srvs = srvs;
2940 ctx->nsrvs = rn->nsrvs;
2941
2942 if (ctx->event && ctx->event->timer_set) {
2943 ngx_del_timer(ctx->event);
2944 }
2945
2946 for (i = 0; i < (ngx_uint_t) rn->nsrvs; i++) {
2947 srvs[i].name.data = ngx_resolver_alloc(r, rn->u.srvs[i].name.len);
2948 if (srvs[i].name.data == NULL) {
2949 goto failed;
2950 }
2951
2952 srvs[i].name.len = rn->u.srvs[i].name.len;
2953 ngx_memcpy(srvs[i].name.data, rn->u.srvs[i].name.data,
2954 srvs[i].name.len);
2955
2956 cctx = ngx_resolve_start(r, NULL);
2957 if (cctx == NULL) {
2958 goto failed;
2959 }
2960
2961 cctx->name = srvs[i].name;
2962 cctx->handler = ngx_resolver_srv_names_handler;
2963 cctx->data = ctx;
2964 cctx->srvs = &srvs[i];
2965 cctx->timeout = ctx->timeout;
2966
2967 srvs[i].priority = rn->u.srvs[i].priority;
2968 srvs[i].weight = rn->u.srvs[i].weight;
2969 srvs[i].port = rn->u.srvs[i].port;
2970 srvs[i].ctx = cctx;
2971
2972 if (ngx_resolve_name(cctx) == NGX_ERROR) {
2973 srvs[i].ctx = NULL;
2974 goto failed;
2975 }
2976 }
2977
2978 return;
2979
2980 failed:
2981
2982 ctx->state = NGX_ERROR;
2983 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
2984
2985 ctx->handler(ctx);
2986 }
2987
2988
2989 static void
ngx_resolver_srv_names_handler(ngx_resolver_ctx_t * cctx)2990 ngx_resolver_srv_names_handler(ngx_resolver_ctx_t *cctx)
2991 {
2992 ngx_uint_t i;
2993 ngx_addr_t *addrs;
2994 ngx_resolver_t *r;
2995 ngx_sockaddr_t *sockaddr;
2996 ngx_resolver_ctx_t *ctx;
2997 ngx_resolver_srv_name_t *srv;
2998
2999 r = cctx->resolver;
3000 ctx = cctx->data;
3001 srv = cctx->srvs;
3002
3003 ctx->count--;
3004 ctx->async |= cctx->async;
3005
3006 srv->ctx = NULL;
3007 srv->state = cctx->state;
3008
3009 if (cctx->naddrs) {
3010
3011 ctx->valid = ngx_min(ctx->valid, cctx->valid);
3012
3013 addrs = ngx_resolver_calloc(r, cctx->naddrs * sizeof(ngx_addr_t));
3014 if (addrs == NULL) {
3015 srv->state = NGX_ERROR;
3016 goto done;
3017 }
3018
3019 sockaddr = ngx_resolver_alloc(r, cctx->naddrs * sizeof(ngx_sockaddr_t));
3020 if (sockaddr == NULL) {
3021 ngx_resolver_free(r, addrs);
3022 srv->state = NGX_ERROR;
3023 goto done;
3024 }
3025
3026 for (i = 0; i < cctx->naddrs; i++) {
3027 addrs[i].sockaddr = &sockaddr[i].sockaddr;
3028 addrs[i].socklen = cctx->addrs[i].socklen;
3029
3030 ngx_memcpy(&sockaddr[i], cctx->addrs[i].sockaddr,
3031 addrs[i].socklen);
3032
3033 ngx_inet_set_port(addrs[i].sockaddr, srv->port);
3034 }
3035
3036 srv->addrs = addrs;
3037 srv->naddrs = cctx->naddrs;
3038 }
3039
3040 done:
3041
3042 ngx_resolve_name_done(cctx);
3043
3044 if (ctx->count == 0) {
3045 ngx_resolver_report_srv(r, ctx);
3046 }
3047 }
3048
3049
3050 static void
ngx_resolver_process_ptr(ngx_resolver_t * r,u_char * buf,size_t n,ngx_uint_t ident,ngx_uint_t code,ngx_uint_t nan)3051 ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
3052 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan)
3053 {
3054 char *err;
3055 size_t len;
3056 in_addr_t addr;
3057 int32_t ttl;
3058 ngx_int_t octet;
3059 ngx_str_t name;
3060 ngx_uint_t mask, type, class, qident, a, i, start;
3061 ngx_queue_t *expire_queue;
3062 ngx_rbtree_t *tree;
3063 ngx_resolver_an_t *an;
3064 ngx_resolver_ctx_t *ctx, *next;
3065 ngx_resolver_node_t *rn;
3066 #if (NGX_HAVE_INET6)
3067 uint32_t hash;
3068 ngx_int_t digit;
3069 struct in6_addr addr6;
3070 #endif
3071
3072 if (ngx_resolver_copy(r, &name, buf,
3073 buf + sizeof(ngx_resolver_hdr_t), buf + n)
3074 != NGX_OK)
3075 {
3076 return;
3077 }
3078
3079 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
3080
3081 /* AF_INET */
3082
3083 addr = 0;
3084 i = sizeof(ngx_resolver_hdr_t);
3085
3086 for (mask = 0; mask < 32; mask += 8) {
3087 len = buf[i++];
3088
3089 octet = ngx_atoi(&buf[i], len);
3090 if (octet == NGX_ERROR || octet > 255) {
3091 goto invalid_in_addr_arpa;
3092 }
3093
3094 addr += octet << mask;
3095 i += len;
3096 }
3097
3098 if (ngx_strcasecmp(&buf[i], (u_char *) "\7in-addr\4arpa") == 0) {
3099 i += sizeof("\7in-addr\4arpa");
3100
3101 /* lock addr mutex */
3102
3103 rn = ngx_resolver_lookup_addr(r, addr);
3104
3105 tree = &r->addr_rbtree;
3106 expire_queue = &r->addr_expire_queue;
3107
3108 goto valid;
3109 }
3110
3111 invalid_in_addr_arpa:
3112
3113 #if (NGX_HAVE_INET6)
3114
3115 i = sizeof(ngx_resolver_hdr_t);
3116
3117 for (octet = 15; octet >= 0; octet--) {
3118 if (buf[i++] != '\1') {
3119 goto invalid_ip6_arpa;
3120 }
3121
3122 digit = ngx_hextoi(&buf[i++], 1);
3123 if (digit == NGX_ERROR) {
3124 goto invalid_ip6_arpa;
3125 }
3126
3127 addr6.s6_addr[octet] = (u_char) digit;
3128
3129 if (buf[i++] != '\1') {
3130 goto invalid_ip6_arpa;
3131 }
3132
3133 digit = ngx_hextoi(&buf[i++], 1);
3134 if (digit == NGX_ERROR) {
3135 goto invalid_ip6_arpa;
3136 }
3137
3138 addr6.s6_addr[octet] += (u_char) (digit * 16);
3139 }
3140
3141 if (ngx_strcasecmp(&buf[i], (u_char *) "\3ip6\4arpa") == 0) {
3142 i += sizeof("\3ip6\4arpa");
3143
3144 /* lock addr mutex */
3145
3146 hash = ngx_crc32_short(addr6.s6_addr, 16);
3147 rn = ngx_resolver_lookup_addr6(r, &addr6, hash);
3148
3149 tree = &r->addr6_rbtree;
3150 expire_queue = &r->addr6_expire_queue;
3151
3152 goto valid;
3153 }
3154
3155 invalid_ip6_arpa:
3156 #endif
3157
3158 ngx_log_error(r->log_level, r->log, 0,
3159 "invalid in-addr.arpa or ip6.arpa name in DNS response");
3160 ngx_resolver_free(r, name.data);
3161 return;
3162
3163 valid:
3164
3165 if (rn == NULL || rn->query == NULL) {
3166 ngx_log_error(r->log_level, r->log, 0,
3167 "unexpected response for %V", &name);
3168 ngx_resolver_free(r, name.data);
3169 goto failed;
3170 }
3171
3172 qident = (rn->query[0] << 8) + rn->query[1];
3173
3174 if (ident != qident) {
3175 ngx_log_error(r->log_level, r->log, 0,
3176 "wrong ident %ui response for %V, expect %ui",
3177 ident, &name, qident);
3178 ngx_resolver_free(r, name.data);
3179 goto failed;
3180 }
3181
3182 ngx_resolver_free(r, name.data);
3183
3184 if (code == 0 && nan == 0) {
3185 code = NGX_RESOLVE_NXDOMAIN;
3186 }
3187
3188 if (code) {
3189 next = rn->waiting;
3190 rn->waiting = NULL;
3191
3192 ngx_queue_remove(&rn->queue);
3193
3194 ngx_rbtree_delete(tree, &rn->node);
3195
3196 /* unlock addr mutex */
3197
3198 while (next) {
3199 ctx = next;
3200 ctx->state = code;
3201 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
3202 next = ctx->next;
3203
3204 ctx->handler(ctx);
3205 }
3206
3207 ngx_resolver_free_node(r, rn);
3208
3209 return;
3210 }
3211
3212 i += sizeof(ngx_resolver_qs_t);
3213
3214 for (a = 0; a < nan; a++) {
3215
3216 start = i;
3217
3218 while (i < n) {
3219
3220 if (buf[i] & 0xc0) {
3221 i += 2;
3222 goto found;
3223 }
3224
3225 if (buf[i] == 0) {
3226 i++;
3227 goto test_length;
3228 }
3229
3230 i += 1 + buf[i];
3231 }
3232
3233 goto short_response;
3234
3235 test_length:
3236
3237 if (i - start < 2) {
3238 err = "invalid name in DNS response";
3239 goto invalid;
3240 }
3241
3242 found:
3243
3244 if (i + sizeof(ngx_resolver_an_t) >= n) {
3245 goto short_response;
3246 }
3247
3248 an = (ngx_resolver_an_t *) &buf[i];
3249
3250 type = (an->type_hi << 8) + an->type_lo;
3251 class = (an->class_hi << 8) + an->class_lo;
3252 len = (an->len_hi << 8) + an->len_lo;
3253 ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
3254 + (an->ttl[2] << 8) + (an->ttl[3]);
3255
3256 if (class != 1) {
3257 ngx_log_error(r->log_level, r->log, 0,
3258 "unexpected RR class %ui", class);
3259 goto failed;
3260 }
3261
3262 if (ttl < 0) {
3263 ttl = 0;
3264 }
3265
3266 ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
3267 "resolver qt:%ui cl:%ui len:%uz",
3268 type, class, len);
3269
3270 i += sizeof(ngx_resolver_an_t);
3271
3272 switch (type) {
3273
3274 case NGX_RESOLVE_PTR:
3275
3276 goto ptr;
3277
3278 case NGX_RESOLVE_CNAME:
3279
3280 break;
3281
3282 default:
3283
3284 ngx_log_error(r->log_level, r->log, 0,
3285 "unexpected RR type %ui", type);
3286 }
3287
3288 i += len;
3289 }
3290
3291 /* unlock addr mutex */
3292
3293 ngx_log_error(r->log_level, r->log, 0,
3294 "no PTR type in DNS response");
3295 return;
3296
3297 ptr:
3298
3299 if (ngx_resolver_copy(r, &name, buf, buf + i, buf + n) != NGX_OK) {
3300 goto failed;
3301 }
3302
3303 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name);
3304
3305 if (name.len != (size_t) rn->nlen
3306 || ngx_strncmp(name.data, rn->name, name.len) != 0)
3307 {
3308 if (rn->nlen) {
3309 ngx_resolver_free(r, rn->name);
3310 }
3311
3312 rn->nlen = (u_short) name.len;
3313 rn->name = name.data;
3314
3315 name.data = ngx_resolver_dup(r, rn->name, name.len);
3316 if (name.data == NULL) {
3317 goto failed;
3318 }
3319 }
3320
3321 ngx_queue_remove(&rn->queue);
3322
3323 rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
3324 rn->expire = ngx_time() + r->expire;
3325
3326 ngx_queue_insert_head(expire_queue, &rn->queue);
3327
3328 next = rn->waiting;
3329 rn->waiting = NULL;
3330
3331 /* unlock addr mutex */
3332
3333 while (next) {
3334 ctx = next;
3335 ctx->state = NGX_OK;
3336 ctx->valid = rn->valid;
3337 ctx->name = name;
3338 next = ctx->next;
3339
3340 ctx->handler(ctx);
3341 }
3342
3343 ngx_resolver_free(r, name.data);
3344
3345 return;
3346
3347 short_response:
3348
3349 err = "short DNS response";
3350
3351 invalid:
3352
3353 /* unlock addr mutex */
3354
3355 ngx_log_error(r->log_level, r->log, 0, err);
3356
3357 return;
3358
3359 failed:
3360
3361 /* unlock addr mutex */
3362
3363 return;
3364 }
3365
3366
3367 static ngx_resolver_node_t *
ngx_resolver_lookup_name(ngx_resolver_t * r,ngx_str_t * name,uint32_t hash)3368 ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
3369 {
3370 ngx_int_t rc;
3371 ngx_rbtree_node_t *node, *sentinel;
3372 ngx_resolver_node_t *rn;
3373
3374 node = r->name_rbtree.root;
3375 sentinel = r->name_rbtree.sentinel;
3376
3377 while (node != sentinel) {
3378
3379 if (hash < node->key) {
3380 node = node->left;
3381 continue;
3382 }
3383
3384 if (hash > node->key) {
3385 node = node->right;
3386 continue;
3387 }
3388
3389 /* hash == node->key */
3390
3391 rn = ngx_resolver_node(node);
3392
3393 rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen);
3394
3395 if (rc == 0) {
3396 return rn;
3397 }
3398
3399 node = (rc < 0) ? node->left : node->right;
3400 }
3401
3402 /* not found */
3403
3404 return NULL;
3405 }
3406
3407
3408 static ngx_resolver_node_t *
ngx_resolver_lookup_srv(ngx_resolver_t * r,ngx_str_t * name,uint32_t hash)3409 ngx_resolver_lookup_srv(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
3410 {
3411 ngx_int_t rc;
3412 ngx_rbtree_node_t *node, *sentinel;
3413 ngx_resolver_node_t *rn;
3414
3415 node = r->srv_rbtree.root;
3416 sentinel = r->srv_rbtree.sentinel;
3417
3418 while (node != sentinel) {
3419
3420 if (hash < node->key) {
3421 node = node->left;
3422 continue;
3423 }
3424
3425 if (hash > node->key) {
3426 node = node->right;
3427 continue;
3428 }
3429
3430 /* hash == node->key */
3431
3432 rn = ngx_resolver_node(node);
3433
3434 rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen);
3435
3436 if (rc == 0) {
3437 return rn;
3438 }
3439
3440 node = (rc < 0) ? node->left : node->right;
3441 }
3442
3443 /* not found */
3444
3445 return NULL;
3446 }
3447
3448
3449 static ngx_resolver_node_t *
ngx_resolver_lookup_addr(ngx_resolver_t * r,in_addr_t addr)3450 ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr)
3451 {
3452 ngx_rbtree_node_t *node, *sentinel;
3453
3454 node = r->addr_rbtree.root;
3455 sentinel = r->addr_rbtree.sentinel;
3456
3457 while (node != sentinel) {
3458
3459 if (addr < node->key) {
3460 node = node->left;
3461 continue;
3462 }
3463
3464 if (addr > node->key) {
3465 node = node->right;
3466 continue;
3467 }
3468
3469 /* addr == node->key */
3470
3471 return ngx_resolver_node(node);
3472 }
3473
3474 /* not found */
3475
3476 return NULL;
3477 }
3478
3479
3480 #if (NGX_HAVE_INET6)
3481
3482 static ngx_resolver_node_t *
ngx_resolver_lookup_addr6(ngx_resolver_t * r,struct in6_addr * addr,uint32_t hash)3483 ngx_resolver_lookup_addr6(ngx_resolver_t *r, struct in6_addr *addr,
3484 uint32_t hash)
3485 {
3486 ngx_int_t rc;
3487 ngx_rbtree_node_t *node, *sentinel;
3488 ngx_resolver_node_t *rn;
3489
3490 node = r->addr6_rbtree.root;
3491 sentinel = r->addr6_rbtree.sentinel;
3492
3493 while (node != sentinel) {
3494
3495 if (hash < node->key) {
3496 node = node->left;
3497 continue;
3498 }
3499
3500 if (hash > node->key) {
3501 node = node->right;
3502 continue;
3503 }
3504
3505 /* hash == node->key */
3506
3507 rn = ngx_resolver_node(node);
3508
3509 rc = ngx_memcmp(addr, &rn->addr6, 16);
3510
3511 if (rc == 0) {
3512 return rn;
3513 }
3514
3515 node = (rc < 0) ? node->left : node->right;
3516 }
3517
3518 /* not found */
3519
3520 return NULL;
3521 }
3522
3523 #endif
3524
3525
3526 static void
ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t * temp,ngx_rbtree_node_t * node,ngx_rbtree_node_t * sentinel)3527 ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
3528 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
3529 {
3530 ngx_rbtree_node_t **p;
3531 ngx_resolver_node_t *rn, *rn_temp;
3532
3533 for ( ;; ) {
3534
3535 if (node->key < temp->key) {
3536
3537 p = &temp->left;
3538
3539 } else if (node->key > temp->key) {
3540
3541 p = &temp->right;
3542
3543 } else { /* node->key == temp->key */
3544
3545 rn = ngx_resolver_node(node);
3546 rn_temp = ngx_resolver_node(temp);
3547
3548 p = (ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen, rn_temp->nlen)
3549 < 0) ? &temp->left : &temp->right;
3550 }
3551
3552 if (*p == sentinel) {
3553 break;
3554 }
3555
3556 temp = *p;
3557 }
3558
3559 *p = node;
3560 node->parent = temp;
3561 node->left = sentinel;
3562 node->right = sentinel;
3563 ngx_rbt_red(node);
3564 }
3565
3566
3567 #if (NGX_HAVE_INET6)
3568
3569 static void
ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t * temp,ngx_rbtree_node_t * node,ngx_rbtree_node_t * sentinel)3570 ngx_resolver_rbtree_insert_addr6_value(ngx_rbtree_node_t *temp,
3571 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
3572 {
3573 ngx_rbtree_node_t **p;
3574 ngx_resolver_node_t *rn, *rn_temp;
3575
3576 for ( ;; ) {
3577
3578 if (node->key < temp->key) {
3579
3580 p = &temp->left;
3581
3582 } else if (node->key > temp->key) {
3583
3584 p = &temp->right;
3585
3586 } else { /* node->key == temp->key */
3587
3588 rn = ngx_resolver_node(node);
3589 rn_temp = ngx_resolver_node(temp);
3590
3591 p = (ngx_memcmp(&rn->addr6, &rn_temp->addr6, 16)
3592 < 0) ? &temp->left : &temp->right;
3593 }
3594
3595 if (*p == sentinel) {
3596 break;
3597 }
3598
3599 temp = *p;
3600 }
3601
3602 *p = node;
3603 node->parent = temp;
3604 node->left = sentinel;
3605 node->right = sentinel;
3606 ngx_rbt_red(node);
3607 }
3608
3609 #endif
3610
3611
3612 static ngx_int_t
ngx_resolver_create_name_query(ngx_resolver_t * r,ngx_resolver_node_t * rn,ngx_str_t * name)3613 ngx_resolver_create_name_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
3614 ngx_str_t *name)
3615 {
3616 u_char *p, *s;
3617 size_t len, nlen;
3618 ngx_uint_t ident;
3619 ngx_resolver_qs_t *qs;
3620 ngx_resolver_hdr_t *query;
3621
3622 nlen = name->len ? (1 + name->len + 1) : 1;
3623
3624 len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t);
3625
3626 #if (NGX_HAVE_INET6)
3627 p = ngx_resolver_alloc(r, r->ipv6 ? len * 2 : len);
3628 #else
3629 p = ngx_resolver_alloc(r, len);
3630 #endif
3631 if (p == NULL) {
3632 return NGX_ERROR;
3633 }
3634
3635 rn->qlen = (u_short) len;
3636 rn->query = p;
3637
3638 #if (NGX_HAVE_INET6)
3639 if (r->ipv6) {
3640 rn->query6 = p + len;
3641 }
3642 #endif
3643
3644 query = (ngx_resolver_hdr_t *) p;
3645
3646 ident = ngx_random();
3647
3648 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
3649 "resolve: \"%V\" A %i", name, ident & 0xffff);
3650
3651 query->ident_hi = (u_char) ((ident >> 8) & 0xff);
3652 query->ident_lo = (u_char) (ident & 0xff);
3653
3654 /* recursion query */
3655 query->flags_hi = 1; query->flags_lo = 0;
3656
3657 /* one question */
3658 query->nqs_hi = 0; query->nqs_lo = 1;
3659 query->nan_hi = 0; query->nan_lo = 0;
3660 query->nns_hi = 0; query->nns_lo = 0;
3661 query->nar_hi = 0; query->nar_lo = 0;
3662
3663 p += sizeof(ngx_resolver_hdr_t) + nlen;
3664
3665 qs = (ngx_resolver_qs_t *) p;
3666
3667 /* query type */
3668 qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_A;
3669
3670 /* IN query class */
3671 qs->class_hi = 0; qs->class_lo = 1;
3672
3673 /* convert "www.example.com" to "\3www\7example\3com\0" */
3674
3675 len = 0;
3676 p--;
3677 *p-- = '\0';
3678
3679 if (name->len == 0) {
3680 return NGX_DECLINED;
3681 }
3682
3683 for (s = name->data + name->len - 1; s >= name->data; s--) {
3684 if (*s != '.') {
3685 *p = *s;
3686 len++;
3687
3688 } else {
3689 if (len == 0 || len > 255) {
3690 return NGX_DECLINED;
3691 }
3692
3693 *p = (u_char) len;
3694 len = 0;
3695 }
3696
3697 p--;
3698 }
3699
3700 if (len == 0 || len > 255) {
3701 return NGX_DECLINED;
3702 }
3703
3704 *p = (u_char) len;
3705
3706 #if (NGX_HAVE_INET6)
3707 if (!r->ipv6) {
3708 return NGX_OK;
3709 }
3710
3711 p = rn->query6;
3712
3713 ngx_memcpy(p, rn->query, rn->qlen);
3714
3715 query = (ngx_resolver_hdr_t *) p;
3716
3717 ident = ngx_random();
3718
3719 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
3720 "resolve: \"%V\" AAAA %i", name, ident & 0xffff);
3721
3722 query->ident_hi = (u_char) ((ident >> 8) & 0xff);
3723 query->ident_lo = (u_char) (ident & 0xff);
3724
3725 p += sizeof(ngx_resolver_hdr_t) + nlen;
3726
3727 qs = (ngx_resolver_qs_t *) p;
3728
3729 qs->type_lo = NGX_RESOLVE_AAAA;
3730 #endif
3731
3732 return NGX_OK;
3733 }
3734
3735
3736 static ngx_int_t
ngx_resolver_create_srv_query(ngx_resolver_t * r,ngx_resolver_node_t * rn,ngx_str_t * name)3737 ngx_resolver_create_srv_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
3738 ngx_str_t *name)
3739 {
3740 u_char *p, *s;
3741 size_t len, nlen;
3742 ngx_uint_t ident;
3743 ngx_resolver_qs_t *qs;
3744 ngx_resolver_hdr_t *query;
3745
3746 nlen = name->len ? (1 + name->len + 1) : 1;
3747
3748 len = sizeof(ngx_resolver_hdr_t) + nlen + sizeof(ngx_resolver_qs_t);
3749
3750 p = ngx_resolver_alloc(r, len);
3751 if (p == NULL) {
3752 return NGX_ERROR;
3753 }
3754
3755 rn->qlen = (u_short) len;
3756 rn->query = p;
3757
3758 query = (ngx_resolver_hdr_t *) p;
3759
3760 ident = ngx_random();
3761
3762 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
3763 "resolve: \"%V\" SRV %i", name, ident & 0xffff);
3764
3765 query->ident_hi = (u_char) ((ident >> 8) & 0xff);
3766 query->ident_lo = (u_char) (ident & 0xff);
3767
3768 /* recursion query */
3769 query->flags_hi = 1; query->flags_lo = 0;
3770
3771 /* one question */
3772 query->nqs_hi = 0; query->nqs_lo = 1;
3773 query->nan_hi = 0; query->nan_lo = 0;
3774 query->nns_hi = 0; query->nns_lo = 0;
3775 query->nar_hi = 0; query->nar_lo = 0;
3776
3777 p += sizeof(ngx_resolver_hdr_t) + nlen;
3778
3779 qs = (ngx_resolver_qs_t *) p;
3780
3781 /* query type */
3782 qs->type_hi = 0; qs->type_lo = NGX_RESOLVE_SRV;
3783
3784 /* IN query class */
3785 qs->class_hi = 0; qs->class_lo = 1;
3786
3787 /* converts "www.example.com" to "\3www\7example\3com\0" */
3788
3789 len = 0;
3790 p--;
3791 *p-- = '\0';
3792
3793 if (name->len == 0) {
3794 return NGX_DECLINED;
3795 }
3796
3797 for (s = name->data + name->len - 1; s >= name->data; s--) {
3798 if (*s != '.') {
3799 *p = *s;
3800 len++;
3801
3802 } else {
3803 if (len == 0 || len > 255) {
3804 return NGX_DECLINED;
3805 }
3806
3807 *p = (u_char) len;
3808 len = 0;
3809 }
3810
3811 p--;
3812 }
3813
3814 if (len == 0 || len > 255) {
3815 return NGX_DECLINED;
3816 }
3817
3818 *p = (u_char) len;
3819
3820 return NGX_OK;
3821 }
3822
3823
3824 static ngx_int_t
ngx_resolver_create_addr_query(ngx_resolver_t * r,ngx_resolver_node_t * rn,ngx_resolver_addr_t * addr)3825 ngx_resolver_create_addr_query(ngx_resolver_t *r, ngx_resolver_node_t *rn,
3826 ngx_resolver_addr_t *addr)
3827 {
3828 u_char *p, *d;
3829 size_t len;
3830 in_addr_t inaddr;
3831 ngx_int_t n;
3832 ngx_uint_t ident;
3833 ngx_resolver_hdr_t *query;
3834 struct sockaddr_in *sin;
3835 #if (NGX_HAVE_INET6)
3836 struct sockaddr_in6 *sin6;
3837 #endif
3838
3839 switch (addr->sockaddr->sa_family) {
3840
3841 #if (NGX_HAVE_INET6)
3842 case AF_INET6:
3843 len = sizeof(ngx_resolver_hdr_t)
3844 + 64 + sizeof(".ip6.arpa.") - 1
3845 + sizeof(ngx_resolver_qs_t);
3846
3847 break;
3848 #endif
3849
3850 default: /* AF_INET */
3851 len = sizeof(ngx_resolver_hdr_t)
3852 + sizeof(".255.255.255.255.in-addr.arpa.") - 1
3853 + sizeof(ngx_resolver_qs_t);
3854 }
3855
3856 p = ngx_resolver_alloc(r, len);
3857 if (p == NULL) {
3858 return NGX_ERROR;
3859 }
3860
3861 rn->query = p;
3862 query = (ngx_resolver_hdr_t *) p;
3863
3864 ident = ngx_random();
3865
3866 query->ident_hi = (u_char) ((ident >> 8) & 0xff);
3867 query->ident_lo = (u_char) (ident & 0xff);
3868
3869 /* recursion query */
3870 query->flags_hi = 1; query->flags_lo = 0;
3871
3872 /* one question */
3873 query->nqs_hi = 0; query->nqs_lo = 1;
3874 query->nan_hi = 0; query->nan_lo = 0;
3875 query->nns_hi = 0; query->nns_lo = 0;
3876 query->nar_hi = 0; query->nar_lo = 0;
3877
3878 p += sizeof(ngx_resolver_hdr_t);
3879
3880 switch (addr->sockaddr->sa_family) {
3881
3882 #if (NGX_HAVE_INET6)
3883 case AF_INET6:
3884 sin6 = (struct sockaddr_in6 *) addr->sockaddr;
3885
3886 for (n = 15; n >= 0; n--) {
3887 p = ngx_sprintf(p, "\1%xd\1%xd",
3888 sin6->sin6_addr.s6_addr[n] & 0xf,
3889 (sin6->sin6_addr.s6_addr[n] >> 4) & 0xf);
3890 }
3891
3892 p = ngx_cpymem(p, "\3ip6\4arpa\0", 10);
3893
3894 break;
3895 #endif
3896
3897 default: /* AF_INET */
3898
3899 sin = (struct sockaddr_in *) addr->sockaddr;
3900 inaddr = ntohl(sin->sin_addr.s_addr);
3901
3902 for (n = 0; n < 32; n += 8) {
3903 d = ngx_sprintf(&p[1], "%ud", (inaddr >> n) & 0xff);
3904 *p = (u_char) (d - &p[1]);
3905 p = d;
3906 }
3907
3908 p = ngx_cpymem(p, "\7in-addr\4arpa\0", 14);
3909 }
3910
3911 /* query type "PTR", IN query class */
3912 p = ngx_cpymem(p, "\0\14\0\1", 4);
3913
3914 rn->qlen = (u_short) (p - rn->query);
3915
3916 return NGX_OK;
3917 }
3918
3919
3920 static ngx_int_t
ngx_resolver_copy(ngx_resolver_t * r,ngx_str_t * name,u_char * buf,u_char * src,u_char * last)3921 ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src,
3922 u_char *last)
3923 {
3924 char *err;
3925 u_char *p, *dst;
3926 ssize_t len;
3927 ngx_uint_t i, n;
3928
3929 p = src;
3930 len = -1;
3931
3932 /*
3933 * compression pointers allow to create endless loop, so we set limit;
3934 * 128 pointers should be enough to store 255-byte name
3935 */
3936
3937 for (i = 0; i < 128; i++) {
3938 n = *p++;
3939
3940 if (n == 0) {
3941 goto done;
3942 }
3943
3944 if (n & 0xc0) {
3945 n = ((n & 0x3f) << 8) + *p;
3946 p = &buf[n];
3947
3948 } else {
3949 len += 1 + n;
3950 p = &p[n];
3951 }
3952
3953 if (p >= last) {
3954 err = "name is out of response";
3955 goto invalid;
3956 }
3957 }
3958
3959 err = "compression pointers loop";
3960
3961 invalid:
3962
3963 ngx_log_error(r->log_level, r->log, 0, err);
3964
3965 return NGX_ERROR;
3966
3967 done:
3968
3969 if (name == NULL) {
3970 return NGX_OK;
3971 }
3972
3973 if (len == -1) {
3974 ngx_str_null(name);
3975 return NGX_OK;
3976 }
3977
3978 dst = ngx_resolver_alloc(r, len);
3979 if (dst == NULL) {
3980 return NGX_ERROR;
3981 }
3982
3983 name->data = dst;
3984
3985 n = *src++;
3986
3987 for ( ;; ) {
3988 if (n & 0xc0) {
3989 n = ((n & 0x3f) << 8) + *src;
3990 src = &buf[n];
3991
3992 n = *src++;
3993
3994 } else {
3995 ngx_strlow(dst, src, n);
3996 dst += n;
3997 src += n;
3998
3999 n = *src++;
4000
4001 if (n != 0) {
4002 *dst++ = '.';
4003 }
4004 }
4005
4006 if (n == 0) {
4007 name->len = dst - name->data;
4008 return NGX_OK;
4009 }
4010 }
4011 }
4012
4013
4014 static ngx_int_t
ngx_resolver_set_timeout(ngx_resolver_t * r,ngx_resolver_ctx_t * ctx)4015 ngx_resolver_set_timeout(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
4016 {
4017 if (ctx->event || ctx->timeout == 0) {
4018 return NGX_OK;
4019 }
4020
4021 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
4022 if (ctx->event == NULL) {
4023 return NGX_ERROR;
4024 }
4025
4026 ctx->event->handler = ngx_resolver_timeout_handler;
4027 ctx->event->data = ctx;
4028 ctx->event->log = r->log;
4029 ctx->event->cancelable = ctx->cancelable;
4030 ctx->ident = -1;
4031
4032 ngx_add_timer(ctx->event, ctx->timeout);
4033
4034 return NGX_OK;
4035 }
4036
4037
4038 static void
ngx_resolver_timeout_handler(ngx_event_t * ev)4039 ngx_resolver_timeout_handler(ngx_event_t *ev)
4040 {
4041 ngx_resolver_ctx_t *ctx;
4042
4043 ctx = ev->data;
4044
4045 ctx->state = NGX_RESOLVE_TIMEDOUT;
4046
4047 ctx->handler(ctx);
4048 }
4049
4050
4051 static void
ngx_resolver_free_node(ngx_resolver_t * r,ngx_resolver_node_t * rn)4052 ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn)
4053 {
4054 ngx_uint_t i;
4055
4056 /* lock alloc mutex */
4057
4058 if (rn->query) {
4059 ngx_resolver_free_locked(r, rn->query);
4060 }
4061
4062 if (rn->name) {
4063 ngx_resolver_free_locked(r, rn->name);
4064 }
4065
4066 if (rn->cnlen) {
4067 ngx_resolver_free_locked(r, rn->u.cname);
4068 }
4069
4070 if (rn->naddrs > 1 && rn->naddrs != (u_short) -1) {
4071 ngx_resolver_free_locked(r, rn->u.addrs);
4072 }
4073
4074 #if (NGX_HAVE_INET6)
4075 if (rn->naddrs6 > 1 && rn->naddrs6 != (u_short) -1) {
4076 ngx_resolver_free_locked(r, rn->u6.addrs6);
4077 }
4078 #endif
4079
4080 if (rn->nsrvs) {
4081 for (i = 0; i < (ngx_uint_t) rn->nsrvs; i++) {
4082 if (rn->u.srvs[i].name.data) {
4083 ngx_resolver_free_locked(r, rn->u.srvs[i].name.data);
4084 }
4085 }
4086
4087 ngx_resolver_free_locked(r, rn->u.srvs);
4088 }
4089
4090 ngx_resolver_free_locked(r, rn);
4091
4092 /* unlock alloc mutex */
4093 }
4094
4095
4096 static void *
ngx_resolver_alloc(ngx_resolver_t * r,size_t size)4097 ngx_resolver_alloc(ngx_resolver_t *r, size_t size)
4098 {
4099 u_char *p;
4100
4101 /* lock alloc mutex */
4102
4103 p = ngx_alloc(size, r->log);
4104
4105 /* unlock alloc mutex */
4106
4107 return p;
4108 }
4109
4110
4111 static void *
ngx_resolver_calloc(ngx_resolver_t * r,size_t size)4112 ngx_resolver_calloc(ngx_resolver_t *r, size_t size)
4113 {
4114 u_char *p;
4115
4116 p = ngx_resolver_alloc(r, size);
4117
4118 if (p) {
4119 ngx_memzero(p, size);
4120 }
4121
4122 return p;
4123 }
4124
4125
4126 static void
ngx_resolver_free(ngx_resolver_t * r,void * p)4127 ngx_resolver_free(ngx_resolver_t *r, void *p)
4128 {
4129 /* lock alloc mutex */
4130
4131 ngx_free(p);
4132
4133 /* unlock alloc mutex */
4134 }
4135
4136
4137 static void
ngx_resolver_free_locked(ngx_resolver_t * r,void * p)4138 ngx_resolver_free_locked(ngx_resolver_t *r, void *p)
4139 {
4140 ngx_free(p);
4141 }
4142
4143
4144 static void *
ngx_resolver_dup(ngx_resolver_t * r,void * src,size_t size)4145 ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size)
4146 {
4147 void *dst;
4148
4149 dst = ngx_resolver_alloc(r, size);
4150
4151 if (dst == NULL) {
4152 return dst;
4153 }
4154
4155 ngx_memcpy(dst, src, size);
4156
4157 return dst;
4158 }
4159
4160
4161 static ngx_resolver_addr_t *
ngx_resolver_export(ngx_resolver_t * r,ngx_resolver_node_t * rn,ngx_uint_t rotate)4162 ngx_resolver_export(ngx_resolver_t *r, ngx_resolver_node_t *rn,
4163 ngx_uint_t rotate)
4164 {
4165 ngx_uint_t d, i, j, n;
4166 in_addr_t *addr;
4167 ngx_sockaddr_t *sockaddr;
4168 struct sockaddr_in *sin;
4169 ngx_resolver_addr_t *dst;
4170 #if (NGX_HAVE_INET6)
4171 struct in6_addr *addr6;
4172 struct sockaddr_in6 *sin6;
4173 #endif
4174
4175 n = rn->naddrs;
4176 #if (NGX_HAVE_INET6)
4177 n += rn->naddrs6;
4178 #endif
4179
4180 dst = ngx_resolver_calloc(r, n * sizeof(ngx_resolver_addr_t));
4181 if (dst == NULL) {
4182 return NULL;
4183 }
4184
4185 sockaddr = ngx_resolver_calloc(r, n * sizeof(ngx_sockaddr_t));
4186 if (sockaddr == NULL) {
4187 ngx_resolver_free(r, dst);
4188 return NULL;
4189 }
4190
4191 i = 0;
4192 d = rotate ? ngx_random() % n : 0;
4193
4194 if (rn->naddrs) {
4195 j = rotate ? ngx_random() % rn->naddrs : 0;
4196
4197 addr = (rn->naddrs == 1) ? &rn->u.addr : rn->u.addrs;
4198
4199 do {
4200 sin = &sockaddr[d].sockaddr_in;
4201 sin->sin_family = AF_INET;
4202 sin->sin_addr.s_addr = addr[j++];
4203 dst[d].sockaddr = (struct sockaddr *) sin;
4204 dst[d++].socklen = sizeof(struct sockaddr_in);
4205
4206 if (d == n) {
4207 d = 0;
4208 }
4209
4210 if (j == (ngx_uint_t) rn->naddrs) {
4211 j = 0;
4212 }
4213 } while (++i < (ngx_uint_t) rn->naddrs);
4214 }
4215
4216 #if (NGX_HAVE_INET6)
4217 if (rn->naddrs6) {
4218 j = rotate ? ngx_random() % rn->naddrs6 : 0;
4219
4220 addr6 = (rn->naddrs6 == 1) ? &rn->u6.addr6 : rn->u6.addrs6;
4221
4222 do {
4223 sin6 = &sockaddr[d].sockaddr_in6;
4224 sin6->sin6_family = AF_INET6;
4225 ngx_memcpy(sin6->sin6_addr.s6_addr, addr6[j++].s6_addr, 16);
4226 dst[d].sockaddr = (struct sockaddr *) sin6;
4227 dst[d++].socklen = sizeof(struct sockaddr_in6);
4228
4229 if (d == n) {
4230 d = 0;
4231 }
4232
4233 if (j == rn->naddrs6) {
4234 j = 0;
4235 }
4236 } while (++i < n);
4237 }
4238 #endif
4239
4240 return dst;
4241 }
4242
4243
4244 static void
ngx_resolver_report_srv(ngx_resolver_t * r,ngx_resolver_ctx_t * ctx)4245 ngx_resolver_report_srv(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
4246 {
4247 ngx_uint_t naddrs, nsrvs, nw, i, j, k, l, m, n, w;
4248 ngx_resolver_addr_t *addrs;
4249 ngx_resolver_srv_name_t *srvs;
4250
4251 srvs = ctx->srvs;
4252 nsrvs = ctx->nsrvs;
4253
4254 naddrs = 0;
4255
4256 for (i = 0; i < nsrvs; i++) {
4257 if (srvs[i].state == NGX_ERROR) {
4258 ctx->state = NGX_ERROR;
4259 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
4260
4261 ctx->handler(ctx);
4262 return;
4263 }
4264
4265 naddrs += srvs[i].naddrs;
4266 }
4267
4268 if (naddrs == 0) {
4269 ctx->state = srvs[0].state;
4270
4271 for (i = 0; i < nsrvs; i++) {
4272 if (srvs[i].state == NGX_RESOLVE_NXDOMAIN) {
4273 ctx->state = NGX_RESOLVE_NXDOMAIN;
4274 break;
4275 }
4276 }
4277
4278 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
4279
4280 ctx->handler(ctx);
4281 return;
4282 }
4283
4284 addrs = ngx_resolver_calloc(r, naddrs * sizeof(ngx_resolver_addr_t));
4285 if (addrs == NULL) {
4286 ctx->state = NGX_ERROR;
4287 ctx->valid = ngx_time() + (r->valid ? r->valid : 10);
4288
4289 ctx->handler(ctx);
4290 return;
4291 }
4292
4293 i = 0;
4294 n = 0;
4295
4296 do {
4297 nw = 0;
4298
4299 for (j = i; j < nsrvs; j++) {
4300 if (srvs[j].priority != srvs[i].priority) {
4301 break;
4302 }
4303
4304 nw += srvs[j].naddrs * srvs[j].weight;
4305 }
4306
4307 if (nw == 0) {
4308 goto next_srv;
4309 }
4310
4311 w = ngx_random() % nw;
4312
4313 for (k = i; k < j; k++) {
4314 if (w < srvs[k].naddrs * srvs[k].weight) {
4315 break;
4316 }
4317
4318 w -= srvs[k].naddrs * srvs[k].weight;
4319 }
4320
4321 for (l = i; l < j; l++) {
4322
4323 for (m = 0; m < srvs[k].naddrs; m++) {
4324 addrs[n].socklen = srvs[k].addrs[m].socklen;
4325 addrs[n].sockaddr = srvs[k].addrs[m].sockaddr;
4326 addrs[n].name = srvs[k].name;
4327 addrs[n].priority = srvs[k].priority;
4328 addrs[n].weight = srvs[k].weight;
4329 n++;
4330 }
4331
4332 if (++k == j) {
4333 k = i;
4334 }
4335 }
4336
4337 next_srv:
4338
4339 i = j;
4340
4341 } while (i < ctx->nsrvs);
4342
4343 ctx->state = NGX_OK;
4344 ctx->addrs = addrs;
4345 ctx->naddrs = naddrs;
4346
4347 ctx->handler(ctx);
4348
4349 ngx_resolver_free(r, addrs);
4350 }
4351
4352
4353 char *
ngx_resolver_strerror(ngx_int_t err)4354 ngx_resolver_strerror(ngx_int_t err)
4355 {
4356 static char *errors[] = {
4357 "Format error", /* FORMERR */
4358 "Server failure", /* SERVFAIL */
4359 "Host not found", /* NXDOMAIN */
4360 "Unimplemented", /* NOTIMP */
4361 "Operation refused" /* REFUSED */
4362 };
4363
4364 if (err > 0 && err < 6) {
4365 return errors[err - 1];
4366 }
4367
4368 if (err == NGX_RESOLVE_TIMEDOUT) {
4369 return "Operation timed out";
4370 }
4371
4372 return "Unknown error";
4373 }
4374
4375
4376 static u_char *
ngx_resolver_log_error(ngx_log_t * log,u_char * buf,size_t len)4377 ngx_resolver_log_error(ngx_log_t *log, u_char *buf, size_t len)
4378 {
4379 u_char *p;
4380 ngx_resolver_connection_t *rec;
4381
4382 p = buf;
4383
4384 if (log->action) {
4385 p = ngx_snprintf(buf, len, " while %s", log->action);
4386 len -= p - buf;
4387 }
4388
4389 rec = log->data;
4390
4391 if (rec) {
4392 p = ngx_snprintf(p, len, ", resolver: %V", &rec->server);
4393 }
4394
4395 return p;
4396 }
4397
4398
4399 static ngx_int_t
ngx_udp_connect(ngx_resolver_connection_t * rec)4400 ngx_udp_connect(ngx_resolver_connection_t *rec)
4401 {
4402 int rc;
4403 ngx_int_t event;
4404 ngx_event_t *rev, *wev;
4405 ngx_socket_t s;
4406 ngx_connection_t *c;
4407
4408 s = ngx_socket(rec->sockaddr->sa_family, SOCK_DGRAM, 0);
4409
4410 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "UDP socket %d", s);
4411
4412 if (s == (ngx_socket_t) -1) {
4413 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4414 ngx_socket_n " failed");
4415 return NGX_ERROR;
4416 }
4417
4418 c = ngx_get_connection(s, &rec->log);
4419
4420 if (c == NULL) {
4421 if (ngx_close_socket(s) == -1) {
4422 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4423 ngx_close_socket_n " failed");
4424 }
4425
4426 return NGX_ERROR;
4427 }
4428
4429 if (ngx_nonblocking(s) == -1) {
4430 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4431 ngx_nonblocking_n " failed");
4432
4433 goto failed;
4434 }
4435
4436 rev = c->read;
4437 wev = c->write;
4438
4439 rev->log = &rec->log;
4440 wev->log = &rec->log;
4441
4442 rec->udp = c;
4443
4444 c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
4445
4446 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0,
4447 "connect to %V, fd:%d #%uA", &rec->server, s, c->number);
4448
4449 rc = connect(s, rec->sockaddr, rec->socklen);
4450
4451 /* TODO: iocp */
4452
4453 if (rc == -1) {
4454 ngx_log_error(NGX_LOG_CRIT, &rec->log, ngx_socket_errno,
4455 "connect() failed");
4456
4457 goto failed;
4458 }
4459
4460 /* UDP sockets are always ready to write */
4461 wev->ready = 1;
4462
4463 event = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ?
4464 /* kqueue, epoll */ NGX_CLEAR_EVENT:
4465 /* select, poll, /dev/poll */ NGX_LEVEL_EVENT;
4466 /* eventport event type has no meaning: oneshot only */
4467
4468 if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
4469 goto failed;
4470 }
4471
4472 return NGX_OK;
4473
4474 failed:
4475
4476 ngx_close_connection(c);
4477 rec->udp = NULL;
4478
4479 return NGX_ERROR;
4480 }
4481
4482
4483 static ngx_int_t
ngx_tcp_connect(ngx_resolver_connection_t * rec)4484 ngx_tcp_connect(ngx_resolver_connection_t *rec)
4485 {
4486 int rc;
4487 ngx_int_t event;
4488 ngx_err_t err;
4489 ngx_uint_t level;
4490 ngx_socket_t s;
4491 ngx_event_t *rev, *wev;
4492 ngx_connection_t *c;
4493
4494 s = ngx_socket(rec->sockaddr->sa_family, SOCK_STREAM, 0);
4495
4496 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "TCP socket %d", s);
4497
4498 if (s == (ngx_socket_t) -1) {
4499 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4500 ngx_socket_n " failed");
4501 return NGX_ERROR;
4502 }
4503
4504 c = ngx_get_connection(s, &rec->log);
4505
4506 if (c == NULL) {
4507 if (ngx_close_socket(s) == -1) {
4508 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4509 ngx_close_socket_n " failed");
4510 }
4511
4512 return NGX_ERROR;
4513 }
4514
4515 if (ngx_nonblocking(s) == -1) {
4516 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4517 ngx_nonblocking_n " failed");
4518
4519 goto failed;
4520 }
4521
4522 rev = c->read;
4523 wev = c->write;
4524
4525 rev->log = &rec->log;
4526 wev->log = &rec->log;
4527
4528 rec->tcp = c;
4529
4530 c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
4531
4532 #if (NGX_HAVE_FSTACK)
4533 if (ngx_event_actions.add_conn) {
4534 #else
4535 if (ngx_add_conn) {
4536 #endif
4537 if (ngx_add_conn(c) == NGX_ERROR) {
4538 goto failed;
4539 }
4540 }
4541
4542 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, &rec->log, 0,
4543 "connect to %V, fd:%d #%uA", &rec->server, s, c->number);
4544
4545 rc = connect(s, rec->sockaddr, rec->socklen);
4546
4547 if (rc == -1) {
4548 err = ngx_socket_errno;
4549
4550
4551 if (err != NGX_EINPROGRESS
4552 #if (NGX_WIN32)
4553 /* Winsock returns WSAEWOULDBLOCK (NGX_EAGAIN) */
4554 && err != NGX_EAGAIN
4555 #endif
4556 )
4557 {
4558 if (err == NGX_ECONNREFUSED
4559 #if (NGX_LINUX)
4560 /*
4561 * Linux returns EAGAIN instead of ECONNREFUSED
4562 * for unix sockets if listen queue is full
4563 */
4564 || err == NGX_EAGAIN
4565 #endif
4566 || err == NGX_ECONNRESET
4567 || err == NGX_ENETDOWN
4568 || err == NGX_ENETUNREACH
4569 || err == NGX_EHOSTDOWN
4570 || err == NGX_EHOSTUNREACH)
4571 {
4572 level = NGX_LOG_ERR;
4573
4574 } else {
4575 level = NGX_LOG_CRIT;
4576 }
4577
4578 ngx_log_error(level, &rec->log, err, "connect() to %V failed",
4579 &rec->server);
4580
4581 ngx_close_connection(c);
4582 rec->tcp = NULL;
4583
4584 return NGX_ERROR;
4585 }
4586 }
4587
4588 #if (NGX_HAVE_FSTACK)
4589 if (ngx_event_actions.add_conn) {
4590 #else
4591 if (ngx_add_conn) {
4592 #endif
4593 if (rc == -1) {
4594
4595 /* NGX_EINPROGRESS */
4596
4597 return NGX_AGAIN;
4598 }
4599
4600 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected");
4601
4602 wev->ready = 1;
4603
4604 return NGX_OK;
4605 }
4606
4607 if (ngx_event_flags & NGX_USE_IOCP_EVENT) {
4608
4609 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, &rec->log, ngx_socket_errno,
4610 "connect(): %d", rc);
4611
4612 if (ngx_blocking(s) == -1) {
4613 ngx_log_error(NGX_LOG_ALERT, &rec->log, ngx_socket_errno,
4614 ngx_blocking_n " failed");
4615 goto failed;
4616 }
4617
4618 /*
4619 * FreeBSD's aio allows to post an operation on non-connected socket.
4620 * NT does not support it.
4621 *
4622 * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
4623 */
4624
4625 rev->ready = 1;
4626 wev->ready = 1;
4627
4628 return NGX_OK;
4629 }
4630
4631 if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
4632
4633 /* kqueue */
4634
4635 event = NGX_CLEAR_EVENT;
4636
4637 } else {
4638
4639 /* select, poll, /dev/poll */
4640
4641 event = NGX_LEVEL_EVENT;
4642 }
4643
4644 if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
4645 goto failed;
4646 }
4647
4648 if (rc == -1) {
4649
4650 /* NGX_EINPROGRESS */
4651
4652 if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
4653 goto failed;
4654 }
4655
4656 return NGX_AGAIN;
4657 }
4658
4659 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, &rec->log, 0, "connected");
4660
4661 wev->ready = 1;
4662
4663 return NGX_OK;
4664
4665 failed:
4666
4667 ngx_close_connection(c);
4668 rec->tcp = NULL;
4669
4670 return NGX_ERROR;
4671 }
4672
4673
4674 static ngx_int_t
4675 ngx_resolver_cmp_srvs(const void *one, const void *two)
4676 {
4677 ngx_int_t p1, p2;
4678 ngx_resolver_srv_t *first, *second;
4679
4680 first = (ngx_resolver_srv_t *) one;
4681 second = (ngx_resolver_srv_t *) two;
4682
4683 p1 = first->priority;
4684 p2 = second->priority;
4685
4686 return p1 - p2;
4687 }
4688