1 #! /usr/bin/perl -w |
1 #! /usr/bin/perl -w |
2 my $USAGE = <<'#'; |
2 my $USAGE = <<'#'; |
3 Usage: $ME [options] |
3 Usage: $ME [options] |
4 -l --logfile=s Name of the logfile we've to read [$opt_logfile] |
4 -l --logfile=s Name of the logfile we've to read [$opt_logfile] |
5 -z --zonesdir=s Where the named.conf's are expected [$opt_zonesdir] |
5 -z --zonesdir=s Where the named.conf's are expected [$opt_zonesdir] |
6 -u --[no]update Update the "masters"-entries [$opt_update] |
6 -u --[no]update Update the \"masters\"-entries [$opt_update] |
7 -f --[no]follow Follow the end of the logfile [$opt_follow] |
7 -f --[no]follow Follow the end of the logfile [$opt_follow] |
8 -d --[no]debug extra debug output [$opt_debug] |
8 -d --[no]debug extra debug output [$opt_debug] |
9 -h --help This text [$opt_help] |
9 -h --help This text [$opt_help] |
10 # |
10 # |
11 # Es wird ein Verzeichnis geben, in diesem Verzeichnis liegt für |
11 # Es wird ein Verzeichnis geben, in diesem Verzeichnis liegt für |
128 # Konfigurations-Datei haben) |
126 # Konfigurations-Datei haben) |
129 next if exists $missing{$domain}; # schon erledigt |
127 next if exists $missing{$domain}; # schon erledigt |
130 |
128 |
131 debug("Missing file for $domain\n"); |
129 debug("Missing file for $domain\n"); |
132 $missing{$domain} = 1; |
130 $missing{$domain} = 1; |
|
131 next; |
133 }; |
132 }; |
134 |
133 |
135 # Wenn wir ein "... loaded" finden, dann fehlt das File nicht gänzlich! |
134 # Wenn wir ein "... loaded" finden, dann fehlt das File nicht gänzlich! |
136 /slave zone "(\S+?)" .*loaded/ and do { |
135 /slave zone "(\S+?)" .*loaded/ and do { |
137 my $domain = $1; |
136 my $domain = $1; |
138 next if not exists $missing{$domain}; # ist noch nicht vermißt worden |
137 next if not exists $missing{$domain}; # ist noch nicht vermißt worden |
139 |
138 |
140 debug("Missing file for $domain is not longer missing\n"); |
139 debug("Missing file for $domain is not longer missing\n"); |
141 delete $missing{$domain}; |
140 delete $missing{$domain}; |
|
141 next; |
|
142 }; |
|
143 |
|
144 /\[([\d.]+)\] not authoritative for (\S+), SOA/ and do { |
|
145 my ($master, $domain) = ($1, $2); |
|
146 next if exists $nomasters{$domain}->{$master}; |
|
147 |
|
148 debug "$master isn't a auth. master for $domain\n"; |
|
149 $masters{$domain}->{$master} = 1; # sieht blöd aus, wird aber gebraucht, |
|
150 # weil wir nur die bearbeiten, die einen |
|
151 # master haben |
|
152 $nomasters{$domain}->{$master} = 1; |
|
153 next; |
142 }; |
154 }; |
143 } |
155 } |
144 |
156 |
145 # Jetzt sind wir erstmal durch und verarbeiten alles |
157 # Jetzt sind wir erstmal durch und verarbeiten alles |
146 my $changed = 0; |
158 my $changed = 0; |
147 foreach my $domain (sort ($opt_update ? keys %masters : keys %missing)) { |
159 foreach my $domain (sort ($opt_update ? keys %masters : keys %missing)) { |
148 $changed += updateFile($domain, keys %{$masters{$domain}}); |
160 $changed += updateFile($domain, [keys %{$masters{$domain}}], [keys %{$nomasters{$domain}}]); |
149 delete $masters{$domain}; |
161 delete $masters{$domain}; |
150 delete $missing{$domain} if exists $missing{$domain}; |
162 delete $missing{$domain} if exists $missing{$domain}; |
|
163 delete $nomasters{$domain} if exists $nomasters{$domain}; |
151 } |
164 } |
152 |
165 |
153 debug "$changed changes."; |
166 debug "$changed changes."; |
154 if ($changed) { |
167 if ($changed) { |
155 debug("bind reload required\n"); |
168 debug("bind reload required\n"); |
161 } |
174 } |
162 system qw(ndc reload); |
175 system qw(ndc reload); |
163 } |
176 } |
164 |
177 |
165 last if !$opt_follow; |
178 last if !$opt_follow; |
166 debug("Sleeping for $naptime seconds\n"); |
179 syslog LOG_INFO, "Sleeping for $naptime seconds\n"; |
167 sleep $naptime; |
180 sleep $naptime; |
168 if ((LOGFILE->stat())[1] != $inode) { |
181 if ((LOGFILE->stat())[1] != (stat($opt_logfile))[1]) { |
169 # new file to follow |
182 # new file to follow |
170 syslog(LOG_NOTICE, "Logfile changed, re-open it.\n"); |
183 syslog(LOG_NOTICE, "Logfile changed, re-open it.\n"); |
171 open(LOGFILE, $_ = "<$opt_logfile") |
184 open(LOGFILE, $_ = "<$opt_logfile") |
172 or die "Can't open $_: $!\n"; |
185 or die "Can't open $_: $!\n"; |
173 $inode = (LOGFILE->stat())[1]; |
|
174 } else { |
186 } else { |
175 LOGFILE->clearerr(); |
187 LOGFILE->clearerr(); |
176 } |
188 } |
177 } |
189 } |
178 } |
190 } |
179 |
191 |
180 sub updateFile($@) |
192 sub updateFile($$$) |
181 { |
193 { |
182 local $_; |
194 local $_; |
183 my $domain = shift; |
195 my $domain = $_[0]; |
184 my %new_masters = map { $_, 1 } @_; |
196 my @new_masters = @{$_[1]}; |
185 my %old_masters = (); |
197 my @no_masters = @{$_[2]}; |
|
198 |
|
199 my %masters = (); |
186 my $masters; |
200 my $masters; |
|
201 |
187 my $file = "$opt_zonesdir/$domain"; |
202 my $file = "$opt_zonesdir/$domain"; |
|
203 |
|
204 debug "updateFile: $domain, @new_masters, @no_masters\n"; |
188 |
205 |
189 if (-f $file) { |
206 if (-f $file) { |
190 # Das File ist also schon da, wir müssen nur mal gucken, ob die Master, |
207 # Das File ist also schon da, wir müssen nur mal gucken, ob die Master, |
191 # von denen wir ein NOTIFY erhalten haben, auch in unserer Datei stehen. |
208 # von denen wir ein NOTIFY erhalten haben, auch in unserer Datei stehen. |
192 # Vorerst entfernen wir keinen Master, wir fügen lediglich welche hinzu, |
|
193 # wenn Sie noch nicht dabei sind. |
|
194 # |
209 # |
195 open (F, $_ = "+<$file") or die "Can't open $_: $!\n"; |
210 open (F, $_ = "+<$file") or die "Can't open $_: $!\n"; |
196 flock(F, LOCK_EX); seek(F, 0, 0); |
211 flock(F, LOCK_EX); seek(F, 0, 0); |
197 |
212 |
198 $_ = join "", <F>; |
213 $_ = join "", <F>; |
199 |
214 |
200 # Liste der Master raussuchen |
215 # Liste der Master raussuchen, darus noch die löschen, die uns |
|
216 # die Mitarbeit verweigert haben.. |
201 /^(\s*masters\s*{\s*)(.*?);(\s*}\s*;)(\s*\/\/.*?\n)/ims; |
217 /^(\s*masters\s*{\s*)(.*?);(\s*}\s*;)(\s*\/\/.*?\n)/ims; |
202 %old_masters = map { $_, 1 } split/\s*;\s*/, $2; |
218 %masters = map { $_, 1 } split/\s*;\s*/, $2; |
203 |
219 $masters = %masters; # für den späteren Vergleich |
204 # Aus den neuen löschen wir die, die bereits bekannt sind |
220 |
205 delete @new_masters{keys %old_masters}; |
221 # noch unsere neuen hinzufügen... |
206 |
222 @masters{@new_masters} = map { 1 } @new_masters; |
207 # Wenn nun noch welche übring sind, dann müssen wir diese |
223 |
208 # mit eintragen. Ansonsten haben wir fertig. |
224 # nun die weg, die sich nicht zuständig fühlen |
209 if (not %new_masters) { |
225 delete @masters{@no_masters}; |
210 debug("Uptodate file for $domain\n"); |
226 |
|
227 # Wenn sich nach alldem nichts verändert hat, haben wir fertig. |
|
228 if ($masters eq %masters) { |
|
229 debug("File is up-to-date for $domain\n"); |
211 syslog(LOG_NOTICE, "No changes made for $domain (no \"loaded\" seen, defective master?)\n") |
230 syslog(LOG_NOTICE, "No changes made for $domain (no \"loaded\" seen, defective master?)\n") |
212 unless $opt_update; |
231 unless $opt_update; |
213 close(F); |
232 close(F); |
214 return 0; |
233 return 0; |
215 } |
234 } |
216 |
235 |
217 syslog(LOG_NOTICE, "Updated masters list for $domain\n"); |
236 if (not %masters) { |
218 $masters = join ";", keys %old_masters, keys %new_masters; |
237 syslog LOG_NOTICE, "REMOVING $file (empty masters list)\n"; |
|
238 close F; |
|
239 unlink $file; |
|
240 return 1; |
|
241 } |
|
242 |
|
243 $masters = join ";", keys %masters; |
|
244 syslog(LOG_NOTICE, "Updated masters ($masters) list for $domain\n"); |
219 s/^(\s*masters\s*{\s*)(.*?);(\s*}\s*;)/$1$masters;$3/ims; |
245 s/^(\s*masters\s*{\s*)(.*?);(\s*}\s*;)/$1$masters;$3/ims; |
220 |
246 |
221 truncate(F, 0); |
247 truncate(F, 0); |
222 seek(F, 0, 0); |
248 seek(F, 0, 0); |
223 print F; |
249 print F; |
226 return 1; |
252 return 1; |
227 } |
253 } |
228 |
254 |
229 |
255 |
230 my $date = localtime(); |
256 my $date = localtime(); |
231 $masters = join "; ", keys %new_masters; |
257 my %new_masters = map { $_, 1 } @new_masters; |
|
258 delete @new_masters{@no_masters}; |
|
259 |
|
260 if (not %new_masters) { |
|
261 syslog LOG_INFO, "not creating $file (empty masters list)\n"; |
|
262 return 0; |
|
263 } |
|
264 |
|
265 $masters = join "; ", @new_masters; |
232 |
266 |
233 -d $opt_zonesdir or mkpath($opt_zonesdir, 0, 0755); |
267 -d $opt_zonesdir or mkpath($opt_zonesdir, 0, 0755); |
234 |
268 |
235 syslog(LOG_NOTICE, "Creating $file for $domain"); |
269 syslog(LOG_NOTICE, "Creating $file for $domain"); |
236 open(OUT, $_ = ">$file") or die "Can't open $_: $!\n"; |
270 open(OUT, $_ = ">$file") or die "Can't open $_: $!\n"; |