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