1 /* $OpenBSD: ntp_dns.c,v 1.26 2020/04/12 14:20:56 otto 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 <netinet/in.h> 27 28 #include <err.h> 29 #include <errno.h> 30 #include <poll.h> 31 #include <fcntl.h> 32 #include <signal.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <syslog.h> 36 #include <resolv.h> 37 #include <unistd.h> 38 39 #include "ntpd.h" 40 41 volatile sig_atomic_t quit_dns = 0; 42 static struct imsgbuf *ibuf_dns; 43 extern int non_numeric; 44 45 void sighdlr_dns(int); 46 int dns_dispatch_imsg(struct ntpd_conf *); 47 int probe_root_ns(void); 48 void probe_root(void); 49 50 void 51 sighdlr_dns(int sig) 52 { 53 switch (sig) { 54 case SIGTERM: 55 case SIGINT: 56 quit_dns = 1; 57 break; 58 } 59 } 60 61 void 62 ntp_dns(struct ntpd_conf *nconf, struct passwd *pw) 63 { 64 struct pollfd pfd[1]; 65 int nfds, nullfd; 66 67 res_init(); 68 if (setpriority(PRIO_PROCESS, 0, 0) == -1) 69 log_warn("could not set priority"); 70 71 log_init(nconf->debug ? LOG_TO_STDERR : LOG_TO_SYSLOG, nconf->verbose, 72 LOG_DAEMON); 73 if (!nconf->debug && setsid() == -1) 74 fatal("setsid"); 75 log_procinit("dns"); 76 77 if ((nullfd = open("/dev/null", O_RDWR, 0)) == -1) 78 fatal(NULL); 79 80 if (!nconf->debug) { 81 dup2(nullfd, STDIN_FILENO); 82 dup2(nullfd, STDOUT_FILENO); 83 dup2(nullfd, STDERR_FILENO); 84 } 85 close(nullfd); 86 87 setproctitle("dns engine"); 88 89 if (setgroups(1, &pw->pw_gid) || 90 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 91 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 92 fatal("can't drop privileges"); 93 94 signal(SIGTERM, sighdlr_dns); 95 signal(SIGINT, sighdlr_dns); 96 signal(SIGHUP, SIG_IGN); 97 98 if ((ibuf_dns = malloc(sizeof(struct imsgbuf))) == NULL) 99 fatal(NULL); 100 imsg_init(ibuf_dns, PARENT_SOCK_FILENO); 101 102 if (pledge("stdio dns", NULL) == -1) 103 err(1, "pledge"); 104 105 if (non_numeric) 106 probe_root(); 107 else 108 log_debug("all addresses numeric, no dns probe"); 109 110 while (quit_dns == 0) { 111 pfd[0].fd = ibuf_dns->fd; 112 pfd[0].events = POLLIN; 113 if (ibuf_dns->w.queued) 114 pfd[0].events |= POLLOUT; 115 116 if ((nfds = poll(pfd, 1, INFTIM)) == -1) 117 if (errno != EINTR) { 118 log_warn("poll error"); 119 quit_dns = 1; 120 } 121 122 if (nfds > 0 && (pfd[0].revents & POLLOUT)) 123 if (msgbuf_write(&ibuf_dns->w) <= 0 && 124 errno != EAGAIN) { 125 log_warn("pipe write error (to ntp engine)"); 126 quit_dns = 1; 127 } 128 129 if (nfds > 0 && pfd[0].revents & POLLIN) { 130 nfds--; 131 if (dns_dispatch_imsg(nconf) == -1) 132 quit_dns = 1; 133 } 134 } 135 136 msgbuf_clear(&ibuf_dns->w); 137 free(ibuf_dns); 138 exit(0); 139 } 140 141 int 142 dns_dispatch_imsg(struct ntpd_conf *nconf) 143 { 144 struct imsg imsg; 145 int n, cnt; 146 char *name; 147 struct ntp_addr *h, *hn; 148 struct ibuf *buf; 149 const char *str; 150 size_t len; 151 152 if (((n = imsg_read(ibuf_dns)) == -1 && errno != EAGAIN) || n == 0) 153 return (-1); 154 155 for (;;) { 156 if ((n = imsg_get(ibuf_dns, &imsg)) == -1) 157 return (-1); 158 159 if (n == 0) 160 break; 161 162 switch (imsg.hdr.type) { 163 case IMSG_HOST_DNS: 164 case IMSG_CONSTRAINT_DNS: 165 if (imsg.hdr.type == IMSG_HOST_DNS) 166 str = "IMSG_HOST_DNS"; 167 else 168 str = "IMSG_CONSTRAINT_DNS"; 169 name = imsg.data; 170 if (imsg.hdr.len < 1 + IMSG_HEADER_SIZE) 171 fatalx("invalid %s received", str); 172 len = imsg.hdr.len - 1 - IMSG_HEADER_SIZE; 173 if (name[len] != '\0' || 174 strlen(name) != len) 175 fatalx("invalid %s received", str); 176 if ((cnt = host_dns(name, nconf->status.synced, 177 &hn)) == -1) 178 break; 179 buf = imsg_create(ibuf_dns, imsg.hdr.type, 180 imsg.hdr.peerid, 0, 181 cnt * (sizeof(struct sockaddr_storage) + sizeof(int))); 182 if (cnt > 0) { 183 if (buf) { 184 for (h = hn; h != NULL; h = h->next) { 185 if (imsg_add(buf, &h->ss, 186 sizeof(h->ss)) == -1) { 187 buf = NULL; 188 break; 189 } 190 if (imsg_add(buf, &h->notauth, 191 sizeof(int)) == -1) { 192 buf = NULL; 193 break; 194 } 195 } 196 } 197 host_dns_free(hn); 198 hn = NULL; 199 } 200 if (buf) 201 imsg_close(ibuf_dns, buf); 202 break; 203 case IMSG_SYNCED: 204 nconf->status.synced = 1; 205 break; 206 case IMSG_UNSYNCED: 207 nconf->status.synced = 0; 208 break; 209 default: 210 break; 211 } 212 imsg_free(&imsg); 213 } 214 return (0); 215 } 216 217 int 218 probe_root_ns(void) 219 { 220 int ret; 221 int old_retrans, old_retry, old_options; 222 unsigned char buf[4096]; 223 224 old_retrans = _res.retrans; 225 old_retry = _res.retry; 226 old_options = _res.options; 227 _res.retrans = 1; 228 _res.retry = 1; 229 _res.options |= RES_USE_CD; 230 231 ret = res_query(".", C_IN, T_NS, buf, sizeof(buf)); 232 233 _res.retrans = old_retrans; 234 _res.retry = old_retry; 235 _res.options = old_options; 236 237 return ret; 238 } 239 240 void 241 probe_root(void) 242 { 243 int n; 244 245 n = probe_root_ns(); 246 if (n < 0) { 247 /* give programs like unwind a second chance */ 248 sleep(1); 249 n = probe_root_ns(); 250 } 251 if (imsg_compose(ibuf_dns, IMSG_PROBE_ROOT, 0, 0, -1, &n, 252 sizeof(int)) == -1) 253 fatalx("probe_root"); 254 } 255