1238384Sjkim/*-
2238384Sjkim * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
3238384Sjkim * All rights reserved.
4238384Sjkim *
5238384Sjkim * Redistribution and use in source and binary forms, with or without
6238384Sjkim * modification, are permitted provided that the following conditions
7238384Sjkim * are met:
8280297Sjkim * 1. Redistributions of source code must retain the above copyright
9238384Sjkim *    notice, this list of conditions and the following disclaimer.
10238384Sjkim * 2. Redistributions in binary form must reproduce the above copyright
11238384Sjkim *    notice, this list of conditions and the following disclaimer in the
12238384Sjkim *    documentation and/or other materials provided with the distribution.
13238384Sjkim *
14238384Sjkim * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
15280297Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16238384Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17238384Sjkim * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
18238384Sjkim * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19238384Sjkim * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20238384Sjkim * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
21238384Sjkim * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22280297Sjkim * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23238384Sjkim * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
24238384Sjkim * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25238384Sjkim *
26238384Sjkim * $FreeBSD$
27238384Sjkim *
28238384Sjkim */
29238384Sjkim
30238384Sjkim#include <sys/queue.h>
31238384Sjkim#include <sys/types.h>
32238384Sjkim#include <sys/socket.h>
33238384Sjkim#include <sys/stat.h>
34238384Sjkim#include <sys/un.h>
35238384Sjkim#include <sys/uio.h>
36238384Sjkim#include <net/if.h>
37280297Sjkim#include <net/if_dl.h>
38238384Sjkim#include <net/if_types.h>
39238384Sjkim#include <net/if_var.h>
40280297Sjkim#include <net/ethernet.h>
41238384Sjkim#include <netinet/in.h>
42238384Sjkim#include <netinet/ip6.h>
43238384Sjkim#include <netinet/icmp6.h>
44238384Sjkim#include <netinet6/in6_var.h>
45238384Sjkim#include <netinet6/nd6.h>
46238384Sjkim#include <arpa/inet.h>
47238384Sjkim#include <fcntl.h>
48238384Sjkim#include <errno.h>
49238384Sjkim#include <inttypes.h>
50238384Sjkim#include <netdb.h>
51238384Sjkim#include <unistd.h>
52280297Sjkim#include <string.h>
53238384Sjkim#include <stdarg.h>
54238384Sjkim#include <stdio.h>
55238384Sjkim#include <stdlib.h>
56238384Sjkim#include <stdarg.h>
57238384Sjkim#include <syslog.h>
58238384Sjkim#include <time.h>
59238384Sjkim#include <err.h>
60238384Sjkim
61238384Sjkim#include "pathnames.h"
62238384Sjkim#include "rtadvd.h"
63238384Sjkim#include "if.h"
64238384Sjkim#include "timer_subr.h"
65238384Sjkim#include "timer.h"
66280297Sjkim#include "control.h"
67280297Sjkim#include "control_client.h"
68280297Sjkim
69238384Sjkim#define RA_IFSTATUS_INACTIVE	0
70280297Sjkim#define RA_IFSTATUS_RA_RECV	1
71280297Sjkim#define RA_IFSTATUS_RA_SEND	2
72280297Sjkim
73280297Sjkimstatic int vflag = LOG_ERR;
74280297Sjkim
75280297Sjkimstatic void	usage(void);
76280297Sjkim
77280297Sjkimstatic int	action_propset(char *);
78280297Sjkimstatic int	action_propget(char *, struct ctrl_msg_pl *);
79238384Sjkimstatic int	action_plgeneric(int, char *, char *);
80
81static int	action_enable(int, char **);
82static int	action_disable(int, char **);
83static int	action_reload(int, char **);
84static int	action_echo(int, char **);
85static int	action_version(int, char **);
86static int	action_shutdown(int, char **);
87
88static int	action_show(int, char **);
89static int	action_show_prefix(struct prefix *);
90static int	action_show_rtinfo(struct rtinfo *);
91static int	action_show_rdnss(void *);
92static int	action_show_dnssl(void *);
93
94static int	csock_client_open(struct sockinfo *);
95static size_t	dname_labeldec(char *, size_t, const char *);
96static void	mysyslog(int, const char *, ...);
97
98static const char *rtpref_str[] = {
99	"medium",		/* 00 */
100	"high",			/* 01 */
101	"rsv",			/* 10 */
102	"low"			/* 11 */
103};
104
105static struct dispatch_table {
106	const char	*dt_comm;
107	int (*dt_act)(int, char **);
108} dtable[] = {
109	{ "show", action_show },
110	{ "reload", action_reload },
111	{ "shutdown", action_shutdown },
112	{ "enable", action_enable },
113	{ "disable", action_disable },
114	{ NULL, NULL },
115	{ "echo", action_echo },
116	{ "version", action_version },
117	{ NULL, NULL },
118};
119
120static char errmsgbuf[1024];
121static char *errmsg = NULL;
122
123static void
124mysyslog(int priority, const char * restrict fmt, ...)
125{
126	va_list ap;
127
128	if (vflag >= priority) {
129		va_start(ap, fmt);
130		vfprintf(stderr, fmt, ap);
131		fprintf(stderr, "\n");
132		va_end(ap);
133	}
134}
135
136static void
137usage(void)
138{
139	int i;
140
141	for (i = 0; (size_t)i < sizeof(dtable)/sizeof(dtable[0]); i++) {
142		if (dtable[i].dt_comm == NULL)
143			break;
144		printf("%s\n", dtable[i].dt_comm);
145	}
146
147	exit(1);
148}
149
150int
151main(int argc, char *argv[])
152{
153	int i;
154	int ch;
155	int (*action)(int, char **) = NULL;
156	int error;
157
158	while ((ch = getopt(argc, argv, "Dv")) != -1) {
159		switch (ch) {
160		case 'D':
161			vflag = LOG_DEBUG;
162			break;
163		case 'v':
164			vflag++;
165			break;
166		default:
167			usage();
168		}
169	}
170	argc -= optind;
171	argv += optind;
172
173	if (argc == 0)
174		usage();
175
176	for (i = 0; (size_t)i < sizeof(dtable)/sizeof(dtable[0]); i++) {
177		if (dtable[i].dt_comm == NULL ||
178		    strcmp(dtable[i].dt_comm, argv[0]) == 0) {
179			action = dtable[i].dt_act;
180			break;
181		}
182	}
183
184	if (action == NULL)
185		usage();
186
187	error = (dtable[i].dt_act)(--argc, ++argv);
188	if (error) {
189		fprintf(stderr, "%s failed", dtable[i].dt_comm);
190		if (errmsg != NULL)
191			fprintf(stderr, ": %s", errmsg);
192		fprintf(stderr, ".\n");
193	}
194
195	return (error);
196}
197
198static int
199csock_client_open(struct sockinfo *s)
200{
201	struct sockaddr_un sun;
202
203	if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
204		err(1, "cannot open control socket.");
205
206	memset(&sun, 0, sizeof(sun));
207	sun.sun_family = AF_UNIX;
208	sun.sun_len = sizeof(sun);
209	strlcpy(sun.sun_path, s->si_name, sizeof(sun.sun_path));
210
211	if (connect(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
212		err(1, "connect: %s", s->si_name);
213
214	mysyslog(LOG_DEBUG,
215	    "<%s> connected to %s", __func__, sun.sun_path);
216
217	return (0);
218}
219
220static int
221action_plgeneric(int action, char *plstr, char *buf)
222{
223	struct ctrl_msg_hdr *cm;
224	struct ctrl_msg_pl cp;
225	struct sockinfo *s;
226	char *msg;
227	char *p;
228	char *q;
229
230	s = &ctrlsock;
231	csock_client_open(s);
232
233	cm = (struct ctrl_msg_hdr *)buf;
234	msg = (char *)buf + sizeof(*cm);
235
236	cm->cm_version = CM_VERSION;
237	cm->cm_type = action;
238	cm->cm_len = sizeof(*cm);
239
240	if (plstr != NULL) {
241		memset(&cp, 0, sizeof(cp));
242		p = strchr(plstr, ':');
243		q = strchr(plstr, '=');
244		if (p != NULL && q != NULL && p > q)
245			return (1);
246
247		if (p == NULL) {		/* No : */
248			cp.cp_ifname = NULL;
249			cp.cp_key = plstr;
250		} else if  (p == plstr) {	/* empty */
251			cp.cp_ifname = NULL;
252			cp.cp_key = plstr + 1;
253		} else {
254			*p++ = '\0';
255			cp.cp_ifname = plstr;
256			cp.cp_key = p;
257		}
258		if (q == NULL)
259			cp.cp_val = NULL;
260		else {
261			*q++ = '\0';
262			cp.cp_val = q;
263		}
264		cm->cm_len += cm_pl2bin(msg, &cp);
265
266		mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s",
267		    __func__,cp.cp_key, cp.cp_val_len, cp.cp_ifname);
268	}
269
270	return (cm_handler_client(s->si_fd, CM_STATE_MSG_DISPATCH, buf));
271}
272
273static int
274action_propget(char *argv, struct ctrl_msg_pl *cp)
275{
276	int error;
277	struct ctrl_msg_hdr *cm;
278	char buf[CM_MSG_MAXLEN];
279	char *msg;
280
281	memset(cp, 0, sizeof(*cp));
282	cm = (struct ctrl_msg_hdr *)buf;
283	msg = (char *)buf + sizeof(*cm);
284
285	error = action_plgeneric(CM_TYPE_REQ_GET_PROP, argv, buf);
286	if (error || cm->cm_len <= sizeof(*cm))
287		return (1);
288
289	cm_bin2pl(msg, cp);
290	mysyslog(LOG_DEBUG, "<%s> type=%d, len=%d",
291	    __func__, cm->cm_type, cm->cm_len);
292	mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s",
293	    __func__,cp->cp_key, cp->cp_val_len, cp->cp_ifname);
294
295	return (0);
296}
297
298static int
299action_propset(char *argv)
300{
301	char buf[CM_MSG_MAXLEN];
302
303	return (action_plgeneric(CM_TYPE_REQ_SET_PROP, argv, buf));
304}
305
306static int
307action_disable(int argc, char **argv)
308{
309	char *action_argv;
310	char argv_disable[IFNAMSIZ + sizeof(":disable=")];
311	int i;
312	int error;
313
314	if (argc < 1)
315		return (1);
316
317	error = 0;
318	for (i = 0; i < argc; i++) {
319		sprintf(argv_disable, "%s:disable=", argv[i]);
320		action_argv = argv_disable;
321		error += action_propset(action_argv);
322	}
323
324	return (error);
325}
326
327static int
328action_enable(int argc, char **argv)
329{
330	char *action_argv;
331	char argv_enable[IFNAMSIZ + sizeof(":enable=")];
332	int i;
333	int error;
334
335	if (argc < 1)
336		return (1);
337
338	error = 0;
339	for (i = 0; i < argc; i++) {
340		sprintf(argv_enable, "%s:enable=", argv[i]);
341		action_argv = argv_enable;
342		error += action_propset(action_argv);
343	}
344
345	return (error);
346}
347
348static int
349action_reload(int argc, char **argv)
350{
351	char *action_argv;
352	char argv_reload[IFNAMSIZ + sizeof(":reload=")];
353	int i;
354	int error;
355
356	if (argc == 0) {
357		action_argv = strdup(":reload=");
358		return (action_propset(action_argv));
359	}
360
361	error = 0;
362	for (i = 0; i < argc; i++) {
363		sprintf(argv_reload, "%s:reload=", argv[i]);
364		action_argv = argv_reload;
365		error += action_propset(action_argv);
366	}
367
368	return (error);
369}
370
371static int
372action_echo(int argc __unused, char **argv __unused)
373{
374	char *action_argv;
375
376	action_argv = strdup("echo");
377	return (action_propset(action_argv));
378}
379
380static int
381action_shutdown(int argc __unused, char **argv __unused)
382{
383	char *action_argv;
384
385	action_argv = strdup("shutdown");
386	return (action_propset(action_argv));
387}
388
389/* XXX */
390static int
391action_version(int argc __unused, char **argv __unused)
392{
393	char *action_argv;
394	struct ctrl_msg_pl cp;
395	int error;
396
397	action_argv = strdup(":version=");
398	error = action_propget(action_argv, &cp);
399	if (error)
400		return (error);
401
402	printf("version=%s\n", cp.cp_val);
403	return (0);
404}
405
406static int
407action_show(int argc, char **argv)
408{
409	char *action_argv;
410	char argv_ifilist[sizeof(":ifilist=")] = ":ifilist=";
411	char argv_ifi[IFNAMSIZ + sizeof(":ifi=")];
412	char argv_rai[IFNAMSIZ + sizeof(":rai=")];
413	char argv_rti[IFNAMSIZ + sizeof(":rti=")];
414	char argv_pfx[IFNAMSIZ + sizeof(":pfx=")];
415	char argv_ifi_ra_timer[IFNAMSIZ + sizeof(":ifi_ra_timer=")];
416	char argv_rdnss[IFNAMSIZ + sizeof(":rdnss=")];
417	char argv_dnssl[IFNAMSIZ + sizeof(":dnssl=")];
418	char ssbuf[SSBUFLEN];
419
420	struct timespec now, ts0, ts;
421	struct ctrl_msg_pl cp;
422	struct ifinfo *ifi;
423	TAILQ_HEAD(, ifinfo) ifl = TAILQ_HEAD_INITIALIZER(ifl);
424	char *endp;
425	char *p;
426	int error;
427	int i;
428	int len;
429
430	if (argc == 0) {
431		action_argv = argv_ifilist;
432		error = action_propget(action_argv, &cp);
433		if (error)
434			return (error);
435
436		p = cp.cp_val;
437		endp = p + cp.cp_val_len;
438		while (p < endp) {
439			ifi = malloc(sizeof(*ifi));
440			if (ifi == NULL)
441				return (1);
442			memset(ifi, 0, sizeof(*ifi));
443
444			strcpy(ifi->ifi_ifname, p);
445			ifi->ifi_ifindex = if_nametoindex(ifi->ifi_ifname);
446			TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next);
447			p += strlen(ifi->ifi_ifname) + 1;
448		}
449	} else {
450		for (i = 0; i < argc; i++) {
451			ifi = malloc(sizeof(*ifi));
452			if (ifi == NULL)
453				return (1);
454			memset(ifi, 0, sizeof(*ifi));
455
456			strcpy(ifi->ifi_ifname, argv[i]);
457			ifi->ifi_ifindex = if_nametoindex(ifi->ifi_ifname);
458			if (ifi->ifi_ifindex == 0) {
459				sprintf(errmsgbuf, "invalid interface %s",
460				    ifi->ifi_ifname);
461				errmsg = errmsgbuf;
462				return (1);
463			}
464
465			TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next);
466		}
467	}
468
469	clock_gettime(CLOCK_REALTIME_FAST, &now);
470	clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
471	TS_SUB(&now, &ts, &ts0);
472
473	TAILQ_FOREACH(ifi, &ifl, ifi_next) {
474		struct ifinfo *ifi_s;
475		struct rtadvd_timer *rat;
476		struct rainfo *rai;
477		struct rtinfo *rti;
478		struct prefix *pfx;
479		int c;
480		int ra_ifstatus;
481
482		sprintf(argv_ifi, "%s:ifi=", ifi->ifi_ifname);
483		action_argv = argv_ifi;
484		error = action_propget(action_argv, &cp);
485		if (error)
486			return (error);
487		ifi_s = (struct ifinfo *)cp.cp_val;
488
489		if (!(ifi_s->ifi_persist) && vflag < LOG_NOTICE)
490			continue;
491
492		printf("%s: flags=<", ifi->ifi_ifname);
493
494		c = 0;
495		if (ifi_s->ifi_ifindex == 0)
496			c += printf("NONEXISTENT");
497		else
498			c += printf("%s", (ifi_s->ifi_flags & IFF_UP) ?
499			    "UP" : "DOWN");
500		switch (ifi_s->ifi_state) {
501		case IFI_STATE_CONFIGURED:
502			c += printf("%s%s", (c) ? "," : "", "CONFIGURED");
503			break;
504		case IFI_STATE_TRANSITIVE:
505			c += printf("%s%s", (c) ? "," : "", "TRANSITIVE");
506			break;
507		}
508		if (ifi_s->ifi_persist)
509			c += printf("%s%s", (c) ? "," : "", "PERSIST");
510		printf(">");
511
512		ra_ifstatus = RA_IFSTATUS_INACTIVE;
513		if ((ifi_s->ifi_flags & IFF_UP) &&
514		    ((ifi_s->ifi_state == IFI_STATE_CONFIGURED) ||
515			(ifi_s->ifi_state == IFI_STATE_TRANSITIVE))) {
516#if (__FreeBSD_version < 900000)
517			/*
518			 * RA_RECV: !ip6.forwarding && ip6.accept_rtadv
519			 * RA_SEND: ip6.forwarding
520			 */
521			if (getinet6sysctl(IPV6CTL_FORWARDING) == 0) {
522				if (getinet6sysctl(IPV6CTL_ACCEPT_RTADV))
523					ra_ifstatus = RA_IFSTATUS_RA_RECV;
524				else
525					ra_ifstatus = RA_IFSTATUS_INACTIVE;
526			} else
527				ra_ifstatus = RA_IFSTATUS_RA_SEND;
528#else
529			/*
530			 * RA_RECV: ND6_IFF_ACCEPT_RTADV
531			 * RA_SEND: ip6.forwarding
532			 */
533			if (ifi_s->ifi_nd_flags & ND6_IFF_ACCEPT_RTADV)
534				ra_ifstatus = RA_IFSTATUS_RA_RECV;
535			else if (getinet6sysctl(IPV6CTL_FORWARDING))
536				ra_ifstatus = RA_IFSTATUS_RA_SEND;
537			else
538				ra_ifstatus = RA_IFSTATUS_INACTIVE;
539#endif
540		}
541
542		c = 0;
543		printf(" status=<");
544		if (ra_ifstatus == RA_IFSTATUS_INACTIVE)
545			printf("%s%s", (c) ? "," : "", "INACTIVE");
546		else if (ra_ifstatus == RA_IFSTATUS_RA_RECV)
547			printf("%s%s", (c) ? "," : "", "RA_RECV");
548		else if (ra_ifstatus == RA_IFSTATUS_RA_SEND)
549			printf("%s%s", (c) ? "," : "", "RA_SEND");
550		printf("> ");
551
552		switch (ifi_s->ifi_state) {
553		case IFI_STATE_CONFIGURED:
554		case IFI_STATE_TRANSITIVE:
555			break;
556		default:
557			printf("\n");
558			continue;
559		}
560
561		printf("mtu %d\n", ifi_s->ifi_phymtu);
562
563		sprintf(argv_rai, "%s:rai=", ifi->ifi_ifname);
564		action_argv = argv_rai;
565
566		error = action_propget(action_argv, &cp);
567		if (error)
568			continue;
569
570		rai = (struct rainfo *)cp.cp_val;
571
572		printf("\tDefaultLifetime: %s",
573		    sec2str(rai->rai_lifetime, ssbuf));
574		if (ra_ifstatus != RA_IFSTATUS_RA_SEND &&
575		    rai->rai_lifetime == 0)
576			printf(" (RAs will be sent with zero lifetime)");
577
578		printf("\n");
579
580		printf("\tMinAdvInterval/MaxAdvInterval: ");
581		printf("%s/", sec2str(rai->rai_mininterval, ssbuf));
582		printf("%s\n", sec2str(rai->rai_maxinterval, ssbuf));
583		if (rai->rai_linkmtu)
584			printf("\tAdvLinkMTU: %d", rai->rai_linkmtu);
585		else
586			printf("\tAdvLinkMTU: <none>");
587
588		printf(", ");
589
590		printf("Flags: ");
591		if (rai->rai_managedflg || rai->rai_otherflg) {
592			printf("%s", rai->rai_managedflg ? "M" : "");
593			printf("%s", rai->rai_otherflg ? "O" : "");
594		} else
595			printf("<none>");
596
597		printf(", ");
598
599		printf("Preference: %s\n",
600		    rtpref_str[(rai->rai_rtpref >> 3) & 0xff]);
601
602		printf("\tReachableTime: %s, ",
603		    sec2str(rai->rai_reachabletime, ssbuf));
604		printf("RetransTimer: %s, "
605		    "CurHopLimit: %d\n",
606		    sec2str(rai->rai_retranstimer, ssbuf),
607		    rai->rai_hoplimit);
608		printf("\tAdvIfPrefixes: %s\n",
609		    rai->rai_advifprefix ? "yes" : "no");
610
611		/* RA timer */
612		rat = NULL;
613		if (ifi_s->ifi_ra_timer != NULL) {
614			sprintf(argv_ifi_ra_timer, "%s:ifi_ra_timer=",
615			    ifi->ifi_ifname);
616			action_argv = argv_ifi_ra_timer;
617
618			error = action_propget(action_argv, &cp);
619			if (error)
620				return (error);
621
622			rat = (struct rtadvd_timer *)cp.cp_val;
623		}
624		printf("\tNext RA send: ");
625		if (rat == NULL)
626			printf("never\n");
627		else {
628			ts.tv_sec = rat->rat_tm.tv_sec + ts0.tv_sec;
629			printf("%s", ctime(&ts.tv_sec));
630		}
631		printf("\tLast RA send: ");
632		if (ifi_s->ifi_ra_lastsent.tv_sec == 0)
633			printf("never\n");
634		else {
635			ts.tv_sec = ifi_s->ifi_ra_lastsent.tv_sec + ts0.tv_sec;
636			printf("%s", ctime(&ts.tv_sec));
637		}
638		if (rai->rai_clockskew)
639			printf("\tClock skew: %" PRIu16 "sec\n",
640			    rai->rai_clockskew);
641
642		if (vflag < LOG_WARNING)
643			continue;
644
645		/* route information */
646		sprintf(argv_rti, "%s:rti=", ifi->ifi_ifname);
647		action_argv = argv_rti;
648		error = action_propget(action_argv, &cp);
649		if (error)
650			return (error);
651
652		rti = (struct rtinfo *)cp.cp_val;
653		len = cp.cp_val_len / sizeof(*rti);
654		if (len > 0) {
655			printf("\tRoute Info:\n");
656
657			for (i = 0; i < len; i++)
658				action_show_rtinfo(&rti[i]);
659		}
660
661		/* prefix information */
662		sprintf(argv_pfx, "%s:pfx=", ifi->ifi_ifname);
663		action_argv = argv_pfx;
664
665		error = action_propget(action_argv, &cp);
666		if (error)
667			continue;
668
669		pfx = (struct prefix *)cp.cp_val;
670		len = cp.cp_val_len / sizeof(*pfx);
671
672		if (len > 0) {
673			printf("\tPrefixes (%d):\n", len);
674
675			for (i = 0; i < len; i++)
676				action_show_prefix(&pfx[i]);
677		}
678
679		/* RDNSS information */
680		sprintf(argv_rdnss, "%s:rdnss=", ifi->ifi_ifname);
681		action_argv = argv_rdnss;
682
683		error = action_propget(action_argv, &cp);
684		if (error)
685			continue;
686
687		len = *((uint16_t *)cp.cp_val);
688
689		if (len > 0) {
690			printf("\tRDNSS entries:\n");
691			action_show_rdnss(cp.cp_val);
692		}
693
694		/* DNSSL information */
695		sprintf(argv_dnssl, "%s:dnssl=", ifi->ifi_ifname);
696		action_argv = argv_dnssl;
697
698		error = action_propget(action_argv, &cp);
699		if (error)
700			continue;
701
702		len = *((uint16_t *)cp.cp_val);
703
704		if (len > 0) {
705			printf("\tDNSSL entries:\n");
706			action_show_dnssl(cp.cp_val);
707		}
708
709		if (vflag < LOG_NOTICE)
710			continue;
711
712		printf("\n");
713
714		printf("\tCounters\n"
715		    "\t RA burst counts: %" PRIu16 " (interval: %s)\n"
716		    "\t RS wait counts: %" PRIu16 "\n",
717		    ifi_s->ifi_burstcount,
718		    sec2str(ifi_s->ifi_burstinterval, ssbuf),
719		    ifi_s->ifi_rs_waitcount);
720
721		printf("\tOutputs\n"
722		    "\t RA: %" PRIu64 "\n", ifi_s->ifi_raoutput);
723
724		printf("\tInputs\n"
725		    "\t RA: %" PRIu64 " (normal)\n"
726		    "\t RA: %" PRIu64 " (inconsistent)\n"
727		    "\t RS: %" PRIu64 "\n",
728		    ifi_s->ifi_rainput,
729		    ifi_s->ifi_rainconsistent,
730		    ifi_s->ifi_rsinput);
731
732		printf("\n");
733
734#if 0	/* Not implemented yet */
735		printf("\tReceived RAs:\n");
736#endif
737	}
738
739	return (0);
740}
741
742static int
743action_show_rtinfo(struct rtinfo *rti)
744{
745	char ntopbuf[INET6_ADDRSTRLEN];
746	char ssbuf[SSBUFLEN];
747
748	printf("\t  %s/%d (pref: %s, ltime: %s)\n",
749	    inet_ntop(AF_INET6, &rti->rti_prefix,
750		ntopbuf, sizeof(ntopbuf)),
751	    rti->rti_prefixlen,
752	    rtpref_str[0xff & (rti->rti_rtpref >> 3)],
753	    (rti->rti_ltime == ND6_INFINITE_LIFETIME) ?
754	    "infinity" : sec2str(rti->rti_ltime, ssbuf));
755
756	return (0);
757}
758
759static int
760action_show_prefix(struct prefix *pfx)
761{
762	char ntopbuf[INET6_ADDRSTRLEN];
763	char ssbuf[SSBUFLEN];
764	struct timespec now;
765
766	clock_gettime(CLOCK_MONOTONIC_FAST, &now);
767	printf("\t  %s/%d", inet_ntop(AF_INET6, &pfx->pfx_prefix,
768		ntopbuf, sizeof(ntopbuf)), pfx->pfx_prefixlen);
769
770	printf(" (");
771	switch (pfx->pfx_origin) {
772	case PREFIX_FROM_KERNEL:
773		printf("KERNEL");
774		break;
775	case PREFIX_FROM_CONFIG:
776		printf("CONFIG");
777		break;
778	case PREFIX_FROM_DYNAMIC:
779		printf("DYNAMIC");
780		break;
781	}
782
783	printf(",");
784
785	printf(" vltime=%s",
786	    (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME) ?
787	    "infinity" : sec2str(pfx->pfx_validlifetime, ssbuf));
788
789	if (pfx->pfx_vltimeexpire > 0)
790		printf("(expire: %s)",
791		    ((long)pfx->pfx_vltimeexpire > now.tv_sec) ?
792		    sec2str(pfx->pfx_vltimeexpire - now.tv_sec, ssbuf) :
793		    "0");
794
795	printf(",");
796
797	printf(" pltime=%s",
798	    (pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME) ?
799	    "infinity" : sec2str(pfx->pfx_preflifetime, ssbuf));
800
801	if (pfx->pfx_pltimeexpire > 0)
802		printf("(expire %s)",
803		    ((long)pfx->pfx_pltimeexpire > now.tv_sec) ?
804		    sec2str(pfx->pfx_pltimeexpire - now.tv_sec, ssbuf) :
805		    "0");
806
807	printf(",");
808
809	printf(" flags=");
810	if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) {
811		printf("%s", pfx->pfx_onlinkflg ? "L" : "");
812		printf("%s", pfx->pfx_autoconfflg ? "A" : "");
813	} else
814		printf("<none>");
815
816	if (pfx->pfx_timer) {
817		struct timespec *rest;
818
819		rest = rtadvd_timer_rest(pfx->pfx_timer);
820		if (rest) { /* XXX: what if not? */
821			printf(" expire=%s", sec2str(rest->tv_sec, ssbuf));
822		}
823	}
824
825	printf(")\n");
826
827	return (0);
828}
829
830static int
831action_show_rdnss(void *msg)
832{
833	struct rdnss *rdn;
834	struct rdnss_addr *rda;
835	uint16_t *rdn_cnt;
836	uint16_t *rda_cnt;
837	int i;
838	int j;
839	char *p;
840	uint32_t	ltime;
841	char ntopbuf[INET6_ADDRSTRLEN];
842	char ssbuf[SSBUFLEN];
843
844	p = msg;
845	rdn_cnt = (uint16_t *)p;
846	p += sizeof(*rdn_cnt);
847
848	if (*rdn_cnt > 0) {
849		for (i = 0; i < *rdn_cnt; i++) {
850			rdn = (struct rdnss *)p;
851			ltime = rdn->rd_ltime;
852			p += sizeof(*rdn);
853
854			rda_cnt = (uint16_t *)p;
855			p += sizeof(*rda_cnt);
856			if (*rda_cnt > 0)
857				for (j = 0; j < *rda_cnt; j++) {
858					rda = (struct rdnss_addr *)p;
859					printf("\t  %s (ltime=%s)\n",
860					    inet_ntop(AF_INET6,
861						&rda->ra_dns,
862						ntopbuf,
863						sizeof(ntopbuf)),
864					    sec2str(ltime, ssbuf));
865					p += sizeof(*rda);
866				}
867		}
868	}
869
870	return (0);
871}
872
873static int
874action_show_dnssl(void *msg)
875{
876	struct dnssl *dns;
877	struct dnssl_addr *dna;
878	uint16_t *dns_cnt;
879	uint16_t *dna_cnt;
880	int i;
881	int j;
882	char *p;
883	uint32_t ltime;
884	char hbuf[NI_MAXHOST];
885	char ssbuf[SSBUFLEN];
886
887	p = msg;
888	dns_cnt = (uint16_t *)p;
889	p += sizeof(*dns_cnt);
890
891	if (*dns_cnt > 0) {
892		for (i = 0; i < *dns_cnt; i++) {
893			dns = (struct dnssl *)p;
894			ltime = dns->dn_ltime;
895			p += sizeof(*dns);
896
897			dna_cnt = (uint16_t *)p;
898			p += sizeof(*dna_cnt);
899			if (*dna_cnt > 0)
900				for (j = 0; j < *dna_cnt; j++) {
901					dna = (struct dnssl_addr *)p;
902					dname_labeldec(hbuf, sizeof(hbuf),
903					    dna->da_dom);
904					printf("\t  %s (ltime=%s)\n",
905					    hbuf, sec2str(ltime, ssbuf));
906					p += sizeof(*dna);
907				}
908		}
909	}
910
911	return (0);
912}
913
914/* Decode domain name label encoding in RFC 1035 Section 3.1 */
915static size_t
916dname_labeldec(char *dst, size_t dlen, const char *src)
917{
918	size_t len;
919	const char *src_origin;
920	const char *src_last;
921	const char *dst_origin;
922
923	src_origin = src;
924	src_last = strchr(src, '\0');
925	dst_origin = dst;
926	memset(dst, '\0', dlen);
927	while (src && (len = (uint8_t)(*src++) & 0x3f) &&
928	    (src + len) <= src_last) {
929		if (dst != dst_origin)
930			*dst++ = '.';
931		mysyslog(LOG_DEBUG, "<%s> labellen = %zd", __func__, len);
932		memcpy(dst, src, len);
933		src += len;
934		dst += len;
935	}
936	*dst = '\0';
937
938	return (src - src_origin);
939}
940