From d8b6b8cd878568df71395443fab7a2d93259aaa6 Mon Sep 17 00:00:00 2001 From: ianmdlvl Date: Sun, 30 Dec 2001 21:57:15 +0000 Subject: [PATCH] Seems able to read configuration. --- scripts/named-conf | 214 ++++++++++++++++++++++++++++++---------- scripts/named-conf.8 | 226 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 389 insertions(+), 51 deletions(-) create mode 100644 scripts/named-conf.8 diff --git a/scripts/named-conf b/scripts/named-conf index e788f07..b037492 100755 --- a/scripts/named-conf +++ b/scripts/named-conf @@ -1,66 +1,178 @@ -#!/usr/bin/perl +#!/usr/bin/perl -w -$base= "/var/named"; -$conf= "$base/conf"; -$etcfile= "/etc/named/zones-rgc"; +use IO::File; +use Data::Dumper; -$check= 1; -$progress= 1; +$etcfile= "/etc/bind/chiark-conf-gen.zones"; +$where= ''; -while ($ARGV[0] =~ m/^\-/) { +$mode= ''; +$verbosity= 1; +$fromroot= 0; + +while (@ARGV && $ARGV[0] =~ m/^\-/) { $_= shift @ARGV; - last if m/^\-\-?$/; - while (m/^\-./) { - if (s/^\-f/-/) { $usage=0; $check=0; $install++; } - elsif (s/^\-y/-/) { $usage=0; $check=1; $install++; } - elsif (s/^\-n/-/) { $usage=0; $check=1; $install=0; } - elsif (s/^\-h/-/) { $hostdelg=1; $hostzone=0; } - elsif (s/^\-z/-/) { $hostdelg=1; $hostzone=1; } - elsif (s/^\-q/-/) { $progress=0; } - else { $usage=1; break; } + if (s/^\-\-//) { + last if m/^$/; + if (m/^quiet$/) { $verbosity=0; } + elsif (m/^verbose$/) { $verbosity=2; } + elsif (m/^root$/) { $fromroot=1; } + elsif (m/^(yes|no|force)$/) { m/^./; $mode= $&; } + elsif (m/^config$/) { $etcfile= loarg(); $where= '--config option'; } + else { usageerr("unknown option --$_"); } + } else { + s/^\-//; + last if m/^$/; + while (m/^./) { + if (s/^[ynf]//) { $mode=$&; } + elsif (s/^r//) { $fromroot=1; } + elsif (s/^v//) { $verbosity=2; } + elsif (s/^q//) { $verbosity=0; } + elsif (s/^C//) { $etcfile= soarg(); $where= '-C option'; } + else { usageerr("unknown option -$&"); } + } } } -die -"usage: named-conf-regen -f|-y|-n [-h|-z]\n". +sub loarg() { usageerr("missing option value") if !@ARGV; return shift @ARGV; } +sub soarg() { my ($rv); $rv=$_; $_=''; return length $rv ? $rv : loarg(); } + +usageerr("must specify either -f|-y|-n or zones (and not both)") + if !!$mode == !!@ARGV; + +sub usageerr ($) { + die +"$_[0] +usage: named-conf-regen [-rvq] -f|-y|-n|...\n". "operation modes:\n". -" -f install without checking -ff and then ndc reload\n". -" -y check and install -yy and then ndc reload\n". -" -n check only\n". +" -f --force install without checking\n". +" -y --yes check and install\n". +" -n --no check only\n". "additional options:\n". -" -h check output from host -C\n". -" -z check output from host -C and host -val\n". - if $usage; - -beginfile('secondary.zones'); -open E, "< $etcfile" or die "$0: open $etcfile: $!\n"; -for (;;) { - $!=0; defined $_= or die "$0: read $etcfile $!\n"; - s/^\s+//; chomp; s/\s+$//; - next if m/^\#/; - last if m/^end$/; - if (m/^myname\s+(\S.*\S)/) { - @mynames= split /\s+/, $1; - } elsif (m/^(secondary|backup|unoff)\s+(\S+)\s+([0-9. \t]+)$/) { - $style= $1; - $zone= $2; - @servers= split /\s+/, $3; - $file= "slave/$zone"; - progress(); - check(); - } else { - die "$0: $etcfile:$.: syntax error in \`$_'\n"; +" -r --root check all the way back to the root\n". +" -q --quiet no output for OK zones\n". +" -v --verbose extra verbose\n"; +} + +cfg_fail("config filename $etcfile should have been absolute path of a file") + unless $etcfile =~ m,^/, && $etcfile !~ m,/$,; + +$default_dir= $etcfile; +$default_dir =~ s,/[^/]+$,,; + +$slave_dir= 'slave'; +$slave_prefix= ''; +$slave_suffix= ''; +@self_ns= @self_soa= (); +%zone_cfg= (); +@zone_cfg_list= (); +$output= ''; +$default_output= ''; +%output_contents= (); + +read_config($etcfile); + +print Dumper(@zone_cfg_list), Dumper(%zone_cfg); + +sub cfg_fail ($) { die "$0: $where:\n $_[0]\n"; } + +sub read_config ($) { + my ($if) = @_; + my ($fh,$z,@self, $dir,$prefix,$suffix,$lprefix,$lsuffix); + local ($_,$1,$2,$3); + + $fh= new IO::File $if,'r' or cfg_fail("open $if:\n $!"); + for (;;) { + if (!defined($_= <$fh>)) { + cfg_fail("read config file $if:\n $!") if $fh->error(); + last; + } + $where= "$if:$."; + s/^\s+//; chomp; s/\s+$//; + next if m/^\#/; + last if m/^end$/; + next unless m/\S/; + if (m/^self(\-ns|\-soa|)\s+(\S.*\S)/) { + @self= split /\s+/, $2; + @self_ns= @self if $1 ne '-soa'; + @self_soa= @self if $1 ne '-ns'; + } elsif (m/^primary\-dir\s+(\S+)((?:\s+(\S+))??:\s+(\S+))?$/) { + ($dir, $prefix, $suffix) = (qualify($1),$2,$3); + $suffix= '_db' if !length $suffix; + opendir D, $dir or cfg_fail("open primary-dir $dir:\n $!"); + $lprefix= length $prefix; $lsuffix= length $suffix; + while ($!=0, $_= readdir D) { + next if m/^\./ && !$lprefix; + next unless length > $lprefix+$lsuffix; + next unless substr($_,0,$lprefix) eq $prefix; + next unless substr($_,length($_)-$lsuffix) eq $suffix; + $z= substr($_,$lprefix,length($_)-($lprefix+$lsuffix)); + zone_conf($z,'primary',"$dir/$_"); + } + $! and cfg_fail("read primary-dir $dir:\n $!"); + closedir D or cfg_fail("close primary-dir $dir:\n $!"); + } elsif (m/^primary\s+(\S+)\s+(\S+)$/) { + zone_conf($1,'primary',qualify($2)); + } elsif (m/^secondary\s+(\S+)\s+([0-9.\t]+)$/) { + zone_conf($1,'secondary','',$2); + } elsif (m/^stealth\s+(\S+)\s+([0-9. \t]+)$/) { + zone_conf($1,'stealth','',split /\s+/, $2); + } elsif (m/^slave\-dir\s+(\S+)((?:\s+(\S+))??:\s+(\S+))?$/) { + ($slave_dir, $slave_prefix, $slave_suffix) = (qualify($1),$2,$3); + } elsif (m/^output\s+bind8\+(\S+)$/) { + cfg_fail("default output may not apply to only some zones") + if @zone_cfg_list && length $default_output; + set_output(qualify($1)); + } elsif (m/^include\s+(\S+)$/) { + read_config($1); + } else { + cfg_fail("unknown configuration directive". + " or incorrect syntax or arguments"); + } + } + $fh->close or cfg_fail("close config file $if:\n $!"); +} + +sub qualify ($) { + my ($i) = @_; + $i= "$default_dir/$i" unless $i =~ m,^/,; +} + +sub zone_conf ($$@) { + my ($zone,$style,$file,@servers) = @_; + $file= qualify("$slave_dir/$slave_prefix".$zone.$slave_suffix) + unless length $file; + if (!length $output) { + $default_output= qualify('chiark-conf-gen.bind8') + unless length $default_output; + set_output($default_output); } + cfg_fail("redefined zone $zone") if exists $zone_cfg{$zone}; + $zone_cfg{$zone}{'file'}= $file; + $zone_cfg{$zone}{'style'}= $style; + $zone_cfg{$zone}{'servers'}= @servers; + $zone_cfg{$zone}{'output'}= $output; + push @zone_cfg_list, $zone; +} + +sub set_output($) { + my ($newout) = @_; + $output= $newout; + $output_contents{$output}= ''; } +__DATA__ + + + sub lookup ($$) { my ($type,$domain) = @_; my ($c,@result); - defined($c=open ADH, "-|") or die "$0: fork adnshost: $!\n"; + defined($c=open ADH, "-|") or die "$0: fork adnshost:\n $!\n"; if (!$c) { exec 'adnshost','+Do','+Dt','+Dc','-Cf',"-t$type", '-',"$domain."; - die "$0: exec adnshost: $!\n"; + die "$0: exec adnshost:\n $!\n"; } @result= ; chomp @result; @@ -121,7 +233,7 @@ sub check () { for $super_ns (@super_ns) { @deleg_ns= (); open DIG, "dig @$super_ns. -t ns +norecurse $zone." - or die "$0: fork for dig: $!\n"; + or die "$0: fork for dig:\n $!\n"; while () { @@ -197,7 +309,7 @@ done endfile -chdir "$base/primary" or die "$0: chdir $base/primary: $!"; +chdir "$base/primary" or die "$0: chdir $base/primary:\n $!"; beginfile('primary.zones'); for $f (<*_db>) { @@ -221,19 +333,19 @@ endfile sub beginfile ($) { $currentfile= $_[0]; $currentfile_opened= $install ? "$conf/$currentfile.new" : "/dev/null"; - open CFF, "> $toopen" or die "$0: begin $currentfile_opened: $!\n"; + open CFF, "> $toopen" or die "$0: begin $currentfile_opened:\n $!\n"; } endfile () { - close CFF or die "$0: close $currentfile_opened: $!\n"; + close CFF or die "$0: close $currentfile_opened:\n $!\n"; push @files, $currentfile; } sub installfiles () { return unless $install; - chdir $conf or die "$0: chdir $conf: $!\n"; + chdir $conf or die "$0: chdir $conf:\n $!\n"; for $f (@files) { - rename "$f.new", $f or die "$0: install new $f: $!\n"; + rename "$f.new", $f or die "$0: install new $f:\n $!\n"; } } diff --git a/scripts/named-conf.8 b/scripts/named-conf.8 new file mode 100644 index 0000000..0ba18b9 --- /dev/null +++ b/scripts/named-conf.8 @@ -0,0 +1,226 @@ +.\" Hey, Emacs! This is an -*- nroff -*- source file. +.TH CHIARK\-NAMED\-CONF 8 "30th December 2001" "Greenend" "chiark utilities" +.SH NAME +chiark\-named\-conf \- check and generate nameserver configuration + +.SH SYNOPSIS +.B chiark\-named\-conf [\fIoptions\fP] \-n|\-y|\-f +.br +.B chiark\-named\-conf [\fIoptions\fP] \fIzone ...\fP + +.SH DESCRIPTION +.B chiark\-named\-conf +is a tool for managing nameserver configurations and checking for +suspected DNS problems. Its main functions are to check that +delegations are appropriate and working, optionally from the root zone +down, and to generate a configuration for +.BR BIND , +from its own input file. + +.SH OPTIONS +.SS MODE OPTIONS +If one of the options +.BR -n ", " -y ", or " -f +is supplied then chiark-named-conf will read its main configuration +file for the list of relevant zones. It will then check the +configuration and delegation for each zone +and/or generate and install a new configuration file for +the nameserver: +.TP +.BR \-y | \-\-yes +Generate and install new nameserver config, as well as checking +configuration, for all listed zones. +.TP +.BR \-n | \-\-no +Check configuration, for all listed zones, but +do not generate new nameserver config. +.TP +.BR \-f | \-\-force +Generate and install new nameserver config, without doing any +configuration cross-checking. (Syntax errors in our input +configuration will still abort this operation.) +.LP +Alternatively, one or more zone names may be supplied as arguments, in +which case their delegations will be checked, and compared with the +data for that zone in the main configuration (if any). In this case +no new configuration file for the nameserver will be made. + +.SS ADDITIONAL OPTIONS +.TP +\fB\-C\fP|\-\-config \fIconfig\-file\fP +Use +.I config\-file +instead of +.BR /etc/bind/chiark-conf-gen.zones . +.TP +.BR \-q | \-\-quiet +Do not print any information about zone(s) which do not have warnings. +.TP +.BR \-v | \-\-verbose +Print additional information about each zone. +.TP +.BR \-r | \-\-root +Check the delegation all the way to the root zone. By default, +checks are only carried out on the delegations supplied by (all) the +nameservers for the immediate superzone. +.SH CONFIGURATION +The file +.B /etc/bind/chiark-conf-gen.zones +(or other file specified with the +.B \-C +option) contains a sequence of directives, one per line. Blank lines +are permitted. Leading and trailing whitespace on each line is +ignored. Comments are lines starting with +.BR # . +.SS GENERAL DIRECTIVES +These directives specify general configuration details. They should +appear before directives specifying zones, as each will affect only +later zone directives. +.TP +\fBself\-ns\fP \fIfqdn ...\fP +Specifies the list of names that this server may be known by in NS +records. There is no default. +.TP +\fBself\-soa\fP \fIfqdn ...\fP +Specifies the list of names that this server may be known by in +the ORIGIN field of SOA records. There is no default. +.TP +\fBself\fP \fIfqdn ...\fP +Equivalent to both +.BR self\-ns " and " self-\soa +with the same set of names. +.TP +\fBslave\-dir\fP \fIdirectory\fP [[\fIprefix\fP] \fIsuffix\fP] +Specifies the directory in which slave (secondary and stealth) +zonefiles should be placed. The default +.I directory +is +.BR /var/cache/bind/chiark-slave . +The default +.IR suffix " and " prefix +are empty; they also will be reset to these defaults by a +.B slave\-dir +directive which does not specify them. +.TP +\fBdefault\-dir\fP \fIdirectory\fP +Makes +.I directory +be the default directory (which affects the interpretation of +relative filenames). The default is the directory containing +the main configuration file, ie +.BR /etc/bind +if no +.B -C +option is specified. +.TP +\fBoutput\fP \fIformat\fP \fIfilename\fP [\fIformat\fP \fIfilename ...\fP] +Arranges that each +.I filename +will be overwritten when +.BR -y " or " -f +are used; its new contents will be configuration +directives for the zones which follow for the +nameserver in question. Currently the only +.I format +supported is +.B bind8 +which indicates new-style BIND 8. If no zones follow, then each +file will still be overwritten, by an effectively empty file. +Default: if there is no +.B output +directive in the configuration then the default is to use +.BR bind8 " " chiark-conf-gen.bind8 ; +otherwise it is an error for there to be any zones in the +configuration before the first +.B output +directive. +.SS ZONE DIRECTIVES +These directives specify one or more zones. +.TP +\fBprimary\fP \fIzone\fP \fIfilename\fP +Specifies that this server is supposed to be the primary nameserver +for +.I zone +and that the zone data is to be found in +.IR filename . +.TP +\fBprimary-dir\fP \fIdirectory\fP [[\fIprefix\fP] \fIsuffix\fP] +Search +.I directory +for files whose names match the glob pattern +.IR suffix * prefix . +Each such file is taken to represent a zone file for which this server +is supposed to be the primary. * is the name of the zone. The +default for +.I suffix +is +.BR _db ; +the default for +.I prefix +is empty. +.TP +\fBsecondary\fP \fIzone\fP \fIorigin\-addr\fP +Specifies that this server is supposed to be a published secondary for +the zone in question. +.TP +\fBstealth\fP \fIzone\fP \fIserver\-addr ...\fP +Specifies that this server is supposed to be an unpublished secondary +(aka stealth secondary) for the zone in question. +.SS OTHER DIRECTIVES +.TP +\fBinclude\fP \fIfile\fP +Reads +.I file +as if it were included here. +.TP +\fBend\fP +Ends processing of this file; any data beyond this point is ignored. +.SH CHECKS +chiark\-named\-conf makes the following checks: + +Delegations: Each delegation from a server for the superzone should +contain the same set of nameservers. None of the delegations should +lack glue. The glue addresses should be the same in each delegation, +and agree with the local default nameserver. + +Delegated servers: Each server mentioned in the delegation should have +the same SOA record (and obviously, should be authoritative). + +Origin server's data: The set of nameservers in the origin server's +version of the zone should be a superset of those in the delegations. +(The addresses of any additional servers will be acquired from the +local default nameserver at this point.) + +All published nameservers - including delegated servers and servers +named in the zone's nameserver set: All nameservers for the zone +should supply the same list of nameservers for the zone as the origin +server does, and none of this authority information should be +glueless. All the glue should always give the same addresses. + +Our zone configuration: For +.B primary +zones, the SOA origin should be one of the names specified with +.BR self\-soa " (or " self ). For +.B secondary +zones, the address should be that of the SOA origin. For +.B stealth +zones, the address should be that of the SOA origin or one of the +published nameservers. +.SH FILES +.TP +.B /etc/bind/chiark-conf-gen.zones +Default input configuration file. (Override with +.BR -C .) +.TP +.B /etc/bind +Default directory. (Override with +.BR -C " or " default\-dir .) +.TP +.IB dir /chiark-conf-gen.bind8 +Default output file. +.TP +.B /var/cache/bind/chiark-slave +Default location for slave zones. +.SH AUTHOR +.B chiark\-named\-conf +and this manpage were written by Ian Jackson . -- 2.30.2