Home | History | Annotate | Line # | Download | only in dist
      1      1.1  christos /*
      2      1.1  christos  * verify.c -- running verifiers and serving the zone to be verified.
      3      1.1  christos  *
      4      1.1  christos  * Copyright (c) 2012-2020, NLnet Labs. All rights reserved.
      5      1.1  christos  *
      6      1.1  christos  * See LICENSE for the license.
      7      1.1  christos  *
      8      1.1  christos  */
      9      1.1  christos 
     10      1.1  christos #include "config.h"
     11      1.1  christos 
     12      1.1  christos #include <assert.h>
     13      1.1  christos #include <ctype.h>
     14      1.1  christos #include <errno.h>
     15      1.1  christos #include <stdarg.h>
     16      1.1  christos #include <stdio.h>
     17      1.1  christos #include <stdlib.h>
     18      1.1  christos #include <string.h>
     19      1.1  christos #ifdef HAVE_SYSLOG_H
     20      1.1  christos #include <syslog.h>
     21      1.1  christos #endif /* HAVE_SYSLOG_H */
     22      1.1  christos #include <unistd.h>
     23      1.1  christos #include <fcntl.h>
     24      1.1  christos #include <sys/wait.h>
     25      1.1  christos 
     26      1.1  christos #include "region-allocator.h"
     27      1.1  christos #include "namedb.h"
     28      1.1  christos #include "nsd.h"
     29      1.1  christos #include "options.h"
     30      1.1  christos #include "difffile.h"
     31      1.1  christos #include "verify.h"
     32      1.1  christos #include "popen3.h"
     33      1.1  christos 
     34      1.1  christos struct zone *verify_next_zone(struct nsd *nsd, struct zone *zone)
     35      1.1  christos {
     36      1.1  christos 	int verify;
     37      1.1  christos 	struct radnode *node;
     38      1.1  christos 
     39      1.1  christos 	if(zone != NULL) {
     40      1.1  christos 		node = radix_next(zone->node);
     41      1.1  christos 	} else {
     42      1.1  christos 		node = radix_first(nsd->db->zonetree);
     43      1.1  christos 	}
     44      1.1  christos 
     45      1.1  christos 	while(node != NULL) {
     46      1.1  christos 		zone = (struct zone *)node->elem;
     47      1.1  christos 		verify = zone->opts->pattern->verify_zone;
     48      1.1  christos 		if(verify == VERIFY_ZONE_INHERIT) {
     49      1.1  christos 			verify = nsd->options->verify_zones;
     50      1.1  christos 		}
     51      1.1  christos 		if(verify && zone->is_updated && !zone->is_checked) {
     52      1.1  christos 			return zone;
     53      1.1  christos 		}
     54      1.1  christos 		node = radix_next(node);
     55      1.1  christos 	}
     56      1.1  christos 
     57      1.1  christos 	return NULL;
     58      1.1  christos }
     59      1.1  christos 
     60      1.1  christos static inline ssize_t fill_buffer(struct verifier_stream *stream)
     61      1.1  christos {
     62      1.1  christos 	ssize_t cnt = 0;
     63      1.1  christos 
     64      1.1  christos 	assert(stream);
     65      1.1  christos 	assert(stream->fd != -1);
     66      1.1  christos 	assert(stream->cnt <= LOGBUFSIZE);
     67      1.1  christos 	assert(stream->off <= stream->cnt);
     68      1.1  christos 
     69      1.1  christos 	// move data to start of buffer assuming all complete lines are printed
     70      1.1  christos 	if (stream->off) {
     71      1.1  christos 		size_t len = stream->cnt - stream->off;
     72      1.1  christos 		memmove(stream->buf, stream->buf + stream->off, len);
     73      1.1  christos 		stream->off = 0;
     74      1.1  christos 		stream->cnt = len;
     75      1.1  christos 		stream->buf[stream->cnt] = '\0'; // always null-terminate
     76      1.1  christos 	}
     77      1.1  christos 
     78      1.1  christos 	// read data if space is available
     79      1.1  christos 	cnt = read(stream->fd, stream->buf + stream->cnt, LOGBUFSIZE - stream->cnt);
     80      1.1  christos 	if (cnt > 0)
     81      1.1  christos 		stream->cnt += (size_t)cnt;
     82      1.1  christos 	assert(stream->cnt <= LOGBUFSIZE);
     83      1.1  christos 	assert(stream->off <= stream->cnt);
     84      1.1  christos 	stream->buf[stream->cnt] = '\0'; // always null-terminate
     85      1.1  christos 
     86      1.1  christos 	return cnt;
     87      1.1  christos }
     88      1.1  christos 
     89      1.1  christos static inline size_t print_line(struct verifier_stream *stream, int eof)
     90      1.1  christos {
     91      1.1  christos 	char *eol = NULL;
     92      1.1  christos 	size_t len;
     93      1.1  christos 	const char *fmt;
     94      1.1  christos 
     95      1.1  christos 	if (stream->cnt == 0)
     96      1.1  christos 		return 0;
     97      1.1  christos 	assert(stream->off <= stream->cnt);
     98      1.1  christos 	if (stream->off == stream->cnt)
     99      1.1  christos 		return 0;
    100      1.1  christos 
    101      1.1  christos 	// try to locate natural line break
    102      1.1  christos 	assert(stream->buf[stream->cnt] == '\0');
    103      1.1  christos 	if ((eol = strchr(stream->buf + stream->off, '\n'))) {
    104      1.1  christos 		len = eol - (stream->buf + stream->off);
    105      1.1  christos 	} else {
    106      1.1  christos 		len = stream->cnt - stream->off;
    107      1.1  christos 	}
    108      1.1  christos 
    109      1.1  christos 	assert(len <= (stream->cnt - stream->off));
    110      1.1  christos 	// wait for buffer to contain a full line except on eof
    111      1.1  christos 	if (len < LOGLINELEN && !eol && !eof)
    112      1.1  christos 		return 0;
    113      1.1  christos 
    114      1.1  christos 	if (len > LOGLINELEN) {
    115  1.1.1.2  christos 		fmt = stream->cut ? "verifier: .. %.*s .." : "verifier: %.*s ..";
    116      1.1  christos 		len = LOGLINELEN; // remainder printed next iteration
    117      1.1  christos 		stream->cut = 1;
    118      1.1  christos 	} else {
    119  1.1.1.2  christos 		fmt = stream->cut ? "verifier: .. %.*s" : "verifier: %.*s";
    120      1.1  christos 		stream->cut = 0;
    121      1.1  christos 	}
    122      1.1  christos 	log_msg(stream->priority, fmt, len, stream->buf + stream->off);
    123      1.1  christos 
    124      1.1  christos 	stream->off += len + (eol != NULL);
    125      1.1  christos 	assert(stream->off <= stream->cnt);
    126      1.1  christos 	return len;
    127      1.1  christos }
    128      1.1  christos 
    129      1.1  christos /*
    130      1.1  christos  * Log verifier output on STDOUT and STDERR. Lines longer than LOGLINELEN are
    131      1.1  christos  * split over multiple lines. Line-breaks are indicated in the log with "...".
    132      1.1  christos  */
    133      1.1  christos static void verify_handle_stream(int fd, short event, void *arg)
    134      1.1  christos {
    135      1.1  christos 	int eof = 0;
    136      1.1  christos 	ssize_t cnt;
    137      1.1  christos 	struct verifier *verifier;
    138      1.1  christos 	struct verifier_stream *stream;
    139      1.1  christos 
    140  1.1.1.3  christos 	assert((event & EV_READ));
    141      1.1  christos 	assert(arg != NULL);
    142      1.1  christos 
    143      1.1  christos 	verifier = (struct verifier *)arg;
    144      1.1  christos 	if (fd == verifier->output_stream.fd) {
    145      1.1  christos 		stream = &verifier->output_stream;
    146      1.1  christos 	} else {
    147      1.1  christos 		assert(fd == verifier->error_stream.fd);
    148      1.1  christos 		stream = &verifier->error_stream;
    149      1.1  christos 	}
    150      1.1  christos 
    151      1.1  christos 	assert(stream);
    152      1.1  christos 	assert(stream->fd != -1);
    153      1.1  christos 
    154      1.1  christos 	do {
    155      1.1  christos 		cnt = fill_buffer(stream);
    156      1.1  christos 		eof = !cnt || (cnt < 0 && errno != EAGAIN && errno != EINTR);
    157      1.1  christos 		while (print_line(stream, eof)) ;
    158      1.1  christos 	} while (cnt > 0);
    159      1.1  christos 
    160      1.1  christos 	if(eof) {
    161      1.1  christos 		event_del(&stream->event);
    162      1.1  christos 		close(stream->fd);
    163      1.1  christos 		stream->fd = -1;
    164      1.1  christos 	}
    165      1.1  christos }
    166      1.1  christos 
    167      1.1  christos static void kill_verifier(struct verifier *verifier)
    168      1.1  christos {
    169      1.1  christos 	assert(verifier != NULL);
    170      1.1  christos 	assert(verifier->zone != NULL);
    171      1.1  christos 
    172      1.1  christos 	if(kill(verifier->pid, SIGTERM) == -1) {
    173      1.1  christos 		log_msg(LOG_ERR, "verify: cannot kill verifier for "
    174      1.1  christos 		                 "zone %s (pid %d): %s",
    175      1.1  christos 		                 verifier->zone->opts->name,
    176      1.1  christos 		                 verifier->pid,
    177      1.1  christos 		                 strerror(errno));
    178      1.1  christos 	}
    179      1.1  christos }
    180      1.1  christos 
    181      1.1  christos static void close_stream(struct verifier *verifier, struct verifier_stream *stream)
    182      1.1  christos {
    183      1.1  christos 	if (stream->fd == -1)
    184      1.1  christos 		return;
    185      1.1  christos 	verify_handle_stream(stream->fd, EV_READ, verifier);
    186      1.1  christos 	if (stream->fd == -1)
    187      1.1  christos 		return;
    188      1.1  christos 	event_del(&stream->event);
    189      1.1  christos 	close(stream->fd);
    190      1.1  christos 	stream->fd = -1;
    191      1.1  christos }
    192      1.1  christos 
    193      1.1  christos static void close_verifier(struct verifier *verifier)
    194      1.1  christos {
    195      1.1  christos 	/* unregister events and close streams (in that order) */
    196      1.1  christos 	if(verifier->timeout.tv_sec > 0) {
    197      1.1  christos 		event_del(&verifier->timeout_event);
    198      1.1  christos 		verifier->timeout.tv_sec = 0;
    199      1.1  christos 		verifier->timeout.tv_usec = 0;
    200      1.1  christos 	}
    201      1.1  christos 
    202      1.1  christos 	if(verifier->zone_feed.fh != NULL) {
    203      1.1  christos 		event_del(&verifier->zone_feed.event);
    204      1.1  christos 		fclose(verifier->zone_feed.fh);
    205      1.1  christos 		verifier->zone_feed.fh = NULL;
    206      1.1  christos 		region_destroy(verifier->zone_feed.region);
    207      1.1  christos 	}
    208      1.1  christos 
    209      1.1  christos 	close_stream(verifier, &verifier->error_stream);
    210      1.1  christos 	close_stream(verifier, &verifier->output_stream);
    211      1.1  christos 
    212      1.1  christos 	verifier->zone->is_ok = verifier->was_ok;
    213      1.1  christos 	verifier->pid = -1;
    214      1.1  christos 	verifier->zone = NULL;
    215      1.1  christos }
    216      1.1  christos 
    217      1.1  christos /*
    218      1.1  christos  * Feed zone to verifier over STDIN as it becomes available.
    219      1.1  christos  */
    220      1.1  christos static void verify_handle_feed(int fd, short event, void *arg)
    221      1.1  christos {
    222      1.1  christos 	struct verifier *verifier;
    223      1.1  christos 	struct rr *rr;
    224      1.1  christos 
    225      1.1  christos 	(void)fd;
    226      1.1  christos 	assert(event == EV_WRITE);
    227      1.1  christos 	assert(arg != NULL);
    228      1.1  christos 
    229      1.1  christos 	verifier = (struct verifier *)arg;
    230      1.1  christos 	if((rr = zone_rr_iter_next(&verifier->zone_feed.rriter)) != NULL) {
    231      1.1  christos 		print_rr(verifier->zone_feed.fh,
    232      1.1  christos 		         verifier->zone_feed.rrprinter,
    233      1.1  christos 		         rr,
    234      1.1  christos 		         verifier->zone_feed.region,
    235      1.1  christos 		         verifier->zone_feed.buffer);
    236      1.1  christos 	} else {
    237      1.1  christos 		event_del(&verifier->zone_feed.event);
    238      1.1  christos 		fclose(verifier->zone_feed.fh);
    239      1.1  christos 		verifier->zone_feed.fh = NULL;
    240      1.1  christos 		region_destroy(verifier->zone_feed.region);
    241      1.1  christos 	}
    242      1.1  christos }
    243      1.1  christos 
    244      1.1  christos /*
    245      1.1  christos  * This handler will be called when a verifier-timeout alarm goes off. It just
    246      1.1  christos  * kills the verifier. server_verify_zones will make sure the zone will be
    247      1.1  christos  * considered bad.
    248      1.1  christos  */
    249      1.1  christos void verify_handle_timeout(int fd, short event, void *arg)
    250      1.1  christos {
    251      1.1  christos 	struct verifier *verifier;
    252      1.1  christos 
    253      1.1  christos 	(void)fd;
    254  1.1.1.3  christos 	assert((event & EV_TIMEOUT));
    255      1.1  christos 	assert(arg != NULL);
    256      1.1  christos 
    257      1.1  christos 	verifier = (struct verifier *)arg;
    258      1.1  christos 	verifier->zone->is_bad = 1;
    259      1.1  christos 
    260      1.1  christos 	log_msg(LOG_ERR, "verify: verifier for zone %s (pid %d) timed out",
    261      1.1  christos 	                 verifier->zone->opts->name, verifier->pid);
    262      1.1  christos 
    263      1.1  christos 	/* kill verifier, process reaped by exit handler */
    264      1.1  christos 	kill_verifier(verifier);
    265      1.1  christos }
    266      1.1  christos 
    267      1.1  christos void verify_handle_signal(int sig, short event, void *arg)
    268      1.1  christos {
    269      1.1  christos 	char buf[1] = { '\0' };
    270      1.1  christos 	struct nsd *nsd;
    271      1.1  christos 
    272      1.1  christos 	assert(sig == SIGCHLD);
    273  1.1.1.3  christos 	assert((event & EV_SIGNAL));
    274      1.1  christos 	assert(arg != NULL);
    275      1.1  christos 
    276      1.1  christos 	nsd = (struct nsd *)arg;
    277  1.1.1.2  christos 	if(write(nsd->verifier_pipe[1], buf, sizeof(buf)) == -1) {
    278  1.1.1.2  christos 		log_msg(LOG_ERR, "verify_handle_signal: write failed: %s",
    279  1.1.1.2  christos 				strerror(errno));
    280  1.1.1.2  christos 	}
    281      1.1  christos }
    282      1.1  christos 
    283      1.1  christos /*
    284      1.1  christos  * Reap process and update status of respective zone based on the exit code
    285      1.1  christos  * of a verifier. Everything from STDOUT and STDERR still available is read and
    286      1.1  christos  * written to the log as it might contain valuable information.
    287      1.1  christos  *
    288      1.1  christos  * NOTE: A timeout might have caused the verifier to be terminated.
    289      1.1  christos  */
    290      1.1  christos void verify_handle_exit(int fd, short event, void *arg)
    291      1.1  christos {
    292      1.1  christos 	int wstatus;
    293      1.1  christos 	pid_t pid;
    294      1.1  christos 	struct nsd *nsd;
    295      1.1  christos 	char buf[1];
    296      1.1  christos 
    297  1.1.1.3  christos 	assert((event & EV_READ));
    298      1.1  christos 	assert(arg != NULL);
    299      1.1  christos 
    300      1.1  christos 	nsd = (struct nsd *)arg;
    301      1.1  christos 
    302  1.1.1.2  christos 	if(read(fd, buf, sizeof(buf)) == -1) {
    303  1.1.1.2  christos 		if(errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK)
    304  1.1.1.2  christos 			log_msg(LOG_ERR, "verify_handle_exit: read failed: %s",
    305  1.1.1.2  christos 				strerror(errno));
    306  1.1.1.2  christos 	}
    307      1.1  christos 
    308      1.1  christos 	while(((pid = waitpid(-1, &wstatus, WNOHANG)) == -1 && errno == EINTR)
    309      1.1  christos 	    || (pid > 0))
    310      1.1  christos 	{
    311      1.1  christos 		struct verifier *verifier = NULL;
    312      1.1  christos 
    313      1.1  christos 		for(size_t i = 0; !verifier && i < nsd->verifier_limit; i++) {
    314      1.1  christos 			if(nsd->verifiers[i].zone != NULL &&
    315      1.1  christos 			   nsd->verifiers[i].pid == pid)
    316      1.1  christos 			{
    317      1.1  christos 				verifier = &nsd->verifiers[i];
    318      1.1  christos 			}
    319      1.1  christos 		}
    320      1.1  christos 
    321      1.1  christos 		if(verifier == NULL) {
    322      1.1  christos 			continue;
    323      1.1  christos 		}
    324      1.1  christos 
    325      1.1  christos 		if(!WIFEXITED(wstatus)) {
    326      1.1  christos 			log_msg(LOG_ERR, "verify: verifier for zone %s "
    327      1.1  christos 			                 "(pid %d) exited abnormally",
    328      1.1  christos 			                 verifier->zone->opts->name, pid);
    329      1.1  christos 		} else {
    330      1.1  christos 			int priority = LOG_INFO;
    331      1.1  christos 			int status = WEXITSTATUS(wstatus);
    332      1.1  christos 			if(status != 0) {
    333      1.1  christos 				priority = LOG_ERR;
    334      1.1  christos 				verifier->zone->is_bad = 1;
    335      1.1  christos 			}
    336      1.1  christos 			log_msg(priority, "verify: verifier for zone %s "
    337      1.1  christos 			                  "(pid %d) exited with %d",
    338      1.1  christos 			                  verifier->zone->opts->name, pid, status);
    339      1.1  christos 		}
    340      1.1  christos 
    341      1.1  christos 		close_verifier(verifier);
    342      1.1  christos 		nsd->verifier_count--;
    343      1.1  christos 	}
    344      1.1  christos 
    345      1.1  christos 	while(nsd->mode == NSD_RUN &&
    346      1.1  christos 	      nsd->verifier_count < nsd->verifier_limit &&
    347      1.1  christos 	      nsd->next_zone_to_verify != NULL)
    348      1.1  christos 	{
    349      1.1  christos 		verify_zone(nsd, nsd->next_zone_to_verify);
    350      1.1  christos 		nsd->next_zone_to_verify
    351      1.1  christos 			= verify_next_zone(nsd, nsd->next_zone_to_verify);
    352      1.1  christos 	}
    353      1.1  christos 
    354      1.1  christos 	if(nsd->next_zone_to_verify == NULL && nsd->verifier_count == 0) {
    355      1.1  christos 		event_base_loopexit(nsd->event_base, NULL);
    356      1.1  christos 		return;
    357      1.1  christos 	}
    358      1.1  christos }
    359      1.1  christos 
    360      1.1  christos /*
    361      1.1  christos  * A parent may be terminated (by the NSD_QUIT signal (nsdc stop command)).
    362      1.1  christos  * When a reload server process is running, the parent will then send a
    363      1.1  christos  * NSD_QUIT command to that server. This handler makes sure that this command
    364      1.1  christos  * is not neglected and that the reload server process will exit (gracefully).
    365      1.1  christos  */
    366      1.1  christos void
    367      1.1  christos verify_handle_command(int fd, short event, void *arg)
    368      1.1  christos {
    369      1.1  christos 	struct nsd *nsd = (struct nsd *)arg;
    370      1.1  christos 	int len;
    371      1.1  christos 	sig_atomic_t mode;
    372      1.1  christos 
    373      1.1  christos 	assert(nsd != NULL);
    374  1.1.1.3  christos 	assert((event & (EV_READ
    375      1.1  christos #ifdef EV_CLOSED
    376      1.1  christos 	| EV_CLOSED
    377      1.1  christos #endif
    378  1.1.1.3  christos 	)));
    379      1.1  christos 
    380      1.1  christos 	if((len = read(fd, &mode, sizeof(mode))) == -1) {
    381      1.1  christos 		log_msg(LOG_ERR, "verify: verify_handle_command: read: %s",
    382      1.1  christos 		                 strerror(errno));
    383      1.1  christos 		return;
    384      1.1  christos 	} else if(len == 0) {
    385      1.1  christos 		log_msg(LOG_INFO, "verify: command channel closed");
    386      1.1  christos 		mode = NSD_QUIT;
    387      1.1  christos 	} else if(mode != NSD_QUIT) {
    388      1.1  christos 		log_msg(LOG_ERR, "verify: bad command: %d", (int)mode);
    389      1.1  christos 		return;
    390      1.1  christos 	}
    391      1.1  christos 
    392      1.1  christos 	nsd->mode = mode;
    393      1.1  christos 
    394      1.1  christos 	if(nsd->verifier_count == 0) {
    395      1.1  christos 		event_base_loopexit(nsd->event_base, NULL);
    396      1.1  christos 		return; /* exit early if no verifiers are executing */
    397      1.1  christos 	}
    398      1.1  christos 
    399      1.1  christos 	/* kill verifiers, processes reaped elsewhere */
    400      1.1  christos 	for(size_t i = 0; i < nsd->verifier_limit; i++) {
    401      1.1  christos 		if(nsd->verifiers[i].zone != NULL) {
    402      1.1  christos 			kill_verifier(&nsd->verifiers[i]);
    403      1.1  christos 		}
    404      1.1  christos 	}
    405      1.1  christos }
    406      1.1  christos 
    407      1.1  christos /*
    408      1.1  christos  * A verifier is executed for the specified zone (if a verifier is configured
    409      1.1  christos  * and the zone has not been verified before). If one of the verifiers exits
    410      1.1  christos  * with non-zero, the zone is marked bad and nsd drops the zone update and
    411      1.1  christos  * reloads again.
    412      1.1  christos  */
    413      1.1  christos void verify_zone(struct nsd *nsd, struct zone *zone)
    414      1.1  christos {
    415      1.1  christos 	struct verifier *verifier = NULL;
    416      1.1  christos 	int32_t timeout;
    417      1.1  christos 	char **command;
    418      1.1  christos 	FILE *fin;
    419      1.1  christos 	int fdin, fderr, fdout, flags;
    420      1.1  christos 
    421      1.1  christos 	assert(nsd != NULL);
    422      1.1  christos 	assert(nsd->verifier_count < nsd->verifier_limit);
    423      1.1  christos 	assert(zone != NULL);
    424      1.1  christos 
    425      1.1  christos 	fin = NULL;
    426      1.1  christos 	fdin = fdout = fderr = -1;
    427      1.1  christos 
    428      1.1  christos 	/* search for available verifier slot */
    429      1.1  christos 	for(size_t i = 0; i < nsd->verifier_limit && !verifier; i++) {
    430      1.1  christos 		if(nsd->verifiers[i].zone == NULL) {
    431      1.1  christos 			verifier = &nsd->verifiers[i];
    432      1.1  christos 		}
    433      1.1  christos 	}
    434      1.1  christos 
    435      1.1  christos 	assert(verifier != NULL);
    436      1.1  christos 
    437      1.1  christos 	if(zone->opts->pattern->verifier != NULL) {
    438      1.1  christos 		command = zone->opts->pattern->verifier;
    439      1.1  christos 	} else if (nsd->options->verifier != NULL) {
    440      1.1  christos 		command = nsd->options->verifier;
    441      1.1  christos 	} else {
    442      1.1  christos 		log_msg(LOG_ERR, "verify: no verifier for zone %s",
    443      1.1  christos 		                 zone->opts->name);
    444      1.1  christos 		return;
    445      1.1  christos 	}
    446      1.1  christos 
    447      1.1  christos 	if(zone->opts->pattern->verifier_timeout
    448      1.1  christos 		!= VERIFIER_TIMEOUT_INHERIT)
    449      1.1  christos 	{
    450      1.1  christos 		timeout = zone->opts->pattern->verifier_timeout;
    451      1.1  christos 	} else {
    452      1.1  christos 		timeout = nsd->options->verifier_timeout;
    453      1.1  christos 	}
    454      1.1  christos 
    455      1.1  christos 	if(zone->opts->pattern->verifier_feed_zone
    456      1.1  christos 		!= VERIFIER_FEED_ZONE_INHERIT)
    457      1.1  christos 	{
    458      1.1  christos 		fdin = zone->opts->pattern->verifier_feed_zone ? -2 : -1;
    459      1.1  christos 	} else {
    460      1.1  christos 		fdin = nsd->options->verifier_feed_zone ? -2 : -1;
    461      1.1  christos 	}
    462      1.1  christos 
    463      1.1  christos 	assert(timeout >= 0);
    464      1.1  christos 
    465      1.1  christos 	setenv("VERIFY_ZONE", zone->opts->name, 1);
    466      1.1  christos 	setenv("VERIFY_ZONE_ON_STDIN", fdin == -2 ? "yes" : "no", 1);
    467      1.1  christos 
    468      1.1  christos 	verifier->pid = popen3(
    469      1.1  christos 		command, fdin == -2 ? &fdin : NULL, &fdout, &fderr);
    470      1.1  christos 	if(verifier->pid == -1) {
    471      1.1  christos 		log_msg(LOG_ERR, "verify: could not start verifier for zone "
    472      1.1  christos 				 "%s: %s", zone->opts->name, strerror(errno));
    473      1.1  christos 		goto fail_popen3;
    474      1.1  christos 	}
    475      1.1  christos 	flags = fcntl(fderr, F_GETFL, 0);
    476      1.1  christos 	if (fcntl(fderr, F_SETFL, flags | O_NONBLOCK) == -1) {
    477      1.1  christos 		log_msg(LOG_ERR, "verify: fcntl(stderr, ..., O_NONBLOCK) for "
    478      1.1  christos 		                 "zone %s: %s",
    479      1.1  christos 		                 zone->opts->name, strerror(errno));
    480      1.1  christos 		goto fail_fcntl;
    481      1.1  christos 	}
    482      1.1  christos 	flags = fcntl(fdout, F_GETFL, 0);
    483      1.1  christos 	if(fcntl(fdout, F_SETFL, flags | O_NONBLOCK) == -1) {
    484      1.1  christos 		log_msg(LOG_ERR, "verify: fcntl(stdout, ..., O_NONBLOCK) for "
    485      1.1  christos 		                 "zone %s: %s",
    486      1.1  christos 		                 zone->opts->name, strerror(errno));
    487      1.1  christos 		goto fail_fcntl;
    488      1.1  christos 	}
    489      1.1  christos 	if (fdin >= 0) {
    490      1.1  christos 		if ((fin = fdopen(fdin, "w")) == NULL) {
    491      1.1  christos 			log_msg(LOG_ERR, "verify: fdopen(stdin, ...) for "
    492      1.1  christos 			                 "zone %s: %s",
    493      1.1  christos 		                         zone->opts->name, strerror(errno));
    494      1.1  christos 			goto fail_fcntl;
    495      1.1  christos 		}
    496      1.1  christos 		/* write unbuffered */
    497      1.1  christos 		setbuf(fin, NULL);
    498      1.1  christos 	}
    499      1.1  christos 
    500      1.1  christos 	verifier->zone = zone;
    501      1.1  christos 	verifier->was_ok = zone->is_ok;
    502      1.1  christos 
    503      1.1  christos 	unsetenv("VERIFY_ZONE");
    504      1.1  christos 	unsetenv("VERIFY_ZONE_ON_STDIN");
    505      1.1  christos 
    506      1.1  christos 	verifier->error_stream.fd = fderr;
    507      1.1  christos 	verifier->error_stream.cnt = 0;
    508      1.1  christos 	verifier->error_stream.off = 0;
    509      1.1  christos 	verifier->error_stream.buf[0] = '\0';
    510      1.1  christos 	event_set(&verifier->error_stream.event,
    511      1.1  christos 	          verifier->error_stream.fd,
    512      1.1  christos 	          EV_READ|EV_PERSIST,
    513      1.1  christos 	          verify_handle_stream,
    514      1.1  christos 		  verifier);
    515      1.1  christos 	event_base_set(nsd->event_base, &verifier->error_stream.event);
    516      1.1  christos 	if(event_add(&verifier->error_stream.event, NULL) != 0) {
    517      1.1  christos 		log_msg(LOG_ERR, "verify: could not add error event for "
    518      1.1  christos 		                 "zone %s", zone->opts->name);
    519      1.1  christos 		goto fail_stderr;
    520      1.1  christos 	}
    521      1.1  christos 
    522      1.1  christos 	verifier->output_stream.fd = fdout;
    523      1.1  christos 	verifier->output_stream.cnt = 0;
    524      1.1  christos 	verifier->output_stream.off = 0;
    525      1.1  christos 	verifier->output_stream.buf[0] = '\0';
    526      1.1  christos 	event_set(&verifier->output_stream.event,
    527      1.1  christos 	          verifier->output_stream.fd,
    528      1.1  christos 	          EV_READ|EV_PERSIST,
    529      1.1  christos 	          verify_handle_stream,
    530      1.1  christos 	          verifier);
    531      1.1  christos 	event_base_set(nsd->event_base, &verifier->output_stream.event);
    532      1.1  christos 	if(event_add(&verifier->output_stream.event, NULL) != 0) {
    533      1.1  christos 		log_msg(LOG_ERR, "verify: could not add output event for "
    534      1.1  christos 		                 "zone %s", zone->opts->name);
    535      1.1  christos 		goto fail_stdout;
    536      1.1  christos 	}
    537      1.1  christos 
    538      1.1  christos 	if(fin != NULL) {
    539      1.1  christos 		verifier->zone_feed.fh = fin;
    540      1.1  christos 
    541      1.1  christos 		zone_rr_iter_init(&verifier->zone_feed.rriter, zone);
    542      1.1  christos 
    543      1.1  christos 		verifier->zone_feed.rrprinter
    544      1.1  christos 			= create_pretty_rr(nsd->server_region);
    545      1.1  christos 		verifier->zone_feed.region
    546      1.1  christos 			= region_create(xalloc, free);
    547      1.1  christos 		verifier->zone_feed.buffer
    548      1.1  christos 			= buffer_create(nsd->server_region, MAX_RDLENGTH);
    549      1.1  christos 
    550      1.1  christos 		event_set(&verifier->zone_feed.event,
    551      1.1  christos 		          fileno(verifier->zone_feed.fh),
    552      1.1  christos 			  EV_WRITE|EV_PERSIST,
    553      1.1  christos 			  &verify_handle_feed,
    554      1.1  christos 			  verifier);
    555      1.1  christos 		event_base_set(nsd->event_base, &verifier->zone_feed.event);
    556      1.1  christos 		if(event_add(&verifier->zone_feed.event, NULL) != 0) {
    557      1.1  christos 			log_msg(LOG_ERR, "verify: could not add input event "
    558      1.1  christos 			                 "for zone %s", zone->opts->name);
    559      1.1  christos 			goto fail_stdin;
    560      1.1  christos 		}
    561      1.1  christos 	}
    562      1.1  christos 
    563      1.1  christos 	if(timeout > 0) {
    564      1.1  christos 		verifier->timeout.tv_sec = timeout;
    565      1.1  christos 		verifier->timeout.tv_usec = 0;
    566      1.1  christos 		event_set(&verifier->timeout_event,
    567      1.1  christos 		          -1,
    568      1.1  christos 		          EV_TIMEOUT,
    569      1.1  christos 		          verify_handle_timeout,
    570      1.1  christos 		          verifier);
    571      1.1  christos 		event_base_set(nsd->event_base, &verifier->timeout_event);
    572      1.1  christos 		if(event_add(&verifier->timeout_event, &verifier->timeout) != 0) {
    573      1.1  christos 			log_msg(LOG_ERR, "verify: could not add timeout event "
    574      1.1  christos 			                 "for zone %s", zone->opts->name);
    575      1.1  christos 			goto fail_timeout;
    576      1.1  christos 		}
    577      1.1  christos 
    578      1.1  christos 		log_msg(LOG_INFO, "verify: started verifier for zone %s "
    579      1.1  christos 		                  "(pid %d), timeout is %d seconds",
    580      1.1  christos 		                  zone->opts->name, verifier->pid, timeout);
    581      1.1  christos 	} else {
    582      1.1  christos 		log_msg(LOG_INFO, "verify: started verifier for zone %s "
    583      1.1  christos 		                  "(pid %d)", zone->opts->name, verifier->pid);
    584      1.1  christos 	}
    585      1.1  christos 
    586      1.1  christos 	zone->is_ok = 1;
    587      1.1  christos 	nsd->verifier_count++;
    588      1.1  christos 	return;
    589      1.1  christos 
    590      1.1  christos fail_timeout:
    591      1.1  christos 	verifier->timeout.tv_sec = 0;
    592      1.1  christos 	verifier->timeout.tv_usec = 0;
    593      1.1  christos 	if(fin != NULL) {
    594      1.1  christos 		event_del(&verifier->zone_feed.event);
    595      1.1  christos 	}
    596      1.1  christos fail_stdin:
    597      1.1  christos 	verifier->zone_feed.fh = NULL;
    598      1.1  christos 	event_del(&verifier->output_stream.event);
    599      1.1  christos fail_stdout:
    600      1.1  christos 	verifier->output_stream.fd = -1;
    601      1.1  christos 	event_del(&verifier->error_stream.event);
    602      1.1  christos fail_stderr:
    603      1.1  christos 	verifier->error_stream.fd = -1;
    604      1.1  christos fail_fcntl:
    605      1.1  christos 	kill_verifier(verifier);
    606      1.1  christos 	if(fin != NULL) {
    607      1.1  christos 		fclose(fin);
    608      1.1  christos 	} else if (fdin >= 0) {
    609      1.1  christos 		close(fdin);
    610      1.1  christos 	}
    611      1.1  christos 	close(fdout);
    612      1.1  christos 	close(fderr);
    613      1.1  christos fail_popen3:
    614      1.1  christos 	zone->is_bad = 1;
    615      1.1  christos 	verifier->pid = -1;
    616      1.1  christos 	verifier->zone = NULL;
    617      1.1  christos }
    618