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