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