use strict;
use warnings;
use Test;
BEGIN { plan tests => 119 };
use Unix::Conf;
ok (1);
use Unix::Conf::Bind8;
ok (1);
Unix::Conf->debuglevel (1);
my ($conf, $options, $acl, $ret);
my @options;
# start out with an empty file. test the code in the
# constructor to set options and whether the actual method's
# interface is compatible
`rm -f t/named.conf`;
$conf = Unix::Conf::Bind8->new_conf (
FILE => 't/named.conf',
SECURE_OPEN => 0,
);
ok ($conf->isa ('Unix::Conf::Bind8::Conf'));
$conf->die ("Unix::Conf::Bind8->new_conf () failed") unless ($conf);
ok ($ret = $conf->get_options (), qr/^_get_options: `options' not defined/);
ok ($ret = $conf->delete_options (), qr/^_get_options: `options' not defined/);
# must fail as no options directive is present
ok (
($acl = $conf->new_acl (
ELEMENTS => [ qw (localhost localnets) ]
))->isa ("Unix::Conf::Bind8::Conf::Acl")
);
$options = $conf->new_options (
'DIRECTORY' => '.',
'NAMED-XFER' => '/usr/libexec/named-xfer',
'DUMP-FILE' => '/named/dump.db',
'PID-FILE' => '/var/run/named.pid',
'STATISTICS-FILE' => 'named.stats',
'MEMSTATISTICS-FILE' => 'named.memstats',
'CHECK-NAMES' => { master => 'fail', slave => 'warn', response => 'ignore' },
'HOST-STATISTICS' => 'no',
'DEALLOCATE-ON-EXIT' => 'no',
'DATASIZE' => 'default',
'STACKSIZE' => 'default',
'CORESIZE' => 'default',
'FILES' => 'unlimited',
'RECURSION' => 'yes',
'FETCH-GLUE' => 'yes',
'FAKE-IQUERY' => 'no',
'NOTIFY' => 'yes',
'MAX-SERIAL-QUERIES' => 4,
'AUTH-NXDOMAIN' => 'yes',
'MULTIPLE-CNAMES' => 'no',
'ALLOW-QUERY' => [ 'any' ],
'ALLOW-TRANSFER' => $acl,
'ALLOW-RECURSION' => [ qw(10.0.0.0/24 10.0.1.0/24 10.0.2.0/24 10.0.3.0/24) ],
'TRANSFERS-IN' => 10,
'TRANSFERS-OUT' => 0,
'MAX-TRANSFER-TIME-IN' => 120,
'TRANSFER-FORMAT' => 'one-answer',
'QUERY-SOURCE' => { PORT => '*', ADDRESS => '*' },
'FORWARD' => 'first',
'FORWARDERS' => [],
'TOPOLOGY' => [ qw (localhost localnets) ],
'LISTEN-ON' => {
53 => [ 'any', '5.6.7.8' ],
1234 => [ '!1.2.3.4', '1.2.3/24', ],
},
'RRSET-ORDER' => [
{ ORDER => 'cyclic' },
{ NAME => 'extremix.net', ORDER => 'random' },
{ NAME => 'foo.com', TYPE => 'A', ORDER => 'cyclic' },
{ NAME => 'boo.com', CLASS => 'IN', TYPE => 'NS', ORDER => 'fixed' },
],
'CLEANING-INTERVAL' => 60,
'INTERFACE-INTERVAL' => 60,
'STATISTICS-INTERVAL' => 60,
'MAINTAIN-IXFR-BASE' => 'no',
'MAX-IXFR-LOG-SIZE' => 20,
);
ok ($options->isa ("Unix::Conf::Bind8::Conf::Options"));
$options->die ("couldn't create options") unless ($options);
($conf, $options, $acl, $ret) = (undef) x 4;
# read in the same file we wrote out.
$conf = Unix::Conf::Bind8->new_conf (
FILE => 't/named.conf',
SECURE_OPEN => 0,
);
ok (UNIVERSAL::isa ($conf, 'Unix::Conf::Bind8::Conf'));
# die if we fail as all tests below depend on success of this test.
$conf->die ("\nUnix::Conf::Bind8->new_conf () failed") unless ($conf);
# new_options should fail as options is already defined.
ok ($ret = $conf->new_options (), qr/^_add_options: `options' already defined/);
ok (($options = $conf->get_options ())->isa ("Unix::Conf::Bind8::Conf::Options"));
$options->die ("couldn't get options") unless ($options);
ok (@options = $options->options (), 37);
# test autocreated delete. with this all autocreated deletes are ok.
ok ($ret = $options->delete_directory ());
$ret->die ("couldn't delete option `directory'") unless ($ret);
# should fail as version not yet defined.
ok ($ret = $options->version (), qr/^version: option not defined/);
ok ($ret = $options->version ('NAMED-8.2.3'));
$ret->die ("couldn't set option `version'") unless ($ret);
ok ($ret = $options->version (), 'NAMED-8.2.3');
$ret->die ("couldn't get option `version'") unless ($ret);
# TEST add_to_ code for Acl type options.
ok ($ret = $options->add_to_allow_query ('none'));
$ret->die ("couldn't add to option `allow-query'") unless ($ret);
ok (@{$ret = $options->allow_query_elements ()}, 2);
$ret->die ("couldn't get option `allow-query'") unless ($ret);
# This option is not yet defined. should get created.
ok ($ret = $options->add_to_blackhole ( [ qw (10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4) ]));
$ret->die ("couldn't add to option `blackhole'") unless ($ret);
ok (@{$ret = $options->blackhole_elements ()}, 4);
$ret->die ("couldn't get option `blackhole'") unless ($ret);
# delete_from test for Acl type options.
ok ($ret = $options->delete_from_allow_recursion (qw (10.0.0.0/24 10.0.9.0/24)),
qr/^delete_elements: element `10.0.9.0\/24' not defined/);
ok ($ret = $options->delete_from_allow_recursion (qw (10.0.0.0/24 10.0.3.0/24)));
$ret->die ("could not delete from option `allow-recursion'") unless ($ret);
ok (@{$ret = $options->allow_recursion_elements ()}, 2);
$ret->die ("couldn't get option `allow-recursion'") unless ($ret);
############################### query-source #######################################
ok ($ret = $options->query_source ( PORT => 53, ADDRESS => '192.168.1.1' ));
$ret->die ("couldn't set option `query-source'") unless ($ret);
ok ($ret = $options->query_source ());
$ret->die ("couldn't get option `query-source'") unless ($ret);
ok ($ret->{PORT}, 53);
ok ($ret->{ADDRESS}, '192.168.1.1');
ok ($ret = $options->delete_query_source ());
$ret->die ("couldn't delete option `query-source'") unless ($ret);
ok ($ret = $options->query_source (), qr/^query_source: option not defined/);
############################### check-names #######################################
# set only master to see if we are resetting the old values, or only adding.
ok ($ret = $options->check_names ( master => 'ignore' ));
$ret->die ("couldn't set option `check-names'") unless ($ret);
# if keys > 1 most probably check-names () above is not resetting the values.
# instead it is just adding them.
ok (keys (%{$ret = $options->check_names ()}), 1);
$ret->die ("couldn't get option `check-names'") unless ($ret);
ok ($ret->{master}, 'ignore');
# test add_to with error condition
ok ($ret = $options->add_to_check_names ( master => 'fail'),
qr/^add_to_check_names: `master' already defined/);
# try to delete a key not present `response'
ok ($ret = $options->delete_from_check_names ('master', 'response'),
qr/^delete_from_check_names: `response' not defined/);
# only key being deleted, which should delete the option itself.
ok ($ret = $options->delete_from_check_names ('master'));
$ret->die ("couldn't delete from option `check-names'") unless ($ret);
# getting option should bomb.
ok ($ret = $options->check_names (),
qr/^check_names: option not defined/);
ok ($ret = $options->add_to_check_names ( master => 'warn', slave => 'warn', response => 'warn'));
$ret->die ("couldn't add to option `check-names'") unless ($ret);
ok (keys (%{$ret = $options->check_names ()}), 3);
$ret->die ("couldn't get option `check-names'") unless ($ret);
ok ($ret->{master}, 'warn');
ok ($ret->{slave}, 'warn');
ok ($ret->{response}, 'warn');
############################### forwarders #######################################
ok (@{$ret = $options->forwarders ()}, 0);
$ret->die ("couldn't get forwarders") unless ($ret);
ok ($ret = $options->add_to_forwarders (qw (10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4 10.0.0.5)));
$ret->die ("couldn't add to forwarders") unless ($ret);
ok (@{$ret = $options->forwarders ()}, 5);
$ret->die ("couldn't get forwarders") unless ($ret);
ok (@$ret, 5);
# now add_to_forwarders should bomb.
ok ($ret = $options->add_to_forwarders (qw (10.0.0.2)),
qr/^add_to_forwarders: address `10.0.0.2' already defined/);
# delete from forwarders bombs
ok ($ret = $options->delete_from_forwarders (qw (10.0.0.9)),
qr/^delete_from_forwarders: address `10.0.0.9' not defined/);
# delete from forwarders succceeds.
ok ($ret = $options->delete_from_forwarders (qw (10.0.0.2)));
$ret->die ("couldn't delete from forwarders") unless ($ret);
ok (@{$ret = $options->forwarders ()}, 4);
$ret->die ("couldn't get forwarders") unless ($ret);
# now test set (overwriting previous values)
# try setting to emtpy array
ok ($ret = $options->forwarders ([]));
$ret->die ("couldn't set forwarders") unless ($ret);
ok (@{$ret = $options->forwarders ()}, 0);
$ret->die ("couldn't get forwarders") unless ($ret);
# forwarders get should fail after deleting option
ok ($ret = $options->delete_forwarders ());
$ret->die ("couldn't delete forwarders") unless ($ret);
ok ($ret = $options->forwarders (), qr/^forwarders: option not defined/);
# delete_forwarders should fail.
ok ($ret = $options->delete_forwarders (), qr/^delete_forwarders: option not defined/);
############################### listen-on #######################################
# test get
ok (keys (%{$ret = $options->listen_on ()}), 2);
ok ($_, qr/^(1234|)$/) for (keys (%$ret));
ok ($_, qr/^(any|5\.6\.7\.8)$/) for (@{$ret->{''}});
ok ($_, qr{^(1\.2\.3/24|\!1\.2\.3\.4)$}) for (@{$ret->{1234}});
# listen_on () has been tested in the Options::new ().
# now test for illegal port.
ok ($ret = $options->listen_on (
blah => [ qw (192.168.1.1) ],
), qr/^listen_on: illegal PORT `blah'/);
ok ($ret = $options->listen_on (
53 => [ qw(10.0.0.1) ],
54 => [ qw(10.0.0.1 10.0.0.2 10.0.0.3 10.0.0.4) ],
));
ok ($ret = $options->get_listen_on (55), qr/^get_listen_on: no elements defined for port `55'/);
ok (($ret = $options->get_listen_on (53))->isa ('Unix::Conf::Bind8::Conf::Acl'));
ok (@{$ret = $ret->elements ()}, 1);
ok ($ret = $options->get_listen_on_elements (55),
qr/^get_listen_on_elements: no elements defined for port `55'/);
ok (@{$ret = $options->get_listen_on_elements (53)}, 1);
# deleting the only address should delete the port itself from the datastructure
# so the get below should fail
ok ($ret = $options->delete_from_listen_on (
53 => [ qw(10.0.0.1) ],
));
ok ($ret = $options->get_listen_on (53), qr/^get_listen_on: no elements defined for port `53'/);
ok ($ret = $options->delete_from_listen_on (
54 => [ qw(10.0.0.1 10.0.0.4) ],
));
ok (@{$ret = $options->get_listen_on_elements (54)}, 2);
# with this the whole option must have been deleted.
ok ($ret = $options->delete_from_listen_on (
54 => [ qw(10.0.0.2 10.0.0.3) ],
));
ok ($ret = $options->listen_on (), qr/^get_listen_on_elements: option not defined/);
# set again to test delete_listen_on.
ok ($ret = $options->listen_on (
53 => [ qw(10.0.0.1 10.0.0.2) ],
54 => [ qw(10.0.0.1 10.0.0.2) ],
55 => [ qw(10.0.0.1 10.0.0.2) ],
56 => [ qw(10.0.0.1 10.0.0.2) ],
));
ok ($ret = $options->delete_listen_on (53, 55));
ok (keys (%{$ret = $options->listen_on ()}), 2);
ok ($ret = $options->delete_listen_on ());
ok ($ret = $options->listen_on (), qr/^get_listen_on_elements: option not defined/);
############################### rrset-order #######################################
# check the number of names defined
ok (keys (%{$ret = $options->rrset_order ()}), 4);
# test get_rrset_order successfully.
ok ($ret = $options->get_rrset_order ('*', 'ANY', 'ANY'), 'cyclic');
$ret->die ("couldn't get rrset_order") unless ($ret);
ok ($ret = $options->get_rrset_order ('', '', ''), 'cyclic');
$ret->die ("couldn't get rrset_order") unless ($ret);
ok ($ret = $options->get_rrset_order ('foo.com', 'ANY', 'A'), 'cyclic');
$ret->die ("couldn't get rrset_order") unless ($ret);
ok ($ret = $options->get_rrset_order ('boo.com', 'IN', 'NS'), 'fixed');
$ret->die ("couldn't get rrset_order") unless ($ret);
ok ($ret = $options->get_rrset_order ('extremix.net', 'ANY', 'ANY'), 'random');
$ret->die ("couldn't get rrset_order") unless ($ret);
# test add_to_rrset_order
ok ($ret = $options->add_to_rrset_order (
NAME => 'boo.com',
CLASS => 'IN',
TYPE => 'A',
ORDER => 'fixed',
));
$ret->die ("couldn't add to rrset-order") unless ($ret);
ok ($ret = $options->get_rrset_order ('boo.com', 'IN', 'A'), 'fixed');
$ret->die ("couldn't get rrset-order") unless ($ret);
# test add_to_rrset_order with error condition
ok ($ret = $options->add_to_rrset_order (
ORDER => 'cyclic',
), qr/^add_to_rrset_order: order already defined for \*, ANY, ANY/);
# test the part where keys up the tree are automatically deleted if
# no keys exist, to the option itself being deleted. also test
# get_rrset_order returning differnt parts of the tree, in the process.
ok ($ret = $options->rrset_order (
{
NAME => 'extremix.net',
CLASS => 'IN',
TYPE => 'A',
ORDER => 'cyclic',
},
{
NAME => 'extremix.net',
CLASS => 'IN',
TYPE => 'NS',
ORDER => 'cyclic',
},
{
NAME => 'extremix.net',
CLASS => 'ANY',
TYPE => 'ANY',
ORDER => 'cyclic',
},
{
NAME => 'foo.com',
CLASS => 'IN',
TYPE => 'A',
ORDER => 'cyclic',
},
));
# should get two keys 'extremix.net' and 'foo.com'
ok (keys (%{$ret = $options->get_rrset_order ()}), 2);
ok ($_, qr/^(extremix.net|foo.com)$/) for (keys (%$ret));
# should get two keys 'IN', 'ANY'
ok (keys (%{$ret = $options->get_rrset_order ('extremix.net')}), 2);
ok ($_, qr/^(IN|ANY)$/) for (keys (%$ret));
# should get two keys 'A', 'NS'
ok (keys (%{$ret = $options->get_rrset_order ('extremix.net', 'IN')}), 2);
ok ($_, qr/^(A|NS)$/) for (keys (%$ret));
# test delete_from_rrset_order error handling
ok ($ret = $options->delete_from_rrset_order (
NAME => 'foo.com',
CLASS => 'IN',
TYPE => 'NS'
), qr/^delete_from_rrset_order: NS not defined for foo.com, IN/);
ok ($ret = $options->delete_from_rrset_order (
NAME => 'foo.com',
CLASS => 'ANY',
), qr/^delete_from_rrset_order: ANY not defined for foo.com/);
ok ($ret = $options->delete_from_rrset_order ( NAME => 'boo.com'),
qr/^delete_from_rrset_order: boo.com not defined/);
# progressively delete parts of the tree, and ensure the higher
# nodes get deleted if they are empty.
ok ($ret = $options->delete_from_rrset_order (
NAME => 'extremix.net',
CLASS => 'IN',
TYPE => 'A'
));
$ret->die ("couldnt delete from rrset-order") unless ($ret);
# should get only one key now 'NS'
ok (keys (%{$ret = $options->get_rrset_order ('extremix.net', 'IN')}), 1);
ok ($_, qr/^(NS)$/) for (keys (%$ret));
# now delete the other type defined for `extremix.net' 'IN'
# this should delete `extremix.net', 'IN'
ok ($ret = $options->delete_from_rrset_order (
NAME => 'extremix.net',
CLASS => 'IN',
TYPE => 'NS'
));
$ret->die ("couldnt delete from rrset-order") unless ($ret);
# should get error now
ok ($ret = $options->get_rrset_order ('extremix.net', 'IN'),
qr /^get_rrset_order: IN not defined for extremix.net/);
# delete the only remaining class for 'extremix.net' and the name
# should get deleted too.
ok ($ret = $options->delete_from_rrset_order (
NAME => 'extremix.net',
CLASS => 'ANY',
TYPE => 'ANY'
));
$ret->die ("couldnt delete from rrset-order") unless ($ret);
# should get error now
ok ($ret = $options->get_rrset_order ('extremix.net', 'IN'),
qr/^get_rrset_order: extremix.net not defined/);
# the only remaining name is `foo.com'. once deleted
# the option should get deleted all by itself.
ok ($ret = $options->delete_from_rrset_order (
NAME => 'foo.com',
CLASS => 'IN',
TYPE => 'A'
));
$ret->die ("couldnt delete from rrset-order") unless ($ret);
# should get error now
ok ($ret = $options->get_rrset_order (), qr/^get_rrset_order: option not defined/);
# test delete_rrset_order
ok ($ret = $options->rrset_order (
{
NAME => 'extremix.net',
CLASS => 'IN',
TYPE => 'A',
ORDER => 'cyclic',
},
{
NAME => 'extremix.net',
CLASS => 'IN',
TYPE => 'NS',
ORDER => 'cyclic',
},
{
NAME => 'extremix.net',
CLASS => 'ANY',
TYPE => 'ANY',
ORDER => 'cyclic',
},
{
NAME => 'foo.com',
CLASS => 'IN',
TYPE => 'A',
ORDER => 'cyclic',
},
));
ok ($ret = $options->delete_rrset_order ('extremix.net', 'IN', 'A'));
$ret->die ("couldnt delete rrset-order") unless ($ret);
# should get only one key now 'NS'
ok (keys (%{$ret = $options->get_rrset_order ('extremix.net', 'IN')}), 1);
ok ($_, qr/^(NS)$/) for (keys (%$ret));
# now delete the other type defined for `extremix.net' 'IN'
# this should delete `extremix.net', 'IN'
ok ($ret = $options->delete_rrset_order ('extremix.net', 'IN', 'NS'));
$ret->die ("couldnt delete rrset-order") unless ($ret);
# should get error now
ok ($ret = $options->get_rrset_order ('extremix.net', 'IN'),
qr/^get_rrset_order: IN not defined for extremix.net/);
# delete the only remaining class for 'extremix.net' and the name
# should get deleted too.
ok ($ret = $options->delete_rrset_order ('extremix.net', 'ANY', 'ANY'));
$ret->die ("couldnt delete from rrset-order") unless ($ret);
# should get error now
ok ($ret = $options->get_rrset_order ('extremix.net', 'IN'),
qr /^get_rrset_order: extremix.net not defined/);
# the only remaining name is `foo.com'. once deleted
# the option should get deleted all by itself.
ok ($ret = $options->delete_rrset_order ('foo.com', 'IN', 'A'));
$ret->die ("couldnt delete from rrset-order") unless ($ret);
# should get error now
ok ($ret = $options->get_rrset_order (), qr/^get_rrset_order: option not defined/);
1;