Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 210 lines (164 sloc) 5.17 KB
#!/usr/local/bin/perl -w
#
# $Id
#
# script to generate named.conf files
#
use strict;
use HOSTDB;
use Getopt::Std;
use vars qw ($opt_h $opt_d $opt_m $opt_s $opt_T $opt_I $opt_X $opt_O);
getopts ('hdms:T:I:X:O:');
my $debug = defined ($opt_d);
my $gen_type = $opt_T || 'undef';
my $iplist = $opt_I;
sub usage() {
die (<<EOT);
Syntax: $0 -T type [options]
options :
-d debug output
-s IP generate slave config, fetch zones from IP (deprecated, use -T slave -I IP)
-m generate master config (deprecated, use -T master)
-T type generate [master|slave|forward] config
-I IP-list list of IP adresses for slave and forward
-X file file containing zones to be excluded
-O file file containing zone specific options
-O options file format :
\# this is a comment
foo.se allow-query { xyz; }
\# to match all subdomains of foo.se, but not foo.se itself :
.foo.se allow-query { xyz; }
EOT
}
usage() if ($opt_h);
if ($opt_T and ($opt_m or $opt_s)) {
die ("$0: Can't have both -T and -s or -m (use -T)\n");
}
$gen_type = 'master' if ($opt_m);
$gen_type = 'slave' if ($opt_s);
if ($gen_type ne 'master' and
$gen_type ne 'slave' and
$gen_type ne 'forward') {
die ("$0: Unsupported type (-T) : '$gen_type'\n");
}
usage() if (defined $iplist and $opt_s);
$iplist = $opt_s if (!defined $iplist);
if ($gen_type ne 'master' && !defined $iplist) {
die ("$0: Type '$gen_type' requires an IP list (option -I)\n");
}
#
# We are done processing options, start the real work
#
my $hostdb = HOSTDB::DB->new (inifile => HOSTDB::get_inifile (),
debug => $debug
);
my (%exclude_zones, %zone_options);
load_exclude_zones ($hostdb, $opt_X, \%exclude_zones) if ($opt_X);
load_zone_options ($hostdb, $opt_O, \%zone_options) if ($opt_O);
foreach my $zone ($hostdb->findallzones ()) {
next if ($zone->delegated () eq 'Y');
my $zonename = $zone->zonename ();
next if ($exclude_zones{$zonename});
my $z = tab_format (4, "zone \"$zonename\"");
my $options = get_zone_options ($zonename, \%zone_options);
if ($gen_type eq 'master') {
print ("$z { type master; file \"/approved/$zonename..ZONE\"; $options};\n");
} elsif ($gen_type eq 'slave') {
print ("$z { type slave; masters { $iplist; }; file \"/slave/$zonename..DUMP\"; $options};\n");
} elsif ($gen_type eq 'forward') {
print ("$z { type forward; forward first; forwarders { $iplist }; };\n");
}
}
exit (0);
# indent a string using tabs
sub tab_format
{
my $tab_count = shift;
my $string = shift;
my $minus_tabs = int (length ($string) / 8);
return $string . "\t" x ($tab_count - $minus_tabs);
}
# load file containing zonenames to exclude from the generated named.conf
sub load_exclude_zones
{
my $hostdb = shift;
my $fn = shift;
my $exclude_zones_ref = shift;
open (F, "< $fn") or die ("$0: Could not open exclude-file '$fn' for reading : $!\n");
while (my $rad = <F>) {
chomp ($rad);
next if ($rad =~ /^\s*\#/); # ignore comments
next if ($rad =~ /^\s*$/); # ignore empty lines
if (! $hostdb->clean_domainname ($rad)) {
die ("$0: Invalid domainname '$rad' on line $. of file '$fn'\n");
}
$$exclude_zones_ref{$rad} = 1;
}
close (F);
return 1;
}
# load file containing extra named.conf options to use for zones
#
# file format :
#
# # this is a comment
# foo.se allow-query { xyz; }
# # to match all subdomains of foo.se, but not foo.se itself :
# .foo.se allow-query { xyz; }
sub load_zone_options
{
my $hostdb = shift;
my $fn = shift;
my $zone_options_ref = shift;
open (F, "< $fn") or die ("$0: Could not open options-file '$fn' for reading : $!\n");
while (my $rad = <F>) {
chomp ($rad);
next if ($rad =~ /^\s*\#/); # ignore comments
next if ($rad =~ /^\s*$/); # ignore empty lines
if ($rad =~ /^(\S+)\s+(.+?)\s*$/) {
my $zone = $1;
my $options = "$2 ";
if ($zone =~ /^\.(.+)$/) {
# check if whatever follows the first dot is a valid domainname
my $t = $1;
if (! $hostdb->clean_domainname ($t)) {
die ("$0: Invalid (dot-)zonename '$t' on line $. of options-file '$fn'\n");
}
$zone = ".$t"; # clean_domainname normalizes data
} else {
if (! $hostdb->clean_domainname ($zone)) {
die ("$0: Invalid zonename '$zone' on line $. of options-file '$fn'\n");
}
}
$$zone_options_ref{$zone} = $options;
} else {
die ("$0: Invalid data on line $. of options-file '$fn' : $rad\n");
}
}
close (F);
return 1;
}
# return named.conf options to use for a zone, or ''.
sub get_zone_options
{
my $zonename = shift;
my $zone_options_ref = shift;
if ($$zone_options_ref{$zonename}) {
# exact match
return $$zone_options_ref{$zonename};
}
# look if this is a subdomain we should match
foreach my $t (keys %{$zone_options_ref}) {
next unless ($t =~ /^\./);
# there is probably a very obvious way to do this that I just fail to think of -
# I wanted to avoid having escaped dots in the configuration file, and also
# avoid any ambiguity to keep it simple...
my $rindex = rindex ($zonename, $t);
next unless $rindex;
next if ($rindex < 1);
if (length ($t) + $rindex == length ($zonename)) {
return $$zone_options_ref{$t};
}
}
return '';
}
You can’t perform that action at this time.