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