comparison mail_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 14eba1ad0880
children cdab739eb6ea
comparison
equal deleted inserted replaced
356:7a472e46772c 357:e0c00e695cb5
22 22
23 select STDERR; $| = 1; 23 select STDERR; $| = 1;
24 select STDOUT; $| = 1; 24 select STDOUT; $| = 1;
25 25
26 local $SIG{PIPE} = 'IGNORE'; 26 local $SIG{PIPE} = 'IGNORE';
27
28 eval { require Net::DNS::Nameserver; };
29 plan(skip_all => "Net::DNS::Nameserver not installed") if $@;
30 27
31 my $t = Test::Nginx->new()->has(qw/mail smtp http rewrite/) 28 my $t = Test::Nginx->new()->has(qw/mail smtp http rewrite/)
32 ->run_daemon(\&Test::Nginx::SMTP::smtp_test_daemon); 29 ->run_daemon(\&Test::Nginx::SMTP::smtp_test_daemon);
33 30
34 $t->write_file_expand('nginx.conf', <<'EOF'); 31 $t->write_file_expand('nginx.conf', <<'EOF');
95 } 92 }
96 } 93 }
97 94
98 EOF 95 EOF
99 96
100 $t->run_daemon(\&dns_daemon, 8081); 97 $t->run_daemon(\&dns_daemon, 8081, $t);
101 $t->run_daemon(\&dns_daemon, 8082); 98 $t->run_daemon(\&dns_daemon, 8082, $t);
102 $t->run_daemon(\&dns_daemon, 8083); 99 $t->run_daemon(\&dns_daemon, 8083, $t);
103 $t->run_daemon(\&dns_daemon, 8084); 100 $t->run_daemon(\&dns_daemon, 8084, $t);
104 $t->run(); 101 $t->run();
105 102
106 $t->waitforsocket('127.0.0.1:8081'); 103 $t->waitforfile($t->testdir . '/8081');
107 $t->waitforsocket('127.0.0.1:8082'); 104 $t->waitforfile($t->testdir . '/8082');
108 $t->waitforsocket('127.0.0.1:8083'); 105 $t->waitforfile($t->testdir . '/8083');
109 $t->waitforsocket('127.0.0.1:8084'); 106 $t->waitforfile($t->testdir . '/8084');
110 107
111 $t->plan(5); 108 $t->plan(5);
112 109
113 ############################################################################### 110 ###############################################################################
114 111
203 } 200 }
204 201
205 ############################################################################### 202 ###############################################################################
206 203
207 sub reply_handler { 204 sub reply_handler {
208 my ($name, $class, $type, $peerhost, $query, $conn) = @_; 205 my ($recv_data, $port) = @_;
209 my ($rcode, @ans, $ttl, $rdata); 206
210 207 my (@name, @rdata);
211 $rcode = 'NOERROR'; 208
212 $ttl = 3600; 209 use constant NOERROR => 0;
213 210 use constant SERVFAIL => 2;
214 if ($name eq 'a.example.net' && $type eq 'A') { 211 use constant NXDOMAIN => 3;
215 ($rdata) = ('127.0.0.1'); 212
216 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata"); 213 use constant A => 1;
217 214 use constant CNAME => 5;
218 } elsif ($name eq '1.0.0.127.in-addr.arpa' && $type eq 'PTR') { 215 use constant PTR => 12;
219 if ($conn->{sockport} == 8081) { 216
220 $rdata = 'a.example.net'; 217 use constant IN => 1;
221 push @ans, Net::DNS::RR->new( 218
222 "$name $ttl $class $type $rdata" 219 # default values
223 ); 220
224 221 my ($hdr, $rcode, $ttl) = (0x8180, NOERROR, 3600);
225 } elsif ($conn->{sockport} == 8082) { 222
226 return 'SERVFAIL'; 223 # decode name
227 224
228 } elsif ($conn->{sockport} == 8083) { 225 my ($len, $offset) = (undef, 12);
226 while (1) {
227 $len = unpack("\@$offset C", $recv_data);
228 last if $len == 0;
229 $offset++;
230 push @name, unpack("\@$offset A$len", $recv_data);
231 $offset += $len;
232 }
233
234 $offset -= 1;
235 my ($id, $type, $class) = unpack("n x$offset n2", $recv_data);
236
237 my $name = join('.', @name);
238 if ($name eq 'a.example.net' && $type == A) {
239 push @rdata, rd_addr($ttl, '127.0.0.1');
240
241 } elsif ($name eq '1.0.0.127.in-addr.arpa' && $type == PTR) {
242 if ($port == 8081) {
243 push @rdata, rd_name(PTR, $ttl, 'a.example.net');
244
245 } elsif ($port == 8082) {
246 $rcode = SERVFAIL;
247
248 } elsif ($port == 8083) {
229 # zero length RDATA 249 # zero length RDATA
230 $rdata = ''; 250
231 push @ans, Net::DNS::RR->new( 251 push @rdata, pack("n3N n", 0xc00c, PTR, IN, $ttl, 0);
232 "$name $ttl $class $type $rdata" 252
233 ); 253 } elsif ($port == 8084) {
234
235 } elsif ($conn->{sockport} == 8084) {
236 # PTR answered with CNAME 254 # PTR answered with CNAME
237 ($type, $rdata) = ('CNAME', 255
256 push @rdata, rd_name(CNAME, $ttl,
238 '1.1.0.0.127.in-addr.arpa'); 257 '1.1.0.0.127.in-addr.arpa');
239 push @ans, Net::DNS::RR->new(
240 "$name $ttl $class $type $rdata"
241 );
242 } 258 }
243 259
244 } elsif ($name eq '1.1.0.0.127.in-addr.arpa' && $type eq 'PTR') { 260 } elsif ($name eq '1.1.0.0.127.in-addr.arpa' && $type == PTR) {
245 $rdata = 'a.example.net'; 261 push @rdata, rd_name(PTR, $ttl, 'a.example.net');
246 push @ans, Net::DNS::RR->new("$name $ttl $class $type $rdata");
247 262
248 } else { 263 } else {
249 $rcode = 'NXDOMAIN'; 264 $rcode = NXDOMAIN;
250 } 265 }
251 266
252 return ($rcode, \@ans); 267 $len = @name;
268 pack("n6 (w/a*)$len x n2", $id, $hdr | $rcode, 1, scalar @rdata,
269 0, 0, @name, $type, $class) . join('', @rdata);
270 }
271
272 sub rd_name {
273 my ($type, $ttl, $name) = @_;
274 my ($rdlen, @rdname);
275
276 @rdname = split /\./, $name;
277 $rdlen = length(join '', @rdname) + @rdname + 1;
278 pack("n3N n(w/a*)* x", 0xc00c, PTR, IN, $ttl, $rdlen, @rdname);
279 }
280
281 sub rd_addr {
282 my ($ttl, $addr) = @_;
283
284 my $code = 'split(/\./, $addr)';
285
286 # use a special pack string to not zero pad
287
288 return pack 'n3N', 0xc00c, A, IN, $ttl if $addr eq '';
289
290 pack 'n3N nC4', 0xc00c, A, IN, $ttl, eval "scalar $code", eval($code);
253 } 291 }
254 292
255 sub dns_daemon { 293 sub dns_daemon {
256 my ($port) = @_; 294 my ($port, $t) = @_;
257 295
258 my $ns = Net::DNS::Nameserver->new( 296 my ($data, $recv_data);
297 my $socket = IO::Socket::INET->new(
259 LocalAddr => '127.0.0.1', 298 LocalAddr => '127.0.0.1',
260 LocalPort => $port, 299 LocalPort => $port,
261 Proto => 'udp', 300 Proto => 'udp',
262 ReplyHandler => \&reply_handler,
263 ) 301 )
264 or die "Can't create nameserver object: $!\n"; 302 or die "Can't create listening socket: $!\n";
265 303
266 $ns->main_loop; 304 # signal we are ready
267 } 305
268 306 open my $fh, '>', $t->testdir() . '/' . $port;
269 ############################################################################### 307 close $fh;
308
309 while (1) {
310 $socket->recv($recv_data, 65536);
311 $data = reply_handler($recv_data, $port);
312 $socket->send($data);
313 }
314 }
315
316 ###############################################################################