###
###  Copyright 2000-2007 University of Illinois Board of Trustees
###  All rights reserved. 
###
###  CachingDNS.pm - psgconf control module for caching DNS server
###
###  Campus Information Technologies and Educational Services
###  University of Illinois at Urbana-Champaign
###


package PSGConf::Control::CachingDNS;

use strict;

use PSGConf::Action::GenerateFile::named_conf;
use PSGConf::Action::RunCommand;
use PSGConf::Data::Boolean;
use PSGConf::Data::List;
use PSGConf::Data::String;
use PSGConf::Control::Packages qw(_add_pkgs);


###############################################################################
###  policy methods
###############################################################################

sub _policy_check_resolver
{
	my ($self, $psgconf) = @_;

	$psgconf->data_obj('dns_cache_enable')->set('false')
		if (! $psgconf->data_obj('dns_servers')->count());
}


### add 127.0.0.1 to dns_servers
sub _policy_add_nameserver
{
	my ($self, $psgconf) = @_;

	return
		if ($psgconf->data_obj('dns_cache_enable')->equals('false'));

	$psgconf->data_obj('dns_servers')->add_top('127.0.0.1');
}


sub _policy_enable_rc_scripts
{
	my ($self, $psgconf) = @_;

	$psgconf->data_obj('rc_scripts')->insert(
		{'named' => { 'state' => 'enable' }}
	) if ($psgconf->data_obj('dns_cache_enable')->equals('true'));
}


###############################################################################
###  decide() method
###############################################################################

sub decide
{
	my ($self, $psgconf) = @_;
	my ($optref, $zoneref, $servers);

	return
		if ($psgconf->data_obj('dns_cache_enable')->equals('false'));

	$optref = {
		'listen-on'	=> [ '127.0.0.1' ],
		'allow-query'	=> [ 'localhost' ],
		'allow-transfer' => [ 'none' ]
	};

	if ($psgconf->data_obj('dns_forwarders_enable')->equals('true'))
	{
		$optref->{forwarders} = [
			grep { $_ ne '127.0.0.1' } @{$psgconf->data_obj('dns_servers')->get()}
		];
	}

	$zoneref = {
		'.'	=> {
				type	=> 'hint',
				file	=> '"/etc/named.ca"'
			}
	};

	$psgconf->register_actions(
		PSGConf::Action::GenerateFile::named_conf->new(
			name		=> $psgconf->data_obj('named_conf_path')->get(),
			description	=> 'named configuration file',
			options		=> $optref,
			zones		=> $zoneref
		),
		PSGConf::Action::RunCommand->new(
			name		=> 'generating /etc/named.ca',
			command	=> $psgconf->data_obj('dig_path')->get() . 
						' @' . 
						$psgconf->data_obj('dns_root_server')->get() . 
						' > /etc/named.ca',
			filename	=> [ '/etc/named.ca',
						$psgconf->data_obj('named_conf_path')->get() ]
		)
	);

	if ($psgconf->{'restart_daemons'}) {
		if ($psgconf->data_obj('use_rndc')->equals('true')) {
			$psgconf->register_actions(
				PSGConf::Action::RunCommand->new(
					name		=> 'Stopping named',
					command	=> $psgconf->data_obj('rndc_path')->get() . ' stop'
				),
				PSGConf::Action::RunCommand->new(
					name		=> 'Starting named',
					command	=> $psgconf->data_obj('named_path')->get()
				)
			);
		} else {
			$psgconf->register_actions(
				PSGConf::Action::RunCommand->new(
					name		=> 'Restarting named',
					command	=> $psgconf->data_obj('ndc_path')->get() . ' restart'
				)
			);
		}
	}
}


###############################################################################
###  constructor
###############################################################################

sub new
{
	my ($class, $psgconf) = @_;
	my ($self);

	$self = {};
	bless($self, $class);

	### So that _add_pkgs knows which directives to look at
	$self->{name} = 'dns_cache';
	$self->{enable} = $self->{name} . '_enable';
	$self->{packages} = $self->{name} . '_packages';

	$psgconf->register_data(
		'dig_path'		=> PSGConf::Data::String->new(
						'value_abspath' => 1,
						value => '/usr/bin/dig'
					),
		'dns_root_server'	=> PSGConf::Data::String->new(
						value => 'a.root-servers.net.'
					),
		'dns_cache_enable'	=> PSGConf::Data::Boolean->new(
						value => 'true'
					),
		'dns_cache_packages'	=> PSGConf::Data::List->new(),
		'dns_forwarders_enable'	=> PSGConf::Data::Boolean->new(
						value => 'true'
					),
		'named_conf_path'	=> PSGConf::Data::String->new(
						'value_abspath' => 1,
						value => '/etc/named.conf'
					),
		'named_path'		=> PSGConf::Data::String->new(
						'value_abspath' => 1,
						value => (-e '/usr/sbin/named'
							 ? '/usr/sbin/named'
							 : '/usr/sbin/in.named')
					),
		'ndc_path'		=> PSGConf::Data::String->new(
						'value_abspath' => 1,
						value => '/usr/sbin/ndc'
					),
		'rndc_path'		=> PSGConf::Data::String->new(
						'value_abspath' => 1,
						value => '/usr/sbin/rndc'
					),
		'use_rndc'		=> PSGConf::Data::Boolean->new(
						value => (-e '/usr/sbin/rndc')? 'true': 'false'
					)
	);

	$psgconf->register_policy($self,
		named_check_resolver	=> '_policy_check_resolver',
		named_add_packages	=> '_add_pkgs',
		named_add_nameserver	=> '_policy_add_nameserver',
		named_enable_rc_scripts => '_policy_enable_rc_scripts',
	);

	return $self;
}


###############################################################################
###  documentation
###############################################################################

1;

__END__

=head1 NAME

PSGConf::Control::CachingDNS - psgconf control class for caching DNS server

=head1 SYNOPSIS

In F<psgconf_modules>:

  Control PSGConf::Control::CachingDNS

=head1 DESCRIPTION

The B<PSGConf::Control::CachingDNS> module provides a B<psgconf> Control
object for configuring DNS.  It provides the following methods:

=over 4

=item new()

The constructor.  Its parameter is a reference to the B<PSGConf>
object.  It registers the following data objects:

=over 4

=item I<dig_path>

A B<PSGConf::Data::String> object containing the absolute path to the
C<dig> command.  The default value is F</usr/bin/dig>.

=item I<dns_root_server>

A B<PSGConf::Data::String> object containing the root server to query
when creating the F</etc/named.ca> file from.  The default value is
C<a.root-servers.net.>.

=item I<dns_cache_enable>

A B<PSGConf::Data::Boolean> object that indicates whether a caching-only
DNS server should be configured.  The default is yes.

=item I<dns_cache_packages>

A B<PSGConf::Data::List> object listing all packages that need to be installed.

=item I<dns_forwarders_enable>

A B<PSGConf::Data::Boolean> object that indicates whether forwarders should
be configured as part of the DNS server configs.  The default is yes. 
It uses the values in the I<dns_servers> data object as the forwarder
addresses.

=item I<named_conf_path>

A B<PSGConf::Data::String> object containing the absolute path to the
C<named> config file.  The default value is F</etc/named.conf>.

=item I<named_path>

A B<PSGConf::Data::String> object containing the absolute path to the
C<named> daemon.  The default value is F</usr/sbin/named> if it exists,
or F</usr/sbin/in.named> otherwise.

=item I<ndc_path>

A B<PSGConf::Data::String> object containing the absolute path to the
C<ndc> command.  The default value is F</usr/sbin/ndc>.

=item I<rndc_path>

A B<PSGConf::Data::String> object containing the absolute path to the
C<rndc> command.  The default value is F</usr/sbin/rndc>.

=item I<use_rndc>

A B<PSGConf::Data::Boolean> object that determines whether to use C<rndc>
instead of C<ndc> to restart C<named>.  The default is true if
F</usr/sbin/rndc> exists; false otherwise.

=back

The constructor also registers the following policy methods:

=over 4

=item I<named_check_resolver>

If the I<dns_servers> Data object is not set, disable
I<dns_cache_enable>.

=item I<named_add_nameserver>

If the I<dns_cache_enable> Data object is set, prepends C<127.0.0.1> to
the I<dns_servers> data object (supplied by B<PSGConf::Control::DNS>).

=item I<named_add_packages>

If the I<dns_cache_enable> Data object is set, adds C<bind>
to the I<pkg_install_list> Data object (supplied by
B<PSGConf::Control::Packages>).

=item I<named_enable_rc_scripts>

Modifies the I<rc_scripts> data object (supplied by
B<PSGConf::Control::InitScripts>) to enable C<named>.

=back

=item decide()

Instantiates and registers a B<PSGConf::Action::GenerateFile::named_conf>
object to create F</etc/named.conf>.  The generated file will tell
C<named> to only bind to C<127.0.0.1>.  It will also use the entries
in I<dns_servers> as C<forwarders>.  It uses a hints file called
F</etc/named.ca>.

=back

=head1 BUGS

A special RC script should be created for C<named>, rather than jumping
through all of the hoops to figure out how to restart it.

=head1 SEE ALSO

L<perl>

dig(1)

ndc(8) or rndc(8)

named.conf(5)

L<PSGConf>

L<PSGConf::Action::GenerateFile::named_conf>

L<PSGConf::Action::RunCommand>

L<PSGConf::Control::DNS>

L<PSGConf::Control::InitScripts>

L<PSGConf::Control::Packages>

L<PSGConf::Data::Boolean>

L<PSGConf::Data::List>

L<PSGConf::Data::String>

L<psgconf-intro>

=cut



syntax highlighted by Code2HTML, v. 0.9.1