chiark / gitweb /
e788f07a4251f034d08a030e13c583ff3be5eeca
[chiark-utils.git] / scripts / named-conf
1 #!/usr/bin/perl
2
3 $base= "/var/named";
4 $conf= "$base/conf";
5 $etcfile= "/etc/named/zones-rgc";
6
7 $check= 1;
8 $progress= 1;
9
10 while ($ARGV[0] =~ m/^\-/) {
11     $_= shift @ARGV;
12     last if m/^\-\-?$/;
13     while (m/^\-./) {
14         if (s/^\-f/-/) { $usage=0; $check=0; $install++; }
15         elsif (s/^\-y/-/) { $usage=0; $check=1; $install++; }
16         elsif (s/^\-n/-/) { $usage=0; $check=1; $install=0; }
17         elsif (s/^\-h/-/) { $hostdelg=1; $hostzone=0; }
18         elsif (s/^\-z/-/) { $hostdelg=1; $hostzone=1; }
19         elsif (s/^\-q/-/) { $progress=0; }
20         else { $usage=1; break; }
21     }
22 }
23
24 die
25 "usage: named-conf-regen -f|-y|-n [-h|-z]\n".
26 "operation modes:\n".
27 " -f   install without checking     -ff  and then ndc reload\n".
28 " -y   check and install            -yy  and then ndc reload\n".
29 " -n   check only\n".
30 "additional options:\n".
31 " -h   check output from host -C\n".
32 " -z   check output from host -C and host -val\n".
33     if $usage;
34
35 beginfile('secondary.zones');
36 open E, "< $etcfile" or die "$0: open $etcfile: $!\n";
37 for (;;) {
38     $!=0; defined $_=<E> or die "$0: read $etcfile $!\n";
39     s/^\s+//; chomp; s/\s+$//;
40     next if m/^\#/;
41     last if m/^end$/;
42     if (m/^myname\s+(\S.*\S)/) {
43         @mynames= split /\s+/, $1;
44     } elsif (m/^(secondary|backup|unoff)\s+(\S+)\s+([0-9. \t]+)$/) {
45         $style= $1;
46         $zone= $2;
47         @servers= split /\s+/, $3;
48         $file= "slave/$zone";
49         progress();
50         check();
51     } else {
52         die "$0: $etcfile:$.: syntax error in \`$_'\n";
53     }
54 }
55
56 sub lookup ($$) {
57     my ($type,$domain) = @_;
58     my ($c,@result);
59     defined($c=open ADH, "-|") or die "$0: fork adnshost: $!\n";
60     if (!$c) {
61         exec 'adnshost','+Do','+Dt','+Dc','-Cf',"-t$type",
62              '-',"$domain.";
63         die "$0: exec adnshost: $!\n";
64     }
65     @result= <ADH>;
66     chomp @result;
67     $!=0; close ADH;
68     die "$0: lookup -t$type $domain failed $? $!\n" if $? or $!;
69     return @result;
70 }
71
72 sub lookup1 ($$) {
73     my ($type,$domain) = @_;
74     my (@result)= lookup($type,$domain);
75     @result==1 or die "$0: lookup -t$type $domain gave more than one RR\n";
76     return $result[0];
77 }
78
79 sub check () {
80     return unless $check;
81     eval {
82         $soa= lookup1('soa',$zone);
83         $soa_origin=$soa; $soa_origin =~ s/ .*//;
84         $soa_origin_addr= lookup1('a',$soa_origin);
85
86         @zone_ns= lookup('ns-',$zone);
87
88         @ok_sources= ($soa_origin_addr);
89         $ok_sources_descr= "SOA ORIGIN $soa_origin [$soa_origin_addr]";
90
91         if ($style eq 'unoff' || $style eq 'backup') {
92             for $zone_ns (@zone_ns) {
93                 @zone_ns_addrs= lookup('a',$zone_ns);
94                 push @ok_sources, @zone_ns_addrs;
95                 $ok_sources_descr.= ", NS $zone_ns [@zone_ns_addrs]";
96             }
97         }
98
99         for $server (@servers) {
100             grep { $server eq $_ } @ok_sources
101                 or warn "secondarying from $server which is not ".
102                         "$ok_sources_desc\n";
103         }
104
105         if ($style eq 'secondary') {
106             grep { $zone_ns=$_, grep { $myname eq $_ } @mynames } @zone_n
107                 or warn "supposedly published secondary but we ".
108                         "(@mynames) are not published ($@zone_ns)\n";
109         }
110     }
111     check_after_eval();
112     
113
114                          
115 #       $superzone= $zone; $superzone =~ s/^[^\.]+\.//;
116 #       @super_ns= lookup('ns-',$zone);
117     }
118
119     eval {
120
121         for $super_ns (@super_ns) {
122             @deleg_ns= ();
123             open DIG, "dig @$super_ns. -t ns +norecurse $zone."
124                 or die "$0: fork for dig: $!\n";
125             while (<DIG>) {
126                 
127
128             split /\n/, lookup("
129         
130                 case "$style" in
131                 secondary|backup)
132                         if [ $meadvert = 0 ]
133                         then
134                                 warning "$myname unlisted NS $nsnames"
135                         fi
136                         ;;
137                 unoff)
138                         if $meadvert = 0
139                         then
140                                 warning "$myname advertised NS $nsnames"
141                         fi
142                         ;;
143                 esac
144
145                 addrs=''
146                 for ns in $names
147                 do
148                         set -e; a="`host -t a \"$ns\".`"; set +e
149                         taddrs="`echo \" $a\" | expand | sed -n '
150                                  1s/^ //
151                                 s/^[^ ][^ ]*  *A  *\([0-9][.0-9]*\)/\1/p
152                         '`"
153                         equlines "A $ns" "$a" "$taddrs"
154                         addrs="$addrs $taddrs"
155                 done
156         fi
157
158         cat <<END
159 zone "$zone" {
160         type slave;
161         file "$file";
162         masters {
163 END
164         for server in $servers
165         do
166                 echo "          $server;"
167                 if $check
168                 then
169                         notfound=1
170                         for addr in $addrs
171                         do
172                                 if [ "x$addr" = "x$server" ]
173                                 then
174                                         notfound=0
175                                 fi
176                         done
177                         if $notfound
178                         then
179  warning "server $server? but $rectype $names" $addrs
180                         fi
181                 fi
182         done
183         cat <<END
184         };
185 };
186 END
187         hostfirstwarn=1
188         if $hostdelg
189         then
190                 checkhostout -C
191         fi
192         if $hostzone
193         then
194                 checkhostout -val localhost
195         fi
196 done
197 endfile
198
199     
200 chdir "$base/primary" or die "$0: chdir $base/primary: $!";
201 beginfile('primary.zones');
202
203 for $f (<*_db>) {
204     $zone= $f; $zone =~ s/_db$//;
205     
206
207 for f in $zones
208 do
209         zone="`echo $f | sed -e 's/_db$//'`"
210         cat <<END
211 zone "$zone" {
212         type master;
213         file "primary/$f";
214 };
215 END
216 done
217 endfile
218
219
220     
221 sub beginfile ($) {
222     $currentfile= $_[0];
223     $currentfile_opened= $install ? "$conf/$currentfile.new" : "/dev/null";
224     open CFF, "> $toopen" or die "$0: begin $currentfile_opened: $!\n";
225 }
226
227 endfile () {
228     close CFF or die "$0: close $currentfile_opened: $!\n";
229     push @files, $currentfile;
230 }
231
232 sub installfiles () {
233     return unless $install;
234     chdir $conf or die "$0: chdir $conf: $!\n";
235     for $f (@files) {
236         rename "$f.new", $f or die "$0: install new $f: $!\n";
237     }
238 }
239
240 warning () {
241         echo >&2 "$zone $style: $*"
242         warnings=$[$warnings+1]
243 }
244
245 equlines () {
246         if [ "x`echo \" $2\" | wc -l`" != "x`echo \" $3\" | wc -l`" ]
247         then
248                 warning "$1 >$2|$3<"
249         fi
250 }
251
252 checkhostout () {
253         set +e
254         hostout="`host $1 \"$zone\" 2>&1 >/dev/null $2 | egrep -v \
255 '^ \!\!\! .* SOA primary .* is not advertised via NS$'`"
256         set -e
257         if [ "x$hostout" = x ]; then return; fi
258         if $hostfirstwarn
259         then
260                 warning "warnings from host:"
261                 hostfirstwarn=0
262         fi
263         echo >&2 "$hostout"
264 }
265
266 progress () {
267         if $progress
268         then
269                 echo -n "$zone $style                    " >&2
270                 echo -ne '\r' >&2
271         fi
272 }
273
274 myname=''
275
276 if [ $warnings != 0 ]
277 then
278         echo >&2 "$warnings warnings                                        "
279 fi
280
281 installfiles