control.c revision 224006
1139969Simp/*-
21556Srgrimes * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
31556Srgrimes * All rights reserved.
41556Srgrimes *
51556Srgrimes * Redistribution and use in source and binary forms, with or without
61556Srgrimes * modification, are permitted provided that the following conditions
71556Srgrimes * are met:
81556Srgrimes * 1. Redistributions of source code must retain the above copyright
91556Srgrimes *    notice, this list of conditions and the following disclaimer.
101556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111556Srgrimes *    notice, this list of conditions and the following disclaimer in the
121556Srgrimes *    documentation and/or other materials provided with the distribution.
131556Srgrimes *
141556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
151556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
161556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
171556Srgrimes * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
181556Srgrimes * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
191556Srgrimes * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
201556Srgrimes * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
211556Srgrimes * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
221556Srgrimes * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
231556Srgrimes * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
241556Srgrimes * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
251556Srgrimes *
261556Srgrimes * $FreeBSD$
271556Srgrimes *
281556Srgrimes */
291556Srgrimes
301556Srgrimes#include <sys/queue.h>
311556Srgrimes#include <sys/types.h>
3220419Ssteve#include <sys/socket.h>
3350471Speter#include <sys/stat.h>
341556Srgrimes#include <sys/un.h>
35113380Stjr#include <sys/uio.h>
361556Srgrimes#include <net/if.h>
3779526Sru#include <net/if_dl.h>
381556Srgrimes#include <netinet/in.h>
391556Srgrimes#include <netinet/icmp6.h>
401556Srgrimes#include <fcntl.h>
411556Srgrimes#include <errno.h>
4268935Sru#include <netdb.h>
43115082Sru#include <unistd.h>
441556Srgrimes#include <signal.h>
4594869Scharnier#include <string.h>
4694869Scharnier#include <stdarg.h>
4794869Scharnier#include <stdio.h>
481556Srgrimes#include <stdlib.h>
4951090Ssheldonh#include <syslog.h>
5051090Ssheldonh
5151090Ssheldonh#include "rtadvd.h"
5251275Ssheldonh#include "if.h"
5351275Ssheldonh#include "pathnames.h"
5451090Ssheldonh#include "control.h"
5551090Ssheldonh
5690170Smikeint
5790170Smikecmsg_recv(int fd, char *buf)
5890170Smike{
5990170Smike	int n;
6090170Smike	struct ctrl_msg_hdr	*cm;
6190170Smike	char *msg;
6290170Smike
6390170Smike	syslog(LOG_DEBUG, "<%s> enter, fd=%d", __func__, fd);
6490170Smike
6590170Smike	memset(buf, 0, CM_MSG_MAXLEN);
6696857Stjr	cm = (struct ctrl_msg_hdr *)buf;
6790170Smike	msg = (char *)buf + sizeof(*cm);
6890170Smike
6990170Smike	for (;;) {
7090170Smike		n = read(fd, cm, sizeof(*cm));
7192332Sru		if (n < 0 && errno == EAGAIN) {
7290170Smike			syslog(LOG_DEBUG,
7390170Smike			    "<%s> waiting...", __func__);
7490170Smike			continue;
75140353Sru		}
7681687Sru		break;
771556Srgrimes	}
7851090Ssheldonh
791556Srgrimes	if (n != sizeof(*cm)) {
801556Srgrimes		syslog(LOG_WARNING,
8179366Sru		    "<%s> received a too small message.", __func__);
8279366Sru		goto cmsg_recv_err;
83140353Sru	}
84140353Sru	if (cm->cm_len > CM_MSG_MAXLEN) {
85140353Sru		syslog(LOG_WARNING,
86140353Sru		    "<%s> received a too large message.", __func__);
87140353Sru		goto cmsg_recv_err;
881556Srgrimes	}
891556Srgrimes	if (cm->cm_version != CM_VERSION) {
90131505Sru		syslog(LOG_WARNING,
911556Srgrimes		    "<%s> version mismatch", __func__);
921556Srgrimes		goto cmsg_recv_err;
9351275Ssheldonh	}
9451275Ssheldonh	if (cm->cm_type >= CM_TYPE_MAX) {
951556Srgrimes		syslog(LOG_WARNING,
9651090Ssheldonh		    "<%s> invalid msg type.", __func__);
9790170Smike		goto cmsg_recv_err;
9890170Smike	}
9990170Smike
10090170Smike	syslog(LOG_DEBUG,
10190170Smike	    "<%s> ctrl msg received: type=%d", __func__,
10290170Smike	    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=%d", __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=%d", __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 = %d (actual)", __func__, len);
177	syslog(LOG_DEBUG,
178	    "<%s> write length = %d (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) = %d", __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) = %d", __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) = %d", __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=%d)",
386		    __func__, len);
387		return (0);
388	}
389	syslog(LOG_DEBUG, "<%s> msglen=%d", __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=%d)",
438		    __func__, len);
439		return (0);
440	}
441	syslog(LOG_DEBUG, "<%s> msglen=%d", __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