xref: /openbsd-src/usr.sbin/nsd/verify.c (revision 3efee2e132f9af6db74577d714f3304be2b3af74)
13f21e8ccSflorian /*
23f21e8ccSflorian  * verify.c -- running verifiers and serving the zone to be verified.
33f21e8ccSflorian  *
43f21e8ccSflorian  * Copyright (c) 2012-2020, NLnet Labs. All rights reserved.
53f21e8ccSflorian  *
63f21e8ccSflorian  * See LICENSE for the license.
73f21e8ccSflorian  *
83f21e8ccSflorian  */
93f21e8ccSflorian 
103f21e8ccSflorian #include "config.h"
113f21e8ccSflorian 
123f21e8ccSflorian #include <assert.h>
133f21e8ccSflorian #include <ctype.h>
143f21e8ccSflorian #include <errno.h>
153f21e8ccSflorian #include <stdarg.h>
163f21e8ccSflorian #include <stdio.h>
173f21e8ccSflorian #include <stdlib.h>
183f21e8ccSflorian #include <string.h>
193f21e8ccSflorian #ifdef HAVE_SYSLOG_H
203f21e8ccSflorian #include <syslog.h>
213f21e8ccSflorian #endif /* HAVE_SYSLOG_H */
223f21e8ccSflorian #include <unistd.h>
233f21e8ccSflorian #include <fcntl.h>
243f21e8ccSflorian #include <sys/wait.h>
253f21e8ccSflorian 
263f21e8ccSflorian #include "region-allocator.h"
273f21e8ccSflorian #include "namedb.h"
283f21e8ccSflorian #include "nsd.h"
293f21e8ccSflorian #include "options.h"
303f21e8ccSflorian #include "difffile.h"
313f21e8ccSflorian #include "verify.h"
323f21e8ccSflorian #include "popen3.h"
333f21e8ccSflorian 
verify_next_zone(struct nsd * nsd,struct zone * zone)343f21e8ccSflorian struct zone *verify_next_zone(struct nsd *nsd, struct zone *zone)
353f21e8ccSflorian {
363f21e8ccSflorian 	int verify;
373f21e8ccSflorian 	struct radnode *node;
383f21e8ccSflorian 
393f21e8ccSflorian 	if(zone != NULL) {
403f21e8ccSflorian 		node = radix_next(zone->node);
413f21e8ccSflorian 	} else {
423f21e8ccSflorian 		node = radix_first(nsd->db->zonetree);
433f21e8ccSflorian 	}
443f21e8ccSflorian 
453f21e8ccSflorian 	while(node != NULL) {
463f21e8ccSflorian 		zone = (struct zone *)node->elem;
473f21e8ccSflorian 		verify = zone->opts->pattern->verify_zone;
483f21e8ccSflorian 		if(verify == VERIFY_ZONE_INHERIT) {
493f21e8ccSflorian 			verify = nsd->options->verify_zones;
503f21e8ccSflorian 		}
513f21e8ccSflorian 		if(verify && zone->is_updated && !zone->is_checked) {
523f21e8ccSflorian 			return zone;
533f21e8ccSflorian 		}
543f21e8ccSflorian 		node = radix_next(node);
553f21e8ccSflorian 	}
563f21e8ccSflorian 
573f21e8ccSflorian 	return NULL;
583f21e8ccSflorian }
593f21e8ccSflorian 
fill_buffer(struct verifier_stream * stream)603f21e8ccSflorian static inline ssize_t fill_buffer(struct verifier_stream *stream)
613f21e8ccSflorian {
623f21e8ccSflorian 	ssize_t cnt = 0;
633f21e8ccSflorian 
643f21e8ccSflorian 	assert(stream);
653f21e8ccSflorian 	assert(stream->fd != -1);
663f21e8ccSflorian 	assert(stream->cnt <= LOGBUFSIZE);
673f21e8ccSflorian 	assert(stream->off <= stream->cnt);
683f21e8ccSflorian 
693f21e8ccSflorian 	// move data to start of buffer assuming all complete lines are printed
703f21e8ccSflorian 	if (stream->off) {
713f21e8ccSflorian 		size_t len = stream->cnt - stream->off;
723f21e8ccSflorian 		memmove(stream->buf, stream->buf + stream->off, len);
733f21e8ccSflorian 		stream->off = 0;
743f21e8ccSflorian 		stream->cnt = len;
753f21e8ccSflorian 		stream->buf[stream->cnt] = '\0'; // always null-terminate
763f21e8ccSflorian 	}
773f21e8ccSflorian 
783f21e8ccSflorian 	// read data if space is available
793f21e8ccSflorian 	cnt = read(stream->fd, stream->buf + stream->cnt, LOGBUFSIZE - stream->cnt);
803f21e8ccSflorian 	if (cnt > 0)
813f21e8ccSflorian 		stream->cnt += (size_t)cnt;
823f21e8ccSflorian 	assert(stream->cnt <= LOGBUFSIZE);
833f21e8ccSflorian 	assert(stream->off <= stream->cnt);
843f21e8ccSflorian 	stream->buf[stream->cnt] = '\0'; // always null-terminate
853f21e8ccSflorian 
863f21e8ccSflorian 	return cnt;
873f21e8ccSflorian }
883f21e8ccSflorian 
print_line(struct verifier_stream * stream,int eof)893f21e8ccSflorian static inline size_t print_line(struct verifier_stream *stream, int eof)
903f21e8ccSflorian {
913f21e8ccSflorian 	char *eol = NULL;
923f21e8ccSflorian 	size_t len;
933f21e8ccSflorian 	const char *fmt;
943f21e8ccSflorian 
953f21e8ccSflorian 	if (stream->cnt == 0)
963f21e8ccSflorian 		return 0;
973f21e8ccSflorian 	assert(stream->off <= stream->cnt);
983f21e8ccSflorian 	if (stream->off == stream->cnt)
993f21e8ccSflorian 		return 0;
1003f21e8ccSflorian 
1013f21e8ccSflorian 	// try to locate natural line break
1023f21e8ccSflorian 	assert(stream->buf[stream->cnt] == '\0');
1033f21e8ccSflorian 	if ((eol = strchr(stream->buf + stream->off, '\n'))) {
1043f21e8ccSflorian 		len = eol - (stream->buf + stream->off);
1053f21e8ccSflorian 	} else {
1063f21e8ccSflorian 		len = stream->cnt - stream->off;
1073f21e8ccSflorian 	}
1083f21e8ccSflorian 
1093f21e8ccSflorian 	assert(len <= (stream->cnt - stream->off));
1103f21e8ccSflorian 	// wait for buffer to contain a full line except on eof
1113f21e8ccSflorian 	if (len < LOGLINELEN && !eol && !eof)
1123f21e8ccSflorian 		return 0;
1133f21e8ccSflorian 
1143f21e8ccSflorian 	if (len > LOGLINELEN) {
115*3efee2e1Sflorian 		fmt = stream->cut ? "verifier: .. %.*s .." : "verifier: %.*s ..";
1163f21e8ccSflorian 		len = LOGLINELEN; // remainder printed next iteration
1173f21e8ccSflorian 		stream->cut = 1;
1183f21e8ccSflorian 	} else {
119*3efee2e1Sflorian 		fmt = stream->cut ? "verifier: .. %.*s" : "verifier: %.*s";
1203f21e8ccSflorian 		stream->cut = 0;
1213f21e8ccSflorian 	}
1223f21e8ccSflorian 	log_msg(stream->priority, fmt, len, stream->buf + stream->off);
1233f21e8ccSflorian 
1243f21e8ccSflorian 	stream->off += len + (eol != NULL);
1253f21e8ccSflorian 	assert(stream->off <= stream->cnt);
1263f21e8ccSflorian 	return len;
1273f21e8ccSflorian }
1283f21e8ccSflorian 
1293f21e8ccSflorian /*
1303f21e8ccSflorian  * Log verifier output on STDOUT and STDERR. Lines longer than LOGLINELEN are
1313f21e8ccSflorian  * split over multiple lines. Line-breaks are indicated in the log with "...".
1323f21e8ccSflorian  */
verify_handle_stream(int fd,short event,void * arg)1333f21e8ccSflorian static void verify_handle_stream(int fd, short event, void *arg)
1343f21e8ccSflorian {
1353f21e8ccSflorian 	int eof = 0;
1363f21e8ccSflorian 	ssize_t cnt;
1373f21e8ccSflorian 	struct verifier *verifier;
1383f21e8ccSflorian 	struct verifier_stream *stream;
1393f21e8ccSflorian 
1403f21e8ccSflorian 	assert(event & EV_READ);
1413f21e8ccSflorian 	assert(arg != NULL);
1423f21e8ccSflorian 
1433f21e8ccSflorian 	verifier = (struct verifier *)arg;
1443f21e8ccSflorian 	if (fd == verifier->output_stream.fd) {
1453f21e8ccSflorian 		stream = &verifier->output_stream;
1463f21e8ccSflorian 	} else {
1473f21e8ccSflorian 		assert(fd == verifier->error_stream.fd);
1483f21e8ccSflorian 		stream = &verifier->error_stream;
1493f21e8ccSflorian 	}
1503f21e8ccSflorian 
1513f21e8ccSflorian 	assert(stream);
1523f21e8ccSflorian 	assert(stream->fd != -1);
1533f21e8ccSflorian 
1543f21e8ccSflorian 	do {
1553f21e8ccSflorian 		cnt = fill_buffer(stream);
1563f21e8ccSflorian 		eof = !cnt || (cnt < 0 && errno != EAGAIN && errno != EINTR);
1573f21e8ccSflorian 		while (print_line(stream, eof)) ;
1583f21e8ccSflorian 	} while (cnt > 0);
1593f21e8ccSflorian 
1603f21e8ccSflorian 	if(eof) {
1613f21e8ccSflorian 		event_del(&stream->event);
1623f21e8ccSflorian 		close(stream->fd);
1633f21e8ccSflorian 		stream->fd = -1;
1643f21e8ccSflorian 	}
1653f21e8ccSflorian }
1663f21e8ccSflorian 
kill_verifier(struct verifier * verifier)1673f21e8ccSflorian static void kill_verifier(struct verifier *verifier)
1683f21e8ccSflorian {
1693f21e8ccSflorian 	assert(verifier != NULL);
1703f21e8ccSflorian 	assert(verifier->zone != NULL);
1713f21e8ccSflorian 
1723f21e8ccSflorian 	if(kill(verifier->pid, SIGTERM) == -1) {
1733f21e8ccSflorian 		log_msg(LOG_ERR, "verify: cannot kill verifier for "
1743f21e8ccSflorian 		                 "zone %s (pid %d): %s",
1753f21e8ccSflorian 		                 verifier->zone->opts->name,
1763f21e8ccSflorian 		                 verifier->pid,
1773f21e8ccSflorian 		                 strerror(errno));
1783f21e8ccSflorian 	}
1793f21e8ccSflorian }
1803f21e8ccSflorian 
close_stream(struct verifier * verifier,struct verifier_stream * stream)1813f21e8ccSflorian static void close_stream(struct verifier *verifier, struct verifier_stream *stream)
1823f21e8ccSflorian {
1833f21e8ccSflorian 	if (stream->fd == -1)
1843f21e8ccSflorian 		return;
1853f21e8ccSflorian 	verify_handle_stream(stream->fd, EV_READ, verifier);
1863f21e8ccSflorian 	if (stream->fd == -1)
1873f21e8ccSflorian 		return;
1883f21e8ccSflorian 	event_del(&stream->event);
1893f21e8ccSflorian 	close(stream->fd);
1903f21e8ccSflorian 	stream->fd = -1;
1913f21e8ccSflorian }
1923f21e8ccSflorian 
close_verifier(struct verifier * verifier)1933f21e8ccSflorian static void close_verifier(struct verifier *verifier)
1943f21e8ccSflorian {
1953f21e8ccSflorian 	/* unregister events and close streams (in that order) */
1963f21e8ccSflorian 	if(verifier->timeout.tv_sec > 0) {
1973f21e8ccSflorian 		event_del(&verifier->timeout_event);
1983f21e8ccSflorian 		verifier->timeout.tv_sec = 0;
1993f21e8ccSflorian 		verifier->timeout.tv_usec = 0;
2003f21e8ccSflorian 	}
2013f21e8ccSflorian 
2023f21e8ccSflorian 	if(verifier->zone_feed.fh != NULL) {
2033f21e8ccSflorian 		event_del(&verifier->zone_feed.event);
2043f21e8ccSflorian 		fclose(verifier->zone_feed.fh);
2053f21e8ccSflorian 		verifier->zone_feed.fh = NULL;
2063f21e8ccSflorian 		region_destroy(verifier->zone_feed.region);
2073f21e8ccSflorian 	}
2083f21e8ccSflorian 
2093f21e8ccSflorian 	close_stream(verifier, &verifier->error_stream);
2103f21e8ccSflorian 	close_stream(verifier, &verifier->output_stream);
2113f21e8ccSflorian 
2123f21e8ccSflorian 	verifier->zone->is_ok = verifier->was_ok;
2133f21e8ccSflorian 	verifier->pid = -1;
2143f21e8ccSflorian 	verifier->zone = NULL;
2153f21e8ccSflorian }
2163f21e8ccSflorian 
2173f21e8ccSflorian /*
2183f21e8ccSflorian  * Feed zone to verifier over STDIN as it becomes available.
2193f21e8ccSflorian  */
verify_handle_feed(int fd,short event,void * arg)2203f21e8ccSflorian static void verify_handle_feed(int fd, short event, void *arg)
2213f21e8ccSflorian {
2223f21e8ccSflorian 	struct verifier *verifier;
2233f21e8ccSflorian 	struct rr *rr;
2243f21e8ccSflorian 
2253f21e8ccSflorian 	(void)fd;
2263f21e8ccSflorian 	assert(event == EV_WRITE);
2273f21e8ccSflorian 	assert(arg != NULL);
2283f21e8ccSflorian 
2293f21e8ccSflorian 	verifier = (struct verifier *)arg;
2303f21e8ccSflorian 	if((rr = zone_rr_iter_next(&verifier->zone_feed.rriter)) != NULL) {
2313f21e8ccSflorian 		print_rr(verifier->zone_feed.fh,
2323f21e8ccSflorian 		         verifier->zone_feed.rrprinter,
2333f21e8ccSflorian 		         rr,
2343f21e8ccSflorian 		         verifier->zone_feed.region,
2353f21e8ccSflorian 		         verifier->zone_feed.buffer);
2363f21e8ccSflorian 	} else {
2373f21e8ccSflorian 		event_del(&verifier->zone_feed.event);
2383f21e8ccSflorian 		fclose(verifier->zone_feed.fh);
2393f21e8ccSflorian 		verifier->zone_feed.fh = NULL;
2403f21e8ccSflorian 		region_destroy(verifier->zone_feed.region);
2413f21e8ccSflorian 	}
2423f21e8ccSflorian }
2433f21e8ccSflorian 
2443f21e8ccSflorian /*
2453f21e8ccSflorian  * This handler will be called when a verifier-timeout alarm goes off. It just
2463f21e8ccSflorian  * kills the verifier. server_verify_zones will make sure the zone will be
2473f21e8ccSflorian  * considered bad.
2483f21e8ccSflorian  */
verify_handle_timeout(int fd,short event,void * arg)2493f21e8ccSflorian void verify_handle_timeout(int fd, short event, void *arg)
2503f21e8ccSflorian {
2513f21e8ccSflorian 	struct verifier *verifier;
2523f21e8ccSflorian 
2533f21e8ccSflorian 	(void)fd;
2543f21e8ccSflorian 	assert(event & EV_TIMEOUT);
2553f21e8ccSflorian 	assert(arg != NULL);
2563f21e8ccSflorian 
2573f21e8ccSflorian 	verifier = (struct verifier *)arg;
2583f21e8ccSflorian 	verifier->zone->is_bad = 1;
2593f21e8ccSflorian 
2603f21e8ccSflorian 	log_msg(LOG_ERR, "verify: verifier for zone %s (pid %d) timed out",
2613f21e8ccSflorian 	                 verifier->zone->opts->name, verifier->pid);
2623f21e8ccSflorian 
2633f21e8ccSflorian 	/* kill verifier, process reaped by exit handler */
2643f21e8ccSflorian 	kill_verifier(verifier);
2653f21e8ccSflorian }
2663f21e8ccSflorian 
verify_handle_signal(int sig,short event,void * arg)2673f21e8ccSflorian void verify_handle_signal(int sig, short event, void *arg)
2683f21e8ccSflorian {
2693f21e8ccSflorian 	char buf[1] = { '\0' };
2703f21e8ccSflorian 	struct nsd *nsd;
2713f21e8ccSflorian 
2723f21e8ccSflorian 	assert(sig == SIGCHLD);
2733f21e8ccSflorian 	assert(event & EV_SIGNAL);
2743f21e8ccSflorian 	assert(arg != NULL);
2753f21e8ccSflorian 
2763f21e8ccSflorian 	nsd = (struct nsd *)arg;
277*3efee2e1Sflorian 	if(write(nsd->verifier_pipe[1], buf, sizeof(buf)) == -1) {
278*3efee2e1Sflorian 		log_msg(LOG_ERR, "verify_handle_signal: write failed: %s",
279*3efee2e1Sflorian 				strerror(errno));
280*3efee2e1Sflorian 	}
2813f21e8ccSflorian }
2823f21e8ccSflorian 
2833f21e8ccSflorian /*
2843f21e8ccSflorian  * Reap process and update status of respective zone based on the exit code
2853f21e8ccSflorian  * of a verifier. Everything from STDOUT and STDERR still available is read and
2863f21e8ccSflorian  * written to the log as it might contain valuable information.
2873f21e8ccSflorian  *
2883f21e8ccSflorian  * NOTE: A timeout might have caused the verifier to be terminated.
2893f21e8ccSflorian  */
verify_handle_exit(int fd,short event,void * arg)2903f21e8ccSflorian void verify_handle_exit(int fd, short event, void *arg)
2913f21e8ccSflorian {
2923f21e8ccSflorian 	int wstatus;
2933f21e8ccSflorian 	pid_t pid;
2943f21e8ccSflorian 	struct nsd *nsd;
2953f21e8ccSflorian 	char buf[1];
2963f21e8ccSflorian 
2973f21e8ccSflorian 	assert(event & EV_READ);
2983f21e8ccSflorian 	assert(arg != NULL);
2993f21e8ccSflorian 
3003f21e8ccSflorian 	nsd = (struct nsd *)arg;
3013f21e8ccSflorian 
302de04d855Ssthen 	if(read(fd, buf, sizeof(buf)) == -1) {
303de04d855Ssthen 		if(errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK)
304de04d855Ssthen 			log_msg(LOG_ERR, "verify_handle_exit: read failed: %s",
305de04d855Ssthen 				strerror(errno));
306de04d855Ssthen 	}
3073f21e8ccSflorian 
3083f21e8ccSflorian 	while(((pid = waitpid(-1, &wstatus, WNOHANG)) == -1 && errno == EINTR)
3093f21e8ccSflorian 	    || (pid > 0))
3103f21e8ccSflorian 	{
3113f21e8ccSflorian 		struct verifier *verifier = NULL;
3123f21e8ccSflorian 
313de04d855Ssthen 		for(size_t i = 0; !verifier && i < nsd->verifier_limit; i++) {
3143f21e8ccSflorian 			if(nsd->verifiers[i].zone != NULL &&
3153f21e8ccSflorian 			   nsd->verifiers[i].pid == pid)
3163f21e8ccSflorian 			{
3173f21e8ccSflorian 				verifier = &nsd->verifiers[i];
3183f21e8ccSflorian 			}
3193f21e8ccSflorian 		}
3203f21e8ccSflorian 
3213f21e8ccSflorian 		if(verifier == NULL) {
3223f21e8ccSflorian 			continue;
3233f21e8ccSflorian 		}
3243f21e8ccSflorian 
3253f21e8ccSflorian 		if(!WIFEXITED(wstatus)) {
3263f21e8ccSflorian 			log_msg(LOG_ERR, "verify: verifier for zone %s "
3273f21e8ccSflorian 			                 "(pid %d) exited abnormally",
3283f21e8ccSflorian 			                 verifier->zone->opts->name, pid);
3293f21e8ccSflorian 		} else {
3303f21e8ccSflorian 			int priority = LOG_INFO;
3313f21e8ccSflorian 			int status = WEXITSTATUS(wstatus);
3323f21e8ccSflorian 			if(status != 0) {
3333f21e8ccSflorian 				priority = LOG_ERR;
3343f21e8ccSflorian 				verifier->zone->is_bad = 1;
3353f21e8ccSflorian 			}
3363f21e8ccSflorian 			log_msg(priority, "verify: verifier for zone %s "
3373f21e8ccSflorian 			                  "(pid %d) exited with %d",
3383f21e8ccSflorian 			                  verifier->zone->opts->name, pid, status);
3393f21e8ccSflorian 		}
3403f21e8ccSflorian 
3413f21e8ccSflorian 		close_verifier(verifier);
3423f21e8ccSflorian 		nsd->verifier_count--;
3433f21e8ccSflorian 	}
3443f21e8ccSflorian 
3453f21e8ccSflorian 	while(nsd->mode == NSD_RUN &&
3463f21e8ccSflorian 	      nsd->verifier_count < nsd->verifier_limit &&
3473f21e8ccSflorian 	      nsd->next_zone_to_verify != NULL)
3483f21e8ccSflorian 	{
3493f21e8ccSflorian 		verify_zone(nsd, nsd->next_zone_to_verify);
3503f21e8ccSflorian 		nsd->next_zone_to_verify
3513f21e8ccSflorian 			= verify_next_zone(nsd, nsd->next_zone_to_verify);
3523f21e8ccSflorian 	}
3533f21e8ccSflorian 
3543f21e8ccSflorian 	if(nsd->next_zone_to_verify == NULL && nsd->verifier_count == 0) {
3553f21e8ccSflorian 		event_base_loopexit(nsd->event_base, NULL);
3563f21e8ccSflorian 		return;
3573f21e8ccSflorian 	}
3583f21e8ccSflorian }
3593f21e8ccSflorian 
3603f21e8ccSflorian /*
3613f21e8ccSflorian  * A parent may be terminated (by the NSD_QUIT signal (nsdc stop command)).
3623f21e8ccSflorian  * When a reload server process is running, the parent will then send a
3633f21e8ccSflorian  * NSD_QUIT command to that server. This handler makes sure that this command
3643f21e8ccSflorian  * is not neglected and that the reload server process will exit (gracefully).
3653f21e8ccSflorian  */
3663f21e8ccSflorian void
verify_handle_command(int fd,short event,void * arg)3673f21e8ccSflorian verify_handle_command(int fd, short event, void *arg)
3683f21e8ccSflorian {
3693f21e8ccSflorian 	struct nsd *nsd = (struct nsd *)arg;
3703f21e8ccSflorian 	int len;
3713f21e8ccSflorian 	sig_atomic_t mode;
3723f21e8ccSflorian 
3733f21e8ccSflorian 	assert(nsd != NULL);
3743f21e8ccSflorian 	assert(event & (EV_READ
3753f21e8ccSflorian #ifdef EV_CLOSED
3763f21e8ccSflorian 	| EV_CLOSED
3773f21e8ccSflorian #endif
3783f21e8ccSflorian 	));
3793f21e8ccSflorian 
3803f21e8ccSflorian 	if((len = read(fd, &mode, sizeof(mode))) == -1) {
3813f21e8ccSflorian 		log_msg(LOG_ERR, "verify: verify_handle_command: read: %s",
3823f21e8ccSflorian 		                 strerror(errno));
3833f21e8ccSflorian 		return;
3843f21e8ccSflorian 	} else if(len == 0) {
3853f21e8ccSflorian 		log_msg(LOG_INFO, "verify: command channel closed");
3863f21e8ccSflorian 		mode = NSD_QUIT;
3873f21e8ccSflorian 	} else if(mode != NSD_QUIT) {
3883f21e8ccSflorian 		log_msg(LOG_ERR, "verify: bad command: %d", (int)mode);
3893f21e8ccSflorian 		return;
3903f21e8ccSflorian 	}
3913f21e8ccSflorian 
3923f21e8ccSflorian 	nsd->mode = mode;
3933f21e8ccSflorian 
3943f21e8ccSflorian 	if(nsd->verifier_count == 0) {
3953f21e8ccSflorian 		event_base_loopexit(nsd->event_base, NULL);
3963f21e8ccSflorian 		return; /* exit early if no verifiers are executing */
3973f21e8ccSflorian 	}
3983f21e8ccSflorian 
3993f21e8ccSflorian 	/* kill verifiers, processes reaped elsewhere */
400de04d855Ssthen 	for(size_t i = 0; i < nsd->verifier_limit; i++) {
4013f21e8ccSflorian 		if(nsd->verifiers[i].zone != NULL) {
4023f21e8ccSflorian 			kill_verifier(&nsd->verifiers[i]);
4033f21e8ccSflorian 		}
4043f21e8ccSflorian 	}
4053f21e8ccSflorian }
4063f21e8ccSflorian 
4073f21e8ccSflorian /*
4083f21e8ccSflorian  * A verifier is executed for the specified zone (if a verifier is configured
4093f21e8ccSflorian  * and the zone has not been verified before). If one of the verifiers exits
4103f21e8ccSflorian  * with non-zero, the zone is marked bad and nsd drops the zone update and
4113f21e8ccSflorian  * reloads again.
4123f21e8ccSflorian  */
verify_zone(struct nsd * nsd,struct zone * zone)4133f21e8ccSflorian void verify_zone(struct nsd *nsd, struct zone *zone)
4143f21e8ccSflorian {
4153f21e8ccSflorian 	struct verifier *verifier = NULL;
4163f21e8ccSflorian 	int32_t timeout;
4173f21e8ccSflorian 	char **command;
4183f21e8ccSflorian 	FILE *fin;
4193f21e8ccSflorian 	int fdin, fderr, fdout, flags;
4203f21e8ccSflorian 
4213f21e8ccSflorian 	assert(nsd != NULL);
4223f21e8ccSflorian 	assert(nsd->verifier_count < nsd->verifier_limit);
4233f21e8ccSflorian 	assert(zone != NULL);
4243f21e8ccSflorian 
4253f21e8ccSflorian 	fin = NULL;
4263f21e8ccSflorian 	fdin = fdout = fderr = -1;
4273f21e8ccSflorian 
4283f21e8ccSflorian 	/* search for available verifier slot */
429de04d855Ssthen 	for(size_t i = 0; i < nsd->verifier_limit && !verifier; i++) {
4303f21e8ccSflorian 		if(nsd->verifiers[i].zone == NULL) {
4313f21e8ccSflorian 			verifier = &nsd->verifiers[i];
4323f21e8ccSflorian 		}
4333f21e8ccSflorian 	}
4343f21e8ccSflorian 
4353f21e8ccSflorian 	assert(verifier != NULL);
4363f21e8ccSflorian 
4373f21e8ccSflorian 	if(zone->opts->pattern->verifier != NULL) {
4383f21e8ccSflorian 		command = zone->opts->pattern->verifier;
4393f21e8ccSflorian 	} else if (nsd->options->verifier != NULL) {
4403f21e8ccSflorian 		command = nsd->options->verifier;
4413f21e8ccSflorian 	} else {
4423f21e8ccSflorian 		log_msg(LOG_ERR, "verify: no verifier for zone %s",
4433f21e8ccSflorian 		                 zone->opts->name);
4443f21e8ccSflorian 		return;
4453f21e8ccSflorian 	}
4463f21e8ccSflorian 
4473f21e8ccSflorian 	if(zone->opts->pattern->verifier_timeout
4483f21e8ccSflorian 		!= VERIFIER_TIMEOUT_INHERIT)
4493f21e8ccSflorian 	{
4503f21e8ccSflorian 		timeout = zone->opts->pattern->verifier_timeout;
4513f21e8ccSflorian 	} else {
4523f21e8ccSflorian 		timeout = nsd->options->verifier_timeout;
4533f21e8ccSflorian 	}
4543f21e8ccSflorian 
4553f21e8ccSflorian 	if(zone->opts->pattern->verifier_feed_zone
4563f21e8ccSflorian 		!= VERIFIER_FEED_ZONE_INHERIT)
4573f21e8ccSflorian 	{
4583f21e8ccSflorian 		fdin = zone->opts->pattern->verifier_feed_zone ? -2 : -1;
4593f21e8ccSflorian 	} else {
4603f21e8ccSflorian 		fdin = nsd->options->verifier_feed_zone ? -2 : -1;
4613f21e8ccSflorian 	}
4623f21e8ccSflorian 
4633f21e8ccSflorian 	assert(timeout >= 0);
4643f21e8ccSflorian 
4653f21e8ccSflorian 	setenv("VERIFY_ZONE", zone->opts->name, 1);
4663f21e8ccSflorian 	setenv("VERIFY_ZONE_ON_STDIN", fdin == -2 ? "yes" : "no", 1);
4673f21e8ccSflorian 
4683f21e8ccSflorian 	verifier->pid = popen3(
4693f21e8ccSflorian 		command, fdin == -2 ? &fdin : NULL, &fdout, &fderr);
4703f21e8ccSflorian 	if(verifier->pid == -1) {
4713f21e8ccSflorian 		log_msg(LOG_ERR, "verify: could not start verifier for zone "
4723f21e8ccSflorian 				 "%s: %s", zone->opts->name, strerror(errno));
4733f21e8ccSflorian 		goto fail_popen3;
4743f21e8ccSflorian 	}
4753f21e8ccSflorian 	flags = fcntl(fderr, F_GETFL, 0);
4763f21e8ccSflorian 	if (fcntl(fderr, F_SETFL, flags | O_NONBLOCK) == -1) {
4773f21e8ccSflorian 		log_msg(LOG_ERR, "verify: fcntl(stderr, ..., O_NONBLOCK) for "
4783f21e8ccSflorian 		                 "zone %s: %s",
4793f21e8ccSflorian 		                 zone->opts->name, strerror(errno));
4803f21e8ccSflorian 		goto fail_fcntl;
4813f21e8ccSflorian 	}
4823f21e8ccSflorian 	flags = fcntl(fdout, F_GETFL, 0);
4833f21e8ccSflorian 	if(fcntl(fdout, F_SETFL, flags | O_NONBLOCK) == -1) {
4843f21e8ccSflorian 		log_msg(LOG_ERR, "verify: fcntl(stdout, ..., O_NONBLOCK) for "
4853f21e8ccSflorian 		                 "zone %s: %s",
4863f21e8ccSflorian 		                 zone->opts->name, strerror(errno));
4873f21e8ccSflorian 		goto fail_fcntl;
4883f21e8ccSflorian 	}
4893f21e8ccSflorian 	if (fdin >= 0) {
4903f21e8ccSflorian 		if ((fin = fdopen(fdin, "w")) == NULL) {
4913f21e8ccSflorian 			log_msg(LOG_ERR, "verify: fdopen(stdin, ...) for "
4923f21e8ccSflorian 			                 "zone %s: %s",
4933f21e8ccSflorian 		                         zone->opts->name, strerror(errno));
4943f21e8ccSflorian 			goto fail_fcntl;
4953f21e8ccSflorian 		}
4963f21e8ccSflorian 		/* write unbuffered */
4973f21e8ccSflorian 		setbuf(fin, NULL);
4983f21e8ccSflorian 	}
4993f21e8ccSflorian 
5003f21e8ccSflorian 	verifier->zone = zone;
5013f21e8ccSflorian 	verifier->was_ok = zone->is_ok;
5023f21e8ccSflorian 
5033f21e8ccSflorian 	unsetenv("VERIFY_ZONE");
5043f21e8ccSflorian 	unsetenv("VERIFY_ZONE_ON_STDIN");
5053f21e8ccSflorian 
5063f21e8ccSflorian 	verifier->error_stream.fd = fderr;
5073f21e8ccSflorian 	verifier->error_stream.cnt = 0;
5083f21e8ccSflorian 	verifier->error_stream.off = 0;
5093f21e8ccSflorian 	verifier->error_stream.buf[0] = '\0';
5103f21e8ccSflorian 	event_set(&verifier->error_stream.event,
5113f21e8ccSflorian 	          verifier->error_stream.fd,
5123f21e8ccSflorian 	          EV_READ|EV_PERSIST,
5133f21e8ccSflorian 	          verify_handle_stream,
5143f21e8ccSflorian 		  verifier);
5153f21e8ccSflorian 	event_base_set(nsd->event_base, &verifier->error_stream.event);
5163f21e8ccSflorian 	if(event_add(&verifier->error_stream.event, NULL) != 0) {
5173f21e8ccSflorian 		log_msg(LOG_ERR, "verify: could not add error event for "
5183f21e8ccSflorian 		                 "zone %s", zone->opts->name);
5193f21e8ccSflorian 		goto fail_stderr;
5203f21e8ccSflorian 	}
5213f21e8ccSflorian 
5223f21e8ccSflorian 	verifier->output_stream.fd = fdout;
5233f21e8ccSflorian 	verifier->output_stream.cnt = 0;
5243f21e8ccSflorian 	verifier->output_stream.off = 0;
5253f21e8ccSflorian 	verifier->output_stream.buf[0] = '\0';
5263f21e8ccSflorian 	event_set(&verifier->output_stream.event,
5273f21e8ccSflorian 	          verifier->output_stream.fd,
5283f21e8ccSflorian 	          EV_READ|EV_PERSIST,
5293f21e8ccSflorian 	          verify_handle_stream,
5303f21e8ccSflorian 	          verifier);
5313f21e8ccSflorian 	event_base_set(nsd->event_base, &verifier->output_stream.event);
5323f21e8ccSflorian 	if(event_add(&verifier->output_stream.event, NULL) != 0) {
5333f21e8ccSflorian 		log_msg(LOG_ERR, "verify: could not add output event for "
5343f21e8ccSflorian 		                 "zone %s", zone->opts->name);
5353f21e8ccSflorian 		goto fail_stdout;
5363f21e8ccSflorian 	}
5373f21e8ccSflorian 
5383f21e8ccSflorian 	if(fin != NULL) {
5393f21e8ccSflorian 		verifier->zone_feed.fh = fin;
5403f21e8ccSflorian 
5413f21e8ccSflorian 		zone_rr_iter_init(&verifier->zone_feed.rriter, zone);
5423f21e8ccSflorian 
5433f21e8ccSflorian 		verifier->zone_feed.rrprinter
5443f21e8ccSflorian 			= create_pretty_rr(nsd->server_region);
5453f21e8ccSflorian 		verifier->zone_feed.region
5463f21e8ccSflorian 			= region_create(xalloc, free);
5473f21e8ccSflorian 		verifier->zone_feed.buffer
5483f21e8ccSflorian 			= buffer_create(nsd->server_region, MAX_RDLENGTH);
5493f21e8ccSflorian 
5503f21e8ccSflorian 		event_set(&verifier->zone_feed.event,
5513f21e8ccSflorian 		          fileno(verifier->zone_feed.fh),
5523f21e8ccSflorian 			  EV_WRITE|EV_PERSIST,
5533f21e8ccSflorian 			  &verify_handle_feed,
5543f21e8ccSflorian 			  verifier);
5553f21e8ccSflorian 		event_base_set(nsd->event_base, &verifier->zone_feed.event);
5563f21e8ccSflorian 		if(event_add(&verifier->zone_feed.event, NULL) != 0) {
5573f21e8ccSflorian 			log_msg(LOG_ERR, "verify: could not add input event "
5583f21e8ccSflorian 			                 "for zone %s", zone->opts->name);
5593f21e8ccSflorian 			goto fail_stdin;
5603f21e8ccSflorian 		}
5613f21e8ccSflorian 	}
5623f21e8ccSflorian 
5633f21e8ccSflorian 	if(timeout > 0) {
5643f21e8ccSflorian 		verifier->timeout.tv_sec = timeout;
5653f21e8ccSflorian 		verifier->timeout.tv_usec = 0;
5663f21e8ccSflorian 		event_set(&verifier->timeout_event,
5673f21e8ccSflorian 		          -1,
5683f21e8ccSflorian 		          EV_TIMEOUT,
5693f21e8ccSflorian 		          verify_handle_timeout,
5703f21e8ccSflorian 		          verifier);
5713f21e8ccSflorian 		event_base_set(nsd->event_base, &verifier->timeout_event);
5723f21e8ccSflorian 		if(event_add(&verifier->timeout_event, &verifier->timeout) != 0) {
5733f21e8ccSflorian 			log_msg(LOG_ERR, "verify: could not add timeout event "
5743f21e8ccSflorian 			                 "for zone %s", zone->opts->name);
5753f21e8ccSflorian 			goto fail_timeout;
5763f21e8ccSflorian 		}
5773f21e8ccSflorian 
5783f21e8ccSflorian 		log_msg(LOG_INFO, "verify: started verifier for zone %s "
5793f21e8ccSflorian 		                  "(pid %d), timeout is %d seconds",
5803f21e8ccSflorian 		                  zone->opts->name, verifier->pid, timeout);
5813f21e8ccSflorian 	} else {
5823f21e8ccSflorian 		log_msg(LOG_INFO, "verify: started verifier for zone %s "
5833f21e8ccSflorian 		                  "(pid %d)", zone->opts->name, verifier->pid);
5843f21e8ccSflorian 	}
5853f21e8ccSflorian 
5863f21e8ccSflorian 	zone->is_ok = 1;
5873f21e8ccSflorian 	nsd->verifier_count++;
5883f21e8ccSflorian 	return;
5893f21e8ccSflorian 
5903f21e8ccSflorian fail_timeout:
5913f21e8ccSflorian 	verifier->timeout.tv_sec = 0;
5923f21e8ccSflorian 	verifier->timeout.tv_usec = 0;
5933f21e8ccSflorian 	if(fin != NULL) {
5943f21e8ccSflorian 		event_del(&verifier->zone_feed.event);
5953f21e8ccSflorian 	}
5963f21e8ccSflorian fail_stdin:
5973f21e8ccSflorian 	verifier->zone_feed.fh = NULL;
5983f21e8ccSflorian 	event_del(&verifier->output_stream.event);
5993f21e8ccSflorian fail_stdout:
6003f21e8ccSflorian 	verifier->output_stream.fd = -1;
6013f21e8ccSflorian 	event_del(&verifier->error_stream.event);
6023f21e8ccSflorian fail_stderr:
6033f21e8ccSflorian 	verifier->error_stream.fd = -1;
6043f21e8ccSflorian fail_fcntl:
6053f21e8ccSflorian 	kill_verifier(verifier);
6063f21e8ccSflorian 	if(fin != NULL) {
6073f21e8ccSflorian 		fclose(fin);
6083f21e8ccSflorian 	} else if (fdin >= 0) {
6093f21e8ccSflorian 		close(fdin);
6103f21e8ccSflorian 	}
6113f21e8ccSflorian 	close(fdout);
6123f21e8ccSflorian 	close(fderr);
6133f21e8ccSflorian fail_popen3:
6143f21e8ccSflorian 	zone->is_bad = 1;
6153f21e8ccSflorian 	verifier->pid = -1;
6163f21e8ccSflorian 	verifier->zone = NULL;
6173f21e8ccSflorian }
618