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