#!/usr/bin/perl -w #---------------------------------------------------------------------- # copyright (C) 1999-2008 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 # #---------------------------------------------------------------------- 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; unless (-f "/var/service/dnscache/seed") { system(qw(/bin/dd if=/dev/urandom of=/var/service/dnscache/seed bs=128 count=1)) == 0 or warn("Could not create seed file"); } open(STDIN, "<./seed") or warn "Failed to redirect input from seed file: $!"; open(STDERR, ">&STDOUT") or warn "Failed to redirect stderr to stdout: $!";; my $config = esmith::ConfigDB->open or die "Could not open config db."; my $dnscache = $config->get('dnscache'); my $forwarders = $dnscache->prop("Forwarder") || ""; if ($dnscache->prop("Forwarder2")) { $forwarders .= "," . $dnscache->prop("Forwarder2"); } unless ($dnscache) { die "dnscache not configured in configuration db\n"; } my $localip = $config->get('LocalIP'); unless ($localip) { die "localip not configured in configuration db\n"; } my $tinydns = $config->get('tinydns'); unless ($tinydns) { die "tinydns not configured in configuration db\n"; } my $tinydns_ip = $tinydns->prop('ListenIP') || "127.0.0.1"; $ENV{FORWARDONLY} = '1'; $ENV{IP} = $dnscache->prop('ListenIP') || $localip->value; $ENV{IPSEND} = $dnscache->prop('SendIP') || '0.0.0.0'; $ENV{CACHESIZE} = 200000; $ENV{ROOT} = '/service/dnscache/root'; 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 access. #------------------------------------------------------------ # 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 $systemlocalnetwork = $net->prop('SystemLocalNetwork') || 'no'; my $nameserver = $net->prop('NameServer'); if (defined $nameserver and $nameserver eq $ENV{IP}) { warn("NameServer property for net $key ($nameserver) would create loop - ignoring\n"); $nameserver = undef; } $nameserver ||= ($systemlocalnetwork eq 'yes') ? $tinydns_ip : 'none'; my @all_network_prefixes = esmith::util::computeAllLocalNetworkPrefixes ($key, $mask); push @localnetworks, @all_network_prefixes; unless ($nameserver eq 'none') { foreach (@all_network_prefixes) { my @quads = split(/\./, $_); my $reverse_zone = join('.', reverse @quads) . ".in-addr.arpa"; $reversenets{$reverse_zone} = $nameserver; } } } allow_networks_2access_cache(@localnetworks); delegate_domains_2DNS( %reversenets, map { $_->key => ($_->prop('Nameservers') || $tinydns_ip) } ($domains->get_all_by_prop('type', 'domain'), $domains->get_all_by_prop('type', 'domain-remote') )); my $datalimit = $dnscache->prop('DataLimit') || 3000000; # Ensure that forwarder instance is started system("sv", "u", "/service/dnscache.forwarder"); # http://marc.theaimsgroup.com/?l=djbdns&m=104812086607532&w=2 $SIG{'PIPE'} = 'IGNORE'; exec("envuidgid", "dnscache", "softlimit", "-o250", "-d", "$datalimit", "/usr/local/bin/dnscache") or die "failed to execute envuidgid/softlimit/dnscache: $!"; # NOTREACHED exit (1); sub allow_networks_2access_cache { my %access = map { $_ => 1 } @_; my $dir = '/var/service/dnscache/root/ip'; unless (-f "$dir/127.0.0") { open F,">$dir/127.0.0" || die "Cannot add access file for loopback network: $!\n"; close F; } opendir(ACCESS, $dir) or die "Cannot read dnscache access directory: $!"; foreach my $aclfile (readdir (ACCESS)) { next if "$aclfile" eq "127.0.0"; 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 "$dir/$aclfile" or warn "Could not delete dnscache access file $dir/$aclfile: $!\n"; } } closedir(ACCESS); foreach my $aclfile (keys %access) { link "$dir/127.0.0", "$dir/$aclfile" or die "Cannot add network access for $dir/$aclfile: $!\n"; } } sub delegate_domains_2DNS { my %delegations = @_; my $serversdir = '/var/service/dnscache/root/servers'; opendir(SERVERS, $serversdir) or die "Cannot read dnscache servers directory: $!"; foreach my $delegatefile (readdir (SERVERS)) { next if "$delegatefile" eq '@'; next if -d "$serversdir/$delegatefile"; unless (exists $delegations{$delegatefile}) { # We no longer need this entry unlink "$serversdir/$delegatefile" or warn "Could not delete dnscache domain file $serversdir/$delegatefile: $!\n"; } } closedir(SERVERS); foreach my $delegatefile (keys %delegations) { if (-l "$serversdir/$delegatefile") { # Legacy symlink - we use files now unlink "$serversdir/$delegatefile" or warn "Could not delete dnscache domain link $serversdir/$delegatefile: $!\n"; } open DELEGATE, ">$serversdir/$delegatefile" or die "Couldn't create $serversdir/$delegatefile\n"; for my $ns ( split /,/, $delegations{$delegatefile} ) { if ($ns =~ /^localhost$/) { print DELEGATE $tinydns_ip . "\n"; } elsif ($ns =~ /^corporate$/) { print DELEGATE join("\n", split /,/, $forwarders) . "\n"; } elsif ($ns =~ /^internet$/) { unlink "$serversdir/$delegatefile" or warn "Couldn't unlink $serversdir/$delegatefile\n" } else { print DELEGATE $ns . "\n"; } } close DELEGATE; } }