xref: /freebsd/usr.sbin/rtadvd/control.c (revision 56b17de1e8360fe131d425de20b5e75ff3ea897c)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
26  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 
30 #include <sys/param.h>
31 #include <sys/queue.h>
32 #include <sys/socket.h>
33 #include <sys/stat.h>
34 #include <sys/un.h>
35 #include <sys/uio.h>
36 #include <net/if.h>
37 #include <net/if_dl.h>
38 #include <netinet/in.h>
39 #include <netinet/icmp6.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <netdb.h>
43 #include <unistd.h>
44 #include <poll.h>
45 #include <signal.h>
46 #include <string.h>
47 #include <stdarg.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <syslog.h>
51 
52 #include "rtadvd.h"
53 #include "if.h"
54 #include "pathnames.h"
55 #include "control.h"
56 
57 #define	CM_RECV_TIMEOUT	30
58 
59 int
60 cm_recv(int fd, char *buf)
61 {
62 	ssize_t n;
63 	struct ctrl_msg_hdr	*cm;
64 	char *msg;
65 	struct pollfd pfds[1];
66 	int i;
67 
68 	syslog(LOG_DEBUG, "<%s> enter, fd=%d", __func__, fd);
69 
70 	memset(buf, 0, CM_MSG_MAXLEN);
71 	cm = (struct ctrl_msg_hdr *)buf;
72 	msg = (char *)buf + sizeof(*cm);
73 
74 	pfds[0].fd = fd;
75 	pfds[0].events = POLLIN;
76 
77 	for (;;) {
78 		i = poll(pfds, nitems(pfds),
79 		    CM_RECV_TIMEOUT);
80 
81 		if (i == 0)
82 			continue;
83 
84 		if (i < 0) {
85 			syslog(LOG_ERR, "<%s> poll error: %s",
86 			    __func__, strerror(errno));
87 			continue;
88 		}
89 
90 		if (pfds[0].revents & POLLIN) {
91 			n = read(fd, cm, sizeof(*cm));
92 			if (n < 0 && errno == EAGAIN) {
93 				syslog(LOG_DEBUG,
94 				    "<%s> waiting...", __func__);
95 				continue;
96 			}
97 			break;
98 		}
99 	}
100 
101 	if (n != (ssize_t)sizeof(*cm)) {
102 		syslog(LOG_WARNING,
103 		    "<%s> received a too small message.", __func__);
104 		goto cm_recv_err;
105 	}
106 	if (cm->cm_len > CM_MSG_MAXLEN) {
107 		syslog(LOG_WARNING,
108 		    "<%s> received a too large message.", __func__);
109 		goto cm_recv_err;
110 	}
111 	if (cm->cm_version != CM_VERSION) {
112 		syslog(LOG_WARNING,
113 		    "<%s> version mismatch", __func__);
114 		goto cm_recv_err;
115 	}
116 	if (cm->cm_type >= CM_TYPE_MAX) {
117 		syslog(LOG_WARNING,
118 		    "<%s> invalid msg type.", __func__);
119 		goto cm_recv_err;
120 	}
121 
122 	syslog(LOG_DEBUG,
123 	    "<%s> ctrl msg received: type=%d", __func__,
124 	    cm->cm_type);
125 
126 	if (cm->cm_len > sizeof(*cm)) {
127 		size_t msglen = cm->cm_len - sizeof(*cm);
128 
129 		syslog(LOG_DEBUG,
130 		    "<%s> ctrl msg has payload (len=%zu)", __func__,
131 		    msglen);
132 
133 		for (;;) {
134 			i = poll(pfds, nitems(pfds),
135 			    CM_RECV_TIMEOUT);
136 
137 			if (i == 0)
138 				continue;
139 
140 			if (i < 0) {
141 				syslog(LOG_ERR, "<%s> poll error: %s",
142 				    __func__, strerror(errno));
143 				continue;
144 			}
145 
146 			if (pfds[0].revents & POLLIN) {
147 				n = read(fd, msg, msglen);
148 				if (n < 0 && errno == EAGAIN) {
149 					syslog(LOG_DEBUG,
150 					    "<%s> waiting...", __func__);
151 					continue;
152 				}
153 			}
154 			break;
155 		}
156 		if (n != (ssize_t)msglen) {
157 			syslog(LOG_WARNING,
158 			    "<%s> payload size mismatch.", __func__);
159 			goto cm_recv_err;
160 		}
161 		buf[CM_MSG_MAXLEN - 1] = '\0';
162 	}
163 
164 	return (0);
165 
166 cm_recv_err:
167 	close(fd);
168 	return (-1);
169 }
170 
171 int
172 cm_send(int fd, char *buf)
173 {
174 	struct iovec iov[2];
175 	int iovcnt;
176 	ssize_t len;
177 	ssize_t iov_len_total;
178 	struct ctrl_msg_hdr *cm;
179 	char *msg;
180 
181 	cm = (struct ctrl_msg_hdr *)buf;
182 	msg = (char *)buf + sizeof(*cm);
183 
184 	iovcnt = 1;
185 	iov[0].iov_base = cm;
186 	iov[0].iov_len = sizeof(*cm);
187 	iov_len_total = iov[0].iov_len;
188 	if (cm->cm_len > sizeof(*cm)) {
189 		iovcnt++;
190 		iov[1].iov_base = msg;
191 		iov[1].iov_len = cm->cm_len - iov[0].iov_len;
192 		iov_len_total += iov[1].iov_len;
193 	}
194 
195 	syslog(LOG_DEBUG,
196 	    "<%s> ctrl msg send: type=%d, count=%d, total_len=%zd", __func__,
197 	    cm->cm_type, iovcnt, iov_len_total);
198 
199 	len = writev(fd, iov, iovcnt);
200 	syslog(LOG_DEBUG,
201 	    "<%s> ctrl msg send: length=%zd", __func__, len);
202 
203 	if (len == -1) {
204 		syslog(LOG_DEBUG,
205 		    "<%s> write failed: (%d)%s", __func__, errno,
206 		    strerror(errno));
207 		close(fd);
208 		return (-1);
209 	}
210 
211 	syslog(LOG_DEBUG,
212 	    "<%s> write length = %zd (actual)", __func__, len);
213 	syslog(LOG_DEBUG,
214 	    "<%s> write length = %zd (expected)", __func__, iov_len_total);
215 
216 	if (len != iov_len_total) {
217 		close(fd);
218 		return (-1);
219 	}
220 
221 	return (0);
222 }
223 
224 int
225 csock_accept(struct sockinfo *s)
226 {
227 	struct sockaddr_un	sun;
228 	int	flags;
229 	int	fd;
230 
231 	sun.sun_len = sizeof(sun);
232 	if ((fd = accept(s->si_fd, (struct sockaddr *)&sun,
233 		    (socklen_t *)&sun.sun_len)) == -1) {
234 		if (errno != EWOULDBLOCK && errno != EINTR)
235 			syslog(LOG_WARNING, "<%s> accept ", __func__);
236 		syslog(LOG_WARNING, "<%s> Xaccept: %s", __func__, strerror(errno));
237 		return (-1);
238 	}
239 	if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
240 		syslog(LOG_WARNING, "<%s> fcntl F_GETFL", __func__);
241 		close(s->si_fd);
242 		return (-1);
243 	}
244 	if ((flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1) {
245 		syslog(LOG_WARNING, "<%s> fcntl F_SETFL", __func__);
246 		return (-1);
247 	}
248 	syslog(LOG_DEBUG, "<%s> accept connfd=%d, listenfd=%d", __func__,
249 	    fd, s->si_fd);
250 
251 	return (fd);
252 }
253 
254 int
255 csock_close(struct sockinfo *s)
256 {
257 	close(s->si_fd);
258 	unlink(s->si_name);
259 	syslog(LOG_DEBUG, "<%s> remove %s", __func__, s->si_name);
260 	return (0);
261 }
262 
263 int
264 csock_listen(struct sockinfo *s)
265 {
266 	if (s->si_fd == -1) {
267 		syslog(LOG_ERR, "<%s> listen failed", __func__);
268 		return (-1);
269 	}
270 	if (listen(s->si_fd, SOCK_BACKLOG) == -1) {
271 		syslog(LOG_ERR, "<%s> listen failed", __func__);
272 		return (-1);
273 	}
274 
275 	return (0);
276 }
277 
278 int
279 csock_open(struct sockinfo *s, mode_t mode)
280 {
281 	int flags;
282 	struct sockaddr_un	sun;
283 	mode_t	old_umask;
284 
285 	if (s == NULL) {
286 		syslog(LOG_ERR, "<%s> internal error.", __func__);
287 		exit(1);
288 	}
289 	if (s->si_name == NULL)
290 		s->si_name = _PATH_CTRL_SOCK;
291 
292 	if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
293 		syslog(LOG_ERR,
294 		    "<%s> cannot open control socket", __func__);
295 		return (-1);
296 	}
297 	memset(&sun, 0, sizeof(sun));
298 	sun.sun_family = AF_UNIX;
299 	sun.sun_len = sizeof(sun);
300 	strlcpy(sun.sun_path, s->si_name, sizeof(sun.sun_path));
301 
302 	if (unlink(s->si_name) == -1)
303 		if (errno != ENOENT) {
304 			syslog(LOG_ERR,
305 			    "<%s> unlink %s", __func__, s->si_name);
306 			close(s->si_fd);
307 			return (-1);
308 		}
309 	old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
310 	if (bind(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
311 		syslog(LOG_ERR,
312 		    "<%s> bind failed: %s", __func__, s->si_name);
313 		close(s->si_fd);
314 		umask(old_umask);
315 		return (-1);
316 	}
317 	umask(old_umask);
318 	if (chmod(s->si_name, mode) == -1) {
319 		syslog(LOG_ERR,
320 		    "<%s> chmod failed: %s", __func__, s->si_name);
321 		goto csock_open_err;
322 	}
323 	if ((flags = fcntl(s->si_fd, F_GETFL, 0)) == -1) {
324 		syslog(LOG_ERR,
325 		    "<%s> fcntl F_GETFL failed: %s", __func__, s->si_name);
326 		goto csock_open_err;
327 	}
328 	if ((flags = fcntl(s->si_fd, F_SETFL, flags | O_NONBLOCK)) == -1) {
329 		syslog(LOG_ERR,
330 		    "<%s> fcntl F_SETFL failed: %s", __func__, s->si_name);
331 		goto csock_open_err;
332 	}
333 
334 	return (s->si_fd);
335 
336 csock_open_err:
337 	close(s->si_fd);
338 	unlink(s->si_name);
339 	return (-1);
340 }
341 
342 struct ctrl_msg_pl *
343 cm_bin2pl(char *str, struct ctrl_msg_pl *cp)
344 {
345 	size_t len;
346 	size_t *lenp;
347 	char *p;
348 
349 	memset(cp, 0, sizeof(*cp));
350 
351 	p = str;
352 
353 	lenp = (size_t *)p;
354 	len = *lenp++;
355 	p = (char *)lenp;
356 	syslog(LOG_DEBUG, "<%s> len(ifname) = %zu", __func__, len);
357 	if (len > 0) {
358 		cp->cp_ifname = malloc(len + 1);
359 		if (cp->cp_ifname == NULL) {
360 			syslog(LOG_ERR, "<%s> malloc", __func__);
361 			exit(1);
362 		}
363 		memcpy(cp->cp_ifname, p, len);
364 		cp->cp_ifname[len] = '\0';
365 		p += len;
366 	}
367 
368 	lenp = (size_t *)p;
369 	len = *lenp++;
370 	p = (char *)lenp;
371 	syslog(LOG_DEBUG, "<%s> len(key) = %zu", __func__, len);
372 	if (len > 0) {
373 		cp->cp_key = malloc(len + 1);
374 		if (cp->cp_key == NULL) {
375 			syslog(LOG_ERR, "<%s> malloc", __func__);
376 			exit(1);
377 		}
378 		memcpy(cp->cp_key, p, len);
379 		cp->cp_key[len] = '\0';
380 		p += len;
381 	}
382 
383 	lenp = (size_t *)p;
384 	len = *lenp++;
385 	p = (char *)lenp;
386 	syslog(LOG_DEBUG, "<%s> len(val) = %zu", __func__, len);
387 	if (len > 0) {
388 		cp->cp_val = malloc(len + 1);
389 		if (cp->cp_val == NULL) {
390 			syslog(LOG_ERR, "<%s> malloc", __func__);
391 			exit(1);
392 		}
393 		memcpy(cp->cp_val, p, len);
394 		cp->cp_val[len] = '\0';
395 		cp->cp_val_len = len;
396 	} else
397 		cp->cp_val_len = 0;
398 
399 	return (cp);
400 }
401 
402 size_t
403 cm_pl2bin(char *str, struct ctrl_msg_pl *cp)
404 {
405 	size_t len;
406 	size_t *lenp;
407 	char *p;
408 	struct ctrl_msg_hdr *cm;
409 
410 	len = sizeof(size_t);
411 	if (cp->cp_ifname != NULL)
412 		len += strlen(cp->cp_ifname);
413 	len += sizeof(size_t);
414 	if (cp->cp_key != NULL)
415 		len += strlen(cp->cp_key);
416 	len += sizeof(size_t);
417 	if (cp->cp_val != NULL && cp->cp_val_len > 0)
418 		len += cp->cp_val_len;
419 
420 	if (len > CM_MSG_MAXLEN - sizeof(*cm)) {
421 		syslog(LOG_DEBUG, "<%s> msg too long (len=%zu)",
422 		    __func__, len);
423 		return (0);
424 	}
425 	syslog(LOG_DEBUG, "<%s> msglen=%zu", __func__, len);
426 	memset(str, 0, len);
427 	p = str;
428 	lenp = (size_t *)p;
429 
430 	if (cp->cp_ifname != NULL) {
431 		*lenp++ = strlen(cp->cp_ifname);
432 		p = (char *)lenp;
433 		memcpy(p, cp->cp_ifname, strlen(cp->cp_ifname));
434 		p += strlen(cp->cp_ifname);
435 	} else {
436 		*lenp++ = '\0';
437 		p = (char *)lenp;
438 	}
439 
440 	lenp = (size_t *)p;
441 	if (cp->cp_key != NULL) {
442 		*lenp++ = strlen(cp->cp_key);
443 		p = (char *)lenp;
444 		memcpy(p, cp->cp_key, strlen(cp->cp_key));
445 		p += strlen(cp->cp_key);
446 	} else {
447 		*lenp++ = '\0';
448 		p = (char *)lenp;
449 	}
450 
451 	lenp = (size_t *)p;
452 	if (cp->cp_val != NULL && cp->cp_val_len > 0) {
453 		*lenp++ = cp->cp_val_len;
454 		p = (char *)lenp;
455 		memcpy(p, cp->cp_val, cp->cp_val_len);
456 		p += cp->cp_val_len;
457 	} else {
458 		*lenp++ = '\0';
459 		p = (char *)lenp;
460 	}
461 
462 	return (len);
463 }
464 
465 size_t
466 cm_str2bin(char *bin, void *str, size_t len)
467 {
468 	struct ctrl_msg_hdr *cm;
469 
470 	syslog(LOG_DEBUG, "<%s> enter", __func__);
471 
472 	if (len > CM_MSG_MAXLEN - sizeof(*cm)) {
473 		syslog(LOG_DEBUG, "<%s> msg too long (len=%zu)",
474 		    __func__, len);
475 		return (0);
476 	}
477 	syslog(LOG_DEBUG, "<%s> msglen=%zu", __func__, len);
478 	memcpy(bin, (char *)str, len);
479 
480 	return (len);
481 }
482 
483 void *
484 cm_bin2str(char *bin, void *str, size_t len)
485 {
486 
487 	syslog(LOG_DEBUG, "<%s> enter", __func__);
488 
489 	memcpy((char *)str, bin, len);
490 
491 	return (str);
492 }
493