| File: | src/usr.sbin/nsd/verify.c |
| Warning: | line 468, column 16 Access to field 'pid' results in a dereference of a null pointer (loaded from variable 'verifier') |
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 | } |