|
Packit |
e6c8bb |
# $Id: 07-zonefile.t 1601 2017-10-10 14:17:01Z willem $ -*-perl-*-
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
use strict;
|
|
Packit |
e6c8bb |
use IO::File;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
use Test::More tests => 91;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
## vvv verbatim from Domain.pm
|
|
Packit |
e6c8bb |
use constant ASCII => ref eval {
|
|
Packit |
e6c8bb |
require Encode;
|
|
Packit |
e6c8bb |
Encode::find_encoding('ascii');
|
|
Packit |
e6c8bb |
};
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
use constant UTF8 => scalar eval { ## not UTF-EBCDIC [see UTR#16 3.6]
|
|
Packit |
e6c8bb |
Encode::encode_utf8( chr(182) ) eq pack( 'H*', 'C2B6' );
|
|
Packit |
e6c8bb |
};
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
use constant LIBIDN => defined eval 'require Net::LibIDN';
|
|
Packit |
e6c8bb |
use constant LIBIDN2 => ref eval 'require Net::LibIDN2; Net::LibIDN2->can("idn2_to_ascii_8")';
|
|
Packit |
e6c8bb |
## ^^^ verbatim from Domain.pm
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
use constant LIBIDNOK => LIBIDN && scalar eval {
|
|
Packit |
e6c8bb |
my $cn = pack( 'U*', 20013, 22269 );
|
|
Packit |
e6c8bb |
Net::LibIDN::idn_to_ascii( $cn, 'utf-8' ) eq 'xn--fiqs8s';
|
|
Packit |
e6c8bb |
};
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
use constant LIBIDN2OK => LIBIDN2 && scalar eval {
|
|
Packit |
e6c8bb |
my $cn = pack( 'U*', 20013, 22269 );
|
|
Packit |
e6c8bb |
Net::LibIDN2::idn2_to_ascii_8( $cn, 9 ) eq 'xn--fiqs8s';
|
|
Packit |
e6c8bb |
};
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
use_ok('Net::DNS::ZoneFile');
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my @file;
|
|
Packit |
e6c8bb |
my $seq;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
END {
|
|
Packit |
e6c8bb |
unlink $_ foreach @file;
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
sub source { ## zone file builder
|
|
Packit |
e6c8bb |
my $text = shift;
|
|
Packit |
e6c8bb |
my @args = @_;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $tag = ++$seq;
|
|
Packit |
e6c8bb |
my $file = "zone$tag.txt";
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $handle = new IO::File( $file, '>' ); # create test file
|
|
Packit |
e6c8bb |
die "Failed to create $file" unless $handle;
|
|
Packit |
e6c8bb |
eval { binmode($handle) }; # suppress encoding layer
|
|
Packit |
e6c8bb |
push @file, $file;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
print $handle $text;
|
|
Packit |
e6c8bb |
close $handle;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
return new Net::DNS::ZoneFile( $file, @args );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $recursive = join ' ', '$INCLUDE', source('$INCLUDE zone1.txt')->name;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
eval { new Net::DNS::ZoneFile(undef); };
|
|
Packit |
e6c8bb |
my $exception = $1 if $@ =~ /^(.+)\n/;
|
|
Packit |
e6c8bb |
ok( $exception ||= '', "new(): invalid argument\t[$exception]" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
eval { new Net::DNS::ZoneFile( [] ); };
|
|
Packit |
e6c8bb |
my $exception = $1 if $@ =~ /^(.+)\n/;
|
|
Packit |
e6c8bb |
ok( $exception ||= '', "new(): not a file handle\t[$exception]" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
eval { new Net::DNS::ZoneFile('zone0.txt'); }; # presumed not to exist
|
|
Packit |
e6c8bb |
my $exception = $1 if $@ =~ /^(.+)\n/;
|
|
Packit |
e6c8bb |
ok( $exception ||= '', "new(): non-existent file\t[$exception]" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{ ## public methods
|
|
Packit |
e6c8bb |
my $zonefile = source('');
|
|
Packit |
e6c8bb |
ok( $zonefile->isa('Net::DNS::ZoneFile'), 'new ZoneFile object' );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
ok( defined $zonefile->name, 'zonefile->name always defined' );
|
|
Packit |
e6c8bb |
ok( defined $zonefile->line, 'zonefile->line always defined' );
|
|
Packit |
e6c8bb |
ok( defined $zonefile->origin, 'zonefile->origin always defined' );
|
|
Packit |
e6c8bb |
ok( !defined $zonefile->ttl, 'zonefile->ttl initially undefined' );
|
|
Packit |
e6c8bb |
my @rr = $zonefile->read;
|
|
Packit |
e6c8bb |
is( scalar(@rr), 0, 'zonefile->read to end of file' );
|
|
Packit |
e6c8bb |
is( $zonefile->line, 0, 'zonefile->line zero if file empty' );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
is( $zonefile->origin, '.', 'zonefile->origin defaults to DNS root' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{ ## initial origin
|
|
Packit |
e6c8bb |
my $tld = 'test';
|
|
Packit |
e6c8bb |
my $absolute = source( '', "$tld." );
|
|
Packit |
e6c8bb |
is( $absolute->origin, "$tld.", 'new ZoneFile with absolute origin' );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $relative = source( '', "$tld" );
|
|
Packit |
e6c8bb |
is( $relative->origin, "$tld.", 'new ZoneFile->origin always absolute' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{ ## line numbering
|
|
Packit |
e6c8bb |
my $lines = 10;
|
|
Packit |
e6c8bb |
my $zonefile = source( "\n" x $lines );
|
|
Packit |
e6c8bb |
is( $zonefile->line, 0, 'zonefile->line zero before calling read()' );
|
|
Packit |
e6c8bb |
my @rr = $zonefile->read;
|
|
Packit |
e6c8bb |
is( $zonefile->line, $lines, 'zonefile->line number incremented by read()' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my $zonefile = source <<'EOF';
|
|
Packit |
e6c8bb |
$TTL
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
eval { $zonefile->read; };
|
|
Packit |
e6c8bb |
my $exception = $1 if $@ =~ /^(.+)\n/;
|
|
Packit |
e6c8bb |
ok( $exception ||= '', "exception:\t[$exception]" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my $zonefile = source <<'EOF';
|
|
Packit |
e6c8bb |
$INCLUDE
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
eval { $zonefile->read; };
|
|
Packit |
e6c8bb |
my $exception = $1 if $@ =~ /^(.+)\n/;
|
|
Packit |
e6c8bb |
ok( $exception ||= '', "exception:\t[$exception]" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my $zonefile = source <<'EOF';
|
|
Packit |
e6c8bb |
$ORIGIN
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
eval { $zonefile->read; };
|
|
Packit |
e6c8bb |
my $exception = $1 if $@ =~ /^(.+)\n/;
|
|
Packit |
e6c8bb |
ok( $exception ||= '', "exception:\t[$exception]" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my $zonefile = source <<'EOF';
|
|
Packit |
e6c8bb |
$GENERATE
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
eval { $zonefile->read; };
|
|
Packit |
e6c8bb |
my $exception = $1 if $@ =~ /^(.+)\n/;
|
|
Packit |
e6c8bb |
ok( $exception ||= '', "exception:\t[$exception]" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my $zonefile = source <<'EOF';
|
|
Packit |
e6c8bb |
$BOGUS
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
eval { $zonefile->read; };
|
|
Packit |
e6c8bb |
my $exception = $1 if $@ =~ /^(.+)\n/;
|
|
Packit |
e6c8bb |
ok( $exception ||= '', "exception:\t[$exception]" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{ ## $TTL directive at start of zone file
|
|
Packit |
e6c8bb |
my $zonefile = source <<'EOF';
|
|
Packit |
e6c8bb |
$TTL 54321
|
|
Packit |
e6c8bb |
rr0 SOA mname rname 99 6h 1h 1w 12345
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
is( $zonefile->read->ttl, 54321, 'SOA TTL set from $TTL directive' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{ ## no $TTL directive, default implicit
|
|
Packit |
e6c8bb |
my $zonefile = source <<'EOF';
|
|
Packit |
e6c8bb |
rr0 SOA mname rname 99 6h 1h 1w 0
|
|
Packit |
e6c8bb |
rr1 NULL
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
is( $zonefile->read->ttl, 0, 'SOA TTL set from zero SOA minimum field' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->ttl, 0, 'implicit zero default from SOA record' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{ ## $TTL directive following implicit default
|
|
Packit |
e6c8bb |
my $zonefile = source <<'EOF';
|
|
Packit |
e6c8bb |
rr0 SOA mname rname 99 6h 1h 1w 12345
|
|
Packit |
e6c8bb |
rr1 NULL
|
|
Packit |
e6c8bb |
$TTL 54321
|
|
Packit |
e6c8bb |
rr2 NULL
|
|
Packit |
e6c8bb |
rr3 3h NULL
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
is( $zonefile->read->ttl, 12345, 'SOA TTL set from SOA minimum field' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->ttl, 12345, 'implicit default from SOA record' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->ttl, 54321, 'explicit default from $TTL directive' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->ttl, 10800, 'explicit TTL value overrides default' );
|
|
Packit |
e6c8bb |
is( $zonefile->ttl, 54321, '$zonefile->ttl set from $TTL directive' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{ ## $INCLUDE directive
|
|
Packit |
e6c8bb |
my $include = source <<'EOF';
|
|
Packit |
e6c8bb |
rr2 NULL
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $directive = join ' ', '$INCLUDE', $include->name, '.';
|
|
Packit |
e6c8bb |
my $misdirect = join ' ', '$INCLUDE zone0.txt ; presumed not to exist';
|
|
Packit |
e6c8bb |
my $zonefile = source <<"EOF";
|
|
Packit |
e6c8bb |
rr1 NULL
|
|
Packit |
e6c8bb |
$directive
|
|
Packit |
e6c8bb |
rr3 NULL
|
|
Packit |
e6c8bb |
$recursive
|
|
Packit |
e6c8bb |
$misdirect
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $fn1 = $zonefile->name;
|
|
Packit |
e6c8bb |
my $rr1 = $zonefile->read;
|
|
Packit |
e6c8bb |
is( $rr1->name, 'rr1', 'zonefile->read expected record' );
|
|
Packit |
e6c8bb |
is( $zonefile->name, $fn1, 'zonefile->name identifies file' );
|
|
Packit |
e6c8bb |
is( $zonefile->line, 1, 'zonefile->line identifies record' );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $fn2 = $include->name;
|
|
Packit |
e6c8bb |
my $rr2 = $zonefile->read;
|
|
Packit |
e6c8bb |
my $sfx = $zonefile->origin;
|
|
Packit |
e6c8bb |
is( $rr2->name, 'rr2', 'zonefile->read expected record' );
|
|
Packit |
e6c8bb |
is( $zonefile->name, $fn2, 'zonefile->name identifies file' );
|
|
Packit |
e6c8bb |
is( $zonefile->line, 1, 'zonefile->line identifies record' );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $rr3 = $zonefile->read;
|
|
Packit |
e6c8bb |
is( $rr3->name, 'rr3', 'zonefile->read expected record' );
|
|
Packit |
e6c8bb |
is( $zonefile->name, $fn1, 'zonefile->name identifies file' );
|
|
Packit |
e6c8bb |
is( $zonefile->line, 3, 'zonefile->line identifies record' );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my @rr = eval { $zonefile->read };
|
|
Packit |
e6c8bb |
my $exception = $1 if $@ =~ /^(.+)\n/;
|
|
Packit |
e6c8bb |
ok( $exception ||= '', "recursive include\t[$exception]" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my @rr = eval { $zonefile->read };
|
|
Packit |
e6c8bb |
my $exception = $1 if $@ =~ /^(.+)\n/;
|
|
Packit |
e6c8bb |
ok( $exception ||= '', "non-existent include\t[$exception]" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
is( $zonefile->name, $fn1, 'zonefile->name identifies file' );
|
|
Packit |
e6c8bb |
is( $zonefile->line, 5, 'zonefile->line identifies directive' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $zonefile;
|
|
Packit |
e6c8bb |
{ ## $ORIGIN directive
|
|
Packit |
e6c8bb |
my $nested = source <<'EOF';
|
|
Packit |
e6c8bb |
nested NULL
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $origin = 'example.com';
|
|
Packit |
e6c8bb |
my $ORIGIN = '$ORIGIN';
|
|
Packit |
e6c8bb |
my $inner = join ' ', '$INCLUDE', $nested->name;
|
|
Packit |
e6c8bb |
my $include = source <<"EOF";
|
|
Packit |
e6c8bb |
$ORIGIN $origin
|
|
Packit |
e6c8bb |
@ NS host
|
|
Packit |
e6c8bb |
$inner
|
|
Packit |
e6c8bb |
@ NULL
|
|
Packit |
e6c8bb |
$ORIGIN relative
|
|
Packit |
e6c8bb |
@ NULL
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $outer = join ' ', '$INCLUDE', $include->name;
|
|
Packit |
e6c8bb |
$zonefile = source <<"EOF";
|
|
Packit |
e6c8bb |
$outer
|
|
Packit |
e6c8bb |
outer NULL
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
$ORIGIN $origin
|
|
Packit |
e6c8bb |
NULL
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $ns = $zonefile->read;
|
|
Packit |
e6c8bb |
is( $ns->name, $origin, '@ NS has expected name' );
|
|
Packit |
e6c8bb |
is( $ns->nsdname, "host.$origin", '@ NS has expected rdata' );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $rr = $zonefile->read;
|
|
Packit |
e6c8bb |
my $expect = join '.', 'nested', $origin;
|
|
Packit |
e6c8bb |
is( $rr->name, $expect, 'scope of $ORIGIN encompasses nested $INCLUDE' );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
is( $zonefile->read->name, $origin, 'scope of $ORIGIN continues after $INCLUDE' );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
is( $zonefile->read->name, "relative.$origin", '$ORIGIN can be relative to current $ORIGIN' );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
is( $zonefile->read->name, 'outer', 'scope of $ORIGIN curtailed by end of file' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->name, $origin, 'implicit owner following $ORIGIN directive' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{ ## $GENERATE directive
|
|
Packit |
e6c8bb |
my $zonefile = source <<'EOF';
|
|
Packit |
e6c8bb |
$GENERATE 0-0 @ TXT $
|
|
Packit |
e6c8bb |
$GENERATE 10-30/10 @ TXT $
|
|
Packit |
e6c8bb |
$GENERATE 30-10/-10 @ TXT $
|
|
Packit |
e6c8bb |
$GENERATE 123-123 @ TXT ${,,}
|
|
Packit |
e6c8bb |
$GENERATE 123-123 @ TXT ${0,0,d}
|
|
Packit |
e6c8bb |
$GENERATE 123-123 @ TXT ${0,0,o}
|
|
Packit |
e6c8bb |
$GENERATE 123-123 @ TXT ${0,0,x}
|
|
Packit |
e6c8bb |
$GENERATE 123-123 @ TXT ${0,0,X}
|
|
Packit |
e6c8bb |
$GENERATE 123-123 @ TXT ${0,4,X}
|
|
Packit |
e6c8bb |
$GENERATE 123-123 @ TXT ${4096,4,X}
|
|
Packit |
e6c8bb |
$GENERATE 11259375 @ TXT ${0,6,n}
|
|
Packit |
e6c8bb |
$GENERATE 11259375 @ TXT ${0,16,N}
|
|
Packit |
e6c8bb |
$GENERATE 0-0 @ TXT ${0,0,Z}
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, '0', 'generate TXT $' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, '10', 'generate TXT $ with step 10' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, '20', 'generate TXT $ with step 10' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, '30', 'generate TXT $ with step 10' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, '30', 'generate TXT $ with step -10' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, '20', 'generate TXT $ with step -10' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, '10', 'generate TXT $ with step -10' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, '123', 'generate TXT ${,,}' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, '123', 'generate TXT ${0,0,d}' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, '173', 'generate TXT ${0,0,o}' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, '7b', 'generate TXT ${0,0,x}' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, '7B', 'generate TXT ${0,0,X}' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, '007B', 'generate TXT ${0,4,X}' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, '107B', 'generate TXT ${4096,4,X}' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, 'f.e.d.', 'generate TXT ${0,6,n}' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->rdstring, 'F.E.D.C.B.A.0.0.', 'generate TXT ${0,16,N}' );
|
|
Packit |
e6c8bb |
eval { $zonefile->read; };
|
|
Packit |
e6c8bb |
my $exception = $1 if $@ =~ /^(.+)\n/;
|
|
Packit |
e6c8bb |
ok( $exception ||= '', "unknown format:\t[$exception]" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my $zonefile = source <<'EOF';
|
|
Packit |
e6c8bb |
$TTL 1234
|
|
Packit |
e6c8bb |
$ORIGIN example.
|
|
Packit |
e6c8bb |
hosta A 192.0.2.1
|
|
Packit |
e6c8bb |
; whole line comment
|
|
Packit |
e6c8bb |
; indented comment
|
|
Packit |
e6c8bb |
; vvv empty line
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
; ^^^ empty line
|
|
Packit |
e6c8bb |
; vvv line with white space
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
; ^^^ line with white space
|
|
Packit |
e6c8bb |
MX 10 hosta ; end of line comment
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
TXT ( multiline ; interspersed ( mischievously )
|
|
Packit |
e6c8bb |
resource ; with ( confusing )
|
|
Packit |
e6c8bb |
record ) ; comments
|
|
Packit |
e6c8bb |
TXT (string)
|
|
Packit |
e6c8bb |
TXT "(string)"
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
is( $zonefile->read->name, 'hosta.example', 'name of simple RR as expected' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->name, 'hosta.example', 'name of simple RR propagated from previous RR' );
|
|
Packit |
e6c8bb |
my $multilineRR = $zonefile->read;
|
|
Packit |
e6c8bb |
is( $multilineRR->name, 'hosta.example', 'name of multiline RR propagated from previous RR' );
|
|
Packit |
e6c8bb |
is( $multilineRR->txtdata, 'multiline resource record', 'multiline RR correctly reassembled' );
|
|
Packit |
e6c8bb |
my $following = $zonefile->read;
|
|
Packit |
e6c8bb |
is( $following->name, 'hosta.example', 'name of following RR as expected' );
|
|
Packit |
e6c8bb |
is( $following->txtdata, 'string', 'superfluous brackets ignored' );
|
|
Packit |
e6c8bb |
is( $zonefile->read->txtdata, '(string)', 'quoted brackets protected' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{ ## CLASS coersion
|
|
Packit |
e6c8bb |
my $zonefile = source <<'EOF';
|
|
Packit |
e6c8bb |
rr0 CH NULL
|
|
Packit |
e6c8bb |
rr1 CLASS1 NULL
|
|
Packit |
e6c8bb |
rr2 CLASS2 NULL
|
|
Packit |
e6c8bb |
rr3 CLASS3 NULL
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
my $rr = $zonefile->read;
|
|
Packit |
e6c8bb |
foreach ( $zonefile->read ) {
|
|
Packit |
e6c8bb |
is( $_->class, $rr->class, 'rr->class matches initial record' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{ ## compatibility with defunct Net::DNS::ZoneFile 1.04 distro
|
|
Packit |
e6c8bb |
my $listref = Net::DNS::ZoneFile->read( $zonefile->name );
|
|
Packit |
e6c8bb |
ok( scalar(@$listref), 'read(): entire zone file' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my $listref = Net::DNS::ZoneFile->read( $zonefile->name, '.' );
|
|
Packit |
e6c8bb |
ok( scalar(@$listref), 'read(): zone file via path' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
eval {
|
|
Packit |
e6c8bb |
local $SIG{__WARN__} = sub { }; # presumed not to exist
|
|
Packit |
e6c8bb |
my $listref = Net::DNS::ZoneFile->read( '/zone0.txt', '.' );
|
|
Packit |
e6c8bb |
};
|
|
Packit |
e6c8bb |
my $exception = $1 if $@ =~ /^(.+)\n/;
|
|
Packit |
e6c8bb |
ok( $exception ||= '', "read(): non-existent file\t[$exception]" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
eval {
|
|
Packit |
e6c8bb |
local $SIG{__WARN__} = sub { }; # presumed not to exist
|
|
Packit |
e6c8bb |
my $listref = Net::DNS::ZoneFile->read( 'zone0.txt', 't' );
|
|
Packit |
e6c8bb |
};
|
|
Packit |
e6c8bb |
my $exception = $1 if $@ =~ /^(.+)\n/;
|
|
Packit |
e6c8bb |
ok( $exception ||= '', "read(): non-existent file\t[$exception]" );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my $listref = Net::DNS::ZoneFile::read( $zonefile->name, '.' );
|
|
Packit |
e6c8bb |
ok( scalar(@$listref), 'read(): called as subroutine (not object-oriented)' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my $string = "";
|
|
Packit |
e6c8bb |
my $listref = Net::DNS::ZoneFile->parse( \$string );
|
|
Packit |
e6c8bb |
is( scalar(@$listref), 0, 'parse(): empty string' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my $string = <<'EOF';
|
|
Packit |
e6c8bb |
a1.example A 192.0.2.1
|
|
Packit |
e6c8bb |
a2.example A 192.0.2.2
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
my $listref = Net::DNS::ZoneFile->parse( \$string ); # this also tests readfh()
|
|
Packit |
e6c8bb |
is( scalar(@$listref), 2, 'parse(): RR string' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my $string = <<'EOF';
|
|
Packit |
e6c8bb |
a1.example A 192.0.2.1
|
|
Packit |
e6c8bb |
$BOGUS
|
|
Packit |
e6c8bb |
a2.example A 192.0.2.2
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
local $SIG{__WARN__} = sub { };
|
|
Packit |
e6c8bb |
my $listref = Net::DNS::ZoneFile->parse( \$string );
|
|
Packit |
e6c8bb |
is( $listref, undef, 'parse(): erroneous string' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my $string = <<'EOF';
|
|
Packit |
e6c8bb |
a1.example A 192.0.2.1
|
|
Packit |
e6c8bb |
a2.example A 192.0.2.2
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
my @list = Net::DNS::ZoneFile->parse($string);
|
|
Packit |
e6c8bb |
is( scalar(@list), 2, 'parse(): RR string into array' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my $string = <<'EOF';
|
|
Packit |
e6c8bb |
a1.example A 192.0.2.1
|
|
Packit |
e6c8bb |
$BOGUS
|
|
Packit |
e6c8bb |
a2.example A 192.0.2.2
|
|
Packit |
e6c8bb |
EOF
|
|
Packit |
e6c8bb |
local $SIG{__WARN__} = sub { };
|
|
Packit |
e6c8bb |
my @list = Net::DNS::ZoneFile->parse($string);
|
|
Packit |
e6c8bb |
is( scalar(@list), 1, 'parse(): erroneous string into array' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
{
|
|
Packit |
e6c8bb |
my $listref = Net::DNS::ZoneFile::parse('a.example. A 192.0.2.1');
|
|
Packit |
e6c8bb |
ok( scalar(@$listref), 'parse(): called as subroutine (not object-oriented)' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
SKIP: { ## Non-ASCII zone content
|
|
Packit |
e6c8bb |
skip( 'Unicode/UTF-8 not supported', 4 ) unless UTF8;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $greek = pack 'C*', 103, 114, 9, 84, 88, 84, 9, 229, 224, 241, 231, 234, 225, 10;
|
|
Packit |
e6c8bb |
my $file1 = source($greek);
|
|
Packit |
e6c8bb |
my $fh1 = new IO::File( $file1->name, '<:encoding(ISO8859-7)' ); # Greek
|
|
Packit |
e6c8bb |
my $zone1 = new Net::DNS::ZoneFile($fh1);
|
|
Packit |
e6c8bb |
my $txtgr = $zone1->read;
|
|
Packit |
e6c8bb |
my $text = pack 'U*', 949, 944, 961, 951, 954, 945;
|
|
Packit |
e6c8bb |
is( $txtgr->txtdata, $text, 'ISO8859-7 TXT rdata' );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
eval { binmode(DATA) }; # suppress encoding layer
|
|
Packit |
e6c8bb |
my $jptxt = join "\n", <DATA>;
|
|
Packit |
e6c8bb |
my $file2 = source($jptxt);
|
|
Packit |
e6c8bb |
my $fh2 = new IO::File( $file2->name, '<:utf8' ); # UTF-8 character encoding
|
|
Packit |
e6c8bb |
my $zone2 = new Net::DNS::ZoneFile($fh2);
|
|
Packit |
e6c8bb |
my $txtrr = $zone2->read; # TXT RR with kanji RDATA
|
|
Packit |
e6c8bb |
my @rdata = $txtrr->txtdata;
|
|
Packit |
e6c8bb |
my $rdata = $txtrr->txtdata;
|
|
Packit |
e6c8bb |
is( length($rdata), 12, 'Unicode/UTF-8 TXT rdata' );
|
|
Packit |
e6c8bb |
is( scalar(@rdata), 1, 'Unicode/UTF-8 TXT contiguous' );
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
skip( 'Non-ASCII domain - IDNA not supported', 1 ) unless LIBIDNOK || LIBIDN2OK;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
my $jpnull = $zone2->read; # NULL RR with kanji owner name
|
|
Packit |
e6c8bb |
is( $jpnull->name, 'xn--wgv71a', 'Unicode/UTF-8 domain name' );
|
|
Packit |
e6c8bb |
}
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
exit;
|
|
Packit |
e6c8bb |
|
|
Packit |
e6c8bb |
__END__
|
|
Packit |
e6c8bb |
jp TXT 古池や 蛙飛込む 水の音 ; Unicode text string
|
|
Packit |
e6c8bb |
日本 NULL ; Unicode domain name
|
|
Packit |
e6c8bb |
|