1/*-
2 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 * $FreeBSD$
27 *
28 */
29
30#include <sys/queue.h>
31#include <sys/types.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
59int
60cm_recv(int fd, char *buf)
61{
62	int 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, sizeof(pfds)/sizeof(pfds[0]),
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 != 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		int msglen = cm->cm_len - sizeof(*cm);
128
129		syslog(LOG_DEBUG,
130		    "<%s> ctrl msg has payload (len=%d)", __func__,
131		    msglen);
132
133		for (;;) {
134			i = poll(pfds, sizeof(pfds)/sizeof(pfds[0]),
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 != 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
166cm_recv_err:
167	close(fd);
168	return (-1);
169}
170
171int
172cm_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
224int
225csock_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
254int
255csock_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
263int
264csock_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
278int
279csock_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
336csock_open_err:
337	close(s->si_fd);
338	unlink(s->si_name);
339	return (-1);
340}
341
342struct ctrl_msg_pl *
343cm_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
402size_t
403cm_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
465size_t
466cm_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
483void *
484cm_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