Mercurial > hg > nginx-tests
comparison http_resolver.t @ 359:cdab739eb6ea
Tests: resolver tests enabled to work with AAAA capable resolver.
author | Sergey Kandaurov <pluknet@nginx.com> |
---|---|
date | Thu, 12 Dec 2013 18:31:29 +0400 |
parents | e0c00e695cb5 |
children | 8ca9c75c97d2 |
comparison
equal
deleted
inserted
replaced
358:ec9f4f2e67e8 | 359:cdab739eb6ea |
---|---|
20 ############################################################################### | 20 ############################################################################### |
21 | 21 |
22 select STDERR; $| = 1; | 22 select STDERR; $| = 1; |
23 select STDOUT; $| = 1; | 23 select STDOUT; $| = 1; |
24 | 24 |
25 my $t = Test::Nginx->new()->has(qw/http proxy rewrite ipv6/); | 25 my $t = Test::Nginx->new()->has(qw/http proxy rewrite/); |
26 | 26 |
27 $t->write_file_expand('nginx.conf', <<'EOF'); | 27 $t->write_file_expand('nginx.conf', <<'EOF'); |
28 | 28 |
29 %%TEST_GLOBALS%% | 29 %%TEST_GLOBALS%% |
30 | 30 |
36 http { | 36 http { |
37 %%TEST_GLOBALS_HTTP%% | 37 %%TEST_GLOBALS_HTTP%% |
38 | 38 |
39 server { | 39 server { |
40 listen 127.0.0.1:8080; | 40 listen 127.0.0.1:8080; |
41 listen [::1]:8080; | |
42 server_name localhost; | 41 server_name localhost; |
43 | 42 |
44 location / { | 43 location / { |
45 resolver 127.0.0.1:8081; | 44 resolver 127.0.0.1:8081; |
46 # to lower resolving delay for unsupported AAAA | |
47 resolver_timeout 1s; | 45 resolver_timeout 1s; |
48 proxy_pass http://$host:8080/backend; | 46 proxy_pass http://$host:8080/backend; |
49 } | 47 |
50 location /cached { | 48 proxy_next_upstream http_504 timeout error; |
49 proxy_intercept_errors on; | |
50 proxy_connect_timeout 1s; | |
51 error_page 504 502 /50x; | |
52 } | |
53 location /two { | |
51 resolver 127.0.0.1:8081 127.0.0.1:8082; | 54 resolver 127.0.0.1:8081 127.0.0.1:8082; |
52 proxy_pass http://$host:8080/backend; | 55 proxy_pass http://$host:8080/backend; |
53 } | 56 } |
54 location /two { | |
55 resolver 127.0.0.1:8081 127.0.0.1:8082; | |
56 resolver_timeout 2s; | |
57 proxy_pass http://$host:8080/backend; | |
58 } | |
59 location /valid { | 57 location /valid { |
60 resolver 127.0.0.1:8081 127.0.0.1:8082 valid=3s; | 58 resolver 127.0.0.1:8081 valid=3s; |
61 resolver_timeout 2s; | |
62 proxy_pass http://$host:8080/backend; | 59 proxy_pass http://$host:8080/backend; |
63 } | 60 } |
64 location /invalid { | 61 location /invalid { |
65 proxy_pass http://$host:8080/backend; | 62 proxy_pass http://$host:8080/backend; |
66 } | 63 } |
67 location /many { | |
68 resolver 127.0.0.1:8081 127.0.0.1:8082; | |
69 resolver_timeout 2s; | |
70 proxy_pass http://$host:8080/backend; | |
71 proxy_next_upstream http_504 timeout error; | |
72 proxy_intercept_errors on; | |
73 proxy_connect_timeout 2s; | |
74 error_page 504 502 /50x; | |
75 } | |
76 | 64 |
77 location /backend { | 65 location /backend { |
78 return 200; | 66 return 200; |
79 } | 67 } |
80 location /50x { | 68 location /50x { |
83 } | 71 } |
84 } | 72 } |
85 | 73 |
86 EOF | 74 EOF |
87 | 75 |
88 eval { | |
89 open OLDERR, ">&", \*STDERR; close STDERR; | |
90 $t->run(); | |
91 open STDERR, ">&", \*OLDERR; | |
92 }; | |
93 plan(skip_all => 'no inet6 support') if $@; | |
94 | |
95 $t->run_daemon(\&dns_daemon, 8081, $t); | 76 $t->run_daemon(\&dns_daemon, 8081, $t); |
96 $t->run_daemon(\&dns_daemon, 8082, $t); | 77 $t->run_daemon(\&dns_daemon, 8082, $t); |
97 | 78 |
79 $t->run()->plan(27); | |
80 | |
98 $t->waitforfile($t->testdir . '/8081'); | 81 $t->waitforfile($t->testdir . '/8081'); |
99 $t->waitforfile($t->testdir . '/8082'); | 82 $t->waitforfile($t->testdir . '/8082'); |
100 | |
101 $t->plan(28); | |
102 | 83 |
103 ############################################################################### | 84 ############################################################################### |
104 | 85 |
105 like(http_host_header('a.example.net', '/'), qr/200 OK/, 'A'); | 86 like(http_host_header('a.example.net', '/'), qr/200 OK/, 'A'); |
106 like(http_host_header('short.example.net', '/'), qr/502 Bad/, | 87 like(http_host_header('short.example.net', '/'), qr/502 Bad/, |
107 'A short dns response'); | 88 'A short dns response'); |
108 | 89 |
109 TODO: { | |
110 local $TODO = 'support for AAAA'; | |
111 | |
112 like(http_host_header('aaaa.example.net', '/'), qr/200 OK/, 'AAAA'); | |
113 | |
114 } | |
115 | |
116 like(http_host_header('nx.example.net', '/'), qr/502 Bad/, 'NXDOMAIN'); | 90 like(http_host_header('nx.example.net', '/'), qr/502 Bad/, 'NXDOMAIN'); |
117 like(http_host_header('cname.example.net', '/cached'), qr/200 OK/, 'CNAME'); | 91 like(http_host_header('cname.example.net', '/'), qr/200 OK/, 'CNAME'); |
118 like(http_host_header('cname.example.net', '/cached'), qr/200 OK/, | 92 like(http_host_header('cname.example.net', '/'), qr/200 OK/, |
119 'CNAME cached'); | 93 'CNAME cached'); |
120 | 94 |
121 # CNAME + A combined answer | 95 # CNAME + A combined answer |
122 # demonstrates the name in answer section different from what is asked | 96 # demonstrates the name in answer section different from what is asked |
123 | 97 |
134 like(http_host_header('alias.example.com', '/'), qr/200 OK/, 'DNAME'); | 108 like(http_host_header('alias.example.com', '/'), qr/200 OK/, 'DNAME'); |
135 | 109 |
136 # many A records in round robin | 110 # many A records in round robin |
137 # nonexisting IPs enumerated with proxy_next_upstream | 111 # nonexisting IPs enumerated with proxy_next_upstream |
138 | 112 |
139 like(http_host_header('many.example.net', '/many'), | 113 like(http_host_header('many.example.net', '/'), |
140 qr/^127.0.0.20(1:8080, 127.0.0.202:8080|2:8080, 127.0.0.201:8080)$/m, | 114 qr/^127.0.0.20(1:8080, 127.0.0.202:8080|2:8080, 127.0.0.201:8080)$/m, |
141 'A many'); | 115 'A many'); |
142 | 116 |
143 like(http_host_header('many.example.net', '/many'), | 117 like(http_host_header('many.example.net', '/'), |
144 qr/^127.0.0.20(1:8080, 127.0.0.202:8080|2:8080, 127.0.0.201:8080)$/m, | 118 qr/^127.0.0.20(1:8080, 127.0.0.202:8080|2:8080, 127.0.0.201:8080)$/m, |
145 'A many cached'); | 119 'A many cached'); |
146 | 120 |
147 # several resolver addresses with 1st ns bad | 121 # tests for several resolvers specified in directive |
148 # query bad ns, negative responses are not cached | 122 # query bad ns, make sure that error responses are not cached |
149 | 123 |
150 like(http_host_header('2.example.net', '/two'), qr/502 Bad/, 'two ns bad'); | 124 like(http_host_header('2.example.net', '/two'), qr/502 Bad/, 'two ns bad'); |
151 | 125 |
152 # query alive ns | 126 # now get correct response |
153 | 127 |
154 like(http_host_header('2.example.net', '/two'), qr/200 OK/, 'two ns good'); | 128 like(http_host_header('2.example.net', '/two'), qr/200 OK/, 'two ns good'); |
155 | 129 |
156 # cached response prevents querying the next (bad) ns again | 130 # response is cached, actual request would get error |
157 | 131 |
158 like(http_host_header('2.example.net', '/two'), qr/200 OK/, 'two ns cached'); | 132 like(http_host_header('2.example.net', '/two'), qr/200 OK/, 'two ns cached'); |
159 | 133 |
160 # ttl tested with 1st ns good and 2nd ns bad | 134 # ttl tested with 1st req good and 2nd req bad |
161 # query good ns and cache response | 135 # send 1st request and cache its good response |
162 | 136 |
163 like(http_host_header('ttl.example.net', '/two'), qr/200 OK/, 'ttl'); | 137 like(http_host_header('ttl.example.net', '/'), qr/200 OK/, 'ttl'); |
164 | 138 |
165 # cached response prevents querying the next (bad) ns | 139 # response is cached, actual request would get error |
166 | 140 |
167 like(http_host_header('ttl.example.net', '/two'), qr/200 OK/, 'ttl cached 1'); | 141 like(http_host_header('ttl.example.net', '/'), qr/200 OK/, 'ttl cached 1'); |
168 like(http_host_header('ttl.example.net', '/two'), qr/200 OK/, 'ttl cached 2'); | 142 like(http_host_header('ttl.example.net', '/'), qr/200 OK/, 'ttl cached 2'); |
169 | 143 |
170 sleep 2; | 144 sleep 2; |
171 | 145 |
172 # expired ttl causes nginx to query the next (bad) ns | 146 # expired ttl causes nginx to make actual query |
173 | 147 |
174 like(http_host_header('ttl.example.net', '/two'), qr/502 Bad/, 'ttl expired'); | 148 like(http_host_header('ttl.example.net', '/'), qr/502 Bad/, 'ttl expired'); |
175 | 149 |
176 # zero ttl prohibits response caching | 150 # zero ttl prohibits response caching |
177 | 151 |
178 like(http_host_header('ttl0.example.net', '/two'), qr/200 OK/, 'zero ttl'); | 152 like(http_host_header('ttl0.example.net', '/'), qr/200 OK/, 'zero ttl'); |
179 | 153 |
180 TODO: { | 154 TODO: { |
181 local $TODO = 'support for zero ttl'; | 155 local $TODO = 'support for zero ttl'; |
182 | 156 |
183 like(http_host_header('ttl0.example.net', '/two'), qr/502 Bad/, | 157 like(http_host_header('ttl0.example.net', '/'), qr/502 Bad/, |
184 'zero ttl not cached'); | 158 'zero ttl not cached'); |
185 | 159 |
186 } | 160 } |
187 | 161 |
188 # "valid" parameter tested with 1st alive ns and 2nd bad ns | 162 # "valid" parameter tested with 1st req good and 2nd req bad |
189 # query alive ns, and cache response | 163 # send 1st request and cache its good response |
190 | 164 |
191 like(http_host_header('ttl.example.net', '/valid'), qr/200 OK/, 'valid'); | 165 like(http_host_header('ttl.example.net', '/valid'), qr/200 OK/, 'valid'); |
192 | 166 |
193 # cached response prevents querying the next (bad) ns | 167 # response is cached, actual request would get error |
194 | 168 |
195 like(http_host_header('ttl.example.net', '/valid'), qr/200 OK/, | 169 like(http_host_header('ttl.example.net', '/valid'), qr/200 OK/, |
196 'valid cached 1'); | 170 'valid cached 1'); |
197 like(http_host_header('ttl.example.net', '/valid'), qr/200 OK/, | 171 like(http_host_header('ttl.example.net', '/valid'), qr/200 OK/, |
198 'valid cached 2'); | 172 'valid cached 2'); |
205 like(http_host_header('ttl.example.net', '/valid'), qr/200 OK/, | 179 like(http_host_header('ttl.example.net', '/valid'), qr/200 OK/, |
206 'valid overrides ttl'); | 180 'valid overrides ttl'); |
207 | 181 |
208 sleep 2; | 182 sleep 2; |
209 | 183 |
210 # expired "valid" value causes nginx to query the next (bad) ns | 184 # expired "valid" value causes nginx to make actual query |
211 | 185 |
212 like(http_host_header('ttl.example.net', '/valid'), qr/502 Bad/, | 186 like(http_host_header('ttl.example.net', '/valid'), qr/502 Bad/, |
213 'valid expired'); | 187 'valid expired'); |
214 | 188 |
215 like(http_host_header('example.net', '/invalid'), qr/502 Bad/, 'no resolver'); | 189 like(http_host_header('example.net', '/invalid'), qr/502 Bad/, 'no resolver'); |
226 } | 200 } |
227 | 201 |
228 ############################################################################### | 202 ############################################################################### |
229 | 203 |
230 sub reply_handler { | 204 sub reply_handler { |
231 my ($recv_data, $port) = @_; | 205 my ($recv_data, $port, $state) = @_; |
232 | 206 |
233 my (@name, @rdata); | 207 my (@name, @rdata); |
234 | 208 |
235 use constant NOERROR => 0; | 209 use constant NOERROR => 0; |
236 use constant SERVFAIL => 2; | 210 use constant SERVFAIL => 2; |
237 use constant NXDOMAIN => 3; | 211 use constant NXDOMAIN => 3; |
238 | 212 |
239 use constant A => 1; | 213 use constant A => 1; |
240 use constant CNAME => 5; | 214 use constant CNAME => 5; |
241 use constant AAAA => 28; | |
242 use constant DNAME => 39; | 215 use constant DNAME => 39; |
243 | 216 |
244 use constant IN => 1; | 217 use constant IN => 1; |
245 | 218 |
246 # default values | 219 # default values |
261 $offset -= 1; | 234 $offset -= 1; |
262 my ($id, $type, $class) = unpack("n x$offset n2", $recv_data); | 235 my ($id, $type, $class) = unpack("n x$offset n2", $recv_data); |
263 | 236 |
264 my $name = join('.', @name); | 237 my $name = join('.', @name); |
265 if (($name eq 'a.example.net') || ($name eq 'alias.example.net')) { | 238 if (($name eq 'a.example.net') || ($name eq 'alias.example.net')) { |
266 push @rdata, rd_addr($ttl, '127.0.0.1'); | 239 if ($type == A || $type == CNAME) { |
267 | 240 push @rdata, rd_addr($ttl, '127.0.0.1'); |
268 } elsif (($name eq 'many.example.net')) { | 241 } |
269 if ($port == 8082) { | 242 |
243 } elsif (($name eq 'many.example.net') && $type == A) { | |
244 $state->{manycnt}++; | |
245 if ($state->{manycnt} > 1) { | |
270 $rcode = SERVFAIL; | 246 $rcode = SERVFAIL; |
271 } | 247 } |
272 | 248 |
273 push @rdata, rd_addr($ttl, '127.0.0.201'); | 249 push @rdata, rd_addr($ttl, '127.0.0.201'); |
274 push @rdata, rd_addr($ttl, '127.0.0.202'); | 250 push @rdata, rd_addr($ttl, '127.0.0.202'); |
275 | 251 |
276 } elsif (($name eq 'aaaa.example.net')) { | |
277 # AAAA [::1] | |
278 | |
279 push @rdata, pack('n3N nx15C', 0xc00c, AAAA, IN, $ttl, | |
280 16, 1); | |
281 | 252 |
282 } elsif (($name eq 'short.example.net')) { | 253 } elsif (($name eq 'short.example.net')) { |
283 # zero length RDATA in DNS response | 254 # zero length RDATA in DNS response |
284 | 255 |
285 push @rdata, rd_addr($ttl, ''); | 256 if ($type == A) { |
257 push @rdata, rd_addr($ttl, ''); | |
258 } | |
286 | 259 |
287 } elsif (($name eq 'alias.example.com')) { | 260 } elsif (($name eq 'alias.example.com')) { |
288 # example.com. 3600 IN DNAME example.net. | 261 # example.com. 3600 IN DNAME example.net. |
289 | 262 |
290 my @dname = ('example', 'net'); | 263 my @dname = ('example', 'net'); |
296 | 269 |
297 push @rdata, pack("n3N nCa5n", 0xc00c, CNAME, IN, $ttl, | 270 push @rdata, pack("n3N nCa5n", 0xc00c, CNAME, IN, $ttl, |
298 8, 5, 'alias', 0xc02f); | 271 8, 5, 'alias', 0xc02f); |
299 | 272 |
300 } elsif ($name eq 'cname.example.net') { | 273 } elsif ($name eq 'cname.example.net') { |
301 if ($port == 8082) { | 274 $state->{cnamecnt}++; |
302 $rcode = SERVFAIL; | 275 if ($state->{cnamecnt} > 2) { |
276 $rcode = SERVFAIL; | |
303 } | 277 } |
304 push @rdata, pack("n3N nCa5n", 0xc00c, CNAME, IN, $ttl, | 278 push @rdata, pack("n3N nCa5n", 0xc00c, CNAME, IN, $ttl, |
305 8, 5, 'alias', 0xc012); | 279 8, 5, 'alias', 0xc012); |
306 | 280 |
307 } elsif ($name eq 'cname_a.example.net') { | 281 } elsif ($name eq 'cname_a.example.net') { |
308 push @rdata, pack("n3N nCa5n", 0xc00c, CNAME, IN, $ttl, | 282 push @rdata, pack("n3N nCa5n", 0xc00c, CNAME, IN, $ttl, |
309 8, 5, 'alias', 0xc014); | 283 8, 5, 'alias', 0xc014); |
310 | 284 |
311 # points to "alias" set in previous rdata | 285 # points to "alias" set in previous rdata |
312 | 286 |
313 push @rdata, pack('n3N nC4', 0xc031, A, IN, $ttl, | 287 if ($type == A) { |
314 4, split(/\./, '127.0.0.1')); | 288 push @rdata, pack('n3N nC4', 0xc031, A, IN, $ttl, |
289 4, split(/\./, '127.0.0.1')); | |
290 } | |
315 | 291 |
316 } elsif ($name eq 'cname2.example.net') { | 292 } elsif ($name eq 'cname2.example.net') { |
317 # points to non-existing A | 293 # points to non-existing A |
318 | 294 |
319 push @rdata, pack("n3N nCa2n", 0xc00c, CNAME, IN, $ttl, | 295 push @rdata, pack("n3N nCa2n", 0xc00c, CNAME, IN, $ttl, |
321 | 297 |
322 } elsif ($name eq 'long.example.net') { | 298 } elsif ($name eq 'long.example.net') { |
323 push @rdata, pack("n3N nCA63x", 0xc00c, CNAME, IN, $ttl, | 299 push @rdata, pack("n3N nCA63x", 0xc00c, CNAME, IN, $ttl, |
324 65, 63, 'a' x 63); | 300 65, 63, 'a' x 63); |
325 | 301 |
326 } elsif (($name eq 'a' x 63)) { | 302 } elsif (($name eq 'a' x 63) && $type == A) { |
327 push @rdata, rd_addr($ttl, '127.0.0.1'); | 303 push @rdata, rd_addr($ttl, '127.0.0.1'); |
328 | 304 |
329 } elsif ($name eq 'long2.example.net') { | 305 } elsif ($name eq 'long2.example.net') { |
330 push @rdata, pack("n3N n(CA63)4x", 0xc00c, CNAME, IN, $ttl, 257, | 306 push @rdata, pack("n3N n(CA63)4x", 0xc00c, CNAME, IN, $ttl, 257, |
331 63, 'a' x 63, 63, 'a' x 63, 63, 'a' x 63, 63, 'a' x 63); | 307 63, 'a' x 63, 63, 'a' x 63, 63, 'a' x 63, 63, 'a' x 63); |
332 | 308 |
333 } elsif (($name eq 'a' x 63 . '.' . 'a' x 63 . '.' . 'a' x 63 . '.' | 309 } elsif (($name eq 'a' x 63 . '.' . 'a' x 63 . '.' . 'a' x 63 . '.' |
334 . 'a' x 63)) | 310 . 'a' x 63) && $type == A) |
335 { | 311 { |
336 push @rdata, rd_addr($ttl, '127.0.0.1'); | 312 push @rdata, rd_addr($ttl, '127.0.0.1'); |
337 | 313 |
338 } elsif ($name eq 'ttl.example.net') { | 314 } elsif ($name eq 'ttl.example.net' && $type == A) { |
339 if ($port == 8082) { | 315 $state->{ttlcnt}++; |
316 if ($state->{ttlcnt} == 2 || $state->{ttlcnt} == 4) { | |
340 $rcode = SERVFAIL; | 317 $rcode = SERVFAIL; |
341 } | 318 } |
342 | 319 |
343 push @rdata, rd_addr(1, '127.0.0.1'); | 320 push @rdata, rd_addr(1, '127.0.0.1'); |
344 | 321 |
345 } elsif ($name eq 'ttl0.example.net') { | 322 } elsif ($name eq 'ttl0.example.net' && $type == A) { |
346 if ($port == 8082) { | 323 $state->{ttl0cnt}++; |
324 if ($state->{ttl0cnt} == 2) { | |
347 $rcode = SERVFAIL; | 325 $rcode = SERVFAIL; |
348 } | 326 } |
349 | 327 |
350 push @rdata, rd_addr(0, '127.0.0.1'); | 328 push @rdata, rd_addr(0, '127.0.0.1'); |
351 | 329 |
352 } elsif ($name eq '2.example.net') { | 330 } elsif ($name eq '2.example.net') { |
353 if ($port == 8081) { | 331 if ($port == 8081) { |
332 $state->{twocnt}++; | |
333 } | |
334 if ($state->{twocnt} & 1) { | |
354 $rcode = SERVFAIL; | 335 $rcode = SERVFAIL; |
355 } | 336 } |
356 | 337 |
357 push @rdata, rd_addr(0, '127.0.0.1'); | 338 if ($type == A) { |
358 | 339 push @rdata, rd_addr($ttl, '127.0.0.1'); |
359 } else { | 340 } |
360 $rcode = NXDOMAIN; | |
361 } | 341 } |
362 | 342 |
363 $len = @name; | 343 $len = @name; |
364 pack("n6 (w/a*)$len x n2", $id, $hdr | $rcode, 1, scalar @rdata, | 344 pack("n6 (w/a*)$len x n2", $id, $hdr | $rcode, 1, scalar @rdata, |
365 0, 0, @name, $type, $class) . join('', @rdata); | 345 0, 0, @name, $type, $class) . join('', @rdata); |
384 LocalPort => $port, | 364 LocalPort => $port, |
385 Proto => 'udp', | 365 Proto => 'udp', |
386 ) | 366 ) |
387 or die "Can't create listening socket: $!\n"; | 367 or die "Can't create listening socket: $!\n"; |
388 | 368 |
369 # track number of relevant queries | |
370 | |
371 my %state = ( | |
372 cnamecnt => 0, | |
373 twocnt => 0, | |
374 ttlcnt => 0, | |
375 ttl0cnt => 0, | |
376 manycnt => 0, | |
377 ); | |
378 | |
389 # signal we are ready | 379 # signal we are ready |
390 | 380 |
391 open my $fh, '>', $t->testdir() . '/' . $port; | 381 open my $fh, '>', $t->testdir() . '/' . $port; |
392 close $fh; | 382 close $fh; |
393 | 383 |
394 while (1) { | 384 while (1) { |
395 $socket->recv($recv_data, 65536); | 385 $socket->recv($recv_data, 65536); |
396 $data = reply_handler($recv_data, $port); | 386 $data = reply_handler($recv_data, $port, \%state); |
397 $socket->send($data); | 387 $socket->send($data); |
398 } | 388 } |
399 } | 389 } |
400 | 390 |
401 ############################################################################### | 391 ############################################################################### |