1224006Shrs/*-
2224006Shrs * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
3224006Shrs * All rights reserved.
4224006Shrs *
5224006Shrs * Redistribution and use in source and binary forms, with or without
6224006Shrs * modification, are permitted provided that the following conditions
7224006Shrs * are met:
8224006Shrs * 1. Redistributions of source code must retain the above copyright
9224006Shrs *    notice, this list of conditions and the following disclaimer.
10224006Shrs * 2. Redistributions in binary form must reproduce the above copyright
11224006Shrs *    notice, this list of conditions and the following disclaimer in the
12224006Shrs *    documentation and/or other materials provided with the distribution.
13224006Shrs *
14224006Shrs * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
15224006Shrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16224006Shrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17224006Shrs * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
18224006Shrs * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19224006Shrs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20224006Shrs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21224006Shrs * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22224006Shrs * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23224006Shrs * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24224006Shrs * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25224006Shrs *
26224006Shrs * $FreeBSD$
27224006Shrs *
28224006Shrs */
29224006Shrs
30224006Shrs#include <sys/queue.h>
31224006Shrs#include <sys/types.h>
32224006Shrs#include <sys/socket.h>
33224006Shrs#include <sys/stat.h>
34224006Shrs#include <sys/un.h>
35224006Shrs#include <sys/uio.h>
36224006Shrs#include <net/if.h>
37224006Shrs#include <net/if_dl.h>
38224006Shrs#include <netinet/in.h>
39224006Shrs#include <netinet/icmp6.h>
40224006Shrs#include <fcntl.h>
41224006Shrs#include <errno.h>
42224006Shrs#include <netdb.h>
43224006Shrs#include <unistd.h>
44225519Shrs#include <poll.h>
45224006Shrs#include <signal.h>
46224006Shrs#include <string.h>
47224006Shrs#include <stdarg.h>
48224006Shrs#include <stdio.h>
49224006Shrs#include <stdlib.h>
50224006Shrs#include <syslog.h>
51224006Shrs
52224006Shrs#include "rtadvd.h"
53224006Shrs#include "if.h"
54224006Shrs#include "pathnames.h"
55224006Shrs#include "control.h"
56224006Shrs
57225519Shrs#define	CM_RECV_TIMEOUT	30
58225519Shrs
59224006Shrsint
60225519Shrscm_recv(int fd, char *buf)
61224006Shrs{
62301803Sngie	ssize_t n;
63224006Shrs	struct ctrl_msg_hdr	*cm;
64224006Shrs	char *msg;
65225519Shrs	struct pollfd pfds[1];
66225519Shrs	int i;
67224006Shrs
68224006Shrs	syslog(LOG_DEBUG, "<%s> enter, fd=%d", __func__, fd);
69224006Shrs
70224006Shrs	memset(buf, 0, CM_MSG_MAXLEN);
71224006Shrs	cm = (struct ctrl_msg_hdr *)buf;
72224006Shrs	msg = (char *)buf + sizeof(*cm);
73224006Shrs
74225519Shrs	pfds[0].fd = fd;
75225519Shrs	pfds[0].events = POLLIN;
76225519Shrs
77224006Shrs	for (;;) {
78225519Shrs		i = poll(pfds, sizeof(pfds)/sizeof(pfds[0]),
79225519Shrs		    CM_RECV_TIMEOUT);
80225519Shrs
81225519Shrs		if (i == 0)
82224006Shrs			continue;
83225519Shrs
84225519Shrs		if (i < 0) {
85225519Shrs			syslog(LOG_ERR, "<%s> poll error: %s",
86225519Shrs			    __func__, strerror(errno));
87225519Shrs			continue;
88224006Shrs		}
89225519Shrs
90225519Shrs		if (pfds[0].revents & POLLIN) {
91225519Shrs			n = read(fd, cm, sizeof(*cm));
92225519Shrs			if (n < 0 && errno == EAGAIN) {
93225519Shrs				syslog(LOG_DEBUG,
94225519Shrs				    "<%s> waiting...", __func__);
95225519Shrs				continue;
96225519Shrs			}
97225519Shrs			break;
98225519Shrs		}
99224006Shrs	}
100224006Shrs
101301803Sngie	if (n != (ssize_t)sizeof(*cm)) {
102224006Shrs		syslog(LOG_WARNING,
103224006Shrs		    "<%s> received a too small message.", __func__);
104225519Shrs		goto cm_recv_err;
105224006Shrs	}
106224006Shrs	if (cm->cm_len > CM_MSG_MAXLEN) {
107224006Shrs		syslog(LOG_WARNING,
108224006Shrs		    "<%s> received a too large message.", __func__);
109225519Shrs		goto cm_recv_err;
110224006Shrs	}
111224006Shrs	if (cm->cm_version != CM_VERSION) {
112224006Shrs		syslog(LOG_WARNING,
113224006Shrs		    "<%s> version mismatch", __func__);
114225519Shrs		goto cm_recv_err;
115224006Shrs	}
116224006Shrs	if (cm->cm_type >= CM_TYPE_MAX) {
117224006Shrs		syslog(LOG_WARNING,
118224006Shrs		    "<%s> invalid msg type.", __func__);
119225519Shrs		goto cm_recv_err;
120224006Shrs	}
121224006Shrs
122224006Shrs	syslog(LOG_DEBUG,
123224006Shrs	    "<%s> ctrl msg received: type=%d", __func__,
124224006Shrs	    cm->cm_type);
125224006Shrs
126301803Sngie	if (cm->cm_len > sizeof(*cm)) {
127301803Sngie		size_t msglen = cm->cm_len - sizeof(*cm);
128224006Shrs
129224006Shrs		syslog(LOG_DEBUG,
130301803Sngie		    "<%s> ctrl msg has payload (len=%zu)", __func__,
131224006Shrs		    msglen);
132224006Shrs
133224006Shrs		for (;;) {
134225519Shrs			i = poll(pfds, sizeof(pfds)/sizeof(pfds[0]),
135225519Shrs			    CM_RECV_TIMEOUT);
136225519Shrs
137225519Shrs			if (i == 0)
138224006Shrs				continue;
139225519Shrs
140225519Shrs			if (i < 0) {
141225519Shrs				syslog(LOG_ERR, "<%s> poll error: %s",
142225519Shrs				    __func__, strerror(errno));
143225519Shrs				continue;
144224006Shrs			}
145225519Shrs
146225519Shrs			if (pfds[0].revents & POLLIN) {
147225519Shrs				n = read(fd, msg, msglen);
148225519Shrs				if (n < 0 && errno == EAGAIN) {
149225519Shrs					syslog(LOG_DEBUG,
150225519Shrs					    "<%s> waiting...", __func__);
151225519Shrs					continue;
152225519Shrs				}
153225519Shrs			}
154224006Shrs			break;
155224006Shrs		}
156301803Sngie		if (n != (ssize_t)msglen) {
157224006Shrs			syslog(LOG_WARNING,
158224006Shrs			    "<%s> payload size mismatch.", __func__);
159225519Shrs			goto cm_recv_err;
160224006Shrs		}
161224006Shrs		buf[CM_MSG_MAXLEN - 1] = '\0';
162224006Shrs	}
163224006Shrs
164224006Shrs	return (0);
165224006Shrs
166225519Shrscm_recv_err:
167224006Shrs	close(fd);
168224006Shrs	return (-1);
169224006Shrs}
170224006Shrs
171224006Shrsint
172225519Shrscm_send(int fd, char *buf)
173224006Shrs{
174224006Shrs	struct iovec iov[2];
175224006Shrs	int iovcnt;
176224006Shrs	ssize_t len;
177224006Shrs	ssize_t iov_len_total;
178224006Shrs	struct ctrl_msg_hdr *cm;
179224006Shrs	char *msg;
180224006Shrs
181224006Shrs	cm = (struct ctrl_msg_hdr *)buf;
182224006Shrs	msg = (char *)buf + sizeof(*cm);
183224006Shrs
184224006Shrs	iovcnt = 1;
185224006Shrs	iov[0].iov_base = cm;
186224006Shrs	iov[0].iov_len = sizeof(*cm);
187224006Shrs	iov_len_total = iov[0].iov_len;
188224006Shrs	if (cm->cm_len > sizeof(*cm)) {
189224006Shrs		iovcnt++;
190224006Shrs		iov[1].iov_base = msg;
191224006Shrs		iov[1].iov_len = cm->cm_len - iov[0].iov_len;
192224006Shrs		iov_len_total += iov[1].iov_len;
193224006Shrs	}
194224006Shrs
195224006Shrs	syslog(LOG_DEBUG,
196224144Shrs	    "<%s> ctrl msg send: type=%d, count=%d, total_len=%zd", __func__,
197224006Shrs	    cm->cm_type, iovcnt, iov_len_total);
198224006Shrs
199224006Shrs	len = writev(fd, iov, iovcnt);
200224006Shrs	syslog(LOG_DEBUG,
201224144Shrs	    "<%s> ctrl msg send: length=%zd", __func__, len);
202224006Shrs
203224006Shrs	if (len == -1) {
204224006Shrs		syslog(LOG_DEBUG,
205224006Shrs		    "<%s> write failed: (%d)%s", __func__, errno,
206224006Shrs		    strerror(errno));
207224006Shrs		close(fd);
208224006Shrs		return (-1);
209224006Shrs	}
210224006Shrs
211224006Shrs	syslog(LOG_DEBUG,
212224144Shrs	    "<%s> write length = %zd (actual)", __func__, len);
213224006Shrs	syslog(LOG_DEBUG,
214224144Shrs	    "<%s> write length = %zd (expected)", __func__, iov_len_total);
215224006Shrs
216224006Shrs	if (len != iov_len_total) {
217224006Shrs		close(fd);
218224006Shrs		return (-1);
219224006Shrs	}
220224006Shrs
221224006Shrs	return (0);
222224006Shrs}
223224006Shrs
224224006Shrsint
225224006Shrscsock_accept(struct sockinfo *s)
226224006Shrs{
227224006Shrs	struct sockaddr_un	sun;
228224006Shrs	int	flags;
229224006Shrs	int	fd;
230224006Shrs
231224006Shrs	sun.sun_len = sizeof(sun);
232224006Shrs	if ((fd = accept(s->si_fd, (struct sockaddr *)&sun,
233224006Shrs		    (socklen_t *)&sun.sun_len)) == -1) {
234224006Shrs		if (errno != EWOULDBLOCK && errno != EINTR)
235224006Shrs			syslog(LOG_WARNING, "<%s> accept ", __func__);
236224006Shrs		syslog(LOG_WARNING, "<%s> Xaccept: %s", __func__, strerror(errno));
237224006Shrs		return (-1);
238224006Shrs	}
239224006Shrs	if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
240224006Shrs		syslog(LOG_WARNING, "<%s> fcntl F_GETFL", __func__);
241224006Shrs		close(s->si_fd);
242224006Shrs		return (-1);
243224006Shrs	}
244224006Shrs	if ((flags = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1) {
245224006Shrs		syslog(LOG_WARNING, "<%s> fcntl F_SETFL", __func__);
246224006Shrs		return (-1);
247224006Shrs	}
248224006Shrs	syslog(LOG_DEBUG, "<%s> accept connfd=%d, listenfd=%d", __func__,
249224006Shrs	    fd, s->si_fd);
250224006Shrs
251224006Shrs	return (fd);
252224006Shrs}
253224006Shrs
254224006Shrsint
255224006Shrscsock_close(struct sockinfo *s)
256224006Shrs{
257224006Shrs	close(s->si_fd);
258224006Shrs	unlink(s->si_name);
259224006Shrs	syslog(LOG_DEBUG, "<%s> remove %s", __func__, s->si_name);
260224006Shrs	return (0);
261224006Shrs}
262224006Shrs
263224006Shrsint
264224006Shrscsock_listen(struct sockinfo *s)
265224006Shrs{
266224006Shrs	if (s->si_fd == -1) {
267224006Shrs		syslog(LOG_ERR, "<%s> listen failed", __func__);
268224006Shrs		return (-1);
269224006Shrs	}
270224006Shrs	if (listen(s->si_fd, SOCK_BACKLOG) == -1) {
271224006Shrs		syslog(LOG_ERR, "<%s> listen failed", __func__);
272224006Shrs		return (-1);
273224006Shrs	}
274224006Shrs
275224006Shrs	return (0);
276224006Shrs}
277224006Shrs
278224006Shrsint
279224006Shrscsock_open(struct sockinfo *s, mode_t mode)
280224006Shrs{
281224006Shrs	int flags;
282224006Shrs	struct sockaddr_un	sun;
283224006Shrs	mode_t	old_umask;
284224006Shrs
285224006Shrs	if (s == NULL) {
286224006Shrs		syslog(LOG_ERR, "<%s> internal error.", __func__);
287224006Shrs		exit(1);
288224006Shrs	}
289224006Shrs	if (s->si_name == NULL)
290224006Shrs		s->si_name = _PATH_CTRL_SOCK;
291224006Shrs
292224006Shrs	if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
293224006Shrs		syslog(LOG_ERR,
294224006Shrs		    "<%s> cannot open control socket", __func__);
295224006Shrs		return (-1);
296224006Shrs	}
297224006Shrs	memset(&sun, 0, sizeof(sun));
298224006Shrs	sun.sun_family = AF_UNIX;
299224006Shrs	sun.sun_len = sizeof(sun);
300224006Shrs	strlcpy(sun.sun_path, s->si_name, sizeof(sun.sun_path));
301224006Shrs
302224006Shrs	if (unlink(s->si_name) == -1)
303224006Shrs		if (errno != ENOENT) {
304224006Shrs			syslog(LOG_ERR,
305224006Shrs			    "<%s> unlink %s", __func__, s->si_name);
306224006Shrs			close(s->si_fd);
307224006Shrs			return (-1);
308224006Shrs		}
309224006Shrs	old_umask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
310224006Shrs	if (bind(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
311224006Shrs		syslog(LOG_ERR,
312224006Shrs		    "<%s> bind failed: %s", __func__, s->si_name);
313224006Shrs		close(s->si_fd);
314224006Shrs		umask(old_umask);
315224006Shrs		return (-1);
316224006Shrs	}
317224006Shrs	umask(old_umask);
318224006Shrs	if (chmod(s->si_name, mode) == -1) {
319224006Shrs		syslog(LOG_ERR,
320224006Shrs		    "<%s> chmod failed: %s", __func__, s->si_name);
321224006Shrs		goto csock_open_err;
322224006Shrs	}
323224006Shrs	if ((flags = fcntl(s->si_fd, F_GETFL, 0)) == -1) {
324224006Shrs		syslog(LOG_ERR,
325224006Shrs		    "<%s> fcntl F_GETFL failed: %s", __func__, s->si_name);
326224006Shrs		goto csock_open_err;
327224006Shrs	}
328224006Shrs	if ((flags = fcntl(s->si_fd, F_SETFL, flags | O_NONBLOCK)) == -1) {
329224006Shrs		syslog(LOG_ERR,
330224006Shrs		    "<%s> fcntl F_SETFL failed: %s", __func__, s->si_name);
331224006Shrs		goto csock_open_err;
332224006Shrs	}
333224006Shrs
334224006Shrs	return (s->si_fd);
335224006Shrs
336224006Shrscsock_open_err:
337224006Shrs	close(s->si_fd);
338224006Shrs	unlink(s->si_name);
339224006Shrs	return (-1);
340224006Shrs}
341224006Shrs
342224006Shrsstruct ctrl_msg_pl *
343225519Shrscm_bin2pl(char *str, struct ctrl_msg_pl *cp)
344224006Shrs{
345224006Shrs	size_t len;
346224006Shrs	size_t *lenp;
347224006Shrs	char *p;
348224006Shrs
349224006Shrs	memset(cp, 0, sizeof(*cp));
350224006Shrs
351224006Shrs	p = str;
352224006Shrs
353224006Shrs	lenp = (size_t *)p;
354224006Shrs	len = *lenp++;
355224006Shrs	p = (char *)lenp;
356224144Shrs	syslog(LOG_DEBUG, "<%s> len(ifname) = %zu", __func__, len);
357224006Shrs	if (len > 0) {
358224006Shrs		cp->cp_ifname = malloc(len + 1);
359224006Shrs		if (cp->cp_ifname == NULL) {
360224006Shrs			syslog(LOG_ERR, "<%s> malloc", __func__);
361224006Shrs			exit(1);
362224006Shrs		}
363224006Shrs		memcpy(cp->cp_ifname, p, len);
364224006Shrs		cp->cp_ifname[len] = '\0';
365224006Shrs		p += len;
366224006Shrs	}
367224006Shrs
368224006Shrs	lenp = (size_t *)p;
369224006Shrs	len = *lenp++;
370224006Shrs	p = (char *)lenp;
371224144Shrs	syslog(LOG_DEBUG, "<%s> len(key) = %zu", __func__, len);
372224006Shrs	if (len > 0) {
373224006Shrs		cp->cp_key = malloc(len + 1);
374224006Shrs		if (cp->cp_key == NULL) {
375224006Shrs			syslog(LOG_ERR, "<%s> malloc", __func__);
376224006Shrs			exit(1);
377224006Shrs		}
378224006Shrs		memcpy(cp->cp_key, p, len);
379224006Shrs		cp->cp_key[len] = '\0';
380224006Shrs		p += len;
381224006Shrs	}
382224006Shrs
383224006Shrs	lenp = (size_t *)p;
384224006Shrs	len = *lenp++;
385224006Shrs	p = (char *)lenp;
386224144Shrs	syslog(LOG_DEBUG, "<%s> len(val) = %zu", __func__, len);
387224006Shrs	if (len > 0) {
388224006Shrs		cp->cp_val = malloc(len + 1);
389224006Shrs		if (cp->cp_val == NULL) {
390224006Shrs			syslog(LOG_ERR, "<%s> malloc", __func__);
391224006Shrs			exit(1);
392224006Shrs		}
393224006Shrs		memcpy(cp->cp_val, p, len);
394224006Shrs		cp->cp_val[len] = '\0';
395224006Shrs		cp->cp_val_len = len;
396224006Shrs	} else
397224006Shrs		cp->cp_val_len = 0;
398224006Shrs
399224006Shrs	return (cp);
400224006Shrs}
401224006Shrs
402224006Shrssize_t
403225519Shrscm_pl2bin(char *str, struct ctrl_msg_pl *cp)
404224006Shrs{
405224006Shrs	size_t len;
406224006Shrs	size_t *lenp;
407224006Shrs	char *p;
408224006Shrs	struct ctrl_msg_hdr *cm;
409224006Shrs
410224006Shrs	len = sizeof(size_t);
411224006Shrs	if (cp->cp_ifname != NULL)
412224006Shrs		len += strlen(cp->cp_ifname);
413224006Shrs	len += sizeof(size_t);
414224006Shrs	if (cp->cp_key != NULL)
415224006Shrs		len += strlen(cp->cp_key);
416224006Shrs	len += sizeof(size_t);
417224006Shrs	if (cp->cp_val != NULL && cp->cp_val_len > 0)
418224006Shrs		len += cp->cp_val_len;
419224006Shrs
420224006Shrs	if (len > CM_MSG_MAXLEN - sizeof(*cm)) {
421224144Shrs		syslog(LOG_DEBUG, "<%s> msg too long (len=%zu)",
422224006Shrs		    __func__, len);
423224006Shrs		return (0);
424224006Shrs	}
425224144Shrs	syslog(LOG_DEBUG, "<%s> msglen=%zu", __func__, len);
426224006Shrs	memset(str, 0, len);
427224006Shrs	p = str;
428224006Shrs	lenp = (size_t *)p;
429224006Shrs
430224006Shrs	if (cp->cp_ifname != NULL) {
431224006Shrs		*lenp++ = strlen(cp->cp_ifname);
432224006Shrs		p = (char *)lenp;
433224006Shrs		memcpy(p, cp->cp_ifname, strlen(cp->cp_ifname));
434224006Shrs		p += strlen(cp->cp_ifname);
435224006Shrs	} else {
436224006Shrs		*lenp++ = '\0';
437224006Shrs		p = (char *)lenp;
438224006Shrs	}
439224006Shrs
440224006Shrs	lenp = (size_t *)p;
441224006Shrs	if (cp->cp_key != NULL) {
442224006Shrs		*lenp++ = strlen(cp->cp_key);
443224006Shrs		p = (char *)lenp;
444224006Shrs		memcpy(p, cp->cp_key, strlen(cp->cp_key));
445224006Shrs		p += strlen(cp->cp_key);
446224006Shrs	} else {
447224006Shrs		*lenp++ = '\0';
448224006Shrs		p = (char *)lenp;
449224006Shrs	}
450224006Shrs
451224006Shrs	lenp = (size_t *)p;
452224006Shrs	if (cp->cp_val != NULL && cp->cp_val_len > 0) {
453224006Shrs		*lenp++ = cp->cp_val_len;
454224006Shrs		p = (char *)lenp;
455224006Shrs		memcpy(p, cp->cp_val, cp->cp_val_len);
456224006Shrs		p += cp->cp_val_len;
457224006Shrs	} else {
458224006Shrs		*lenp++ = '\0';
459224006Shrs		p = (char *)lenp;
460224006Shrs	}
461224006Shrs
462224006Shrs	return (len);
463224006Shrs}
464224006Shrs
465224006Shrssize_t
466225519Shrscm_str2bin(char *bin, void *str, size_t len)
467224006Shrs{
468224006Shrs	struct ctrl_msg_hdr *cm;
469224006Shrs
470224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
471224006Shrs
472224006Shrs	if (len > CM_MSG_MAXLEN - sizeof(*cm)) {
473224144Shrs		syslog(LOG_DEBUG, "<%s> msg too long (len=%zu)",
474224006Shrs		    __func__, len);
475224006Shrs		return (0);
476224006Shrs	}
477224144Shrs	syslog(LOG_DEBUG, "<%s> msglen=%zu", __func__, len);
478224006Shrs	memcpy(bin, (char *)str, len);
479224006Shrs
480224006Shrs	return (len);
481224006Shrs}
482224006Shrs
483224006Shrsvoid *
484225519Shrscm_bin2str(char *bin, void *str, size_t len)
485224006Shrs{
486224006Shrs
487224006Shrs	syslog(LOG_DEBUG, "<%s> enter", __func__);
488224006Shrs
489224006Shrs	memcpy((char *)str, bin, len);
490224006Shrs
491224006Shrs	return (str);
492224006Shrs}
493