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