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