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