1 /* $NetBSD: ntp_intres.c,v 1.8 2016/01/08 21:35:38 christos Exp $ */ 2 3 /* 4 * ntp_intres.c - Implements a generic blocking worker child or thread, 5 * initially to provide a nonblocking solution for DNS 6 * name to address lookups available with getaddrinfo(). 7 * 8 * This is a new implementation as of 2009 sharing the filename and 9 * very little else with the prior implementation, which used a 10 * temporary file to receive a single set of requests from the parent, 11 * and a NTP mode 7 authenticated request to push back responses. 12 * 13 * A primary goal in rewriting this code was the need to support the 14 * pool configuration directive's requirement to retrieve multiple 15 * addresses resolving a single name, which has previously been 16 * satisfied with blocking resolver calls from the ntpd mainline code. 17 * 18 * A secondary goal is to provide a generic mechanism for other 19 * blocking operations to be delegated to a worker using a common 20 * model for both Unix and Windows ntpd. ntp_worker.c, work_fork.c, 21 * and work_thread.c implement the generic mechanism. This file 22 * implements the two current consumers, getaddrinfo_sometime() and the 23 * presently unused getnameinfo_sometime(). 24 * 25 * Both routines deliver results to a callback and manage memory 26 * allocation, meaning there is no freeaddrinfo_sometime(). 27 * 28 * The initial implementation for Unix uses a pair of unidirectional 29 * pipes, one each for requests and responses, connecting the forked 30 * blocking child worker with the ntpd mainline. The threaded code 31 * uses arrays of pointers to queue requests and responses. 32 * 33 * The parent drives the process, including scheduling sleeps between 34 * retries. 35 * 36 * Memory is managed differently for a child process, which mallocs 37 * request buffers to read from the pipe into, whereas the threaded 38 * code mallocs a copy of the request to hand off to the worker via 39 * the queueing array. The resulting request buffer is free()d by 40 * platform-independent code. A wrinkle is the request needs to be 41 * available to the requestor during response processing. 42 * 43 * Response memory allocation is also platform-dependent. With a 44 * separate process and pipes, the response is free()d after being 45 * written to the pipe. With threads, the same memory is handed 46 * over and the requestor frees it after processing is completed. 47 * 48 * The code should be generalized to support threads on Unix using 49 * much of the same code used for Windows initially. 50 * 51 */ 52 #ifdef HAVE_CONFIG_H 53 # include <config.h> 54 #endif 55 56 #include "ntp_workimpl.h" 57 58 #ifdef WORKER 59 60 #include <stdio.h> 61 #include <ctype.h> 62 #include <signal.h> 63 64 /**/ 65 #ifdef HAVE_SYS_TYPES_H 66 # include <sys/types.h> 67 #endif 68 #ifdef HAVE_NETINET_IN_H 69 #include <netinet/in.h> 70 #endif 71 #include <arpa/inet.h> 72 /**/ 73 #ifdef HAVE_SYS_PARAM_H 74 # include <sys/param.h> 75 #endif 76 77 #if !defined(HAVE_RES_INIT) && defined(HAVE___RES_INIT) 78 # define HAVE_RES_INIT 79 #endif 80 81 #if defined(HAVE_RESOLV_H) && defined(HAVE_RES_INIT) 82 # ifdef HAVE_ARPA_NAMESER_H 83 # include <arpa/nameser.h> /* DNS HEADER struct */ 84 # endif 85 # ifdef HAVE_NETDB_H 86 # include <netdb.h> 87 # endif 88 # include <resolv.h> 89 # ifdef HAVE_INT32_ONLY_WITH_DNS 90 # define HAVE_INT32 91 # endif 92 # ifdef HAVE_U_INT32_ONLY_WITH_DNS 93 # define HAVE_U_INT32 94 # endif 95 #endif 96 97 #include "ntp.h" 98 #include "ntp_debug.h" 99 #include "ntp_malloc.h" 100 #include "ntp_syslog.h" 101 #include "ntp_unixtime.h" 102 #include "ntp_intres.h" 103 #include "intreswork.h" 104 105 106 /* 107 * Following are implementations of getaddrinfo_sometime() and 108 * getnameinfo_sometime(). Each is implemented in three routines: 109 * 110 * getaddrinfo_sometime() getnameinfo_sometime() 111 * blocking_getaddrinfo() blocking_getnameinfo() 112 * getaddrinfo_sometime_complete() getnameinfo_sometime_complete() 113 * 114 * The first runs in the parent and marshalls (or serializes) request 115 * parameters into a request blob which is processed in the child by 116 * the second routine, blocking_*(), which serializes the results into 117 * a response blob unpacked by the third routine, *_complete(), which 118 * calls the callback routine provided with the request and frees 119 * _request_ memory allocated by the first routine. Response memory 120 * is managed by the code which calls the *_complete routines. 121 */ 122 123 /* === typedefs === */ 124 typedef struct blocking_gai_req_tag { /* marshalled args */ 125 size_t octets; 126 u_int dns_idx; 127 time_t scheduled; 128 time_t earliest; 129 struct addrinfo hints; 130 int retry; 131 gai_sometime_callback callback; 132 void * context; 133 size_t nodesize; 134 size_t servsize; 135 } blocking_gai_req; 136 137 typedef struct blocking_gai_resp_tag { 138 size_t octets; 139 int retcode; 140 int retry; 141 int gai_errno; /* for EAI_SYSTEM case */ 142 int ai_count; 143 /* 144 * Followed by ai_count struct addrinfo and then ai_count 145 * sockaddr_u and finally the canonical name strings. 146 */ 147 } blocking_gai_resp; 148 149 typedef struct blocking_gni_req_tag { 150 size_t octets; 151 u_int dns_idx; 152 time_t scheduled; 153 time_t earliest; 154 int retry; 155 size_t hostoctets; 156 size_t servoctets; 157 int flags; 158 gni_sometime_callback callback; 159 void * context; 160 sockaddr_u socku; 161 } blocking_gni_req; 162 163 typedef struct blocking_gni_resp_tag { 164 size_t octets; 165 int retcode; 166 int gni_errno; /* for EAI_SYSTEM case */ 167 int retry; 168 size_t hostoctets; 169 size_t servoctets; 170 /* 171 * Followed by hostoctets bytes of null-terminated host, 172 * then servoctets bytes of null-terminated service. 173 */ 174 } blocking_gni_resp; 175 176 /* per-DNS-worker state in parent */ 177 typedef struct dnschild_ctx_tag { 178 u_int index; 179 time_t next_dns_timeslot; 180 } dnschild_ctx; 181 182 /* per-DNS-worker state in worker */ 183 typedef struct dnsworker_ctx_tag { 184 blocking_child * c; 185 time_t ignore_scheduled_before; 186 #ifdef HAVE_RES_INIT 187 time_t next_res_init; 188 #endif 189 } dnsworker_ctx; 190 191 192 /* === variables === */ 193 dnschild_ctx ** dnschild_contexts; /* parent */ 194 u_int dnschild_contexts_alloc; 195 dnsworker_ctx ** dnsworker_contexts; /* child */ 196 u_int dnsworker_contexts_alloc; 197 198 #ifdef HAVE_RES_INIT 199 static time_t next_res_init; 200 #endif 201 202 203 /* === forward declarations === */ 204 static u_int reserve_dnschild_ctx(void); 205 static u_int get_dnschild_ctx(void); 206 static void alloc_dnsworker_context(u_int); 207 /* static void free_dnsworker_context(u_int); */ 208 static dnsworker_ctx * get_worker_context(blocking_child *, u_int); 209 static void scheduled_sleep(time_t, time_t, 210 dnsworker_ctx *); 211 static void manage_dns_retry_interval(time_t *, time_t *, 212 int *, 213 time_t *); 214 static int should_retry_dns(int, int); 215 #ifdef HAVE_RES_INIT 216 static void reload_resolv_conf(dnsworker_ctx *); 217 #else 218 # define reload_resolv_conf(wc) \ 219 do { \ 220 (void)(wc); \ 221 } while (FALSE) 222 #endif 223 static void getaddrinfo_sometime_complete(blocking_work_req, 224 void *, size_t, 225 void *); 226 static void getnameinfo_sometime_complete(blocking_work_req, 227 void *, size_t, 228 void *); 229 230 231 /* === functions === */ 232 /* 233 * getaddrinfo_sometime - uses blocking child to call getaddrinfo then 234 * invokes provided callback completion function. 235 */ 236 int 237 getaddrinfo_sometime( 238 const char * node, 239 const char * service, 240 const struct addrinfo * hints, 241 int retry, 242 gai_sometime_callback callback, 243 void * context 244 ) 245 { 246 blocking_gai_req * gai_req; 247 u_int idx; 248 dnschild_ctx * child_ctx; 249 size_t req_size; 250 size_t nodesize; 251 size_t servsize; 252 time_t now; 253 254 REQUIRE(NULL != node); 255 if (NULL != hints) { 256 REQUIRE(0 == hints->ai_addrlen); 257 REQUIRE(NULL == hints->ai_addr); 258 REQUIRE(NULL == hints->ai_canonname); 259 REQUIRE(NULL == hints->ai_next); 260 } 261 262 idx = get_dnschild_ctx(); 263 child_ctx = dnschild_contexts[idx]; 264 265 nodesize = strlen(node) + 1; 266 servsize = strlen(service) + 1; 267 req_size = sizeof(*gai_req) + nodesize + servsize; 268 269 gai_req = emalloc_zero(req_size); 270 271 gai_req->octets = req_size; 272 gai_req->dns_idx = idx; 273 now = time(NULL); 274 gai_req->scheduled = now; 275 gai_req->earliest = max(now, child_ctx->next_dns_timeslot); 276 child_ctx->next_dns_timeslot = gai_req->earliest; 277 if (hints != NULL) 278 gai_req->hints = *hints; 279 gai_req->retry = retry; 280 gai_req->callback = callback; 281 gai_req->context = context; 282 gai_req->nodesize = nodesize; 283 gai_req->servsize = servsize; 284 285 memcpy((char *)gai_req + sizeof(*gai_req), node, nodesize); 286 memcpy((char *)gai_req + sizeof(*gai_req) + nodesize, service, 287 servsize); 288 289 if (queue_blocking_request( 290 BLOCKING_GETADDRINFO, 291 gai_req, 292 req_size, 293 &getaddrinfo_sometime_complete, 294 gai_req)) { 295 296 msyslog(LOG_ERR, "unable to queue getaddrinfo request"); 297 errno = EFAULT; 298 return -1; 299 } 300 301 return 0; 302 } 303 304 int 305 blocking_getaddrinfo( 306 blocking_child * c, 307 blocking_pipe_header * req 308 ) 309 { 310 blocking_gai_req * gai_req; 311 dnsworker_ctx * worker_ctx; 312 blocking_pipe_header * resp; 313 blocking_gai_resp * gai_resp; 314 char * node; 315 char * service; 316 struct addrinfo * ai_res; 317 struct addrinfo * ai; 318 struct addrinfo * serialized_ai; 319 size_t canons_octets; 320 size_t this_octets; 321 size_t resp_octets; 322 char * cp; 323 time_t time_now; 324 325 gai_req = (void *)((char *)req + sizeof(*req)); 326 node = (char *)gai_req + sizeof(*gai_req); 327 service = node + gai_req->nodesize; 328 329 worker_ctx = get_worker_context(c, gai_req->dns_idx); 330 scheduled_sleep(gai_req->scheduled, gai_req->earliest, 331 worker_ctx); 332 reload_resolv_conf(worker_ctx); 333 334 /* 335 * Take a shot at the final size, better to overestimate 336 * at first and then realloc to a smaller size. 337 */ 338 339 resp_octets = sizeof(*resp) + sizeof(*gai_resp) + 340 16 * (sizeof(struct addrinfo) + 341 sizeof(sockaddr_u)) + 342 256; 343 resp = emalloc_zero(resp_octets); 344 gai_resp = (void *)(resp + 1); 345 346 TRACE(2, ("blocking_getaddrinfo given node %s serv %s fam %d flags %x\n", 347 node, service, gai_req->hints.ai_family, 348 gai_req->hints.ai_flags)); 349 #ifdef DEBUG 350 if (debug >= 2) 351 fflush(stdout); 352 #endif 353 ai_res = NULL; 354 gai_resp->retcode = getaddrinfo(node, service, &gai_req->hints, 355 &ai_res); 356 gai_resp->retry = gai_req->retry; 357 #ifdef EAI_SYSTEM 358 if (EAI_SYSTEM == gai_resp->retcode) 359 gai_resp->gai_errno = errno; 360 #endif 361 canons_octets = 0; 362 363 if (0 == gai_resp->retcode) { 364 ai = ai_res; 365 while (NULL != ai) { 366 gai_resp->ai_count++; 367 if (ai->ai_canonname) 368 canons_octets += strlen(ai->ai_canonname) + 1; 369 ai = ai->ai_next; 370 } 371 /* 372 * If this query succeeded only after retrying, DNS may have 373 * just become responsive. Ignore previously-scheduled 374 * retry sleeps once for each pending request, similar to 375 * the way scheduled_sleep() does when its worker_sleep() 376 * is interrupted. 377 */ 378 if (gai_resp->retry > INITIAL_DNS_RETRY) { 379 time_now = time(NULL); 380 worker_ctx->ignore_scheduled_before = time_now; 381 TRACE(1, ("DNS success after retry, ignoring sleeps scheduled before now (%s)\n", 382 humantime(time_now))); 383 } 384 } 385 386 /* 387 * Our response consists of a header, followed by ai_count 388 * addrinfo structs followed by ai_count sockaddr_storage 389 * structs followed by the canonical names. 390 */ 391 gai_resp->octets = sizeof(*gai_resp) 392 + gai_resp->ai_count 393 * (sizeof(gai_req->hints) 394 + sizeof(sockaddr_u)) 395 + canons_octets; 396 397 resp_octets = sizeof(*resp) + gai_resp->octets; 398 resp = erealloc(resp, resp_octets); 399 gai_resp = (void *)(resp + 1); 400 401 /* cp serves as our current pointer while serializing */ 402 cp = (void *)(gai_resp + 1); 403 canons_octets = 0; 404 405 if (0 == gai_resp->retcode) { 406 ai = ai_res; 407 while (NULL != ai) { 408 memcpy(cp, ai, sizeof(*ai)); 409 serialized_ai = (void *)cp; 410 cp += sizeof(*ai); 411 412 /* transform ai_canonname into offset */ 413 if (NULL != serialized_ai->ai_canonname) { 414 serialized_ai->ai_canonname = (char *)canons_octets; 415 canons_octets += strlen(ai->ai_canonname) + 1; 416 } 417 418 /* leave fixup of ai_addr pointer for receiver */ 419 420 ai = ai->ai_next; 421 } 422 423 ai = ai_res; 424 while (NULL != ai) { 425 INSIST(ai->ai_addrlen <= sizeof(sockaddr_u)); 426 memcpy(cp, ai->ai_addr, ai->ai_addrlen); 427 cp += sizeof(sockaddr_u); 428 429 ai = ai->ai_next; 430 } 431 432 ai = ai_res; 433 while (NULL != ai) { 434 if (NULL != ai->ai_canonname) { 435 this_octets = strlen(ai->ai_canonname) + 1; 436 memcpy(cp, ai->ai_canonname, this_octets); 437 cp += this_octets; 438 } 439 440 ai = ai->ai_next; 441 } 442 freeaddrinfo(ai_res); 443 } 444 445 /* 446 * make sure our walk and earlier calc match 447 */ 448 DEBUG_INSIST((size_t)(cp - (char *)resp) == resp_octets); 449 450 if (queue_blocking_response(c, resp, resp_octets, req)) { 451 msyslog(LOG_ERR, "blocking_getaddrinfo can not queue response"); 452 return -1; 453 } 454 455 return 0; 456 } 457 458 459 static void 460 getaddrinfo_sometime_complete( 461 blocking_work_req rtype, 462 void * context, 463 size_t respsize, 464 void * resp 465 ) 466 { 467 blocking_gai_req * gai_req; 468 blocking_gai_resp * gai_resp; 469 dnschild_ctx * child_ctx; 470 struct addrinfo * ai; 471 struct addrinfo * next_ai; 472 sockaddr_u * psau; 473 char * node; 474 char * service; 475 char * canon_start; 476 time_t time_now; 477 int again; 478 int af; 479 const char * fam_spec; 480 int i; 481 482 gai_req = context; 483 gai_resp = resp; 484 485 DEBUG_REQUIRE(BLOCKING_GETADDRINFO == rtype); 486 DEBUG_REQUIRE(respsize == gai_resp->octets); 487 488 node = (char *)gai_req + sizeof(*gai_req); 489 service = node + gai_req->nodesize; 490 491 child_ctx = dnschild_contexts[gai_req->dns_idx]; 492 493 if (0 == gai_resp->retcode) { 494 /* 495 * If this query succeeded only after retrying, DNS may have 496 * just become responsive. 497 */ 498 if (gai_resp->retry > INITIAL_DNS_RETRY) { 499 time_now = time(NULL); 500 child_ctx->next_dns_timeslot = time_now; 501 TRACE(1, ("DNS success after retry, %u next_dns_timeslot reset (%s)\n", 502 gai_req->dns_idx, humantime(time_now))); 503 } 504 } else { 505 again = should_retry_dns(gai_resp->retcode, 506 gai_resp->gai_errno); 507 /* 508 * exponential backoff of DNS retries to 64s 509 */ 510 if (gai_req->retry > 0 && again) { 511 /* log the first retry only */ 512 if (INITIAL_DNS_RETRY == gai_req->retry) 513 NLOG(NLOG_SYSINFO) { 514 af = gai_req->hints.ai_family; 515 fam_spec = (AF_INET6 == af) 516 ? " (AAAA)" 517 : (AF_INET == af) 518 ? " (A)" 519 : ""; 520 #ifdef EAI_SYSTEM 521 if (EAI_SYSTEM == gai_resp->retcode) { 522 errno = gai_resp->gai_errno; 523 msyslog(LOG_INFO, 524 "retrying DNS %s%s: EAI_SYSTEM %d: %m", 525 node, fam_spec, 526 gai_resp->gai_errno); 527 } else 528 #endif 529 msyslog(LOG_INFO, 530 "retrying DNS %s%s: %s (%d)", 531 node, fam_spec, 532 gai_strerror(gai_resp->retcode), 533 gai_resp->retcode); 534 } 535 manage_dns_retry_interval(&gai_req->scheduled, 536 &gai_req->earliest, &gai_req->retry, 537 &child_ctx->next_dns_timeslot); 538 if (!queue_blocking_request( 539 BLOCKING_GETADDRINFO, 540 gai_req, 541 gai_req->octets, 542 &getaddrinfo_sometime_complete, 543 gai_req)) 544 return; 545 else 546 msyslog(LOG_ERR, 547 "unable to retry hostname %s", 548 node); 549 } 550 } 551 552 /* 553 * fixup pointers in returned addrinfo array 554 */ 555 ai = (void *)((char *)gai_resp + sizeof(*gai_resp)); 556 next_ai = NULL; 557 for (i = gai_resp->ai_count - 1; i >= 0; i--) { 558 ai[i].ai_next = next_ai; 559 next_ai = &ai[i]; 560 } 561 562 psau = (void *)((char *)ai + gai_resp->ai_count * sizeof(*ai)); 563 canon_start = (char *)psau + gai_resp->ai_count * sizeof(*psau); 564 565 for (i = 0; i < gai_resp->ai_count; i++) { 566 if (NULL != ai[i].ai_addr) 567 ai[i].ai_addr = &psau->sa; 568 psau++; 569 if (NULL != ai[i].ai_canonname) 570 ai[i].ai_canonname += (size_t)canon_start; 571 } 572 573 ENSURE((char *)psau == canon_start); 574 575 if (!gai_resp->ai_count) 576 ai = NULL; 577 578 (*gai_req->callback)(gai_resp->retcode, gai_resp->gai_errno, 579 gai_req->context, node, service, 580 &gai_req->hints, ai); 581 582 free(gai_req); 583 /* gai_resp is part of block freed by process_blocking_resp() */ 584 } 585 586 587 #ifdef TEST_BLOCKING_WORKER 588 void gai_test_callback(int rescode, int gai_errno, void *context, const char *name, const char *service, const struct addrinfo *hints, const struct addrinfo *ai_res) 589 { 590 sockaddr_u addr; 591 592 if (rescode) { 593 TRACE(1, ("gai_test_callback context %p error rescode %d %s serv %s\n", 594 context, rescode, name, service)); 595 return; 596 } 597 while (!rescode && NULL != ai_res) { 598 ZERO_SOCK(&addr); 599 memcpy(&addr, ai_res->ai_addr, ai_res->ai_addrlen); 600 TRACE(1, ("ctx %p fam %d addr %s canon '%s' type %s at %p ai_addr %p ai_next %p\n", 601 context, 602 AF(&addr), 603 stoa(&addr), 604 (ai_res->ai_canonname) 605 ? ai_res->ai_canonname 606 : "", 607 (SOCK_DGRAM == ai_res->ai_socktype) 608 ? "DGRAM" 609 : (SOCK_STREAM == ai_res->ai_socktype) 610 ? "STREAM" 611 : "(other)", 612 ai_res, 613 ai_res->ai_addr, 614 ai_res->ai_next)); 615 616 getnameinfo_sometime((sockaddr_u *)ai_res->ai_addr, 128, 32, 0, gni_test_callback, context); 617 618 ai_res = ai_res->ai_next; 619 } 620 } 621 #endif /* TEST_BLOCKING_WORKER */ 622 623 624 int 625 getnameinfo_sometime( 626 sockaddr_u * psau, 627 size_t hostoctets, 628 size_t servoctets, 629 int flags, 630 gni_sometime_callback callback, 631 void * context 632 ) 633 { 634 blocking_gni_req * gni_req; 635 u_int idx; 636 dnschild_ctx * child_ctx; 637 time_t time_now; 638 639 REQUIRE(hostoctets); 640 REQUIRE(hostoctets + servoctets < 1024); 641 642 idx = get_dnschild_ctx(); 643 child_ctx = dnschild_contexts[idx]; 644 645 gni_req = emalloc_zero(sizeof(*gni_req)); 646 647 gni_req->octets = sizeof(*gni_req); 648 gni_req->dns_idx = idx; 649 time_now = time(NULL); 650 gni_req->scheduled = time_now; 651 gni_req->earliest = max(time_now, child_ctx->next_dns_timeslot); 652 child_ctx->next_dns_timeslot = gni_req->earliest; 653 memcpy(&gni_req->socku, psau, SOCKLEN(psau)); 654 gni_req->hostoctets = hostoctets; 655 gni_req->servoctets = servoctets; 656 gni_req->flags = flags; 657 gni_req->retry = INITIAL_DNS_RETRY; 658 gni_req->callback = callback; 659 gni_req->context = context; 660 661 if (queue_blocking_request( 662 BLOCKING_GETNAMEINFO, 663 gni_req, 664 sizeof(*gni_req), 665 &getnameinfo_sometime_complete, 666 gni_req)) { 667 668 msyslog(LOG_ERR, "unable to queue getnameinfo request"); 669 errno = EFAULT; 670 return -1; 671 } 672 673 return 0; 674 } 675 676 677 int 678 blocking_getnameinfo( 679 blocking_child * c, 680 blocking_pipe_header * req 681 ) 682 { 683 blocking_gni_req * gni_req; 684 dnsworker_ctx * worker_ctx; 685 blocking_pipe_header * resp; 686 blocking_gni_resp * gni_resp; 687 size_t octets; 688 size_t resp_octets; 689 char * service; 690 char * cp; 691 int rc; 692 time_t time_now; 693 char host[1024]; 694 695 gni_req = (void *)((char *)req + sizeof(*req)); 696 697 octets = gni_req->hostoctets + gni_req->servoctets; 698 699 /* 700 * Some alloca() implementations are fragile regarding 701 * large allocations. We only need room for the host 702 * and service names. 703 */ 704 REQUIRE(octets < sizeof(host)); 705 service = host + gni_req->hostoctets; 706 707 worker_ctx = get_worker_context(c, gni_req->dns_idx); 708 scheduled_sleep(gni_req->scheduled, gni_req->earliest, 709 worker_ctx); 710 reload_resolv_conf(worker_ctx); 711 712 /* 713 * Take a shot at the final size, better to overestimate 714 * then realloc to a smaller size. 715 */ 716 717 resp_octets = sizeof(*resp) + sizeof(*gni_resp) + octets; 718 resp = emalloc_zero(resp_octets); 719 gni_resp = (void *)((char *)resp + sizeof(*resp)); 720 721 TRACE(2, ("blocking_getnameinfo given addr %s flags 0x%x hostlen %lu servlen %lu\n", 722 stoa(&gni_req->socku), gni_req->flags, 723 (u_long)gni_req->hostoctets, (u_long)gni_req->servoctets)); 724 725 gni_resp->retcode = getnameinfo(&gni_req->socku.sa, 726 SOCKLEN(&gni_req->socku), 727 host, 728 gni_req->hostoctets, 729 service, 730 gni_req->servoctets, 731 gni_req->flags); 732 gni_resp->retry = gni_req->retry; 733 #ifdef EAI_SYSTEM 734 if (EAI_SYSTEM == gni_resp->retcode) 735 gni_resp->gni_errno = errno; 736 #endif 737 738 if (0 != gni_resp->retcode) { 739 gni_resp->hostoctets = 0; 740 gni_resp->servoctets = 0; 741 } else { 742 gni_resp->hostoctets = strlen(host) + 1; 743 gni_resp->servoctets = strlen(service) + 1; 744 /* 745 * If this query succeeded only after retrying, DNS may have 746 * just become responsive. Ignore previously-scheduled 747 * retry sleeps once for each pending request, similar to 748 * the way scheduled_sleep() does when its worker_sleep() 749 * is interrupted. 750 */ 751 if (gni_req->retry > INITIAL_DNS_RETRY) { 752 time_now = time(NULL); 753 worker_ctx->ignore_scheduled_before = time_now; 754 TRACE(1, ("DNS success after retrying, ignoring sleeps scheduled before now (%s)\n", 755 humantime(time_now))); 756 } 757 } 758 octets = gni_resp->hostoctets + gni_resp->servoctets; 759 /* 760 * Our response consists of a header, followed by the host and 761 * service strings, each null-terminated. 762 */ 763 resp_octets = sizeof(*resp) + sizeof(*gni_resp) + octets; 764 765 resp = erealloc(resp, resp_octets); 766 gni_resp = (void *)(resp + 1); 767 768 gni_resp->octets = sizeof(*gni_resp) + octets; 769 770 /* cp serves as our current pointer while serializing */ 771 cp = (void *)(gni_resp + 1); 772 773 if (0 == gni_resp->retcode) { 774 memcpy(cp, host, gni_resp->hostoctets); 775 cp += gni_resp->hostoctets; 776 memcpy(cp, service, gni_resp->servoctets); 777 cp += gni_resp->servoctets; 778 } 779 780 INSIST((size_t)(cp - (char *)resp) == resp_octets); 781 INSIST(resp_octets - sizeof(*resp) == gni_resp->octets); 782 783 rc = queue_blocking_response(c, resp, resp_octets, req); 784 if (rc) 785 msyslog(LOG_ERR, "blocking_getnameinfo unable to queue response"); 786 return rc; 787 } 788 789 790 static void 791 getnameinfo_sometime_complete( 792 blocking_work_req rtype, 793 void * context, 794 size_t respsize, 795 void * resp 796 ) 797 { 798 blocking_gni_req * gni_req; 799 blocking_gni_resp * gni_resp; 800 dnschild_ctx * child_ctx; 801 char * host; 802 char * service; 803 time_t time_now; 804 int again; 805 806 gni_req = context; 807 gni_resp = resp; 808 809 DEBUG_REQUIRE(BLOCKING_GETNAMEINFO == rtype); 810 DEBUG_REQUIRE(respsize == gni_resp->octets); 811 812 child_ctx = dnschild_contexts[gni_req->dns_idx]; 813 814 if (0 == gni_resp->retcode) { 815 /* 816 * If this query succeeded only after retrying, DNS may have 817 * just become responsive. 818 */ 819 if (gni_resp->retry > INITIAL_DNS_RETRY) { 820 time_now = time(NULL); 821 child_ctx->next_dns_timeslot = time_now; 822 TRACE(1, ("DNS success after retry, %u next_dns_timeslot reset (%s)\n", 823 gni_req->dns_idx, humantime(time_now))); 824 } 825 } else { 826 again = should_retry_dns(gni_resp->retcode, gni_resp->gni_errno); 827 /* 828 * exponential backoff of DNS retries to 64s 829 */ 830 if (gni_req->retry > 0) 831 manage_dns_retry_interval(&gni_req->scheduled, 832 &gni_req->earliest, &gni_req->retry, 833 &child_ctx->next_dns_timeslot); 834 835 if (gni_req->retry > 0 && again) { 836 if (!queue_blocking_request( 837 BLOCKING_GETNAMEINFO, 838 gni_req, 839 gni_req->octets, 840 &getnameinfo_sometime_complete, 841 gni_req)) 842 return; 843 844 msyslog(LOG_ERR, "unable to retry reverse lookup of %s", stoa(&gni_req->socku)); 845 } 846 } 847 848 if (!gni_resp->hostoctets) { 849 host = NULL; 850 service = NULL; 851 } else { 852 host = (char *)gni_resp + sizeof(*gni_resp); 853 service = (gni_resp->servoctets) 854 ? host + gni_resp->hostoctets 855 : NULL; 856 } 857 858 (*gni_req->callback)(gni_resp->retcode, gni_resp->gni_errno, 859 &gni_req->socku, gni_req->flags, host, 860 service, gni_req->context); 861 862 free(gni_req); 863 /* gni_resp is part of block freed by process_blocking_resp() */ 864 } 865 866 867 #ifdef TEST_BLOCKING_WORKER 868 void gni_test_callback(int rescode, int gni_errno, sockaddr_u *psau, int flags, const char *host, const char *service, void *context) 869 { 870 if (!rescode) 871 TRACE(1, ("gni_test_callback got host '%s' serv '%s' for addr %s context %p\n", 872 host, service, stoa(psau), context)); 873 else 874 TRACE(1, ("gni_test_callback context %p rescode %d gni_errno %d flags 0x%x addr %s\n", 875 context, rescode, gni_errno, flags, stoa(psau))); 876 } 877 #endif /* TEST_BLOCKING_WORKER */ 878 879 880 #ifdef HAVE_RES_INIT 881 static void 882 reload_resolv_conf( 883 dnsworker_ctx * worker_ctx 884 ) 885 { 886 time_t time_now; 887 888 /* 889 * This is ad-hoc. Reload /etc/resolv.conf once per minute 890 * to pick up on changes from the DHCP client. [Bug 1226] 891 * When using threads for the workers, this needs to happen 892 * only once per minute process-wide. 893 */ 894 time_now = time(NULL); 895 # ifdef WORK_THREAD 896 worker_ctx->next_res_init = next_res_init; 897 # endif 898 if (worker_ctx->next_res_init <= time_now) { 899 if (worker_ctx->next_res_init != 0) 900 res_init(); 901 worker_ctx->next_res_init = time_now + 60; 902 # ifdef WORK_THREAD 903 next_res_init = worker_ctx->next_res_init; 904 # endif 905 } 906 } 907 #endif /* HAVE_RES_INIT */ 908 909 910 static u_int 911 reserve_dnschild_ctx(void) 912 { 913 const size_t ps = sizeof(dnschild_contexts[0]); 914 const size_t cs = sizeof(*dnschild_contexts[0]); 915 u_int c; 916 u_int new_alloc; 917 size_t octets; 918 size_t new_octets; 919 920 c = 0; 921 while (TRUE) { 922 for ( ; c < dnschild_contexts_alloc; c++) { 923 if (NULL == dnschild_contexts[c]) { 924 dnschild_contexts[c] = emalloc_zero(cs); 925 926 return c; 927 } 928 } 929 new_alloc = dnschild_contexts_alloc + 20; 930 new_octets = new_alloc * ps; 931 octets = dnschild_contexts_alloc * ps; 932 dnschild_contexts = erealloc_zero(dnschild_contexts, 933 new_octets, octets); 934 dnschild_contexts_alloc = new_alloc; 935 } 936 } 937 938 939 static u_int 940 get_dnschild_ctx(void) 941 { 942 static u_int shared_ctx = UINT_MAX; 943 944 if (worker_per_query) 945 return reserve_dnschild_ctx(); 946 947 if (UINT_MAX == shared_ctx) 948 shared_ctx = reserve_dnschild_ctx(); 949 950 return shared_ctx; 951 } 952 953 954 static void 955 alloc_dnsworker_context( 956 u_int idx 957 ) 958 { 959 const size_t worker_context_sz = sizeof(*dnsworker_contexts[0]); 960 961 REQUIRE(NULL == dnsworker_contexts[idx]); 962 dnsworker_contexts[idx] = emalloc_zero(worker_context_sz); 963 } 964 965 966 static dnsworker_ctx * 967 get_worker_context( 968 blocking_child * c, 969 u_int idx 970 ) 971 { 972 static size_t ps = sizeof(dnsworker_contexts[0]); 973 u_int min_new_alloc; 974 u_int new_alloc; 975 size_t octets; 976 size_t new_octets; 977 978 if (dnsworker_contexts_alloc <= idx) { 979 min_new_alloc = 1 + idx; 980 /* round new_alloc up to nearest multiple of 4 */ 981 new_alloc = (min_new_alloc + 4) & ~(4 - 1); 982 new_octets = new_alloc * ps; 983 octets = dnsworker_contexts_alloc * ps; 984 dnsworker_contexts = erealloc_zero(dnsworker_contexts, 985 new_octets, octets); 986 dnsworker_contexts_alloc = new_alloc; 987 } 988 989 if (NULL == dnsworker_contexts[idx]) 990 alloc_dnsworker_context(idx); 991 ZERO(*dnsworker_contexts[idx]); 992 dnsworker_contexts[idx]->c = c; 993 994 return dnsworker_contexts[idx]; 995 } 996 997 998 static void 999 scheduled_sleep( 1000 time_t scheduled, 1001 time_t earliest, 1002 dnsworker_ctx * worker_ctx 1003 ) 1004 { 1005 time_t now; 1006 1007 if (scheduled < worker_ctx->ignore_scheduled_before) { 1008 TRACE(1, ("ignoring sleep until %s scheduled at %s (before %s)\n", 1009 humantime(earliest), humantime(scheduled), 1010 humantime(worker_ctx->ignore_scheduled_before))); 1011 return; 1012 } 1013 1014 now = time(NULL); 1015 1016 if (now < earliest) { 1017 TRACE(1, ("sleep until %s scheduled at %s (>= %s)\n", 1018 humantime(earliest), humantime(scheduled), 1019 humantime(worker_ctx->ignore_scheduled_before))); 1020 if (-1 == worker_sleep(worker_ctx->c, earliest - now)) { 1021 /* our sleep was interrupted */ 1022 now = time(NULL); 1023 worker_ctx->ignore_scheduled_before = now; 1024 #ifdef HAVE_RES_INIT 1025 worker_ctx->next_res_init = now + 60; 1026 next_res_init = worker_ctx->next_res_init; 1027 res_init(); 1028 #endif 1029 TRACE(1, ("sleep interrupted by daemon, ignoring sleeps scheduled before now (%s)\n", 1030 humantime(worker_ctx->ignore_scheduled_before))); 1031 } 1032 } 1033 } 1034 1035 1036 /* 1037 * manage_dns_retry_interval is a helper used by 1038 * getaddrinfo_sometime_complete and getnameinfo_sometime_complete 1039 * to calculate the new retry interval and schedule the next query. 1040 */ 1041 static void 1042 manage_dns_retry_interval( 1043 time_t * pscheduled, 1044 time_t * pwhen, 1045 int * pretry, 1046 time_t * pnext_timeslot 1047 ) 1048 { 1049 time_t now; 1050 time_t when; 1051 int retry; 1052 1053 now = time(NULL); 1054 retry = *pretry; 1055 when = max(now + retry, *pnext_timeslot); 1056 *pnext_timeslot = when; 1057 retry = min(64, retry << 1); 1058 1059 *pscheduled = now; 1060 *pwhen = when; 1061 *pretry = retry; 1062 } 1063 1064 /* 1065 * should_retry_dns is a helper used by getaddrinfo_sometime_complete 1066 * and getnameinfo_sometime_complete which implements ntpd's DNS retry 1067 * policy. 1068 */ 1069 static int 1070 should_retry_dns( 1071 int rescode, 1072 int res_errno 1073 ) 1074 { 1075 static int eai_again_seen; 1076 int again; 1077 #if defined (EAI_SYSTEM) && defined(DEBUG) 1078 char msg[256]; 1079 #endif 1080 1081 /* 1082 * If the resolver failed, see if the failure is 1083 * temporary. If so, return success. 1084 */ 1085 again = 0; 1086 1087 switch (rescode) { 1088 1089 case EAI_FAIL: 1090 again = 1; 1091 break; 1092 1093 case EAI_AGAIN: 1094 again = 1; 1095 eai_again_seen = 1; /* [Bug 1178] */ 1096 break; 1097 1098 case EAI_NONAME: 1099 #if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) 1100 case EAI_NODATA: 1101 #endif 1102 again = !eai_again_seen; /* [Bug 1178] */ 1103 break; 1104 1105 #ifdef EAI_SYSTEM 1106 case EAI_SYSTEM: 1107 /* 1108 * EAI_SYSTEM means the real error is in errno. We should be more 1109 * discriminating about which errno values require retrying, but 1110 * this matches existing behavior. 1111 */ 1112 again = 1; 1113 # ifdef DEBUG 1114 errno_to_str(res_errno, msg, sizeof(msg)); 1115 TRACE(1, ("intres: EAI_SYSTEM errno %d (%s) means try again, right?\n", 1116 res_errno, msg)); 1117 # endif 1118 break; 1119 #endif 1120 } 1121 1122 TRACE(2, ("intres: resolver returned: %s (%d), %sretrying\n", 1123 gai_strerror(rescode), rescode, again ? "" : "not ")); 1124 1125 return again; 1126 } 1127 1128 #else /* !WORKER follows */ 1129 int ntp_intres_nonempty_compilation_unit; 1130 #endif 1131