Klaus Demo nginx / cb4d538
resolver Igor Sysoev 14 years ago
4 changed file(s) with 2095 addition(s) and 126 deletion(s). Raw diff Collapse all Expand all
3131 src/core/ngx_connection.h \
3232 src/core/ngx_cycle.h \
3333 src/core/ngx_conf_file.h \
34 src/core/ngx_resolver.h \
3435 src/core/ngx_open_file_cache.h \
3536 src/core/ngx_garbage_collector.h"
3637
5859 src/core/ngx_spinlock.c \
5960 src/core/ngx_cpuinfo.c \
6061 src/core/ngx_conf_file.c \
62 src/core/ngx_resolver.c \
6163 src/core/ngx_open_file_cache.c \
6264 src/core/ngx_garbage_collector.c"
6365
4949 rm $(TEMP)/$(NGINX)/src/event/modules/ngx_iocp_module.*
5050 rm -r $(TEMP)/$(NGINX)/src/os/win32
5151
52 rm $(TEMP)/$(NGINX)/src/core/ngx_resolver.*
53
5452 rm -r $(TEMP)/$(NGINX)/src/mysql
5553
5654 rm $(TEMP)/$(NGINX)/src/http/modules/ngx_http_status_module.c
88 #include <ngx_event.h>
99
1010
11 #define NGX_RESOLVER_UDP_SIZE 4096
12
13
1114 typedef struct {
12 ngx_connection_t *connection;
13
14 struct sockaddr *sockaddr;
15 socklen_t socklen;
16
17 ngx_str_r server;
18 ngx_str_r name;
19
20 ngx_event_handler_pt handler;
21
22 ngx_log_t *pool;
23 ngx_log_t *log;
24 } ngx_resolver_t;
15 u_char ident_hi;
16 u_char ident_lo;
17 u_char flags_hi;
18 u_char flags_lo;
19 u_char nqs_hi;
20 u_char nqs_lo;
21 u_char nan_hi;
22 u_char nan_lo;
23 u_char nns_hi;
24 u_char nns_lo;
25 u_char nar_hi;
26 u_char nar_lo;
27 } ngx_resolver_query_t;
28
29
30 typedef struct {
31 u_char type_hi;
32 u_char type_lo;
33 u_char class_hi;
34 u_char class_lo;
35 } ngx_resolver_qs_t;
36
37
38 typedef struct {
39 u_char type_hi;
40 u_char type_lo;
41 u_char class_hi;
42 u_char class_lo;
43 u_char ttl[4];
44 u_char len_hi;
45 u_char len_lo;
46 } ngx_resolver_an_t;
47
48
49 ngx_int_t ngx_udp_connect(ngx_udp_connection_t *uc);
50
51
52 static ngx_int_t ngx_resolve_name_locked(ngx_resolver_t *r,
53 ngx_resolver_ctx_t *ctx);
54 static void ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree,
55 ngx_queue_t *queue);
56 static ngx_int_t ngx_resolver_send_query(ngx_resolver_t *r,
57 ngx_resolver_node_t *rn);
58 static ngx_int_t ngx_resolver_create_name_query(ngx_resolver_node_t *rn,
59 ngx_resolver_ctx_t *ctx);
60 static ngx_int_t ngx_resolver_create_addr_query(ngx_resolver_node_t *rn,
61 ngx_resolver_ctx_t *ctx);
62 static void ngx_resolver_resend_handler(ngx_event_t *ev);
63 static time_t ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree,
64 ngx_queue_t *queue);
65 static void ngx_resolver_read_response(ngx_event_t *rev);
66 static void ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf,
67 size_t n);
68 static void ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t n,
69 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t i);
70 static void ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
71 ngx_uint_t ident, ngx_uint_t code);
72 static ngx_resolver_node_t *ngx_resolver_lookup_name(ngx_resolver_t *r,
73 ngx_str_t *name, uint32_t hash);
74 static ngx_resolver_node_t *ngx_resolver_lookup_addr(ngx_resolver_t *r,
75 in_addr_t addr);
76 static void ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
77 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
78 static ngx_int_t ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name,
79 u_char *buf, u_char *src, u_char *last);
80 static void ngx_resolver_timeout_handler(ngx_event_t *ev);
81 static void ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn);
82 static void *ngx_resolver_alloc(ngx_resolver_t *r, size_t size);
83 static void ngx_resolver_free(ngx_resolver_t *r, void *p);
84 static void ngx_resolver_free_locked(ngx_resolver_t *r, void *p);
85 static void *ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size);
86
87
88 /* STUB: ngx_peer_addr_t * */
89
90 ngx_resolver_t *
91 ngx_resolver_create(ngx_peer_addr_t *addr, ngx_log_t *log)
92 {
93 ngx_resolver_t *r;
94 ngx_udp_connection_t *uc;
95
96 r = ngx_calloc(sizeof(ngx_resolver_t), log);
97 if (r == NULL) {
98 return NULL;
99 }
100
101 uc = ngx_calloc(sizeof(ngx_udp_connection_t), log);
102 if (uc == NULL) {
103 return NULL;
104 }
105
106 r->event = ngx_calloc(sizeof(ngx_event_t), log);
107 if (r->event == NULL) {
108 return NULL;
109 }
110
111 ngx_rbtree_sentinel_init(&r->name_sentinel);
112
113 r->name_rbtree.root = &r->name_sentinel;
114 r->name_rbtree.sentinel = &r->name_sentinel;
115 r->name_rbtree.insert = ngx_resolver_rbtree_insert_value;
116
117 ngx_rbtree_sentinel_init(&r->addr_sentinel);
118
119 r->addr_rbtree.root = &r->addr_sentinel;
120 r->addr_rbtree.sentinel = &r->addr_sentinel;
121 r->addr_rbtree.insert = ngx_rbtree_insert_value;
122
123 r->name_resend_queue.prev = &r->name_resend_queue;
124 r->name_resend_queue.next = &r->name_resend_queue;
125
126 r->addr_resend_queue.prev = &r->addr_resend_queue;
127 r->addr_resend_queue.next = &r->addr_resend_queue;
128
129 r->name_expire_queue.prev = &r->name_expire_queue;
130 r->name_expire_queue.next = &r->name_expire_queue;
131
132 r->addr_expire_queue.prev = &r->addr_expire_queue;
133 r->addr_expire_queue.next = &r->addr_expire_queue;
134
135 r->event->handler = ngx_resolver_resend_handler;
136 r->event->data = r;
137 r->event->log = log;
138 r->ident = -1;
139
140 r->udp_connection = uc;
141
142 r->resend_timeout = 5;
143 r->expire = 30;
144 r->valid = 300;
145
146 r->log = log;
147 r->log_level = NGX_LOG_ALERT;
148
149 uc->sockaddr = addr->sockaddr;
150 uc->socklen = addr->socklen;
151 uc->server = addr->name;
152 uc->log = log;
153
154 return r;
155 }
156
157
158 ngx_resolver_ctx_t *
159 ngx_resolve_start(ngx_resolver_t *r, ngx_resolver_ctx_t *temp)
160 {
161 in_addr_t addr;
162 ngx_resolver_ctx_t *ctx;
163
164 if (temp) {
165 addr = ngx_inet_addr(temp->name.data, temp->name.len);
166
167 if (addr != INADDR_NONE) {
168 temp->resolver = r;
169 temp->state = NGX_OK;
170 temp->naddrs = 1;
171 temp->addrs = &temp->addr;
172 temp->addr = addr;
173 temp->quick = 1;
174
175 return temp;
176 }
177 }
178
179 ctx = ngx_resolver_calloc(r, sizeof(ngx_resolver_ctx_t));
180
181 if (ctx) {
182 ctx->resolver = r;
183 }
184
185 return ctx;
186 }
25187
26188
27189 ngx_int_t
28 ngx_gethostbyname(ngx_resolver_t *r)
29 {
30 ngx_socket_t s;
31
32 if (r->connection) {
190 ngx_resolve_name(ngx_resolver_ctx_t *ctx)
191 {
192 ngx_int_t rc;
193 ngx_resolver_t *r;
194
195 r = ctx->resolver;
196
197 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
198 "resolve: \"%V\"", &ctx->name);
199
200 if (ctx->quick) {
201 ctx->handler(ctx);
33202 return NGX_OK;
34203 }
35204
205 /* lock name mutex */
206
207 rc = ngx_resolve_name_locked(r, ctx);
208
209 if (rc == NGX_OK) {
210 return NGX_OK;
211 }
212
213 /* unlock name mutex */
214
215 if (rc == NGX_AGAIN) {
216 return NGX_OK;
217 }
218
219 /* lock alloc mutex */
220
221 if (ctx->event) {
222 ngx_resolver_free_locked(r, ctx->event);
223 }
224
225 ngx_resolver_free_locked(r, ctx);
226
227 /* unlock alloc mutex */
228
229 return NGX_ERROR;
230 }
231
232
233 void
234 ngx_resolve_name_done(ngx_resolver_ctx_t *ctx)
235 {
236 uint32_t hash;
237 ngx_resolver_t *r;
238 ngx_resolver_ctx_t *w, **p;
239 ngx_resolver_node_t *rn;
240
241 r = ctx->resolver;
242
243 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
244 "resolve name done: %i", ctx->state);
245
246 if (ctx->quick) {
247 return;
248 }
249
250 if (ctx->event && ctx->event->timer_set) {
251 ngx_del_timer(ctx->event);
252 }
253
254 /* lock name mutex */
255
256 if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
257
258 hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
259
260 rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
261
262 if (rn) {
263 p = &rn->waiting;
264 w = rn->waiting;
265
266 while (w) {
267 if (w == ctx) {
268 *p = w->next;
269
270 goto done;
271 }
272
273 p = &w->next;
274 w = w->next;
275 }
276 }
277
278 ngx_log_error(NGX_LOG_ALERT, r->log, 0,
279 "could not cancel %V resolving", &ctx->name);
280 }
281
282 done:
283
284 ngx_resolver_expire(r, &r->name_rbtree, &r->name_expire_queue);
285
286 /* unlock name mutex */
287
288 ngx_resolver_free(r, ctx);
289 }
290
291
292 /* NGX_RESOLVE_A only */
293
294 static ngx_int_t
295 ngx_resolve_name_locked(ngx_resolver_t *r, ngx_resolver_ctx_t *ctx)
296 {
297 uint32_t hash;
298 in_addr_t addr, *addrs;
299 ngx_uint_t naddrs;
300 ngx_resolver_ctx_t *next;
301 ngx_resolver_node_t *rn;
302
303 hash = ngx_crc32_short(ctx->name.data, ctx->name.len);
304
305 rn = ngx_resolver_lookup_name(r, &ctx->name, hash);
306
307 if (rn) {
308
309 if (rn->valid >= ngx_time()) {
310
311 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
312
313 ngx_queue_remove(&rn->queue);
314
315 rn->expire = ngx_time() + r->expire;
316
317 ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
318
319 naddrs = rn->naddrs;
320
321 if (naddrs) {
322
323 /* NGX_RESOLVE_A answer */
324
325 if (naddrs != 1) {
326 addr = 0;
327 addrs = ngx_resolver_dup(r, rn->u.addrs,
328 naddrs * sizeof(in_addr_t));
329 if (addrs == NULL) {
330 return NGX_ERROR;
331 }
332
333 } else {
334 addr = rn->u.addr;
335 addrs = NULL;
336 }
337
338 ctx->next = rn->waiting;
339 rn->waiting = NULL;
340
341 /* unlock name mutex */
342
343 do {
344 ctx->state = NGX_OK;
345 ctx->naddrs = naddrs;
346 ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs;
347 ctx->addr = addr;
348 next = ctx->next;
349
350 ctx->handler(ctx);
351
352 ctx = next;
353 } while (ctx);
354
355 if (addrs) {
356 ngx_resolver_free(r, addrs);
357 }
358
359 return NGX_OK;
360 }
361
362 /* NGX_RESOLVE_CNAME */
363
364 ctx->name.len = rn->cnlen;
365 ctx->name.data = rn->u.cname;
366
367 return ngx_resolve_name_locked(r, ctx);
368 }
369
370 if (rn->waiting) {
371
372 ctx->next = rn->waiting;
373 rn->waiting = ctx;
374
375 return NGX_AGAIN;
376 }
377
378 ngx_queue_remove(&rn->queue);
379
380 /* lock alloc mutex */
381
382 ngx_resolver_free_locked(r, rn->query);
383
384 if (rn->cnlen) {
385 ngx_resolver_free_locked(r, rn->u.cname);
386 }
387
388 if (rn->naddrs > 1) {
389 ngx_resolver_free_locked(r, rn->u.addrs);
390 }
391
392 /* unlock alloc mutex */
393
394 } else {
395
396 rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
397 if (rn == NULL) {
398 return NGX_ERROR;
399 }
400
401 rn->name = ngx_resolver_dup(r, ctx->name.data, ctx->name.len);
402 if (rn->name == NULL) {
403 ngx_resolver_free(r, rn);
404 return NGX_ERROR;
405 }
406
407 rn->node.key = hash;
408 rn->nlen = (u_short) ctx->name.len;
409
410 ngx_rbtree_insert(&r->name_rbtree, &rn->node);
411 }
412
413 if (ngx_resolver_create_name_query(rn, ctx) != NGX_OK) {
414 goto failed;
415 }
416
417 if (ngx_resolver_send_query(r, rn) != NGX_OK) {
418 goto failed;
419 }
420
421 if (ctx->event == NULL) {
422 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
423 if (ctx->event == NULL) {
424 goto failed;
425 }
426
427 ctx->event->handler = ngx_resolver_timeout_handler;
428 ctx->event->data = ctx;
429 ctx->event->log = r->log;
430 ctx->ident = -1;
431
432 ngx_add_timer(ctx->event, ctx->timeout);
433 }
434
435 if (ngx_queue_empty(&r->name_resend_queue)) {
436 ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
437 }
438
439 rn->expire = ngx_time() + r->resend_timeout;
440
441 ngx_queue_insert_head(&r->name_resend_queue, &rn->queue);
442
443 rn->cnlen = 0;
444 rn->naddrs = 0;
445 rn->valid = 0;
446 rn->waiting = ctx;
447
448 ctx->state = NGX_AGAIN;
449
450 return NGX_AGAIN;
451
452 failed:
453
454 ngx_rbtree_delete(&r->name_rbtree, &rn->node);
455
456 ngx_resolver_free(r, rn->name);
457
458 ngx_resolver_free(r, rn);
459
460 return NGX_ERROR;
461 }
462
463
464 ngx_int_t
465 ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
466 {
467 ngx_resolver_t *r;
468 ngx_resolver_node_t *rn;
469
470 r = ctx->resolver;
471
472 ctx->addr = ntohl(ctx->addr);
473
474 /* lock addr mutex */
475
476 rn = ngx_resolver_lookup_addr(r, ctx->addr);
477
478 if (rn) {
479
480 if (rn->valid >= ngx_time()) {
481
482 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolve cached");
483
484 ngx_queue_remove(&rn->queue);
485
486 rn->expire = ngx_time() + r->expire;
487
488 ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue);
489
490 ctx->name.len = rn->nlen;
491 ctx->name.data = ngx_resolver_dup(r, rn->name, rn->nlen);
492 if (ctx->name.data == NULL) {
493 goto failed;
494 }
495
496 /* unlock addr mutex */
497
498 ctx->state = NGX_OK;
499
500 ctx->handler(ctx);
501
502 ngx_resolver_free(r, ctx->name.data);
503
504 return NGX_OK;
505 }
506
507 if (rn->waiting) {
508
509 ctx->next = rn->waiting;
510 rn->waiting = ctx;
511
512 return NGX_AGAIN;
513 }
514
515 ngx_queue_remove(&rn->queue);
516
517 ngx_resolver_free(r, rn->query);
518
519 } else {
520 rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t));
521 if (rn == NULL) {
522 goto failed;
523 }
524
525 rn->node.key = ctx->addr;
526
527 ngx_rbtree_insert(&r->addr_rbtree, &rn->node);
528 }
529
530 if (ngx_resolver_create_addr_query(rn, ctx) != NGX_OK) {
531 goto failed;
532 }
533
534 if (ngx_resolver_send_query(r, rn) != NGX_OK) {
535 goto failed;
536 }
537
538 ctx->event = ngx_resolver_calloc(r, sizeof(ngx_event_t));
539 if (ctx->event == NULL) {
540 goto failed;
541 }
542
543 ctx->event->handler = ngx_resolver_timeout_handler;
544 ctx->event->data = ctx;
545 ctx->event->log = r->log;
546 ctx->ident = -1;
547
548 ngx_add_timer(ctx->event, ctx->timeout);
549
550 if (ngx_queue_empty(&r->addr_resend_queue)) {
551 ngx_add_timer(r->event, (ngx_msec_t) (r->resend_timeout * 1000));
552 }
553
554 rn->expire = ngx_time() + r->resend_timeout;
555
556 ngx_queue_insert_head(&r->addr_resend_queue, &rn->queue);
557
558 rn->cnlen = 0;
559 rn->naddrs = 0;
560 rn->name = NULL;
561 rn->nlen = 0;
562 rn->valid = 0;
563 rn->waiting = ctx;
564
565 /* unlock addr mutex */
566
567 ctx->state = NGX_AGAIN;
568
569 return NGX_OK;
570
571 failed:
572
573 if (rn) {
574 ngx_rbtree_delete(&r->addr_rbtree, &rn->node);
575
576 ngx_resolver_free(r, rn);
577 }
578
579 /* unlock addr mutex */
580
581 /* lock alloc mutex */
582
583 if (ctx->event) {
584 ngx_resolver_free_locked(r, ctx->event);
585 }
586
587 ngx_resolver_free_locked(r, ctx);
588
589 /* unlock alloc mutex */
590
591 return NGX_ERROR;
592 }
593
594
595 void
596 ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx)
597 {
598 in_addr_t addr;
599 ngx_resolver_t *r;
600 ngx_resolver_ctx_t *w, **p;
601 ngx_resolver_node_t *rn;
602
603 r = ctx->resolver;
604
605 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
606 "resolve addr done: %i", ctx->state);
607
608 if (ctx->event && ctx->event->timer_set) {
609 ngx_del_timer(ctx->event);
610 }
611
612 /* lock addr mutex */
613
614 if (ctx->state == NGX_AGAIN || ctx->state == NGX_RESOLVE_TIMEDOUT) {
615
616 rn = ngx_resolver_lookup_addr(r, ctx->addr);
617
618 if (rn) {
619 p = &rn->waiting;
620 w = rn->waiting;
621
622 while (w) {
623 if (w == ctx) {
624 *p = w->next;
625
626 goto done;
627 }
628
629 p = &w->next;
630 w = w->next;
631 }
632 }
633
634 addr = ntohl(ctx->addr);
635
636 ngx_log_error(NGX_LOG_ALERT, r->log, 0,
637 "could not cancel %ud.%ud.%ud.%ud resolving",
638 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
639 (addr >> 8) & 0xff, addr & 0xff);
640 }
641
642 done:
643
644 ngx_resolver_expire(r, &r->addr_rbtree, &r->addr_expire_queue);
645
646 /* unlock addr mutex */
647
648 ngx_resolver_free(r, ctx);
649 }
650
651
652 static void
653 ngx_resolver_expire(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
654 {
655 time_t now;
656 ngx_uint_t i;
657 ngx_queue_t *q;
658 ngx_resolver_node_t *rn;
659
660 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver expire");
661
662 now = ngx_time();
663
664 for (i = 0; i < 2; i++) {
665 if (ngx_queue_empty(queue)) {
666 return;
667 }
668
669 q = ngx_queue_last(queue);
670
671 rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
672
673 if (now <= rn->expire) {
674 return;
675 }
676
677 #if (NGX_DEBUG)
678 {
679 ngx_str_t s;
680
681 s.len = rn->nlen;
682 s.data = rn->name;
683
684 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
685 "resolver expire \"%V\"", &s);
686 }
687 #endif
688
689 ngx_queue_remove(q);
690
691 ngx_rbtree_delete(tree, &rn->node);
692
693 ngx_resolver_free_node(r, rn);
694 }
695 }
696
697
698 static ngx_int_t
699 ngx_resolver_send_query(ngx_resolver_t *r, ngx_resolver_node_t *rn)
700 {
701 ssize_t n;
702 ngx_udp_connection_t *uc;
703
704 uc = r->udp_connection;
705
706 if (uc->connection == NULL) {
707 if (ngx_udp_connect(uc) != NGX_OK) {
708 return NGX_ERROR;
709 }
710
711 uc->connection->data = r;
712 uc->connection->read->handler = ngx_resolver_read_response;
713 }
714
715 n = ngx_send(uc->connection, rn->query, rn->qlen);
716
717 if (n == -1) {
718 return NGX_ERROR;
719 }
720
721 if ((size_t) n != (size_t) rn->qlen) {
722 ngx_log_error(NGX_LOG_CRIT, uc->log, 0, "send() incomplete");
723 return NGX_ERROR;
724 }
725
726 return NGX_OK;
727 }
728
729
730 static void
731 ngx_resolver_resend_handler(ngx_event_t *ev)
732 {
733 time_t timer, atimer, ntimer;
734 ngx_resolver_t *r;
735
736 r = ev->data;
737
738 ngx_log_debug0(NGX_LOG_DEBUG_CORE, r->log, 0,
739 "resolver resend handler");
740
741 /* lock name mutex */
742
743 ntimer = ngx_resolver_resend(r, &r->name_rbtree, &r->name_resend_queue);
744
745 /* unlock name mutex */
746
747 /* lock addr mutex */
748
749 atimer = ngx_resolver_resend(r, &r->addr_rbtree, &r->addr_resend_queue);
750
751 /* unlock addr mutex */
752
753 if (ntimer == 0) {
754 timer = atimer;
755
756 } else if (atimer == 0) {
757 timer = ntimer;
758
759 } else {
760 timer = (atimer < ntimer) ? atimer : ntimer;
761 }
762
763 if (timer) {
764 ngx_add_timer(r->event, (ngx_msec_t) (timer * 1000));
765 }
766 }
767
768
769 static time_t
770 ngx_resolver_resend(ngx_resolver_t *r, ngx_rbtree_t *tree, ngx_queue_t *queue)
771 {
772 time_t now;
773 ngx_queue_t *q;
774 ngx_resolver_node_t *rn;
775
776 now = ngx_time();
777
778 for ( ;; ) {
779 if (ngx_queue_empty(queue)) {
780 return 0;
781 }
782
783 q = ngx_queue_last(queue);
784
785 rn = ngx_queue_data(q, ngx_resolver_node_t, queue);
786
787 if (now < rn->expire) {
788 return rn->expire - now;
789 }
790
791 #if (NGX_DEBUG)
792 {
793 ngx_str_t s;
794
795 s.len = rn->nlen;
796 s.data = rn->name;
797
798 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
799 "resolver resend \"%V\" %p", &s, rn->waiting);
800 }
801 #endif
802
803 ngx_queue_remove(q);
804
805 if (rn->waiting) {
806
807 if (ngx_resolver_send_query(r, rn) == NGX_OK) {
808
809 rn->expire = now + r->resend_timeout;
810
811 ngx_queue_insert_head(queue, &rn->queue);
812
813 continue;
814 }
815 }
816
817 ngx_rbtree_delete(tree, &rn->node);
818
819 ngx_resolver_free_node(r, rn);
820 }
821 }
822
823
824 static void
825 ngx_resolver_read_response(ngx_event_t *rev)
826 {
827 ssize_t n;
828 ngx_connection_t *c;
829 u_char buf[NGX_RESOLVER_UDP_SIZE];
830
831 c = rev->data;
832
833 do {
834 n = ngx_recv(c, buf, NGX_RESOLVER_UDP_SIZE);
835
836 if (n == -1) {
837 return;
838 }
839
840 ngx_resolver_process_response(c->data, buf, n);
841
842 } while (rev->ready);
843 }
844
845
846 static void
847 ngx_resolver_process_response(ngx_resolver_t *r, u_char *buf, size_t n)
848 {
849 char *err;
850 size_t len;
851 ngx_uint_t i, ident, flags, code, nqs, nan, qtype, qclass;
852 ngx_resolver_qs_t *qs;
853 ngx_resolver_query_t *query;
854
855 if ((size_t) n < sizeof(ngx_resolver_query_t) + 1) {
856 goto short_response;
857 }
858
859 query = (ngx_resolver_query_t *) buf;
860
861 ident = (query->ident_hi << 8) + query->ident_lo;
862 flags = (query->flags_hi << 8) + query->flags_lo;
863 nqs = (query->nqs_hi << 8) + query->nqs_lo;
864 nan = (query->nan_hi << 8) + query->nan_lo;
865
866 ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0,
867 "resolver DNS response %d fl:%04Xud %d/%d/%d/%d",
868 ident, flags, nqs, nan,
869 (query->nns_hi << 8) + query->nns_lo,
870 (query->nar_hi << 8) + query->nar_lo);
871
872 if (!(flags & 0x8000)) {
873 ngx_log_error(r->log_level, r->log, 0,
874 "invalid DNS response %d fl:%04Xud", ident, flags);
875 return;
876 }
877
878 code = flags & 0x7f;
879
880 if (code == NGX_RESOLVE_FORMERR || code > NGX_RESOLVE_REFUSED) {
881 ngx_log_error(r->log_level, r->log, 0,
882 "DNS error (%d: %s), query id:%d",
883 code, ngx_resolver_strerror(code), ident);
884 return;
885 }
886
887 if (nqs != 1) {
888 err = "invalid number of questions in DNS response";
889 goto done;
890 }
891
892 if (code == 0 && nan == 0) {
893 err = "no answers in DNS response";
894 goto done;
895 }
896
897 i = sizeof(ngx_resolver_query_t);
898
899 while (i < (ngx_uint_t) n) {
900 if (buf[i] == '\0') {
901 goto found;
902 }
903
904 len = buf[i];
905 i += 1 + len;
906 }
907
908 goto short_response;
909
910 found:
911
912 if (i++ == 0) {
913 err = "zero-length domain name in DNS response";
914 goto done;
915 }
916
917 if (i + sizeof(ngx_resolver_qs_t) + nan * (2 + sizeof(ngx_resolver_an_t))
918 > (ngx_uint_t) n)
919 {
920 goto short_response;
921 }
922
923 qs = (ngx_resolver_qs_t *) &buf[i];
924
925 qtype = (qs->type_hi << 8) + qs->type_lo;
926 qclass = (qs->class_hi << 8) + qs->class_lo;
927
928 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
929 "resolver DNS response qt:%d cl:%d", qtype, qclass);
930
931 if (qclass != 1) {
932 ngx_log_error(r->log_level, r->log, 0,
933 "unknown query class %d in DNS response", qclass);
934 return;
935 }
936
937 switch (qtype) {
938
939 case NGX_RESOLVE_A:
940
941 ngx_resolver_process_a(r, buf, n, ident, code, nan,
942 i + sizeof(ngx_resolver_qs_t));
943
944 break;
945
946 case NGX_RESOLVE_PTR:
947
948 ngx_resolver_process_ptr(r, buf, n, ident, code);
949
950 break;
951
952 default:
953 ngx_log_error(r->log_level, r->log, 0,
954 "unknown query type %d in DNS response", qtype);
955 return;
956 }
957
958 return;
959
960 short_response:
961
962 err = "short dns response";
963
964 done:
965
966 ngx_log_error(r->log_level, r->log, 0, err);
967
968 return;
969 }
970
971
972 static void
973 ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
974 ngx_uint_t ident, ngx_uint_t code, ngx_uint_t nan, ngx_uint_t ans)
975 {
976 char *err;
977 u_char *cname;
978 size_t len;
979 uint32_t hash;
980 in_addr_t addr, *addrs;
981 ngx_str_t name;
982 ngx_uint_t qtype, qident, naddrs, a, i, n, start;
983 ngx_resolver_an_t *an;
984 ngx_resolver_ctx_t *ctx, *next;
985 ngx_resolver_node_t *rn;
986
987 if (ngx_resolver_copy(r, &name, buf, &buf[12], &buf[last]) != NGX_OK) {
988 return;
989 }
990
991 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver qs:%V", &name);
992
993 hash = ngx_crc32_short(name.data, name.len);
994
995 /* lock name mutex */
996
997 rn = ngx_resolver_lookup_name(r, &name, hash);
998
999 if (rn == NULL || rn->query == NULL) {
1000 ngx_log_error(r->log_level, r->log, 0,
1001 "unexpected response for %V", &name);
1002 goto failed;
1003 }
1004
1005 qident = (rn->query[0] << 8) + rn->query[1];
1006
1007 if (ident != qident) {
1008 ngx_log_error(r->log_level, r->log, 0,
1009 "wrong ident %d response for %V, expect %d",
1010 ident, &name, qident);
1011 goto failed;
1012 }
1013
1014 if (code) {
1015 next = rn->waiting;
1016 rn->waiting = NULL;
1017
1018 ngx_queue_remove(&rn->queue);
1019
1020 ngx_rbtree_delete(&r->name_rbtree, &rn->node);
1021
1022 ngx_resolver_free_node(r, rn);
1023
1024 /* unlock name mutex */
1025
1026 while (next) {
1027 ctx = next;
1028 ctx->state = code;
1029 next = ctx->next;
1030
1031 ctx->handler(ctx);
1032 }
1033
1034 return;
1035 }
1036
1037 i = ans;
1038 naddrs = 0;
1039 addr = 0;
1040 addrs = NULL;
1041 cname = NULL;
1042 qtype = 0;
1043
1044 for (a = 0; a < nan; a++) {
1045
1046 start = i;
1047
1048 while (i < last) {
1049
1050 if (buf[i] & 0xc0) {
1051 i += 2;
1052 goto found;
1053 }
1054
1055 if (buf[i] == 0) {
1056 i++;
1057 goto test_length;
1058 }
1059
1060 i += 1 + buf[i];
1061 }
1062
1063 goto short_response;
1064
1065 test_length:
1066
1067 if (i - start < 2) {
1068 err = "invalid name in dns response";
1069 goto invalid;
1070 }
1071
1072 found:
1073
1074 if (i + sizeof(ngx_resolver_an_t) >= last) {
1075 goto short_response;
1076 }
1077
1078 an = (ngx_resolver_an_t *) &buf[i];
1079
1080 qtype = (an->type_hi << 8) + an->type_lo;
1081 len = (an->len_hi << 8) + an->len_lo;
1082
1083 if (qtype == NGX_RESOLVE_A) {
1084
1085 i += sizeof(ngx_resolver_an_t);
1086
1087 if (i + len > last) {
1088 goto short_response;
1089 }
1090
1091 addr = htonl((buf[i] << 24) + (buf[i + 1] << 16)
1092 + (buf[i + 2] << 8) + (buf[i + 3]));
1093
1094 naddrs++;
1095
1096 i += len;
1097
1098 } else if (qtype == NGX_RESOLVE_CNAME) {
1099 cname = &buf[i] + sizeof(ngx_resolver_an_t);
1100 i += sizeof(ngx_resolver_an_t) + len;
1101 }
1102 }
1103
1104 ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
1105 "resolver naddrs:%ui cname:%p", naddrs, cname);
1106
1107 if (naddrs) {
1108
1109 if (naddrs == 1) {
1110 rn->u.addr = addr;
1111
1112 } else {
1113
1114 addrs = ngx_resolver_alloc(r, naddrs * sizeof(in_addr_t));
1115 if (addrs == NULL) {
1116 return;
1117 }
1118
1119 n = 0;
1120 i = ans;
1121
1122 for (a = 0; a < nan; a++) {
1123
1124 for ( ;; ) {
1125
1126 if (buf[i] & 0xc0) {
1127 i += 2;
1128 goto ok;
1129 }
1130
1131 if (buf[i] == 0) {
1132 i++;
1133 goto ok;
1134 }
1135
1136 i += 1 + buf[i];
1137 }
1138
1139 ok:
1140
1141 an = (ngx_resolver_an_t *) &buf[i];
1142
1143 qtype = (an->type_hi << 8) + an->type_lo;
1144 len = (an->len_hi << 8) + an->len_lo;
1145
1146 i += sizeof(ngx_resolver_an_t);
1147
1148 if (qtype == NGX_RESOLVE_A) {
1149
1150 addrs[n++] = htonl((buf[i] << 24) + (buf[i + 1] << 16)
1151 + (buf[i + 2] << 8) + (buf[i + 3]));
1152
1153 if (n == naddrs) {
1154 break;
1155 }
1156 }
1157
1158 i += len;
1159 }
1160
1161 rn->u.addrs = addrs;
1162
1163 addrs = ngx_resolver_dup(r, rn->u.addrs,
1164 naddrs * sizeof(in_addr_t));
1165 if (addrs == NULL) {
1166 return;
1167 }
1168 }
1169
1170 rn->naddrs = (u_short) naddrs;
1171
1172 ngx_queue_remove(&rn->queue);
1173
1174 rn->valid = ngx_time() + r->valid;
1175 rn->expire = ngx_time() + r->expire;
1176
1177 ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
1178
1179 next = rn->waiting;
1180 rn->waiting = NULL;
1181
1182 /* unlock name mutex */
1183
1184 while (next) {
1185 ctx = next;
1186 ctx->state = NGX_OK;
1187 ctx->naddrs = naddrs;
1188 ctx->addrs = (naddrs == 1) ? &ctx->addr : addrs;
1189 ctx->addr = addr;
1190 next = ctx->next;
1191
1192 ctx->handler(ctx);
1193 }
1194
1195 if (naddrs) {
1196 ngx_resolver_free(r, addrs);
1197 }
1198
1199 return;
1200
1201 } else if (cname) {
1202
1203 /* CNAME only */
1204
1205 if (ngx_resolver_copy(r, &name, buf, cname, &buf[last]) != NGX_OK) {
1206 return;
1207 }
1208
1209 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0,
1210 "resolver cname:\"%V\"", &name);
1211
1212 rn->cnlen = (u_short) name.len;
1213 rn->u.cname = name.data;
1214 rn->valid = ngx_time() + r->valid;
1215 rn->expire = ngx_time() + r->expire;
1216
1217 ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
1218
1219 ctx = rn->waiting;
1220 rn->waiting = NULL;
1221
1222 if (ctx) {
1223 ctx->name = name;
1224
1225 (void) ngx_resolve_name_locked(r, ctx);
1226 }
1227
1228 return;
1229 }
1230
1231 ngx_log_error(r->log_level, r->log, 0,
1232 "no A or CNAME types in DNS responses, unknown query type: %d",
1233 qtype);
1234 return;
1235
1236 short_response:
1237
1238 err = "short dns response";
1239
1240 invalid:
1241
1242 /* unlock name mutex */
1243
1244 ngx_log_error(r->log_level, r->log, 0, err);
1245
1246 return;
1247
1248 failed:
1249
1250 /* unlock name mutex */
1251
1252 return;
1253 }
1254
1255
1256 static void
1257 ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
1258 ngx_uint_t ident, ngx_uint_t code)
1259 {
1260 char *err;
1261 size_t len;
1262 in_addr_t addr;
1263 ngx_int_t digit;
1264 ngx_str_t name;
1265 ngx_uint_t i, mask, qtype, qclass, qident;
1266 ngx_resolver_an_t *an;
1267 ngx_resolver_ctx_t *ctx, *next;
1268 ngx_resolver_node_t *rn;
1269
1270 if (ngx_resolver_copy(r, NULL, buf, &buf[12], &buf[n]) != NGX_OK) {
1271 goto invalid_in_addr_arpa;
1272 }
1273
1274 addr = 0;
1275 i = 12;
1276
1277 for (mask = 0; mask < 32; mask += 8) {
1278 len = buf[i++];
1279
1280 digit = ngx_atoi(&buf[i], len);
1281 if (digit == NGX_ERROR || digit > 255) {
1282 goto invalid_in_addr_arpa;
1283 }
1284
1285 addr += digit << mask;
1286 i += len;
1287 }
1288
1289 if (ngx_strcmp(&buf[i], "\7in-addr\4arpa") != 0) {
1290 goto invalid_in_addr_arpa;
1291 }
1292
1293 /* lock addr mutex */
1294
1295 rn = ngx_resolver_lookup_addr(r, addr);
1296
1297 if (rn == NULL || rn->query == NULL) {
1298 ngx_log_error(r->log_level, r->log, 0,
1299 "unexpected response for %ud.%ud.%ud.%ud",
1300 (addr >> 24) & 0xff, (addr >> 16) & 0xff,
1301 (addr >> 8) & 0xff, addr & 0xff);
1302 goto failed;
1303 }
1304
1305 qident = (rn->query[0] << 8) + rn->query[1];
1306
1307 if (ident != qident) {
1308 ngx_log_error(r->log_level, r->log, 0,
1309 "wrong ident %d response for %ud.%ud.%ud.%ud, expect %d",
1310 ident, (addr >> 24) & 0xff, (addr >> 16) & 0xff,
1311 (addr >> 8) & 0xff, addr & 0xff, qident);
1312 goto failed;
1313 }
1314
1315 if (code) {
1316 next = rn->waiting;
1317 rn->waiting = NULL;
1318
1319 ngx_queue_remove(&rn->queue);
1320
1321 ngx_rbtree_delete(&r->addr_rbtree, &rn->node);
1322
1323 ngx_resolver_free_node(r, rn);
1324
1325 /* unlock addr mutex */
1326
1327 while (next) {
1328 ctx = next;
1329 ctx->state = code;
1330 next = ctx->next;
1331
1332 ctx->handler(ctx);
1333 }
1334
1335 return;
1336 }
1337
1338 i += sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t);
1339
1340 if (i + 2 + sizeof(ngx_resolver_an_t) > (ngx_uint_t) n) {
1341 goto short_response;
1342 }
1343
1344 /* compression pointer to "XX.XX.XX.XX.in-addr.arpa */
1345
1346 if (buf[i] != 0xc0 || buf[i + 1] != 0x0c) {
1347 err = "invalid in-addr.arpa name in DNS response";
1348 goto invalid;
1349 }
1350
1351 an = (ngx_resolver_an_t *) &buf[i + 2];
1352
1353 qtype = (an->type_hi << 8) + an->type_lo;
1354 qclass = (an->class_hi << 8) + an->class_lo;
1355 len = (an->len_hi << 8) + an->len_lo;
1356
1357 ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
1358 "resolver qt:%d cl:%d len:%uz", qtype, qclass, len);
1359
1360 i += 2 + sizeof(ngx_resolver_an_t);
1361
1362 if (i + len > (ngx_uint_t) n) {
1363 goto short_response;
1364 }
1365
1366 len -= 2;
1367
1368 if (ngx_resolver_copy(r, &name, buf, &buf[i], &buf[n]) != NGX_OK) {
1369 return;
1370 }
1371
1372 ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name);
1373
1374 if (len != (size_t) rn->nlen || ngx_strncmp(name.data, rn->name, len) != 0)
1375 {
1376 ngx_resolver_free(r, rn->name);
1377 rn->name = name.data;
1378
1379 name.data = ngx_resolver_dup(r, rn->name, len);
1380 if (name.data == NULL) {
1381 goto failed;
1382 }
1383 }
1384
1385 ngx_queue_remove(&rn->queue);
1386
1387 rn->valid = ngx_time() + r->valid;
1388 rn->expire = ngx_time() + r->expire;
1389
1390 ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue);
1391
1392 next = rn->waiting;
1393 rn->waiting = NULL;
1394
1395 /* unlock addr mutex */
1396
1397 while (next) {
1398 ctx = next;
1399 ctx->state = NGX_OK;
1400 ctx->name = name;
1401 next = ctx->next;
1402
1403 ctx->handler(ctx);
1404 }
1405
1406 ngx_resolver_free(r, name.data);
1407
1408 return;
1409
1410 invalid_in_addr_arpa:
1411
1412 ngx_log_error(r->log_level, r->log, 0,
1413 "invalid in-addr.arpa name in DNS response");
1414 return;
1415
1416 short_response:
1417
1418 err = "short DNS response";
1419
1420 invalid:
1421
1422 /* unlock addr mutex */
1423
1424 ngx_log_error(r->log_level, r->log, 0, err);
1425
1426 return;
1427
1428 failed:
1429
1430 /* unlock addr mutex */
1431
1432 return;
1433 }
1434
1435
1436 static ngx_resolver_node_t *
1437 ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
1438 {
1439 ngx_int_t rc;
1440 size_t len;
1441 ngx_rbtree_node_t *node, *sentinel;
1442 ngx_resolver_node_t *rn;
1443
1444 node = r->name_rbtree.root;
1445 sentinel = r->name_rbtree.sentinel;
1446
1447 while (node != sentinel) {
1448
1449 if (hash < node->key) {
1450 node = node->left;
1451 continue;
1452 }
1453
1454 if (hash > node->key) {
1455 node = node->right;
1456 continue;
1457 }
1458
1459 /* hash == node->key */
1460
1461 do {
1462 rn = (ngx_resolver_node_t *) node;
1463
1464 len = (name->len > (size_t) rn->nlen) ? rn->nlen : name->len;
1465
1466 rc = ngx_strncmp(name->data, rn->name, len);
1467
1468 if (rc == 0) {
1469 return rn;
1470 }
1471
1472 node = (rc < 0) ? node->left : node->right;
1473
1474 } while (node != sentinel && hash == node->key);
1475
1476 break;
1477 }
1478
1479 /* not found */
1480
1481 return NULL;
1482 }
1483
1484
1485 static ngx_resolver_node_t *
1486 ngx_resolver_lookup_addr(ngx_resolver_t *r, in_addr_t addr)
1487 {
1488 ngx_rbtree_node_t *node, *sentinel;
1489
1490 node = r->addr_rbtree.root;
1491 sentinel = r->addr_rbtree.sentinel;
1492
1493 while (node != sentinel) {
1494
1495 if (addr < node->key) {
1496 node = node->left;
1497 continue;
1498 }
1499
1500 if (addr > node->key) {
1501 node = node->right;
1502 continue;
1503 }
1504
1505 /* addr == node->key */
1506
1507 return (ngx_resolver_node_t *) node;
1508 }
1509
1510 /* not found */
1511
1512 return NULL;
1513 }
1514
1515
1516 static void
1517 ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
1518 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
1519 {
1520 size_t len;
1521 ngx_rbtree_node_t **p;
1522 ngx_resolver_node_t *rn, *rn_temp;
1523
1524 for ( ;; ) {
1525
1526 if (node->key < temp->key) {
1527
1528 p = &temp->left;
1529
1530 } else if (node->key > temp->key) {
1531
1532 p = &temp->right;
1533
1534 } else { /* node->key == temp->key */
1535
1536 rn = (ngx_resolver_node_t *) node;
1537 rn_temp = (ngx_resolver_node_t *) temp;
1538
1539 len = (rn->nlen > rn_temp->nlen) ? rn_temp->nlen : rn->nlen;
1540
1541 p = (ngx_strncmp(rn->name, rn_temp->name, len) < 0)
1542 ? &temp->left : &temp->right;
1543 }
1544
1545 if (*p == sentinel) {
1546 break;
1547 }
1548
1549 temp = *p;
1550 }
1551
1552 *p = node;
1553 node->parent = temp;
1554 node->left = sentinel;
1555 node->right = sentinel;
1556 ngx_rbt_red(node);
1557 }
1558
1559
1560 static ngx_int_t
1561 ngx_resolver_create_name_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
1562 {
1563 u_char *p, *s;
1564 size_t len;
1565 ngx_uint_t ident;
1566 ngx_resolver_qs_t *qs;
1567 ngx_resolver_query_t *query;
1568
1569 len = sizeof(ngx_resolver_query_t)
1570 + 1 + ctx->name.len + 1 + sizeof(ngx_resolver_qs_t);
1571
1572 p = ngx_resolver_calloc(ctx->resolver, len);
1573 if (p == NULL) {
1574 return NGX_ERROR;
1575 }
1576
1577 rn->qlen = (u_short) len;
1578 rn->query = p;
1579
1580 query = (ngx_resolver_query_t *) p;
1581
1582 ident = ngx_random();
1583
1584 ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->resolver->log, 0,
1585 "resolve: \"%V\" %i", &ctx->name, ident & 0xffff);
1586
1587 query->ident_hi = (u_char) ((ident >> 8) & 0xff);
1588 query->ident_lo = (u_char) (ident & 0xff);
1589
1590 /* recursion query */
1591 query->flags_hi = 1; query->flags_lo = 0;
1592
1593 /* one question */
1594 query->nqs_hi = 0; query->nqs_lo = 1;
1595 query->nan_hi = 0; query->nan_lo = 0;
1596 query->nns_hi = 0; query->nns_lo = 0;
1597 query->nar_hi = 0; query->nar_lo = 0;
1598
1599 p += sizeof(ngx_resolver_query_t) + 1 + ctx->name.len + 1;
1600
1601 qs = (ngx_resolver_qs_t *) p;
1602
1603 /* query type */
1604 qs->type_hi = 0; qs->type_lo = (u_char) ctx->type;
1605
1606 /* IP query class */
1607 qs->class_hi = 0; qs->class_lo = 1;
1608
1609 /* convert "www.example.com" to "\3www\7example\3com\0" */
1610
1611 len = 0;
1612 p--;
1613 *p-- = '\0';
1614
1615 for (s = ctx->name.data + ctx->name.len - 1; s >= ctx->name.data; s--) {
1616 if (*s != '.') {
1617 *p = *s;
1618 len++;
1619
1620 } else {
1621 *p = (u_char) len;
1622 len = 0;
1623 }
1624
1625 p--;
1626 }
1627
1628 *p = (u_char) len;
1629
1630 return NGX_OK;
1631 }
1632
1633
1634 /* AF_INET only */
1635
1636 static ngx_int_t
1637 ngx_resolver_create_addr_query(ngx_resolver_node_t *rn, ngx_resolver_ctx_t *ctx)
1638 {
1639 u_char *p, *d;
1640 size_t len;
1641 ngx_int_t n;
1642 ngx_uint_t ident;
1643 ngx_resolver_query_t *query;
1644
1645 len = sizeof(ngx_resolver_query_t)
1646 + sizeof(".255.255.255.255.in-addr.arpa.") - 1
1647 + sizeof(ngx_resolver_qs_t);
1648
1649 p = ngx_resolver_calloc(ctx->resolver, len);
1650 if (p == NULL) {
1651 return NGX_ERROR;
1652 }
1653
1654 rn->query = p;
1655 query = (ngx_resolver_query_t *) p;
1656
1657 ident = ngx_random();
1658
1659 query->ident_hi = (u_char) ((ident >> 8) & 0xff);
1660 query->ident_lo = (u_char) (ident & 0xff);
1661
1662 /* recursion query */
1663 query->flags_hi = 1; query->flags_lo = 0;
1664
1665 /* one question */
1666 query->nqs_hi = 0; query->nqs_lo = 1;
1667 query->nan_hi = 0; query->nan_lo = 0;
1668 query->nns_hi = 0; query->nns_lo = 0;
1669 query->nar_hi = 0; query->nar_lo = 0;
1670
1671 p += sizeof(ngx_resolver_query_t);
1672
1673 for (n = 0; n < 32; n += 8){
1674 d = ngx_sprintf(&p[1], "%ud", (ctx->addr >> n) & 0xff);
1675 *p = (u_char) (d - &p[1]);
1676 p = d;
1677 }
1678
1679 /* query type "PTR", IP query class */
1680 ngx_memcpy(p, "\7in-addr\4arpa\0\0\14\0\1", 18);
1681
1682 rn->qlen = (u_short)
1683 (p + sizeof("\7in-addr\4arpa") + sizeof(ngx_resolver_qs_t)
1684 - rn->query);
1685
1686 return NGX_OK;
1687 }
1688
1689
1690 static ngx_int_t
1691 ngx_resolver_copy(ngx_resolver_t *r, ngx_str_t *name, u_char *buf, u_char *src,
1692 u_char *last)
1693 {
1694 char *err;
1695 u_char *p, *dst;
1696 ssize_t len;
1697 ngx_uint_t i, n;
1698
1699 p = src;
1700 len = -1;
1701
1702 /*
1703 * compression pointers allow to create endless loop, so we set limit;
1704 * 128 pointers should be enough to store 255-byte name
1705 */
1706
1707 for (i = 0; i < 128; i++) {
1708 n = *p++;
1709
1710 if (n == 0) {
1711 goto done;
1712 }
1713
1714 if (n & 0xc0) {
1715 n = (n & 0x3f << 8) + *p;
1716 p = &buf[n];
1717
1718 } else {
1719 len += 1 + n;
1720 p = &p[n];
1721 }
1722
1723 if (p >= last) {
1724 err = "name is out of response";
1725 goto invalid;
1726 }
1727 }
1728
1729 err = "compression pointers loop";
1730
1731 invalid:
1732
1733 ngx_log_error(r->log_level, r->log, 0, err);
1734
1735 return NGX_ERROR;
1736
1737 done:
1738
1739 if (name == NULL) {
1740 return NGX_OK;
1741 }
1742
1743 dst = ngx_resolver_alloc(r, len);
1744 if (dst == NULL) {
1745 return NGX_ERROR;
1746 }
1747
1748 name->data = dst;
1749
1750 n = *src++;
1751
1752 for ( ;; ) {
1753 if (n != 0xc0) {
1754 ngx_memcpy(dst, src, n);
1755 dst += n;
1756 src += n;
1757
1758 n = *src++;
1759
1760 if (n != 0) {
1761 *dst++ = '.';
1762 }
1763
1764 } else {
1765 n = (n & 0x3f << 8) + *src;
1766 src = &buf[n];
1767
1768 n = *src++;
1769 }
1770
1771 if (n == 0) {
1772 name->len = dst - name->data;
1773 return NGX_OK;
1774 }
1775 }
1776 }
1777
1778
1779 static void
1780 ngx_resolver_timeout_handler(ngx_event_t *ev)
1781 {
1782 ngx_resolver_ctx_t *ctx;
1783
1784 ctx = ev->data;
1785
1786 ctx->state = NGX_RESOLVE_TIMEDOUT;
1787
1788 ctx->handler(ctx);
1789 }
1790
1791
1792 static void
1793 ngx_resolver_free_node(ngx_resolver_t *r, ngx_resolver_node_t *rn)
1794 {
1795 /* lock alloc mutex */
1796
1797 if (rn->query) {
1798 ngx_resolver_free_locked(r, rn->query);
1799 }
1800
1801 if (rn->name) {
1802 ngx_resolver_free_locked(r, rn->name);
1803 }
1804
1805 if (rn->cnlen) {
1806 ngx_resolver_free_locked(r, rn->u.cname);
1807 }
1808
1809 if (rn->naddrs > 1) {
1810 ngx_resolver_free_locked(r, rn->u.addrs);
1811 }
1812
1813 ngx_resolver_free_locked(r, rn);
1814
1815 /* unlock alloc mutex */
1816 }
1817
1818
1819 static void *
1820 ngx_resolver_alloc(ngx_resolver_t *r, size_t size)
1821 {
1822 u_char *p;
1823
1824 /* lock alloc mutex */
1825
1826 p = ngx_alloc(size, r->log);
1827
1828 /* unlock alloc mutex */
1829
1830 return p;
1831 }
1832
1833
1834 void *
1835 ngx_resolver_calloc(ngx_resolver_t *r, size_t size)
1836 {
1837 u_char *p;
1838
1839 p = ngx_resolver_alloc(r, size);
1840
1841 if (p) {
1842 ngx_memzero(p, size);
1843 }
1844
1845 return p;
1846 }
1847
1848
1849 static void
1850 ngx_resolver_free(ngx_resolver_t *r, void *p)
1851 {
1852 /* lock alloc mutex */
1853
1854 ngx_free(p);
1855
1856 /* unlock alloc mutex */
1857 }
1858
1859
1860 static void
1861 ngx_resolver_free_locked(ngx_resolver_t *r, void *p)
1862 {
1863 ngx_free(p);
1864 }
1865
1866
1867 static void *
1868 ngx_resolver_dup(ngx_resolver_t *r, void *src, size_t size)
1869 {
1870 void *dst;
1871
1872 dst = ngx_resolver_alloc(r, size);
1873
1874 if (dst == NULL) {
1875 return dst;
1876 }
1877
1878 ngx_memcpy(dst, src, size);
1879
1880 return dst;
1881 }
1882
1883
1884 char *
1885 ngx_resolver_strerror(ngx_int_t err)
1886 {
1887 static char *errors[] = {
1888 "Format error", /* FORMERR */
1889 "Server failure", /* SERVFAIL */
1890 "Host not found", /* NXDOMAIN */
1891 "Unimplemented", /* NOTIMP */
1892 "Operation refused" /* REFUSED */
1893 };
1894
1895 if (err > 0 && err < 6) {
1896 return errors[err - 1];
1897 }
1898
1899 if (err == NGX_RESOLVE_TIMEDOUT) {
1900 return "Operation timed out";
1901 }
1902
1903 return "Unknown error";
1904 }
1905
1906
1907 ngx_int_t
1908 ngx_udp_connect(ngx_udp_connection_t *uc)
1909 {
1910 int rc;
1911 ngx_int_t event;
1912 ngx_event_t *rev, *wev;
1913 ngx_socket_t s;
1914 ngx_connection_t *c;
1915
361916 s = ngx_socket(AF_INET, SOCK_DGRAM, 0);
371917
38 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, r->log, 0, "socket %d", s);
1918 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, uc->log, 0, "UDP socket %d", s);
391919
401920 if (s == -1) {
41 ngx_log_error(NGX_LOG_ALERT, r->log, ngx_socket_errno,
1921 ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
421922 ngx_socket_n " failed");
431923 return NGX_ERROR;
441924 }
451925
46 c = ngx_get_connection(s, r->log);
1926 c = ngx_get_connection(s, uc->log);
471927
481928 if (c == NULL) {
491929 if (ngx_close_socket(s) == -1) {
50 ngx_log_error(NGX_LOG_ALERT, r->log, ngx_socket_errno,
1930 ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
511931 ngx_close_socket_n "failed");
1932 }
1933
1934 return NGX_ERROR;
1935 }
1936
1937 if (ngx_nonblocking(s) == -1) {
1938 ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
1939 ngx_nonblocking_n " failed");
1940
1941 ngx_free_connection(c);
1942
1943 if (ngx_close_socket(s) == -1) {
1944 ngx_log_error(NGX_LOG_ALERT, uc->log, ngx_socket_errno,
1945 ngx_close_socket_n " failed");
521946 }
531947
541948 return NGX_ERROR;
571951 rev = c->read;
581952 wev = c->write;
591953
60 rev->log = pc->log;
61 wev->log = pc->log;
62
63 r->connection = c;
64
65 /*
66 * TODO: MT: - ngx_atomic_fetch_add()
67 * or protection by critical section or mutex
68 *
69 * TODO: MP: - allocated in a shared memory
70 * - ngx_atomic_fetch_add()
71 * or protection by critical section or mutex
72 */
1954 rev->log = uc->log;
1955 wev->log = uc->log;
1956
1957 uc->connection = c;
731958
741959 c->number = ngx_atomic_fetch_add(ngx_connection_counter, 1);
751960
761961 #if (NGX_THREADS)
77 rev->lock = pc->lock;
78 wev->lock = pc->lock;
1962
1963 /* TODO: lock event when call completion handler */
1964
1965 rev->lock = &c->lock;
1966 wev->lock = &c->lock;
791967 rev->own_lock = &c->lock;
801968 wev->own_lock = &c->lock;
1969
811970 #endif
821971
83 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, pc->log, 0,
84 "connect to %V, fd:%d #%d", &r->server, s, c->number);
85
86 rc = connect(s, r->sockaddr, r->socklen);
1972 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, uc->log, 0,
1973 "connect to %V, fd:%d #%d", &uc->server, s, c->number);
1974
1975 rc = connect(s, uc->sockaddr, uc->socklen);
1976
1977 /* TODO: aio, iocp */
871978
881979 if (rc == -1) {
89 ngx_log_error(level, r->log, ngx_socket_errno,
90 "connect() to %V failed", &r->server);
1980 ngx_log_error(NGX_LOG_CRIT, uc->log, ngx_socket_errno,
1981 "connect() to %V failed", &uc->server);
911982
921983 return NGX_ERROR;
931984 }
941985
95
96
97
98
99
100
101 if (ngx_add_conn) {
1986 /* UDP sockets are always ready to write */
1987 wev->ready = 1;
1988
1989 if (ngx_add_event) {
1990
1991 event = (ngx_event_flags & NGX_USE_CLEAR_EVENT) ?
1992 /* kqueue, epoll */ NGX_CLEAR_EVENT:
1993 /* select, poll, /dev/poll */ NGX_LEVEL_EVENT;
1994 /* eventport event type has no meaning: oneshot only */
1995
1996 if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
1997 return NGX_ERROR;
1998 }
1999
2000 } else {
2001 /* rtsig */
2002
1022003 if (ngx_add_conn(c) == NGX_ERROR) {
1032004 return NGX_ERROR;
1042005 }
1052006 }
1062007
107
108 if (ngx_add_conn) {
109 if (rc == -1) {
110
111 /* NGX_EINPROGRESS */
112
113 return NGX_AGAIN;
114 }
115
116 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected");
117
118 wev->ready = 1;
119
120 return NGX_OK;
121 }
122
123 if (ngx_event_flags & NGX_USE_AIO_EVENT) {
124
125 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, pc->log, ngx_socket_errno,
126 "connect(): %d", rc);
127
128 /* aio, iocp */
129
130 if (ngx_blocking(s) == -1) {
131 ngx_log_error(NGX_LOG_ALERT, pc->log, ngx_socket_errno,
132 ngx_blocking_n " failed");
133 return NGX_ERROR;
134 }
135
136 /*
137 * FreeBSD's aio allows to post an operation on non-connected socket.
138 * NT does not support it.
139 *
140 * TODO: check in Win32, etc. As workaround we can use NGX_ONESHOT_EVENT
141 */
142
143 rev->ready = 1;
144 wev->ready = 1;
145
146 return NGX_OK;
147 }
148
149 if (ngx_event_flags & NGX_USE_CLEAR_EVENT) {
150
151 /* kqueue */
152
153 event = NGX_CLEAR_EVENT;
154
155 } else {
156
157 /* select, poll, /dev/poll */
158
159 event = NGX_LEVEL_EVENT;
160 }
161
162 if (ngx_add_event(rev, NGX_READ_EVENT, event) != NGX_OK) {
163 return NGX_ERROR;
164 }
165
166 if (rc == -1) {
167
168 /* NGX_EINPROGRESS */
169
170 if (ngx_add_event(wev, NGX_WRITE_EVENT, event) != NGX_OK) {
171 return NGX_ERROR;
172 }
173
174 return NGX_AGAIN;
175 }
176
177 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, pc->log, 0, "connected");
178
179 wev->ready = 1;
180
1812008 return NGX_OK;
1822009 }
0
1 /*
2 * Copyright (C) Igor Sysoev
3 */
4
5
6 #include <ngx_config.h>
7 #include <ngx_core.h>
8
9
10 #ifndef _NGX_RESOLVER_H_INCLUDED_
11 #define _NGX_RESOLVER_H_INCLUDED_
12
13
14 #define NGX_RESOLVE_A 1
15 #define NGX_RESOLVE_CNAME 5
16 #define NGX_RESOLVE_PTR 12
17 #define NGX_RESOLVE_MX 15
18 #define NGX_RESOLVE_TXT 16
19
20 #define NGX_RESOLVE_FORMERR 1
21 #define NGX_RESOLVE_SERVFAIL 2
22 #define NGX_RESOLVE_NXDOMAIN 3
23 #define NGX_RESOLVE_NOTIMP 4
24 #define NGX_RESOLVE_REFUSED 5
25 #define NGX_RESOLVE_TIMEDOUT NGX_ETIMEDOUT
26
27
28 typedef struct {
29 ngx_connection_t *connection;
30 struct sockaddr *sockaddr;
31 socklen_t socklen;
32 ngx_str_t server;
33 ngx_log_t *log;
34 } ngx_udp_connection_t;
35
36
37 typedef struct ngx_resolver_ctx_s ngx_resolver_ctx_t;
38
39 typedef void (*ngx_resolver_handler_pt)(ngx_resolver_ctx_t *ctx);
40
41
42 typedef struct {
43 ngx_rbtree_node_t node;
44 ngx_queue_t queue;
45
46 /* PTR: resolved name, A: name to resolve */
47 u_char *name;
48
49 u_short nlen;
50 u_short qlen;
51
52 u_char *query;
53
54 union {
55 in_addr_t addr;
56 in_addr_t *addrs;
57 u_char *cname;
58 } u;
59
60 u_short naddrs;
61 u_short cnlen;
62
63 time_t expire;
64 time_t valid;
65
66 ngx_resolver_ctx_t *waiting;
67 } ngx_resolver_node_t;
68
69
70 typedef struct {
71 /* has to be pointer because of "incomplete type" */
72 ngx_event_t *event;
73
74 /* TODO: DNS peers balancer */
75 /* STUB */
76 ngx_udp_connection_t *udp_connection;
77
78 ngx_log_t *log;
79
80 /* ident must be after 3 pointers */
81 ngx_int_t ident;
82
83 ngx_rbtree_t name_rbtree;
84 ngx_rbtree_node_t name_sentinel;
85
86 ngx_rbtree_t addr_rbtree;
87 ngx_rbtree_node_t addr_sentinel;
88
89 ngx_queue_t name_resend_queue;
90 ngx_queue_t addr_resend_queue;
91
92 ngx_queue_t name_expire_queue;
93 ngx_queue_t addr_expire_queue;
94
95 time_t resend_timeout;
96 time_t expire;
97 time_t valid;
98
99 ngx_uint_t log_level;
100 } ngx_resolver_t;
101
102
103 struct ngx_resolver_ctx_s {
104 ngx_resolver_ctx_t *next;
105 ngx_resolver_t *resolver;
106 ngx_udp_connection_t *udp_connection;
107
108 /* ident must be after 3 pointers */
109 ngx_int_t ident;
110
111 ngx_int_t state;
112 ngx_int_t type;
113 ngx_str_t name;
114
115 ngx_uint_t naddrs;
116 in_addr_t *addrs;
117 in_addr_t addr;
118
119 /* TODO: DNS peers balancer ctx */
120
121 ngx_resolver_handler_pt handler;
122 void *data;
123 ngx_msec_t timeout;
124
125 ngx_uint_t quick; /* unsigned quick:1; */
126 ngx_event_t *event;
127 };
128
129
130 ngx_resolver_t *ngx_resolver_create(ngx_peer_addr_t *addr, ngx_log_t *log);
131 ngx_resolver_ctx_t *ngx_resolve_start(ngx_resolver_t *r,
132 ngx_resolver_ctx_t *temp);
133 ngx_int_t ngx_resolve_name(ngx_resolver_ctx_t *ctx);
134 void ngx_resolve_name_done(ngx_resolver_ctx_t *ctx);
135 ngx_int_t ngx_resolve_addr(ngx_resolver_ctx_t *ctx);
136 void ngx_resolve_addr_done(ngx_resolver_ctx_t *ctx);
137 void *ngx_resolver_calloc(ngx_resolver_t *r, size_t size);
138 char *ngx_resolver_strerror(ngx_int_t err);
139
140
141 #endif /* _NGX_RESOLVER_H_INCLUDED_ */