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