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