#!/usr/bin/perl -w
#----------------------------------------------------------------------
# copyright (C) 1999-2003 Mitel Networks Corporation
# 
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
# 
# Technical support for this program is available from Mitel Networks 
# Please visit our web site www.mitel.com/sme/ for details.
#----------------------------------------------------------------------
package esmith;

use strict;
use Errno;
use esmith::ConfigDB;
use esmith::DomainsDB;
use esmith::NetworksDB;
use esmith::util;

sub allow_networks_2access_cache;
sub delegate_domains_2DNS;

my $config = esmith::ConfigDB->open or die "Could not open config db.";
my $dnscache = $config->get('dnscache');
unless ($dnscache)
{
    warn "dnscache not configured in configuration db\n";
    exit 0;
}

my $domains = esmith::DomainsDB->open or die "Could not open Domains db.";
my $nets = esmith::NetworksDB->open or die "Could not open Networks db.";

#------------------------------------------------------------
# Configure DNS cache.
#------------------------------------------------------------

unless (-f "/var/service/dnscache/seed")
{
    system(qw(/bin/dd
              if=/dev/random
              of=/var/service/dnscache/seed
              bs=128 count=1)) == 0
                  or warn("Could not create seed file");
}

my $event = shift || "Unknown";

foreach my $file (qw(CACHESIZE IP IPSEND))
{
    esmith::util::processTemplate ({
                        TEMPLATE_PATH => "/var/service/dnscache/env/$file",
                        PERMS => 0644,
                        });
}
# Remove FORWARDONLY which might be left behind from previous template
# expansion.
unlink "/var/service/dnscache/env/FORWARDONLY";

esmith::util::processTemplate ({
                        TEMPLATE_PATH => "/var/service/dnscache/root/servers/@",
                        PERMS => 0644,
                        });

esmith::util::processTemplate ({
                        TEMPLATE_PATH => "/var/service/dnscache/runenv",
                        PERMS => 0644,
                        });

# allow my networks to access the nameserver cache
my @localnetworks = ();
my %reversenets = ();

foreach my $net ($nets->get_all_by_prop('type', 'network'))
{
    my $mask = $net->prop('Mask');
    my $key = $net->key;
    my $nameserver = $net->prop('NameServer') || '127.0.0.1';
    push @localnetworks,
        esmith::util::computeAllLocalNetworkPrefixes ($key, $mask);

    my $reverse = esmith::util::computeLocalNetworkReversed ($key, $mask);
    # Remove the trailing period provided by computeLocalNetworkReversed
    $reverse =~ s/\.$//;
    $reversenets{$reverse} = $nameserver if ($net->prop('SystemLocalNetwork') or $net->prop('NameServer'));
}

allow_networks_2access_cache(@localnetworks);

my $forwardOnly = $dnscache->prop('ForwardOnly') || 'enabled';
if ($dnscache->prop('Forwarder') && $forwardOnly ne 'disabled')
{
    # We handle no domains locally
    delegate_domains_2DNS();
}
else
{
    delegate_domains_2DNS(
        %reversenets,
            map { $_->key => $_->prop('NameServer') || '127.0.0.1' } 
            ($domains->get_all_by_prop('type', 'domain'), 
            $domains->get_all_by_prop('type', 'domain-remote')
    )
);
}

reload_dnscache( $event );

exit (0);

sub allow_networks_2access_cache
{
    my %access = map { $_ => 1 } @_;

    my $dir = '/var/service/dnscache/root/ip';
    chdir $dir
        || die "Cannot chdir to $dir: $!\n";
    unless (-f "127.0.0.1")
    {
        open F,">127.0.0.1"
            || die "Cannot add access file for loopback network: $!\n";
        close F;
    }

    opendir(ACCESS, '.') or
    die "Cannot read dnscache access directory: $!";

    foreach my $aclfile (readdir (ACCESS))
    {
        next if "$aclfile" eq "127.0.0.1";
        next if -d "$aclfile";
        if (exists $access{$aclfile})
        {
            # Cross this one off the list so that we don't bother creating it
            delete $access{$aclfile};
        }
        else
        {
            # We no longer need this entry
            unlink "$aclfile" or
            warn "Could not delete dnscache access file $dir/$aclfile: $!\n";
        }
    }
    closedir(ACCESS);

    foreach my $aclfile (keys %access)
    {
        link "127.0.0.1", $aclfile or 
        die "Cannot add network access for $aclfile: $!\n";
    }
}

sub delegate_domains_2DNS
{
    my %delegations = @_;
    my $serversdir = '/var/service/dnscache/root/servers';
    chdir $serversdir
        || die "Cannot chdir to $serversdir: $!\n";
    unless (-f "127.in-addr.arpa")
    {
        open F,">127.in-addr.arpa"
            || die "Cannot add delegation for loopback network: $!\n";
        print F "127.0.0.1\n";
        close F;
    }

    opendir(SERVERS, '.') or
    die "Cannot read dnscache servers directory: $!";

    foreach my $delegatefile (readdir (SERVERS))
    {
        next if "$delegatefile" eq '@';

        next if "$delegatefile" eq "127.in-addr.arpa";

        next if -d "$delegatefile";

        unless (exists $delegations{$delegatefile})
        {
            # We no longer need this entry
            unlink "$delegatefile" or
            warn "Could not delete dnscache domain file $delegatefile: $!\n";
        }
    }
    closedir(SERVERS);

    foreach my $delegatefile (keys %delegations)
    {
        if (-l $delegatefile)
        {
            # Legacy symlink - we use files now
            unlink "$delegatefile" or
            warn "Could not delete dnscache domain link $delegatefile: $!\n";
        }
        my $nameserver = $delegations{$delegatefile};

        open DELEGATE, ">$delegatefile" or
            die "Couldn't create $delegatefile with value $nameserver\n";
        print DELEGATE "$nameserver\n";
        close DELEGATE;
    }
}

sub reload_dnscache
{
    my ($event) = @_;
    
    return if ($event eq "bootstrap-console-save");

    return if ($event =~ /post-(install|upgrade)/);

    # we might have changed from forwarding to not forwarding DNS requests
    esmith::util::serviceControl(
        NAME => 'dnscache',
        ACTION => 'restart'
    ) or warn "Failed to restart dnscache";
}
