# HG changeset patch # User Sergey Kandaurov # Date 1387205956 -14400 # Node ID 8ca9c75c97d2d24bb9ede5ceaae33ff2b7a76147 # Parent aac06d3bdc057beff858a6e2eb6c310728d8c51d Tests: more resolver tests. - Uncompressed answer section. - TTL handling in CNAME + A combined answer. - Case-insensitive lookups. - PTR type checking in RR for address to name resolving. diff -r aac06d3bdc05 -r 8ca9c75c97d2 http_resolver.t --- a/http_resolver.t Mon Dec 16 14:44:29 2013 +0400 +++ b/http_resolver.t Mon Dec 16 18:59:16 2013 +0400 @@ -58,6 +58,10 @@ resolver 127.0.0.1:8081 valid=3s; proxy_pass http://$host:8080/backend; } + location /case { + resolver 127.0.0.1:8081; + proxy_pass http://$http_x_name:8080/backend; + } location /invalid { proxy_pass http://$host:8080/backend; } @@ -76,7 +80,7 @@ $t->run_daemon(\&dns_daemon, 8081, $t); $t->run_daemon(\&dns_daemon, 8082, $t); -$t->run()->plan(27); +$t->run()->plan(31); $t->waitforfile($t->testdir . '/8081'); $t->waitforfile($t->testdir . '/8082'); @@ -84,6 +88,20 @@ ############################################################################### like(http_host_header('a.example.net', '/'), qr/200 OK/, 'A'); + +# ensure that resolver serves queries from cache in a case-insensitive manner +# we check this by marking 2nd and subsequent queries on backend with SERVFAIL + +TODO: { +local $TODO = 'not yet' unless $t->has_version('1.5.8'); + +http_x_name_header('case.example.net', '/case'); +like(http_x_name_header('CASE.example.net', '/case'), qr/200 OK/, + 'A case-insensitive'); + +} + +like(http_host_header('awide.example.net', '/'), qr/200 OK/, 'A uncompressed'); like(http_host_header('short.example.net', '/'), qr/502 Bad/, 'A short dns response'); @@ -186,6 +204,31 @@ like(http_host_header('ttl.example.net', '/valid'), qr/502 Bad/, 'valid expired'); +TODO: { +local $TODO = 'not yet'; + +# Ensure that resolver respects expired A in CNAME + A combined response. +# When ttl in A is expired, only the canonical name should be queried. +# Catch this by returning SERVFAIL on the 2nd and subsequent queries for +# original name. + +http_host_header('cname_a_ttl.example.net', '/'); + +# Ensure that resolver respects expired CNAME in CNAME + A combined response. +# When ttl in CNAME is expired, the answer should not be served from cache. +# Catch this by returning SERVFAIL on the 2nd and subsequent queries. + +http_host_header('cname_a_ttl2.example.net', '/'); + +sleep 2; + +like(http_host_header('cname_a_ttl.example.net', '/'), qr/200 OK/, + 'CNAME + A with expired A ttl'); +like(http_host_header('cname_a_ttl2.example.net', '/'), qr/502 Bad/, + 'CNAME + A with expired CNAME ttl'); + +} + like(http_host_header('example.net', '/invalid'), qr/502 Bad/, 'no resolver'); ############################################################################### @@ -199,6 +242,15 @@ EOF } +sub http_x_name_header { + my ($host, $uri) = @_; + return http(<{casecnt} > 1) { + $rcode = SERVFAIL; + } + + push @rdata, rd_addr($ttl, '127.0.0.1'); + + } elsif ($name eq 'awide.example.net' && $type == A) { + push @rdata, pack '(w/a*)3x n2N nC4', + ('awide', 'example', 'net'), A, IN, $ttl, + 4, (127, 0, 0, 1); + } elsif (($name eq 'many.example.net') && $type == A) { $state->{manycnt}++; if ($state->{manycnt} > 1) { @@ -289,6 +353,30 @@ 4, split(/\./, '127.0.0.1')); } + } elsif ($name eq 'cname_a_ttl.example.net') { + push @rdata, pack("n3N nCa17n", 0xc00c, CNAME, IN, $ttl, + 20, 17, 'cname_a_ttl_alias', 0xc018); + + if ($type == A) { + if (++$state->{cttlcnt} >= 2) { + $rcode = SERVFAIL; + } + push @rdata, pack('n3N nC4', 0xc035, A, IN, 1, + 4, split(/\./, '127.0.0.1')); + } + + } elsif ($name eq 'cname_a_ttl2.example.net' && $type == A) { + push @rdata, pack("n3N nCa18n", 0xc00c, CNAME, IN, 1, + 21, 18, 'cname_a_ttl2_alias', 0xc019); + if (++$state->{cttl2cnt} >= 2) { + $rcode = SERVFAIL; + } + push @rdata, pack('n3N nC4', 0xc036, A, IN, $ttl, + 4, split(/\./, '127.0.0.1')); + + } elsif ($name eq 'cname_a_ttl_alias.example.net' && $type == A) { + push @rdata, rd_addr($ttl, '127.0.0.1'); + } elsif ($name eq 'cname2.example.net') { # points to non-existing A @@ -373,7 +461,10 @@ twocnt => 0, ttlcnt => 0, ttl0cnt => 0, + cttlcnt => 0, + cttl2cnt => 0, manycnt => 0, + casecnt => 0, ); # signal we are ready diff -r aac06d3bdc05 -r 8ca9c75c97d2 mail_resolver.t --- a/mail_resolver.t Mon Dec 16 14:44:29 2013 +0400 +++ b/mail_resolver.t Mon Dec 16 18:59:16 2013 +0400 @@ -42,6 +42,9 @@ smtp_auth none; server_name locahost; + # prevent useless resend + resolver_timeout 1s; + server { listen 127.0.0.1:8025; protocol smtp; @@ -59,8 +62,6 @@ protocol smtp; resolver 127.0.0.1:8083; - # prevent useless resend - resolver_timeout 1s; } server { @@ -68,6 +69,18 @@ protocol smtp; resolver 127.0.0.1:8084; } + + server { + listen 127.0.0.1:8030; + protocol smtp; + resolver 127.0.0.1:8085; + } + + server { + listen 127.0.0.1:8031; + protocol smtp; + resolver 127.0.0.1:8086; + } } http { @@ -94,18 +107,16 @@ EOF -$t->run_daemon(\&dns_daemon, 8081, $t); -$t->run_daemon(\&dns_daemon, 8082, $t); -$t->run_daemon(\&dns_daemon, 8083, $t); -$t->run_daemon(\&dns_daemon, 8084, $t); +for (8081 .. 8086) { + $t->run_daemon(\&dns_daemon, $_, $t); +} $t->run(); -$t->waitforfile($t->testdir . '/8081'); -$t->waitforfile($t->testdir . '/8082'); -$t->waitforfile($t->testdir . '/8083'); -$t->waitforfile($t->testdir . '/8084'); +for (8081 .. 8086) { + $t->waitforfile($t->testdir . "/$_"); +} -$t->plan(5); +$t->plan(7); ############################################################################### @@ -199,6 +210,46 @@ } +# uncompressed answer + +TODO: { +local $TODO = 'support for uncompressed name in PTR'; + +$s = Test::Nginx::SMTP->new(PeerAddr => "127.0.0.1:8030"); +$s->read(); +$s->send('EHLO example.com'); +$s->read(); +$s->send('MAIL FROM: SIZE=100'); +$s->read(); + +$s->send('RCPT TO:'); +$s->ok('uncompressed PTR'); + +$s->send('QUIT'); +$s->read(); +close $s; + +} + +TODO: { +local $TODO = 'PTR type checking'; + +$s = Test::Nginx::SMTP->new(PeerAddr => "127.0.0.1:8031"); +$s->read(); +$s->send('EHLO example.com'); +$s->read(); +$s->send('MAIL FROM: SIZE=100'); +$s->read(); + +$s->send('RCPT TO:'); +$s->check(qr/TEMPUNAVAIL/, 'PTR type'); + +$s->send('QUIT'); +$s->read(); +close $s; + +} + ############################################################################### sub reply_handler { @@ -255,6 +306,16 @@ push @rdata, rd_name(CNAME, $ttl, '1.1.0.0.127.in-addr.arpa'); + + } elsif ($port == 8085) { + # uncompressed answer + + push @rdata, pack("(w/a*)6x n2N n(w/a*)3x", + ('1', '0', '0', '127', 'in-addr', 'arpa'), + PTR, IN, $ttl, 15, ('a', 'example', 'net')); + + } elsif ($port == 8086) { + push @rdata, rd_name(CNAME, $ttl, 'a.example.net'); } } elsif ($name eq '1.1.0.0.127.in-addr.arpa' && $type == PTR) { @@ -272,7 +333,7 @@ @rdname = split /\./, $name; $rdlen = length(join '', @rdname) + @rdname + 1; - pack("n3N n(w/a*)* x", 0xc00c, PTR, IN, $ttl, $rdlen, @rdname); + pack("n3N n(w/a*)* x", 0xc00c, $type, IN, $ttl, $rdlen, @rdname); } sub rd_addr {