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