1*f1b790a5Sclaudio /* $OpenBSD: ntp_dns.c,v 1.36 2024/11/21 13:38:14 claudio Exp $ */ 25f5af31aShenning 35f5af31aShenning /* 45f5af31aShenning * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org> 55f5af31aShenning * 65f5af31aShenning * Permission to use, copy, modify, and distribute this software for any 75f5af31aShenning * purpose with or without fee is hereby granted, provided that the above 85f5af31aShenning * copyright notice and this permission notice appear in all copies. 95f5af31aShenning * 105f5af31aShenning * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 115f5af31aShenning * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 125f5af31aShenning * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 135f5af31aShenning * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14774da4d1Sreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15774da4d1Sreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16774da4d1Sreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 175f5af31aShenning */ 185f5af31aShenning 1961f07045Sderaadt #include <sys/types.h> 20832033eaSdtucker #include <sys/resource.h> 215f5af31aShenning #include <sys/time.h> 2271ba36b6Sotto #include <netinet/in.h> 2371ba36b6Sotto #include <arpa/nameser.h> 2471ba36b6Sotto #include <resolv.h> 25832033eaSdtucker 26832033eaSdtucker #include <err.h> 275f5af31aShenning #include <errno.h> 285f5af31aShenning #include <poll.h> 2965d995a8Sderaadt #include <fcntl.h> 305f5af31aShenning #include <signal.h> 315f5af31aShenning #include <stdlib.h> 325f5af31aShenning #include <string.h> 33579813e4Sreyk #include <syslog.h> 345f5af31aShenning #include <unistd.h> 355f5af31aShenning 365f5af31aShenning #include "ntpd.h" 375f5af31aShenning 385f5af31aShenning volatile sig_atomic_t quit_dns = 0; 396fe90a5aSotto static struct imsgbuf *ibuf_dns; 40911793feSotto extern int non_numeric; 415f5af31aShenning 425f5af31aShenning void sighdlr_dns(int); 43c9addb91Sotto int dns_dispatch_imsg(struct ntpd_conf *); 4471ba36b6Sotto int probe_root_ns(void); 4571ba36b6Sotto void probe_root(void); 465f5af31aShenning 475f5af31aShenning void 485f5af31aShenning sighdlr_dns(int sig) 495f5af31aShenning { 505f5af31aShenning switch (sig) { 515f5af31aShenning case SIGTERM: 525f5af31aShenning case SIGINT: 535f5af31aShenning quit_dns = 1; 545f5af31aShenning break; 555f5af31aShenning } 565f5af31aShenning } 575f5af31aShenning 584e840e7aSrzalamena void 594e840e7aSrzalamena ntp_dns(struct ntpd_conf *nconf, struct passwd *pw) 605f5af31aShenning { 615f5af31aShenning struct pollfd pfd[1]; 6265d995a8Sderaadt int nfds, nullfd; 635f5af31aShenning 64b98b0a5cSotto res_init(); 65832033eaSdtucker if (setpriority(PRIO_PROCESS, 0, 0) == -1) 66579813e4Sreyk log_warn("could not set priority"); 67832033eaSdtucker 688d2ac903Sotto log_init(nconf->debug ? LOG_TO_STDERR : LOG_TO_SYSLOG, nconf->verbose, 698d2ac903Sotto LOG_DAEMON); 70c9addb91Sotto if (!nconf->debug && setsid() == -1) 715f5af31aShenning fatal("setsid"); 72579813e4Sreyk log_procinit("dns"); 735f5af31aShenning 74b7041c07Sderaadt if ((nullfd = open("/dev/null", O_RDWR)) == -1) 7565d995a8Sderaadt fatal(NULL); 7665d995a8Sderaadt 7765d995a8Sderaadt if (!nconf->debug) { 7865d995a8Sderaadt dup2(nullfd, STDIN_FILENO); 7965d995a8Sderaadt dup2(nullfd, STDOUT_FILENO); 8065d995a8Sderaadt dup2(nullfd, STDERR_FILENO); 8165d995a8Sderaadt } 8265d995a8Sderaadt close(nullfd); 8365d995a8Sderaadt 845f5af31aShenning setproctitle("dns engine"); 85579813e4Sreyk 865f5af31aShenning if (setgroups(1, &pw->pw_gid) || 875f5af31aShenning setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 885f5af31aShenning setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 895f5af31aShenning fatal("can't drop privileges"); 905f5af31aShenning 915f5af31aShenning signal(SIGTERM, sighdlr_dns); 925f5af31aShenning signal(SIGINT, sighdlr_dns); 93892d8569Shenning signal(SIGHUP, SIG_IGN); 945f5af31aShenning 955f5af31aShenning if ((ibuf_dns = malloc(sizeof(struct imsgbuf))) == NULL) 965f5af31aShenning fatal(NULL); 97*f1b790a5Sclaudio if (imsgbuf_init(ibuf_dns, PARENT_SOCK_FILENO) == -1) 98*f1b790a5Sclaudio fatal(NULL); 995f5af31aShenning 100b5b9767fSderaadt if (pledge("stdio dns", NULL) == -1) 1010bd1216cSderaadt err(1, "pledge"); 1022a8590bcSderaadt 103911793feSotto if (non_numeric) 10471ba36b6Sotto probe_root(); 105911793feSotto else 106911793feSotto log_debug("all addresses numeric, no dns probe"); 10771ba36b6Sotto 1085f5af31aShenning while (quit_dns == 0) { 1095f5af31aShenning pfd[0].fd = ibuf_dns->fd; 1105f5af31aShenning pfd[0].events = POLLIN; 11131be28caSclaudio if (imsgbuf_queuelen(ibuf_dns) > 0) 1125f5af31aShenning pfd[0].events |= POLLOUT; 1135f5af31aShenning 1145f5af31aShenning if ((nfds = poll(pfd, 1, INFTIM)) == -1) 1155f5af31aShenning if (errno != EINTR) { 1165f5af31aShenning log_warn("poll error"); 1175f5af31aShenning quit_dns = 1; 1185f5af31aShenning } 1195f5af31aShenning 1205f5af31aShenning if (nfds > 0 && (pfd[0].revents & POLLOUT)) 121dd7efffeSclaudio if (imsgbuf_write(ibuf_dns) == -1) { 1225f5af31aShenning log_warn("pipe write error (to ntp engine)"); 1235f5af31aShenning quit_dns = 1; 1245f5af31aShenning } 1255f5af31aShenning 1265f5af31aShenning if (nfds > 0 && pfd[0].revents & POLLIN) { 1275f5af31aShenning nfds--; 128c9addb91Sotto if (dns_dispatch_imsg(nconf) == -1) 1295f5af31aShenning quit_dns = 1; 1305f5af31aShenning } 1315f5af31aShenning } 1325f5af31aShenning 1339cbf9e90Sclaudio imsgbuf_clear(ibuf_dns); 1345f5af31aShenning free(ibuf_dns); 1354e840e7aSrzalamena exit(0); 1365f5af31aShenning } 1375f5af31aShenning 1385f5af31aShenning int 139c9addb91Sotto dns_dispatch_imsg(struct ntpd_conf *nconf) 1405f5af31aShenning { 1415f5af31aShenning struct imsg imsg; 1425f5af31aShenning int n, cnt; 1435f5af31aShenning char *name; 1445f5af31aShenning struct ntp_addr *h, *hn; 145e39620e5Snicm struct ibuf *buf; 146b775b3eeSreyk const char *str; 1474ffc0b90Sotto size_t len; 1485f5af31aShenning 149f6bd242eSclaudio if (imsgbuf_read(ibuf_dns) != 1) 1505f5af31aShenning return (-1); 1515f5af31aShenning 1525f5af31aShenning for (;;) { 1535f5af31aShenning if ((n = imsg_get(ibuf_dns, &imsg)) == -1) 1545f5af31aShenning return (-1); 1555f5af31aShenning 1565f5af31aShenning if (n == 0) 1575f5af31aShenning break; 1585f5af31aShenning 1595f5af31aShenning switch (imsg.hdr.type) { 1605f5af31aShenning case IMSG_HOST_DNS: 161b775b3eeSreyk case IMSG_CONSTRAINT_DNS: 162b775b3eeSreyk if (imsg.hdr.type == IMSG_HOST_DNS) 163b775b3eeSreyk str = "IMSG_HOST_DNS"; 164b775b3eeSreyk else 165b775b3eeSreyk str = "IMSG_CONSTRAINT_DNS"; 1665f5af31aShenning name = imsg.data; 1675f5af31aShenning if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE) 168b775b3eeSreyk fatalx("invalid %s received", str); 1694ffc0b90Sotto len = imsg.hdr.len - 1 - IMSG_HEADER_SIZE; 1704ffc0b90Sotto if (name[len] != '\0' || 1714ffc0b90Sotto strlen(name) != len) 172b775b3eeSreyk fatalx("invalid %s received", str); 173c9addb91Sotto if ((cnt = host_dns(name, nconf->status.synced, 174c9addb91Sotto &hn)) == -1) 1755f5af31aShenning break; 176b775b3eeSreyk buf = imsg_create(ibuf_dns, imsg.hdr.type, 1775f5af31aShenning imsg.hdr.peerid, 0, 178b98b0a5cSotto cnt * (sizeof(struct sockaddr_storage) + sizeof(int))); 179c0cb3bf1Sbcook if (cnt > 0) { 180c0cb3bf1Sbcook if (buf) { 181b98b0a5cSotto for (h = hn; h != NULL; h = h->next) { 182c0cb3bf1Sbcook if (imsg_add(buf, &h->ss, 183c0cb3bf1Sbcook sizeof(h->ss)) == -1) { 184c0cb3bf1Sbcook buf = NULL; 185c0cb3bf1Sbcook break; 186c0cb3bf1Sbcook } 187b98b0a5cSotto if (imsg_add(buf, &h->notauth, 188b98b0a5cSotto sizeof(int)) == -1) { 189b98b0a5cSotto buf = NULL; 190b98b0a5cSotto break; 191b98b0a5cSotto } 192b98b0a5cSotto } 193c0cb3bf1Sbcook } 194c0cb3bf1Sbcook host_dns_free(hn); 195c0cb3bf1Sbcook hn = NULL; 196c0cb3bf1Sbcook } 19744624868Sbcook if (buf) 19844624868Sbcook imsg_close(ibuf_dns, buf); 1995f5af31aShenning break; 200c9addb91Sotto case IMSG_SYNCED: 201c9addb91Sotto nconf->status.synced = 1; 202c9addb91Sotto break; 203c9addb91Sotto case IMSG_UNSYNCED: 204c9addb91Sotto nconf->status.synced = 0; 205c9addb91Sotto break; 2065f5af31aShenning default: 2075f5af31aShenning break; 2085f5af31aShenning } 2095f5af31aShenning imsg_free(&imsg); 2105f5af31aShenning } 2115f5af31aShenning return (0); 2125f5af31aShenning } 21371ba36b6Sotto 21471ba36b6Sotto int 21571ba36b6Sotto probe_root_ns(void) 21671ba36b6Sotto { 21771ba36b6Sotto int ret; 21871ba36b6Sotto int old_retrans, old_retry, old_options; 21971ba36b6Sotto unsigned char buf[4096]; 22071ba36b6Sotto 22171ba36b6Sotto old_retrans = _res.retrans; 22271ba36b6Sotto old_retry = _res.retry; 22371ba36b6Sotto old_options = _res.options; 22471ba36b6Sotto _res.retrans = 1; 22571ba36b6Sotto _res.retry = 1; 22671ba36b6Sotto _res.options |= RES_USE_CD; 22771ba36b6Sotto 22871ba36b6Sotto ret = res_query(".", C_IN, T_NS, buf, sizeof(buf)); 22971ba36b6Sotto 23071ba36b6Sotto _res.retrans = old_retrans; 23171ba36b6Sotto _res.retry = old_retry; 23271ba36b6Sotto _res.options = old_options; 23371ba36b6Sotto 23471ba36b6Sotto return ret; 23571ba36b6Sotto } 23671ba36b6Sotto 23771ba36b6Sotto void 23871ba36b6Sotto probe_root(void) 23971ba36b6Sotto { 240be5c6adaSotto int i, n; 241be5c6adaSotto struct timespec start, probe_start, probe_end; 242be5c6adaSotto struct timespec duration; 24371ba36b6Sotto 244be5c6adaSotto clock_gettime(CLOCK_MONOTONIC, &start); 245be5c6adaSotto for (i = 0; ; i++) { 246be5c6adaSotto clock_gettime(CLOCK_MONOTONIC, &probe_start); 24771ba36b6Sotto n = probe_root_ns(); 248be5c6adaSotto clock_gettime(CLOCK_MONOTONIC, &probe_end); 249be5c6adaSotto if (n >= 0) 250be5c6adaSotto break; 251be5c6adaSotto timespecsub(&probe_end, &start, &duration); 252be5c6adaSotto if (duration.tv_sec > 5) 253be5c6adaSotto break; 254be5c6adaSotto timespecsub(&probe_end, &probe_start, &duration); 255be5c6adaSotto /* normally the probe takes 1s * nscount, but 256be5c6adaSotto sleep a little if the probe returned quickly */ 257be5c6adaSotto if (duration.tv_sec == 0) 25871ba36b6Sotto sleep(1); 25971ba36b6Sotto } 260be5c6adaSotto if (i > 0) 261be5c6adaSotto log_warnx("DNS root probe failed %d times (%s)", i, 262be5c6adaSotto n >= 0 ? "eventually succeeded": "gave up"); 26371ba36b6Sotto if (imsg_compose(ibuf_dns, IMSG_PROBE_ROOT, 0, 0, -1, &n, 26471ba36b6Sotto sizeof(int)) == -1) 26571ba36b6Sotto fatalx("probe_root"); 26671ba36b6Sotto } 267