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