1 /* $OpenBSD: ntp_dns.c,v 1.28 2023/04/19 12:58:16 jsg Exp $ */ 2 3 /* 4 * Copyright (c) 2003-2008 Henning Brauer <henning@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/resource.h> 21 #include <sys/time.h> 22 #include <netinet/in.h> 23 #include <arpa/nameser.h> 24 #include <resolv.h> 25 26 #include <err.h> 27 #include <errno.h> 28 #include <poll.h> 29 #include <fcntl.h> 30 #include <signal.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <syslog.h> 34 #include <unistd.h> 35 36 #include "ntpd.h" 37 38 volatile sig_atomic_t quit_dns = 0; 39 static struct imsgbuf *ibuf_dns; 40 extern int non_numeric; 41 42 void sighdlr_dns(int); 43 int dns_dispatch_imsg(struct ntpd_conf *); 44 int probe_root_ns(void); 45 void probe_root(void); 46 47 void 48 sighdlr_dns(int sig) 49 { 50 switch (sig) { 51 case SIGTERM: 52 case SIGINT: 53 quit_dns = 1; 54 break; 55 } 56 } 57 58 void 59 ntp_dns(struct ntpd_conf *nconf, struct passwd *pw) 60 { 61 struct pollfd pfd[1]; 62 int nfds, nullfd; 63 64 res_init(); 65 if (setpriority(PRIO_PROCESS, 0, 0) == -1) 66 log_warn("could not set priority"); 67 68 log_init(nconf->debug ? LOG_TO_STDERR : LOG_TO_SYSLOG, nconf->verbose, 69 LOG_DAEMON); 70 if (!nconf->debug && setsid() == -1) 71 fatal("setsid"); 72 log_procinit("dns"); 73 74 if ((nullfd = open("/dev/null", O_RDWR)) == -1) 75 fatal(NULL); 76 77 if (!nconf->debug) { 78 dup2(nullfd, STDIN_FILENO); 79 dup2(nullfd, STDOUT_FILENO); 80 dup2(nullfd, STDERR_FILENO); 81 } 82 close(nullfd); 83 84 setproctitle("dns engine"); 85 86 if (setgroups(1, &pw->pw_gid) || 87 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 88 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 89 fatal("can't drop privileges"); 90 91 signal(SIGTERM, sighdlr_dns); 92 signal(SIGINT, sighdlr_dns); 93 signal(SIGHUP, SIG_IGN); 94 95 if ((ibuf_dns = malloc(sizeof(struct imsgbuf))) == NULL) 96 fatal(NULL); 97 imsg_init(ibuf_dns, PARENT_SOCK_FILENO); 98 99 if (pledge("stdio dns", NULL) == -1) 100 err(1, "pledge"); 101 102 if (non_numeric) 103 probe_root(); 104 else 105 log_debug("all addresses numeric, no dns probe"); 106 107 while (quit_dns == 0) { 108 pfd[0].fd = ibuf_dns->fd; 109 pfd[0].events = POLLIN; 110 if (ibuf_dns->w.queued) 111 pfd[0].events |= POLLOUT; 112 113 if ((nfds = poll(pfd, 1, INFTIM)) == -1) 114 if (errno != EINTR) { 115 log_warn("poll error"); 116 quit_dns = 1; 117 } 118 119 if (nfds > 0 && (pfd[0].revents & POLLOUT)) 120 if (msgbuf_write(&ibuf_dns->w) <= 0 && 121 errno != EAGAIN) { 122 log_warn("pipe write error (to ntp engine)"); 123 quit_dns = 1; 124 } 125 126 if (nfds > 0 && pfd[0].revents & POLLIN) { 127 nfds--; 128 if (dns_dispatch_imsg(nconf) == -1) 129 quit_dns = 1; 130 } 131 } 132 133 msgbuf_clear(&ibuf_dns->w); 134 free(ibuf_dns); 135 exit(0); 136 } 137 138 int 139 dns_dispatch_imsg(struct ntpd_conf *nconf) 140 { 141 struct imsg imsg; 142 int n, cnt; 143 char *name; 144 struct ntp_addr *h, *hn; 145 struct ibuf *buf; 146 const char *str; 147 size_t len; 148 149 if (((n = imsg_read(ibuf_dns)) == -1 && errno != EAGAIN) || n == 0) 150 return (-1); 151 152 for (;;) { 153 if ((n = imsg_get(ibuf_dns, &imsg)) == -1) 154 return (-1); 155 156 if (n == 0) 157 break; 158 159 switch (imsg.hdr.type) { 160 case IMSG_HOST_DNS: 161 case IMSG_CONSTRAINT_DNS: 162 if (imsg.hdr.type == IMSG_HOST_DNS) 163 str = "IMSG_HOST_DNS"; 164 else 165 str = "IMSG_CONSTRAINT_DNS"; 166 name = imsg.data; 167 if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE) 168 fatalx("invalid %s received", str); 169 len = imsg.hdr.len - 1 - IMSG_HEADER_SIZE; 170 if (name[len] != '\0' || 171 strlen(name) != len) 172 fatalx("invalid %s received", str); 173 if ((cnt = host_dns(name, nconf->status.synced, 174 &hn)) == -1) 175 break; 176 buf = imsg_create(ibuf_dns, imsg.hdr.type, 177 imsg.hdr.peerid, 0, 178 cnt * (sizeof(struct sockaddr_storage) + sizeof(int))); 179 if (cnt > 0) { 180 if (buf) { 181 for (h = hn; h != NULL; h = h->next) { 182 if (imsg_add(buf, &h->ss, 183 sizeof(h->ss)) == -1) { 184 buf = NULL; 185 break; 186 } 187 if (imsg_add(buf, &h->notauth, 188 sizeof(int)) == -1) { 189 buf = NULL; 190 break; 191 } 192 } 193 } 194 host_dns_free(hn); 195 hn = NULL; 196 } 197 if (buf) 198 imsg_close(ibuf_dns, buf); 199 break; 200 case IMSG_SYNCED: 201 nconf->status.synced = 1; 202 break; 203 case IMSG_UNSYNCED: 204 nconf->status.synced = 0; 205 break; 206 default: 207 break; 208 } 209 imsg_free(&imsg); 210 } 211 return (0); 212 } 213 214 int 215 probe_root_ns(void) 216 { 217 int ret; 218 int old_retrans, old_retry, old_options; 219 unsigned char buf[4096]; 220 221 old_retrans = _res.retrans; 222 old_retry = _res.retry; 223 old_options = _res.options; 224 _res.retrans = 1; 225 _res.retry = 1; 226 _res.options |= RES_USE_CD; 227 228 ret = res_query(".", C_IN, T_NS, buf, sizeof(buf)); 229 230 _res.retrans = old_retrans; 231 _res.retry = old_retry; 232 _res.options = old_options; 233 234 return ret; 235 } 236 237 void 238 probe_root(void) 239 { 240 int n; 241 242 n = probe_root_ns(); 243 if (n < 0) { 244 /* give programs like unwind a second chance */ 245 sleep(1); 246 n = probe_root_ns(); 247 } 248 if (imsg_compose(ibuf_dns, IMSG_PROBE_ROOT, 0, 0, -1, &n, 249 sizeof(int)) == -1) 250 fatalx("probe_root"); 251 } 252