xref: /openbsd/usr.sbin/ntpd/ntp_dns.c (revision 4bdff4be)
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