xref: /386bsd/usr/src/usr.sbin/named/ns_maint.c (revision a2142627)
1 /*
2  * Copyright (c) 1986, 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 static char sccsid[] = "@(#)ns_maint.c	4.39 (Berkeley) 3/2/91";
36 #endif /* not lint */
37 
38 #include <sys/param.h>
39 #include <sys/socket.h>
40 #include <sys/time.h>
41 #if defined(SYSV)
42 #include <unistd.h>
43 #endif SYSV
44 #include <netinet/in.h>
45 #include <stdio.h>
46 #include <syslog.h>
47 #include <signal.h>
48 #include <errno.h>
49 #include <arpa/nameser.h>
50 #include <sys/wait.h>
51 #include "ns.h"
52 #include "db.h"
53 #include "pathnames.h"
54 
55 extern int errno;
56 extern int maint_interval;
57 extern int needzoneload;
58 extern u_short ns_port;
59 extern char *ctime();
60 
61 int xfers_running;	       /* number of xfers running */
62 int xfers_deferred;	       /* number of needed xfers not run yet */
63 static int alarm_pending;
64 
65 
66 /*
67  * Invoked at regular intervals by signal interrupt; refresh all secondary
68  * zones from primary name server and remove old cache entries.  Also,
69  * ifdef'd ALLOW_UPDATES, dump database if it has changed since last
70  * dump/bootup.
71  */
ns_maint()72 ns_maint()
73 {
74 	register struct zoneinfo *zp;
75 	struct itimerval ival;
76 	time_t next_refresh = 0;
77 	int zonenum;
78 
79 	gettime(&tt);
80 
81 #ifdef DEBUG
82 	if (debug)
83 		fprintf(ddt,"\nns_maint(); now %s", ctime(&tt.tv_sec));
84 #endif
85 
86 	xfers_deferred = 0;
87 	alarm_pending = 0;
88 	for (zp = zones, zonenum = 0; zp < &zones[nzones]; zp++, zonenum++) {
89 #ifdef DEBUG
90 		if (debug >= 2)
91 			printzoneinfo(zonenum);
92 #endif
93 		if (tt.tv_sec >= zp->z_time && zp->z_refresh > 0) {
94 			/*
95 			 * Set default time for next action first,
96 			 * so that it can be changed later if necessary.
97 			 */
98 			zp->z_time = tt.tv_sec + zp->z_refresh;
99 
100 			switch (zp->z_type) {
101 
102 			case Z_CACHE:
103 				doachkpt();
104 				break;
105 
106 			case Z_SECONDARY:
107 				if ((zp->z_state & Z_NEED_RELOAD) == 0) {
108 				    if (zp->z_state & Z_XFER_RUNNING)
109 					abortxfer(zp);
110 				    else if (xfers_running < MAX_XFERS_RUNNING)
111 					startxfer(zp);
112 				    else {
113 					zp->z_state |= Z_NEED_XFER;
114 					++xfers_deferred;
115 #ifdef DEBUG
116 					if (debug > 1)
117 					    fprintf(ddt,
118 						"xfer deferred for %s\n",
119 						zp->z_origin);
120 #endif
121 				    }
122 				}
123 				break;
124 #ifdef ALLOW_UPDATES
125 			case Z_PRIMARY:
126 				/*
127 				 * Checkpoint the zone if it has changed
128 				 * since we last checkpointed
129 				 */
130 				if (zp->hasChanged)
131 					zonedump(zp);
132 				break;
133 #endif ALLOW_UPDATES
134 			}
135 			gettime(&tt);
136 		}
137 	}
138 	sched_maint();
139 #ifdef DEBUG
140 	if (debug)
141 		fprintf(ddt,"exit ns_maint()\n");
142 #endif
143 }
144 
145 /*
146  * Find when the next refresh needs to be and set
147  * interrupt time accordingly.
148  */
sched_maint()149 sched_maint()
150 {
151 	register struct zoneinfo *zp;
152 	struct itimerval ival;
153 	time_t next_refresh = 0;
154 	static time_t next_alarm;
155 
156 	for (zp = zones; zp < &zones[nzones]; zp++)
157 		if (zp->z_time != 0 &&
158 		    (next_refresh == 0 || next_refresh > zp->z_time))
159 			next_refresh = zp->z_time;
160         /*
161 	 *  Schedule the next call to ns_maint.
162 	 *  Don't visit any sooner than maint_interval.
163 	 */
164 	bzero((char *)&ival, sizeof (ival));
165 	if (next_refresh != 0) {
166 		if (next_refresh == next_alarm && alarm_pending) {
167 #ifdef DEBUG
168 			if (debug)
169 			    fprintf(ddt,"sched_maint: no schedule change\n");
170 #endif
171 			return;
172 		}
173 		ival.it_value.tv_sec = next_refresh - tt.tv_sec;
174 		if (ival.it_value.tv_sec < maint_interval)
175 			ival.it_value.tv_sec = maint_interval;
176 		next_alarm = next_refresh;
177 		alarm_pending = 1;
178 	}
179 	(void) setitimer(ITIMER_REAL, &ival, (struct itimerval *)NULL);
180 #ifdef DEBUG
181 	if (debug)
182 		fprintf(ddt,"sched_maint: Next interrupt in %d sec\n",
183 			ival.it_value.tv_sec);
184 #endif
185 }
186 
187 /*
188  * Start an asynchronous zone transfer for a zone.
189  * Depends on current time being in tt.
190  * The caller must call sched_maint after startxfer.
191  */
192 startxfer(zp)
193 	struct zoneinfo *zp;
194 {
195 	static char *argv[NSMAX + 20], argv_ns[NSMAX][MAXDNAME];
196 	int cnt, argc = 0, argc_ns = 0, pid, omask;
197 	char debug_str[10];
198 	char serial_str[10];
199 	char port_str[10];
200 
201 #ifdef DEBUG
202 	if (debug)
203 		fprintf(ddt,"startxfer() %s\n", zp->z_origin);
204 #endif
205 
206 	argv[argc++] = "named-xfer";
207 	argv[argc++] = "-z";
208 	argv[argc++] = zp->z_origin;
209 	argv[argc++] = "-f";
210 	argv[argc++] = zp->z_source;
211 	argv[argc++] = "-s";
212 	sprintf(serial_str, "%d", zp->z_serial);
213 	argv[argc++] = serial_str;
214 	if (zp->z_state & Z_SYSLOGGED)
215 		argv[argc++] = "-q";
216 	argv[argc++] = "-P";
217 	sprintf(port_str, "%d", ns_port);
218 	argv[argc++] = port_str;
219 #ifdef DEBUG
220 	if (debug) {
221 		argv[argc++] = "-d";
222 		sprintf(debug_str, "%d", debug);
223 		argv[argc++] = debug_str;
224 		argv[argc++] = "-l";
225 		argv[argc++] = "/usr/tmp/xfer.ddt";
226 		if (debug > 5) {
227 			argv[argc++] = "-t";
228 			argv[argc++] = "/usr/tmp/xfer.trace";
229 		}
230 	}
231 #endif
232 
233 	/*
234 	 * Copy the server ip addresses into argv, after converting
235 	 * to ascii and saving the static inet_ntoa result
236 	 */
237 	for (cnt = 0; cnt < zp->z_addrcnt; cnt++)
238 		argv[argc++] = strcpy(argv_ns[argc_ns++],
239 		    inet_ntoa(zp->z_addr[cnt]));
240 
241 	argv[argc] = 0;
242 
243 #ifdef DEBUG
244 #ifdef ECHOARGS
245 	if (debug) {
246 		int i;
247 		for (i = 0; i < argc; i++)
248 			fprintf(ddt, "Arg %d=%s\n", i, argv[i]);
249         }
250 #endif /* ECHOARGS */
251 #endif /* DEBUG */
252 
253 #ifdef SYSV
254 #define vfork fork
255 #else
256 	gettime(&tt);
257 	omask = sigblock(sigmask(SIGCHLD));
258 #endif
259 	if ((pid = vfork()) == -1) {
260 #ifdef DEBUG
261 		if (debug)
262 			fprintf(ddt, "xfer [v]fork: %d\n", errno);
263 #endif
264 		syslog(LOG_ERR, "xfer [v]fork: %m");
265 #ifndef SYSV
266 		(void) sigsetmask(omask);
267 #endif
268 		zp->z_time = tt.tv_sec + 10;
269 		return;
270 	}
271 
272 	if (pid) {
273 #ifdef DEBUG
274 		if (debug)
275 			fprintf(ddt, "started xfer child %d\n", pid);
276 #endif
277 		zp->z_state &= ~Z_NEED_XFER;
278 		zp->z_state |= Z_XFER_RUNNING;
279 		zp->z_xferpid = pid;
280 		xfers_running++;
281 		zp->z_time = tt.tv_sec + MAX_XFER_TIME;
282 #ifndef SYSV
283 		(void) sigsetmask(omask);
284 #endif
285 	} else {
286 		execve(_PATH_XFER, argv, NULL);
287 		syslog(LOG_ERR, "can't exec %s: %m", _PATH_XFER);
288 		_exit(XFER_FAIL);	/* avoid duplicate buffer flushes */
289 	}
290 }
291 
292 #ifdef DEBUG
printzoneinfo(zonenum)293 printzoneinfo(zonenum)
294 int zonenum;
295 {
296 	struct timeval  tt;
297 	struct zoneinfo *zp = &zones[zonenum];
298 	char *ZoneType;
299 
300 	if (!debug)
301 		return; /* Else fprintf to ddt will bomb */
302 	fprintf(ddt, "printzoneinfo(%d):\n", zonenum);
303 
304 	gettime(&tt);
305 	switch (zp->z_type) {
306 		case Z_PRIMARY: ZoneType = "Primary"; break;
307 		case Z_SECONDARY: ZoneType = "Secondary"; break;
308 		case Z_CACHE: ZoneType = "Cache"; break;
309 		default: ZoneType = "Unknown";
310 	}
311 	if (zp->z_origin[0] == '\0')
312 		fprintf(ddt,"origin ='.'");
313 	else
314 		fprintf(ddt,"origin ='%s'", zp->z_origin);
315 	fprintf(ddt,", type = %s", ZoneType);
316 	fprintf(ddt,", source = %s\n", zp->z_source);
317 	fprintf(ddt,"z_refresh = %ld", zp->z_refresh);
318 	fprintf(ddt,", retry = %ld", zp->z_retry);
319 	fprintf(ddt,", expire = %ld", zp->z_expire);
320 	fprintf(ddt,", minimum = %ld", zp->z_minimum);
321 	fprintf(ddt,", serial = %ld\n", zp->z_serial);
322 	fprintf(ddt,"z_time = %d", zp->z_time);
323 	if (zp->z_time) {
324 		fprintf(ddt,", now time : %d sec", tt.tv_sec);
325 		fprintf(ddt,", time left: %d sec", zp->z_time - tt.tv_sec);
326 	}
327 	fprintf(ddt,"; state %x\n", zp->z_state);
328 }
329 #endif DEBUG
330 
331 /*
332  * remove_zone (htp, zone) --
333  *     Delete all RR's in the zone "zone" under specified hash table.
334  */
remove_zone(htp,zone)335 remove_zone(htp, zone)
336 	register struct hashbuf *htp;
337 	register int zone;
338 {
339 	register struct databuf *dp, *pdp;
340 	register struct namebuf *np;
341 	struct namebuf **npp, **nppend;
342 
343 	nppend = htp->h_tab + htp->h_size;
344 	for (npp = htp->h_tab; npp < nppend; npp++)
345 	    for (np = *npp; np != NULL; np = np->n_next) {
346 		for (pdp = NULL, dp = np->n_data; dp != NULL; ) {
347 			if (dp->d_zone == zone)
348 				dp = rm_datum(dp, np, pdp);
349 			else {
350 				pdp = dp;
351 				dp = dp->d_next;
352 			}
353 		}
354 		/* Call recursively to remove subdomains. */
355 		if (np->n_hash)
356 			remove_zone(np->n_hash, zone);
357 	    }
358 }
359 
360 /*
361  * Abort an xfer that has taken too long.
362  */
abortxfer(zp)363 abortxfer(zp)
364 	register struct zoneinfo *zp;
365 {
366 
367 	kill(zp->z_xferpid, SIGKILL); /* don't trust it at all */
368 #ifdef DEBUG
369 	if (debug)
370 	  fprintf(ddt, "Killed child %d (zone %s) due to timeout\n",
371 	     zp->z_xferpid, zp->z_origin);
372 #endif /* DEBUG */
373 	zp->z_time = tt.tv_sec + zp->z_retry;
374 }
375 
376 #ifdef SYSV
377 union wait {
378 	unsigned short	w_termsig:7;	/* termination signal */
379 	unsigned short	w_coredump:1;	/* core dump indicator */
380 	unsigned short	w_retcode:8;	/* exit code if w_termsig==0 */
381 };
382 #endif
383 
384 /*
385  * SIGCHLD signal handler: process exit of xfer's.
386  * (Note: also called when outgoing transfer completes.)
387  */
388 SIG_FN
endxfer()389 endxfer()
390 {
391     	register struct zoneinfo *zp;
392 	int pid, xfers = 0;
393 	union wait status;
394 
395 	gettime(&tt);
396 #if defined(SYSV)
397 	{ int stat;
398 	pid = wait(&stat);
399 	status.w_termsig = stat & 0x7f;
400 	status.w_retcode = stat >> 8;
401 	}
402 #else /* SYSV */
403 	while ((pid =
404 	    wait3((int *)&status, WNOHANG, (struct rusage *)NULL)) > 0) {
405 #endif /* SYSV */
406 		for (zp = zones; zp < &zones[nzones]; zp++)
407 		    if (zp->z_xferpid == pid) {
408 			xfers++;
409 			xfers_running--;
410 			zp->z_xferpid = 0;
411 			zp->z_state &= ~Z_XFER_RUNNING;
412 #ifdef DEBUG
413 			if (debug)
414 			    fprintf(ddt,
415 		"\nendxfer: child %d zone %s returned status=%d termsig=%d\n",
416 				pid, zp->z_origin, status.w_retcode,
417 				status.w_termsig);
418 #endif
419 			if (status.w_termsig != 0) {
420 				if (status.w_termsig != SIGKILL) {
421 					syslog(LOG_ERR,
422 					   "named-xfer exited with signal %d\n",
423 					   status.w_termsig);
424 #ifdef DEBUG
425 					if (debug)
426 					    fprintf(ddt,
427 					 "\tchild termination with signal %d\n",
428 						status.w_termsig);
429 #endif
430 				}
431 				zp->z_time = tt.tv_sec + zp->z_retry;
432 			} else switch (status.w_retcode) {
433 				case XFER_UPTODATE:
434 					zp->z_state &= ~Z_SYSLOGGED;
435 					zp->z_lastupdate = tt.tv_sec;
436 					zp->z_time = tt.tv_sec + zp->z_refresh;
437 					/*
438 					 * Restore z_auth in case expired,
439 					 * but only if there were no errors
440 					 * in the zone file.
441 					 */
442 					if ((zp->z_state & Z_DB_BAD) == 0)
443 						zp->z_auth = 1;
444 					if (zp->z_source) {
445 #if defined(SYSV)
446 						struct utimbuf t;
447 
448 						t.actime = tt.tv_sec;
449 						t.modtime = tt.tv_sec;
450 						(void) utime(zp->z_source, &t);
451 #else
452 						struct timeval t[2];
453 
454 						t[0] = tt;
455 						t[1] = tt;
456 						(void) utimes(zp->z_source, t);
457 #endif /* SYSV */
458 					}
459 					break;
460 
461 				case XFER_SUCCESS:
462 					zp->z_state |= Z_NEED_RELOAD;
463 					zp->z_state &= ~Z_SYSLOGGED;
464 					needzoneload++;
465 					break;
466 
467 				case XFER_TIMEOUT:
468 #ifdef DEBUG
469 					if (debug) fprintf(ddt,
470 		    "zoneref: Masters for secondary zone %s unreachable\n",
471 					    zp->z_origin);
472 #endif
473 					if ((zp->z_state & Z_SYSLOGGED) == 0) {
474 						zp->z_state |= Z_SYSLOGGED;
475 						syslog(LOG_WARNING,
476 		      "zoneref: Masters for secondary zone %s unreachable",
477 						    zp->z_origin);
478 					}
479 					zp->z_time = tt.tv_sec + zp->z_retry;
480 					break;
481 
482 				default:
483 					if ((zp->z_state & Z_SYSLOGGED) == 0) {
484 						zp->z_state |= Z_SYSLOGGED;
485 						syslog(LOG_ERR,
486 						    "named-xfer exit code %d",
487 						    status.w_retcode);
488 					}
489 					/* FALLTHROUGH */
490 				case XFER_FAIL:
491 					zp->z_state |= Z_SYSLOGGED;
492 					zp->z_time = tt.tv_sec + zp->z_retry;
493 					break;
494 			}
495 			break;
496 		}
497 #ifndef SYSV
498 	}
499 #endif /* SYSV */
500 	if (xfers) {
501 		for (zp = zones;
502 		    xfers_deferred != 0 && xfers_running < MAX_XFERS_RUNNING &&
503 		    zp < &zones[nzones]; zp++)
504 			if (zp->z_state & Z_NEED_XFER) {
505 				xfers_deferred--;
506 				startxfer(zp);
507 			}
508 		sched_maint();
509 	}
510 #if defined(SYSV)
511 	(void)signal(SIGCLD, endxfer);
512 #endif
513 }
514 
515 /*
516  * Reload zones whose transfers have completed.
517  */
loadxfer()518 loadxfer()
519 {
520     	register struct zoneinfo *zp;
521 
522 	gettime(&tt);
523 	for (zp = zones; zp < &zones[nzones]; zp++)
524 	    if (zp->z_state & Z_NEED_RELOAD) {
525 #ifdef DEBUG
526 		if (debug)
527 			fprintf(ddt, "loadxfer() '%s'\n",
528 			zp->z_origin[0] ? zp->z_origin : ".");
529 #endif
530 		zp->z_state &= ~Z_NEED_RELOAD;
531 		zp->z_auth = 0;
532 		remove_zone(hashtab, zp - zones);
533 		if (db_load(zp->z_source, zp->z_origin, zp, 0) == 0)
534 			zp->z_auth = 1;
535 		if (zp->z_state & Z_TMP_FILE)
536 			(void) unlink(zp->z_source);
537 	    }
538 	sched_maint();
539 }
540