control_server.c revision 224006
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 <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 "pathnames.h"
52#include "rtadvd.h"
53#include "if.h"
54#include "control.h"
55#include "control_server.h"
56#include "timer.h"
57
58static sig_atomic_t p_do_reload;
59static sig_atomic_t p_do_die;
60
61void set_do_reload(int sig __unused)	{ p_do_reload = 1; }
62void set_do_die(int sig __unused)	{ p_do_die = 1; }
63void reset_do_reload(void)	{ p_do_reload = 0; }
64void reset_do_die(void)		{ p_do_die = 0; }
65int do_reload(void)	{ return (p_do_reload); }
66int do_die(void)	{ return (p_do_die); }
67
68#define	DEF_PL_HANDLER(key)	{ #key, cmsg_getprop_##key }
69
70static int cmsg_getprop_echo(struct ctrl_msg_pl *);
71static int cmsg_getprop_version(struct ctrl_msg_pl *);
72static int cmsg_getprop_ifilist(struct ctrl_msg_pl *);
73static int cmsg_getprop_ifi(struct ctrl_msg_pl *);
74static int cmsg_getprop_rai(struct ctrl_msg_pl *);
75static int cmsg_getprop_rai_timer(struct ctrl_msg_pl *);
76static int cmsg_getprop_pfx(struct ctrl_msg_pl *);
77static int cmsg_getprop_rdnss(struct ctrl_msg_pl *);
78static int cmsg_getprop_dnssl(struct ctrl_msg_pl *);
79#ifdef ROUTEINFO
80static int cmsg_getprop_rti(struct ctrl_msg_pl *);
81#endif
82
83static struct dispatch_table {
84	const char	*dt_comm;
85	int		(*dt_act)(struct ctrl_msg_pl *cp);
86} getprop_dtable[] = {
87	{ "",	cmsg_getprop_echo },
88	DEF_PL_HANDLER(echo),
89	DEF_PL_HANDLER(version),
90	DEF_PL_HANDLER(ifilist),
91	DEF_PL_HANDLER(ifi),
92	DEF_PL_HANDLER(rai),
93	DEF_PL_HANDLER(rai_timer),
94#ifdef ROUTEINFO
95	DEF_PL_HANDLER(rti),
96#endif
97	DEF_PL_HANDLER(pfx),
98	DEF_PL_HANDLER(rdnss),
99	DEF_PL_HANDLER(dnssl),
100};
101
102static int
103cmsg_getprop_echo(struct ctrl_msg_pl *cp)
104{
105
106	syslog(LOG_DEBUG, "<%s> enter", __func__);
107	cp->cp_val = strdup("");
108	cp->cp_val_len = strlen(cp->cp_val) + 1;
109
110	return (0);
111}
112
113static int
114cmsg_getprop_version(struct ctrl_msg_pl *cp)
115{
116
117	syslog(LOG_DEBUG, "<%s> enter", __func__);
118	cp->cp_val = strdup(CM_VERSION_STR);
119	cp->cp_val_len = strlen(cp->cp_val) + 1;
120
121	return (0);
122}
123
124static int
125cmsg_getprop_ifilist(struct ctrl_msg_pl *cp)
126{
127	struct ifinfo *ifi;
128	char *p;
129	size_t len;
130
131	syslog(LOG_DEBUG, "<%s> enter", __func__);
132
133	len = 0;
134	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
135		len += strlen(ifi->ifi_ifname) + 1;
136	}
137
138	syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
139
140	p = malloc(len);
141	if (p == NULL)
142		exit(1);
143	memset(p, 0, len);
144	cp->cp_val = p;
145
146	if (len > 0)
147		TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
148			syslog(LOG_DEBUG, "<%s> add ifname=%s(%d)",
149			    __func__, ifi->ifi_ifname, ifi->ifi_ifindex);
150			strcpy(p, ifi->ifi_ifname);
151			p += strlen(ifi->ifi_ifname) + 1;
152		}
153	cp->cp_val_len = p - cp->cp_val;
154
155	return (0);
156}
157
158static int
159cmsg_getprop_ifi(struct ctrl_msg_pl *cp)
160{
161	struct ifinfo *ifi;
162	char *p;
163	size_t len;
164
165	syslog(LOG_DEBUG, "<%s> enter", __func__);
166
167	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
168		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
169			break;
170	}
171	if (ifi == NULL) {
172		syslog(LOG_ERR, "<%s> %s not found", __func__,
173		    cp->cp_ifname);
174		return (1);
175	}
176
177	p = malloc(sizeof(*ifi));
178	if (p == NULL)
179		exit(1);
180	len = cmsg_str2bin(p, ifi, sizeof(*ifi));
181
182	syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
183
184	if (len == 0)
185		return (1);
186
187	cp->cp_val = p;
188	cp->cp_val_len = len;
189
190	return (0);
191}
192
193static int
194cmsg_getprop_rai(struct ctrl_msg_pl *cp)
195{
196	struct ifinfo *ifi;
197	struct rainfo *rai;
198	char *p;
199	size_t len;
200
201	syslog(LOG_DEBUG, "<%s> enter", __func__);
202
203	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
204		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
205			break;
206	}
207	if (ifi == NULL) {
208		syslog(LOG_ERR, "<%s> %s not found", __func__,
209		    cp->cp_ifname);
210		return (1);
211	}
212	if ((rai = ifi->ifi_rainfo) == NULL) {
213		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
214		    cp->cp_ifname);
215		return (1);
216	}
217
218	p = malloc(sizeof(*rai));
219	if (p == NULL)
220		exit(1);
221	len = cmsg_str2bin(p, rai, sizeof(*rai));
222
223	syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
224
225	if (len == 0)
226		return (1);
227
228	cp->cp_val = p;
229	cp->cp_val_len = len;
230
231	return (0);
232}
233
234static int
235cmsg_getprop_rai_timer(struct ctrl_msg_pl *cp)
236{
237	struct ifinfo *ifi;
238	struct rainfo *rai;
239	struct rtadvd_timer	*rtimer;
240	char *p;
241	size_t len;
242
243	syslog(LOG_DEBUG, "<%s> enter", __func__);
244
245	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
246		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
247			break;
248	}
249	if (ifi == NULL) {
250		syslog(LOG_ERR, "<%s> %s not found", __func__,
251		    cp->cp_ifname);
252		return (1);
253	}
254	if ((rai = ifi->ifi_rainfo) == NULL) {
255		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
256		    cp->cp_ifname);
257		return (1);
258	}
259	if ((rtimer = rai->rai_timer) == NULL) {
260		syslog(LOG_ERR, "<%s> %s has no rai_timer", __func__,
261		    cp->cp_ifname);
262		return (1);
263	}
264	p = malloc(sizeof(*rtimer));
265	if (p == NULL)
266		exit(1);
267	len = cmsg_str2bin(p, rtimer, sizeof(*rtimer));
268
269	syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
270
271	if (len == 0)
272		return (1);
273
274	cp->cp_val = p;
275	cp->cp_val_len = len;
276
277	return (0);
278}
279
280#ifdef ROUTEINFO
281static int
282cmsg_getprop_rti(struct ctrl_msg_pl *cp)
283{
284	struct ifinfo *ifi;
285	struct rainfo *rai;
286	struct rtinfo *rti;
287	char *p;
288	size_t len;
289
290	syslog(LOG_DEBUG, "<%s> enter", __func__);
291
292	len = 0;
293	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
294		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
295			break;
296	}
297	if (ifi == NULL) {
298		syslog(LOG_ERR, "<%s> %s not found", __func__,
299		    cp->cp_ifname);
300		return (1);
301	}
302	if (ifi->ifi_rainfo == NULL) {
303		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
304		    cp->cp_ifname);
305		return (1);
306	}
307	rai = ifi->ifi_rainfo;
308	TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
309		len += sizeof(*rti);
310	}
311
312	syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
313
314	p = malloc(len);
315	if (p == NULL)
316		exit(1);
317	memset(p, 0, len);
318	cp->cp_val = p;
319
320	if (len > 0)
321		TAILQ_FOREACH(rti, &rai->rai_route, rti_next) {
322			memcpy(p, rti, sizeof(*rti));
323			p += sizeof(*rti);
324		}
325	cp->cp_val_len = p - cp->cp_val;
326
327	return (0);
328}
329#endif
330
331static int
332cmsg_getprop_pfx(struct ctrl_msg_pl *cp)
333{
334	struct ifinfo *ifi;
335	struct rainfo *rai;
336	struct prefix *pfx;
337	char *p;
338	size_t len;
339
340	syslog(LOG_DEBUG, "<%s> enter", __func__);
341
342	len = 0;
343	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
344		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
345			break;
346	}
347	if (ifi == NULL) {
348		syslog(LOG_ERR, "<%s> %s not found", __func__,
349		    cp->cp_ifname);
350		return (1);
351	}
352	if (ifi->ifi_rainfo == NULL) {
353		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
354		    cp->cp_ifname);
355		return (1);
356	}
357	rai = ifi->ifi_rainfo;
358	TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
359		len += sizeof(*pfx);
360	}
361
362	syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
363
364	p = malloc(len);
365	if (p == NULL)
366		exit(1);
367	memset(p, 0, len);
368	cp->cp_val = p;
369
370	if (len > 0)
371		TAILQ_FOREACH(pfx, &rai->rai_prefix, pfx_next) {
372			memcpy(p, pfx, sizeof(*pfx));
373			p += sizeof(*pfx);
374		}
375	cp->cp_val_len = p - cp->cp_val;
376
377	return (0);
378}
379
380static int
381cmsg_getprop_rdnss(struct ctrl_msg_pl *cp)
382{
383	struct ifinfo *ifi;
384	struct rainfo *rai;
385	struct rdnss *rdn;
386	struct rdnss_addr *rda;
387	char *p;
388	size_t len;
389	u_int16_t *rdn_cnt;
390	u_int16_t *rda_cnt;
391
392	syslog(LOG_DEBUG, "<%s> enter", __func__);
393
394	len = 0;
395	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
396		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
397			break;
398	}
399	if (ifi == NULL) {
400		syslog(LOG_ERR, "<%s> %s not found", __func__,
401		    cp->cp_ifname);
402		return (1);
403	}
404	if (ifi->ifi_rainfo == NULL) {
405		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
406		    cp->cp_ifname);
407		return (1);
408	}
409	rai = ifi->ifi_rainfo;
410
411	len = sizeof(*rdn_cnt);
412	TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
413		len += sizeof(*rdn);
414		len += sizeof(*rda_cnt);
415		TAILQ_FOREACH(rda, &rdn->rd_list, ra_next) {
416			len += sizeof(*rda);
417		}
418	}
419
420	syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
421
422	p = malloc(len);
423	if (p == NULL)
424		exit(1);
425	memset(p, 0, len);
426	cp->cp_val = p;
427
428	rdn_cnt = (u_int16_t *)p;
429	p += sizeof(*rdn_cnt);
430	TAILQ_FOREACH(rdn, &rai->rai_rdnss, rd_next) {
431		*rdn_cnt += 1;
432		memcpy(p, rdn, sizeof(*rdn));
433		p += sizeof(*rdn);
434
435		rda_cnt = (u_int16_t *)p;
436		p += sizeof(*rda_cnt);
437		TAILQ_FOREACH(rda, &rdn->rd_list, ra_next) {
438			*rda_cnt += 1;
439			memcpy(p, rda, sizeof(*rda));
440			p += sizeof(*rda);
441		}
442	}
443	syslog(LOG_DEBUG, "<%s> rdn_cnt = %d", __func__, *rdn_cnt);
444	cp->cp_val_len = p - cp->cp_val;
445
446	return (0);
447}
448
449static int
450cmsg_getprop_dnssl(struct ctrl_msg_pl *cp)
451{
452	struct ifinfo *ifi;
453	struct rainfo *rai;
454	struct dnssl *dns;
455	struct dnssl_addr *dna;
456	char *p;
457	size_t len;
458	u_int16_t *dns_cnt;
459	u_int16_t *dna_cnt;
460
461	syslog(LOG_DEBUG, "<%s> enter", __func__);
462
463	len = 0;
464	TAILQ_FOREACH(ifi, &ifilist, ifi_next) {
465		if (strcmp(cp->cp_ifname, ifi->ifi_ifname) == 0)
466			break;
467	}
468	if (ifi == NULL) {
469		syslog(LOG_ERR, "<%s> %s not found", __func__,
470		    cp->cp_ifname);
471		return (1);
472	}
473	if (ifi->ifi_rainfo == NULL) {
474		syslog(LOG_ERR, "<%s> %s has no rainfo", __func__,
475		    cp->cp_ifname);
476		return (1);
477	}
478	rai = ifi->ifi_rainfo;
479
480	len = sizeof(*dns_cnt);
481	TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
482		len += sizeof(*dns);
483		len += sizeof(*dna_cnt);
484		TAILQ_FOREACH(dna, &dns->dn_list, da_next) {
485			len += sizeof(*dna);
486		}
487	}
488
489	syslog(LOG_DEBUG, "<%s> len = %d", __func__, len);
490
491	p = malloc(len);
492	if (p == NULL)
493		exit(1);
494	memset(p, 0, len);
495	cp->cp_val = p;
496
497	dns_cnt = (u_int16_t *)cp->cp_val;
498	p += sizeof(*dns_cnt);
499	TAILQ_FOREACH(dns, &rai->rai_dnssl, dn_next) {
500		(*dns_cnt)++;
501		memcpy(p, dns, sizeof(*dns));
502		p += sizeof(*dns);
503
504		dna_cnt = (u_int16_t *)p;
505		p += sizeof(*dna_cnt);
506		TAILQ_FOREACH(dna, &dns->dn_list, da_next) {
507			(*dna_cnt)++;
508			memcpy(p, dna, sizeof(*dna));
509			p += sizeof(*dna);
510		}
511	}
512	cp->cp_val_len = p - cp->cp_val;
513
514	return (0);
515}
516
517int
518cmsg_getprop(struct ctrl_msg_pl *cp)
519{
520	size_t i;
521
522	syslog(LOG_DEBUG, "<%s> enter", __func__);
523
524	if (cp == NULL)
525		return (1);
526
527	for (i = 0;
528	     i < sizeof(getprop_dtable) / sizeof(getprop_dtable[0]);
529	     i++) {
530		if (strcmp(cp->cp_key, getprop_dtable[i].dt_comm) == 0)
531			return (getprop_dtable[i].dt_act(cp));
532	}
533	return (1);
534}
535
536int
537cmsg_setprop(struct ctrl_msg_pl *cp)
538{
539	syslog(LOG_DEBUG, "<%s> enter", __func__);
540
541	if (cp == NULL || cp->cp_key == NULL)
542		return (1);
543
544	if (strncmp(cp->cp_key, "reload", 8) == 0)
545		set_do_reload(0);
546	else if (strncmp(cp->cp_key, "shutdown", 8) == 0)
547		set_do_die(0);
548	else if (strncmp(cp->cp_key, "echo", 8) == 0)
549		; 		/* do nothing */
550	else
551		return (1);
552
553	return (0);
554}
555
556int
557cmsg_handler_server(int fd)
558{
559	int state;
560	char *msg;
561	struct ctrl_msg_hdr *cm;
562	struct ctrl_msg_pl cp;
563	char buf[CM_MSG_MAXLEN];
564	char pbuf[CM_MSG_MAXLEN];
565	int error;
566
567	syslog(LOG_DEBUG, "<%s> enter", __func__);
568
569	memset(buf, 0, sizeof(buf));
570	memset(pbuf, 0, sizeof(pbuf));
571	cm = (struct ctrl_msg_hdr *)buf;
572	msg = (char *)buf + sizeof(*cm);
573
574	state = CM_STATE_INIT;
575	while (state != CM_STATE_EOM) {
576		syslog(LOG_DEBUG, "<%s> state = %d", __func__, state);
577
578		switch (state) {
579		case CM_STATE_INIT:
580			state = CM_STATE_MSG_RECV;
581			break;
582		case CM_STATE_MSG_DISPATCH:
583			cm->cm_version = CM_VERSION;
584			error = cmsg_send(fd, buf);
585			if (error)
586				syslog(LOG_WARNING,
587				    "<%s> cmsg_send()", __func__);
588			state = CM_STATE_EOM;
589			break;
590		case CM_STATE_ACK_WAIT:
591			error = cmsg_recv(fd, buf);
592			if (error) {
593				syslog(LOG_ERR,
594				    "<%s> cmsg_recv()", __func__);
595				close(fd);
596				return (-1);
597			}
598
599			switch (cm->cm_type) {
600			case CM_TYPE_ACK:
601				break;
602			case CM_TYPE_ERR:
603				syslog(LOG_DEBUG,
604				    "<%s> CM_TYPE_ERR", __func__);
605				close(fd);
606				return (-1);
607			default:
608				syslog(LOG_DEBUG,
609				    "<%s> unknown status", __func__);
610				close(fd);
611				return (-1);
612			}
613			state = CM_STATE_EOM;
614			break;
615		case CM_STATE_MSG_RECV:
616			error = cmsg_recv(fd, buf);
617
618			if (error) {
619				syslog(LOG_ERR,
620				    "<%s> cmsg_recv()", __func__);
621				close(fd);
622				return (-1);
623			}
624			memset(&cp, 0, sizeof(cp));
625
626			syslog(LOG_DEBUG,
627			    "<%s> cm->cm_type = %d", __func__, cm->cm_type);
628			syslog(LOG_DEBUG,
629			    "<%s> cm->cm_len = %d", __func__, cm->cm_len);
630
631			switch (cm->cm_type) {
632			case CM_TYPE_EOM:
633				state = CM_STATE_EOM;
634			case CM_TYPE_NUL:
635				cm->cm_type = CM_TYPE_ACK;
636				cm->cm_len = sizeof(*cm);
637				break;
638			case CM_TYPE_REQ_GET_PROP:
639				cmsg_bin2pl(msg, &cp);
640				error = cmsg_getprop(&cp);
641				if (error) {
642					cm->cm_type = CM_TYPE_ERR;
643					cm->cm_len = sizeof(*cm);
644				} else {
645					cm->cm_type = CM_TYPE_ACK;
646					cm->cm_len = sizeof(*cm);
647					cm->cm_len += cmsg_pl2bin(msg, &cp);
648				}
649				break;
650			case CM_TYPE_REQ_SET_PROP:
651				cmsg_bin2pl(msg, &cp);
652				error = cmsg_setprop(&cp);
653				if (error) {
654					cm->cm_type = CM_TYPE_ERR;
655					cm->cm_len = sizeof(*cm);
656				} else {
657					cm->cm_type = CM_TYPE_ACK;
658					cm->cm_len = sizeof(*cm);
659				}
660				break;
661			default:
662				cm->cm_type = CM_TYPE_ERR;
663				cm->cm_len = sizeof(*cm);
664			}
665
666			switch (cm->cm_type) {
667			case CM_TYPE_ERR:
668			case CM_TYPE_ACK:
669				state = CM_STATE_MSG_DISPATCH;
670				break;
671			}
672		}
673	}
674	syslog(LOG_DEBUG, "<%s> leave", __func__);
675
676	return (0);
677}
678