comparison http_resolver.t @ 357:e0c00e695cb5

Tests: removed Net::DNS dependency.
author Sergey Kandaurov <pluknet@nginx.com>
date Fri, 22 Nov 2013 15:20:16 +0400
parents 7a472e46772c
children cdab739eb6ea
comparison
equal deleted inserted replaced
356:7a472e46772c 357:e0c00e695cb5
19 19
20 ############################################################################### 20 ###############################################################################
21 21
22 select STDERR; $| = 1; 22 select STDERR; $| = 1;
23 select STDOUT; $| = 1; 23 select STDOUT; $| = 1;
24
25 eval { require Net::DNS::Nameserver; };
26 plan(skip_all => "Net::DNS::Nameserver not installed") if $@;
27 24
28 my $t = Test::Nginx->new()->has(qw/http proxy rewrite ipv6/); 25 my $t = Test::Nginx->new()->has(qw/http proxy rewrite ipv6/);
29 26
30 $t->write_file_expand('nginx.conf', <<'EOF'); 27 $t->write_file_expand('nginx.conf', <<'EOF');
31 28
85 } 82 }
86 } 83 }
87 } 84 }
88 85
89 EOF 86 EOF
90
91 $t->run_daemon(\&dns_daemon, 8081);
92 $t->run_daemon(\&dns_daemon, 8082);
93 87
94 eval { 88 eval {
95 open OLDERR, ">&", \*STDERR; close STDERR; 89 open OLDERR, ">&", \*STDERR; close STDERR;
96 $t->run(); 90 $t->run();
97 open STDERR, ">&", \*OLDERR; 91 open STDERR, ">&", \*OLDERR;
98 }; 92 };
99 plan(skip_all => 'no inet6 support') if $@; 93 plan(skip_all => 'no inet6 support') if $@;
100 94
101 $t->waitforsocket('127.0.0.1:8081'); 95 $t->run_daemon(\&dns_daemon, 8081, $t);
102 $t->waitforsocket('127.0.0.1:8082'); 96 $t->run_daemon(\&dns_daemon, 8082, $t);
97
98 $t->waitforfile($t->testdir . '/8081');
99 $t->waitforfile($t->testdir . '/8082');
103 100
104 $t->plan(28); 101 $t->plan(28);
105 102
106 ############################################################################### 103 ###############################################################################
107 104
229 } 226 }
230 227
231 ############################################################################### 228 ###############################################################################
232 229
233 sub reply_handler { 230 sub reply_handler {
234 my ($name, $class, $type, $peerhost, $query, $conn) = @_; 231 my ($recv_data, $port) = @_;
235 my ($rcode, @ans, $ttl, $rdata); 232
236 233 my (@name, @rdata);
237 $rcode = 'NOERROR'; 234
238 $ttl = 3600; 235 use constant NOERROR => 0;
239 236 use constant SERVFAIL => 2;
237 use constant NXDOMAIN => 3;
238
239 use constant A => 1;
240 use constant CNAME => 5;
241 use constant AAAA => 28;
242 use constant DNAME => 39;
243
244 use constant IN => 1;
245
246 # default values
247
248 my ($hdr, $rcode, $ttl) = (0x8180, NOERROR, 3600);
249
250 # decode name
251
252 my ($len, $offset) = (undef, 12);
253 while (1) {
254 $len = unpack("\@$offset C", $recv_data);
255 last if $len == 0;
256 $offset++;
257 push @name, unpack("\@$offset A$len", $recv_data);
258 $offset += $len;
259 }
260
261 $offset -= 1;
262 my ($id, $type, $class) = unpack("n x$offset n2", $recv_data);
263
264 my $name = join('.', @name);
240 if (($name eq 'a.example.net') || ($name eq 'alias.example.net')) { 265 if (($name eq 'a.example.net') || ($name eq 'alias.example.net')) {
241 ($rdata) = ('127.0.0.1'); 266 push @rdata, rd_addr($ttl, '127.0.0.1');
242 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata");
243 267
244 } elsif (($name eq 'many.example.net')) { 268 } elsif (($name eq 'many.example.net')) {
245 if ($conn->{sockport} == 8082) { 269 if ($port == 8082) {
246 return 'SERVFAIL'; 270 $rcode = SERVFAIL;
247 } 271 }
248 ($rdata) = ('127.0.0.201'); 272
249 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); 273 push @rdata, rd_addr($ttl, '127.0.0.201');
250 ($rdata) = ('127.0.0.202'); 274 push @rdata, rd_addr($ttl, '127.0.0.202');
251 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata");
252 275
253 } elsif (($name eq 'aaaa.example.net')) { 276 } elsif (($name eq 'aaaa.example.net')) {
254 ($type, $rdata) = ('AAAA', '::1'); 277 # AAAA [::1]
255 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); 278
279 push @rdata, pack('n3N nx15C', 0xc00c, AAAA, IN, $ttl,
280 16, 1);
256 281
257 } elsif (($name eq 'short.example.net')) { 282 } elsif (($name eq 'short.example.net')) {
258 # zero length RDATA in DNS response 283 # zero length RDATA in DNS response
259 ($name, $rdata) = ($name, ''); 284
260 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); 285 push @rdata, rd_addr($ttl, '');
261 286
262 } elsif (($name eq 'alias.example.com')) { 287 } elsif (($name eq 'alias.example.com')) {
263 my $dname = 'example.com'; 288 # example.com. 3600 IN DNAME example.net.
264 ($type, $rdata) = ('DNAME', 'example.net'); 289
265 push @ans, Net::DNS::RR->new("$dname $ttl $class $type $rdata"); 290 my @dname = ('example', 'net');
266 ($type, $rdata) = ('CNAME', 'alias.example.net'); 291 my $rdlen = length(join '', @dname) + @dname + 1;
267 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); 292 push @rdata, pack("n3N n(w/a*)* x", 0xc012, DNAME, IN, $ttl,
293 $rdlen, @dname);
294
295 # alias.example.com. 3600 IN CNAME alias.example.net.
296
297 push @rdata, pack("n3N nCa5n", 0xc00c, CNAME, IN, $ttl,
298 8, 5, 'alias', 0xc02f);
268 299
269 } elsif ($name eq 'cname.example.net') { 300 } elsif ($name eq 'cname.example.net') {
270 if ($conn->{sockport} == 8082) { 301 if ($port == 8082) {
271 return 'SERVFAIL'; 302 $rcode = SERVFAIL;
272 } 303 }
273 ($type, $rdata) = ('CNAME', 'alias.example.net'); 304 push @rdata, pack("n3N nCa5n", 0xc00c, CNAME, IN, $ttl,
274 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); 305 8, 5, 'alias', 0xc012);
275 306
276 } elsif ($name eq 'cname_a.example.net') { 307 } elsif ($name eq 'cname_a.example.net') {
277 ($type, $rdata) = ('CNAME', 'alias.example.net'); 308 push @rdata, pack("n3N nCa5n", 0xc00c, CNAME, IN, $ttl,
278 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); 309 8, 5, 'alias', 0xc014);
279 310
280 ($name, $type, $rdata) = ('alias.example.net', 'A', '127.0.0.1'); 311 # points to "alias" set in previous rdata
281 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); 312
313 push @rdata, pack('n3N nC4', 0xc031, A, IN, $ttl,
314 4, split(/\./, '127.0.0.1'));
282 315
283 } elsif ($name eq 'cname2.example.net') { 316 } elsif ($name eq 'cname2.example.net') {
284 # points to non-existing A 317 # points to non-existing A
285 ($type, $rdata) = ('CNAME', 'nx.example.net'); 318
286 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); 319 push @rdata, pack("n3N nCa2n", 0xc00c, CNAME, IN, $ttl,
320 5, 2, 'nx', 0xc02f);
287 321
288 } elsif ($name eq 'long.example.net') { 322 } elsif ($name eq 'long.example.net') {
289 ($type, $rdata) = ('CNAME', 'a' x 63); 323 push @rdata, pack("n3N nCA63x", 0xc00c, CNAME, IN, $ttl,
290 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); 324 65, 63, 'a' x 63);
291 325
292 } elsif (($name eq 'a' x 63)) { 326 } elsif (($name eq 'a' x 63)) {
293 ($rdata) = ('127.0.0.1'); 327 push @rdata, rd_addr($ttl, '127.0.0.1');
294 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata");
295 328
296 } elsif ($name eq 'long2.example.net') { 329 } elsif ($name eq 'long2.example.net') {
297 ($type, $rdata) = ('CNAME', 'a' x 63 . '.' . 'a' x 63 . '.' 330 push @rdata, pack("n3N n(CA63)4x", 0xc00c, CNAME, IN, $ttl, 257,
298 . 'a' x 63 . '.' . 'a' x 63); 331 63, 'a' x 63, 63, 'a' x 63, 63, 'a' x 63, 63, 'a' x 63);
299 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata");
300 332
301 } elsif (($name eq 'a' x 63 . '.' . 'a' x 63 . '.' . 'a' x 63 . '.' 333 } elsif (($name eq 'a' x 63 . '.' . 'a' x 63 . '.' . 'a' x 63 . '.'
302 . 'a' x 63)) 334 . 'a' x 63))
303 { 335 {
304 ($rdata) = ('127.0.0.1'); 336 push @rdata, rd_addr($ttl, '127.0.0.1');
305 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata");
306 337
307 } elsif ($name eq 'ttl.example.net') { 338 } elsif ($name eq 'ttl.example.net') {
308 if ($conn->{sockport} == 8082) { 339 if ($port == 8082) {
309 return 'SERVFAIL'; 340 $rcode = SERVFAIL;
310 } 341 }
311 ($ttl, $rdata) = (1, '127.0.0.1'); 342
312 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); 343 push @rdata, rd_addr(1, '127.0.0.1');
313 344
314 } elsif ($name eq 'ttl0.example.net') { 345 } elsif ($name eq 'ttl0.example.net') {
315 if ($conn->{sockport} == 8082) { 346 if ($port == 8082) {
316 return 'SERVFAIL'; 347 $rcode = SERVFAIL;
317 } 348 }
318 ($ttl, $rdata) = (0, '127.0.0.1'); 349
319 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); 350 push @rdata, rd_addr(0, '127.0.0.1');
320 351
321 } elsif ($name eq '2.example.net') { 352 } elsif ($name eq '2.example.net') {
322 if ($conn->{sockport} == 8081) { 353 if ($port == 8081) {
323 return 'SERVFAIL'; 354 $rcode = SERVFAIL;
324 } 355 }
325 ($rdata) = ('127.0.0.1'); 356
326 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); 357 push @rdata, rd_addr(0, '127.0.0.1');
327 358
328 } else { 359 } else {
329 $rcode = 'NXDOMAIN'; 360 $rcode = NXDOMAIN;
330 } 361 }
331 362
332 return ($rcode, \@ans); 363 $len = @name;
364 pack("n6 (w/a*)$len x n2", $id, $hdr | $rcode, 1, scalar @rdata,
365 0, 0, @name, $type, $class) . join('', @rdata);
366 }
367
368 sub rd_addr {
369 my ($ttl, $addr) = @_;
370
371 my $code = 'split(/\./, $addr)';
372
373 return pack 'n3N', 0xc00c, A, IN, $ttl if $addr eq '';
374
375 pack 'n3N nC4', 0xc00c, A, IN, $ttl, eval "scalar $code", eval($code);
333 } 376 }
334 377
335 sub dns_daemon { 378 sub dns_daemon {
336 my ($port) = @_; 379 my ($port, $t) = @_;
337 380
338 my $ns = Net::DNS::Nameserver->new( 381 my ($data, $recv_data);
382 my $socket = IO::Socket::INET->new(
339 LocalAddr => '127.0.0.1', 383 LocalAddr => '127.0.0.1',
340 LocalPort => $port, 384 LocalPort => $port,
341 Proto => 'udp', 385 Proto => 'udp',
342 ReplyHandler => \&reply_handler,
343 ) 386 )
344 or die "Can't create nameserver object: $!\n"; 387 or die "Can't create listening socket: $!\n";
345 388
346 $ns->main_loop; 389 # signal we are ready
347 } 390
348 391 open my $fh, '>', $t->testdir() . '/' . $port;
349 ############################################################################### 392 close $fh;
393
394 while (1) {
395 $socket->recv($recv_data, 65536);
396 $data = reply_handler($recv_data, $port);
397 $socket->send($data);
398 }
399 }
400
401 ###############################################################################