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 ###############################################################################