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