1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
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 */
29
30 #include <sys/param.h>
31 #include <sys/queue.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/ethernet.h>
40 #include <netinet/in.h>
41 #include <netinet/ip6.h>
42 #include <netinet/icmp6.h>
43 #include <netinet6/in6_var.h>
44 #include <netinet6/nd6.h>
45 #include <arpa/inet.h>
46 #include <fcntl.h>
47 #include <errno.h>
48 #include <inttypes.h>
49 #include <netdb.h>
50 #include <unistd.h>
51 #include <string.h>
52 #include <stdarg.h>
53 #include <stdio.h>
54 #include <stdlib.h>
55 #include <stdarg.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 static void action_show_pref64(void *);
93
94 static int csock_client_open(struct sockinfo *);
95 static size_t dname_labeldec(char *, size_t, const char *);
96 static void mysyslog(int, const char *, ...);
97
98 static const char *rtpref_str[] = {
99 "medium", /* 00 */
100 "high", /* 01 */
101 "rsv", /* 10 */
102 "low" /* 11 */
103 };
104
105 static 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
120 static char errmsgbuf[1024];
121 static char *errmsg = NULL;
122
123 static void
mysyslog(int priority,const char * restrict fmt,...)124 mysyslog(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
136 static void
usage(void)137 usage(void)
138 {
139 int i;
140
141 for (i = 0; (size_t)i < nitems(dtable); 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
150 int
main(int argc,char * argv[])151 main(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 < nitems(dtable); 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
198 static int
csock_client_open(struct sockinfo * s)199 csock_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
220 static int
action_plgeneric(int action,char * plstr,char * buf)221 action_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
273 static int
action_propget(char * argv,struct ctrl_msg_pl * cp)274 action_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
298 static int
action_propset(char * argv)299 action_propset(char *argv)
300 {
301 char buf[CM_MSG_MAXLEN];
302
303 return (action_plgeneric(CM_TYPE_REQ_SET_PROP, argv, buf));
304 }
305
306 static int
action_disable(int argc,char ** argv)307 action_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
327 static int
action_enable(int argc,char ** argv)328 action_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
348 static int
action_reload(int argc,char ** argv)349 action_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
371 static int
action_echo(int argc __unused,char ** argv __unused)372 action_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
380 static int
action_shutdown(int argc __unused,char ** argv __unused)381 action_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 */
390 static int
action_version(int argc __unused,char ** argv __unused)391 action_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
406 static int
action_show(int argc,char ** argv)407 action_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 argv_pref64[IFNAMSIZ + sizeof(":pref64=")];
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 /*
518 * RA_RECV: ND6_IFF_ACCEPT_RTADV
519 * RA_SEND: ip6.forwarding
520 */
521 if (ifi_s->ifi_nd_flags & ND6_IFF_ACCEPT_RTADV)
522 ra_ifstatus = RA_IFSTATUS_RA_RECV;
523 else if (getinet6sysctl(IPV6CTL_FORWARDING))
524 ra_ifstatus = RA_IFSTATUS_RA_SEND;
525 else
526 ra_ifstatus = RA_IFSTATUS_INACTIVE;
527 }
528
529 c = 0;
530 printf(" status=<");
531 if (ra_ifstatus == RA_IFSTATUS_INACTIVE)
532 printf("%s%s", (c) ? "," : "", "INACTIVE");
533 else if (ra_ifstatus == RA_IFSTATUS_RA_RECV)
534 printf("%s%s", (c) ? "," : "", "RA_RECV");
535 else if (ra_ifstatus == RA_IFSTATUS_RA_SEND)
536 printf("%s%s", (c) ? "," : "", "RA_SEND");
537 printf("> ");
538
539 switch (ifi_s->ifi_state) {
540 case IFI_STATE_CONFIGURED:
541 case IFI_STATE_TRANSITIVE:
542 break;
543 default:
544 printf("\n");
545 continue;
546 }
547
548 printf("mtu %d\n", ifi_s->ifi_phymtu);
549
550 sprintf(argv_rai, "%s:rai=", ifi->ifi_ifname);
551 action_argv = argv_rai;
552
553 error = action_propget(action_argv, &cp);
554 if (error)
555 continue;
556
557 rai = (struct rainfo *)cp.cp_val;
558
559 printf("\tDefaultLifetime: %s",
560 sec2str(rai->rai_lifetime, ssbuf));
561 if (ra_ifstatus != RA_IFSTATUS_RA_SEND &&
562 rai->rai_lifetime == 0)
563 printf(" (RAs will be sent with zero lifetime)");
564
565 printf("\n");
566
567 printf("\tMinAdvInterval/MaxAdvInterval: ");
568 printf("%s/", sec2str(rai->rai_mininterval, ssbuf));
569 printf("%s\n", sec2str(rai->rai_maxinterval, ssbuf));
570 if (rai->rai_linkmtu)
571 printf("\tAdvLinkMTU: %d", rai->rai_linkmtu);
572 else
573 printf("\tAdvLinkMTU: <none>");
574
575 printf(", ");
576
577 printf("Flags: ");
578 if (rai->rai_managedflg || rai->rai_otherflg) {
579 printf("%s", rai->rai_managedflg ? "M" : "");
580 printf("%s", rai->rai_otherflg ? "O" : "");
581 } else
582 printf("<none>");
583
584 printf(", ");
585
586 printf("Preference: %s\n",
587 rtpref_str[(rai->rai_rtpref >> 3) & 0xff]);
588
589 printf("\tReachableTime: %s, ",
590 sec2str(rai->rai_reachabletime, ssbuf));
591 printf("RetransTimer: %s, "
592 "CurHopLimit: %d\n",
593 sec2str(rai->rai_retranstimer, ssbuf),
594 rai->rai_hoplimit);
595 printf("\tAdvIfPrefixes: %s\n",
596 rai->rai_advifprefix ? "yes" : "no");
597
598 /* RA timer */
599 rat = NULL;
600 if (ifi_s->ifi_ra_timer != NULL) {
601 sprintf(argv_ifi_ra_timer, "%s:ifi_ra_timer=",
602 ifi->ifi_ifname);
603 action_argv = argv_ifi_ra_timer;
604
605 error = action_propget(action_argv, &cp);
606 if (error)
607 return (error);
608
609 rat = (struct rtadvd_timer *)cp.cp_val;
610 }
611 printf("\tNext RA send: ");
612 if (rat == NULL)
613 printf("never\n");
614 else {
615 ts.tv_sec = rat->rat_tm.tv_sec + ts0.tv_sec;
616 printf("%s", ctime(&ts.tv_sec));
617 }
618 printf("\tLast RA send: ");
619 if (ifi_s->ifi_ra_lastsent.tv_sec == 0)
620 printf("never\n");
621 else {
622 ts.tv_sec = ifi_s->ifi_ra_lastsent.tv_sec + ts0.tv_sec;
623 printf("%s", ctime(&ts.tv_sec));
624 }
625 if (rai->rai_clockskew)
626 printf("\tClock skew: %" PRIu16 "sec\n",
627 rai->rai_clockskew);
628
629 if (vflag < LOG_WARNING)
630 continue;
631
632 /* route information */
633 sprintf(argv_rti, "%s:rti=", ifi->ifi_ifname);
634 action_argv = argv_rti;
635 error = action_propget(action_argv, &cp);
636 if (error)
637 return (error);
638
639 rti = (struct rtinfo *)cp.cp_val;
640 len = cp.cp_val_len / sizeof(*rti);
641 if (len > 0) {
642 printf("\tRoute Info:\n");
643
644 for (i = 0; i < len; i++)
645 action_show_rtinfo(&rti[i]);
646 }
647
648 /* prefix information */
649 sprintf(argv_pfx, "%s:pfx=", ifi->ifi_ifname);
650 action_argv = argv_pfx;
651
652 error = action_propget(action_argv, &cp);
653 if (error)
654 continue;
655
656 pfx = (struct prefix *)cp.cp_val;
657 len = cp.cp_val_len / sizeof(*pfx);
658
659 if (len > 0) {
660 printf("\tPrefixes (%d):\n", len);
661
662 for (i = 0; i < len; i++)
663 action_show_prefix(&pfx[i]);
664 }
665
666 /* RDNSS information */
667 sprintf(argv_rdnss, "%s:rdnss=", ifi->ifi_ifname);
668 action_argv = argv_rdnss;
669
670 error = action_propget(action_argv, &cp);
671 if (error)
672 continue;
673
674 len = *((uint16_t *)cp.cp_val);
675
676 if (len > 0) {
677 printf("\tRDNSS entries:\n");
678 action_show_rdnss(cp.cp_val);
679 }
680
681 /* DNSSL information */
682 sprintf(argv_dnssl, "%s:dnssl=", ifi->ifi_ifname);
683 action_argv = argv_dnssl;
684
685 error = action_propget(action_argv, &cp);
686 if (error)
687 continue;
688
689 len = *((uint16_t *)cp.cp_val);
690
691 if (len > 0) {
692 printf("\tDNSSL entries:\n");
693 action_show_dnssl(cp.cp_val);
694 }
695
696 /* PREF64 information */
697 sprintf(argv_pref64, "%s:pref64=", ifi->ifi_ifname);
698 action_argv = argv_pref64;
699
700 error = action_propget(action_argv, &cp);
701 if (error)
702 continue;
703
704 len = *((uint16_t *)cp.cp_val);
705
706 if (len > 0) {
707 printf("\tPREF64:\n");
708 action_show_pref64(cp.cp_val);
709 }
710
711 if (vflag < LOG_NOTICE)
712 continue;
713
714 printf("\n");
715
716 printf("\tCounters\n"
717 "\t RA burst counts: %" PRIu16 " (interval: %s)\n"
718 "\t RS wait counts: %" PRIu16 "\n",
719 ifi_s->ifi_burstcount,
720 sec2str(ifi_s->ifi_burstinterval, ssbuf),
721 ifi_s->ifi_rs_waitcount);
722
723 printf("\tOutputs\n"
724 "\t RA: %" PRIu64 "\n", ifi_s->ifi_raoutput);
725
726 printf("\tInputs\n"
727 "\t RA: %" PRIu64 " (normal)\n"
728 "\t RA: %" PRIu64 " (inconsistent)\n"
729 "\t RS: %" PRIu64 "\n",
730 ifi_s->ifi_rainput,
731 ifi_s->ifi_rainconsistent,
732 ifi_s->ifi_rsinput);
733
734 printf("\n");
735
736 #if 0 /* Not implemented yet */
737 printf("\tReceived RAs:\n");
738 #endif
739 }
740
741 return (0);
742 }
743
744 static int
action_show_rtinfo(struct rtinfo * rti)745 action_show_rtinfo(struct rtinfo *rti)
746 {
747 char ntopbuf[INET6_ADDRSTRLEN];
748 char ssbuf[SSBUFLEN];
749
750 printf("\t %s/%d (pref: %s, ltime: %s)\n",
751 inet_ntop(AF_INET6, &rti->rti_prefix,
752 ntopbuf, sizeof(ntopbuf)),
753 rti->rti_prefixlen,
754 rtpref_str[0xff & (rti->rti_rtpref >> 3)],
755 (rti->rti_ltime == ND6_INFINITE_LIFETIME) ?
756 "infinity" : sec2str(rti->rti_ltime, ssbuf));
757
758 return (0);
759 }
760
761 static int
action_show_prefix(struct prefix * pfx)762 action_show_prefix(struct prefix *pfx)
763 {
764 char ntopbuf[INET6_ADDRSTRLEN];
765 char ssbuf[SSBUFLEN];
766 struct timespec now;
767
768 clock_gettime(CLOCK_MONOTONIC_FAST, &now);
769 printf("\t %s/%d", inet_ntop(AF_INET6, &pfx->pfx_prefix,
770 ntopbuf, sizeof(ntopbuf)), pfx->pfx_prefixlen);
771
772 printf(" (");
773 switch (pfx->pfx_origin) {
774 case PREFIX_FROM_KERNEL:
775 printf("KERNEL");
776 break;
777 case PREFIX_FROM_CONFIG:
778 printf("CONFIG");
779 break;
780 case PREFIX_FROM_DYNAMIC:
781 printf("DYNAMIC");
782 break;
783 }
784
785 printf(",");
786
787 printf(" vltime=%s",
788 (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME) ?
789 "infinity" : sec2str(pfx->pfx_validlifetime, ssbuf));
790
791 if (pfx->pfx_vltimeexpire > 0)
792 printf("(expire: %s)",
793 ((long)pfx->pfx_vltimeexpire > now.tv_sec) ?
794 sec2str(pfx->pfx_vltimeexpire - now.tv_sec, ssbuf) :
795 "0");
796
797 printf(",");
798
799 printf(" pltime=%s",
800 (pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME) ?
801 "infinity" : sec2str(pfx->pfx_preflifetime, ssbuf));
802
803 if (pfx->pfx_pltimeexpire > 0)
804 printf("(expire %s)",
805 ((long)pfx->pfx_pltimeexpire > now.tv_sec) ?
806 sec2str(pfx->pfx_pltimeexpire - now.tv_sec, ssbuf) :
807 "0");
808
809 printf(",");
810
811 printf(" flags=");
812 if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) {
813 printf("%s", pfx->pfx_onlinkflg ? "L" : "");
814 printf("%s", pfx->pfx_autoconfflg ? "A" : "");
815 } else
816 printf("<none>");
817
818 if (pfx->pfx_timer) {
819 struct timespec *rest;
820
821 rest = rtadvd_timer_rest(pfx->pfx_timer);
822 if (rest) { /* XXX: what if not? */
823 printf(" expire=%s", sec2str(rest->tv_sec, ssbuf));
824 }
825 }
826
827 printf(")\n");
828
829 return (0);
830 }
831
832 static int
action_show_rdnss(void * msg)833 action_show_rdnss(void *msg)
834 {
835 struct rdnss *rdn;
836 struct rdnss_addr *rda;
837 uint16_t *rdn_cnt;
838 uint16_t *rda_cnt;
839 int i;
840 int j;
841 char *p;
842 uint32_t ltime;
843 char ntopbuf[INET6_ADDRSTRLEN];
844 char ssbuf[SSBUFLEN];
845
846 p = msg;
847 rdn_cnt = (uint16_t *)p;
848 p += sizeof(*rdn_cnt);
849
850 if (*rdn_cnt > 0) {
851 for (i = 0; i < *rdn_cnt; i++) {
852 rdn = (struct rdnss *)p;
853 ltime = rdn->rd_ltime;
854 p += sizeof(*rdn);
855
856 rda_cnt = (uint16_t *)p;
857 p += sizeof(*rda_cnt);
858 if (*rda_cnt > 0)
859 for (j = 0; j < *rda_cnt; j++) {
860 rda = (struct rdnss_addr *)p;
861 printf("\t %s (ltime=%s)\n",
862 inet_ntop(AF_INET6,
863 &rda->ra_dns,
864 ntopbuf,
865 sizeof(ntopbuf)),
866 sec2str(ltime, ssbuf));
867 p += sizeof(*rda);
868 }
869 }
870 }
871
872 return (0);
873 }
874
875 static int
action_show_dnssl(void * msg)876 action_show_dnssl(void *msg)
877 {
878 struct dnssl *dns;
879 struct dnssl_addr *dna;
880 uint16_t *dns_cnt;
881 uint16_t *dna_cnt;
882 int i;
883 int j;
884 char *p;
885 uint32_t ltime;
886 char hbuf[NI_MAXHOST];
887 char ssbuf[SSBUFLEN];
888
889 p = msg;
890 dns_cnt = (uint16_t *)p;
891 p += sizeof(*dns_cnt);
892
893 if (*dns_cnt > 0) {
894 for (i = 0; i < *dns_cnt; i++) {
895 dns = (struct dnssl *)p;
896 ltime = dns->dn_ltime;
897 p += sizeof(*dns);
898
899 dna_cnt = (uint16_t *)p;
900 p += sizeof(*dna_cnt);
901 if (*dna_cnt > 0)
902 for (j = 0; j < *dna_cnt; j++) {
903 dna = (struct dnssl_addr *)p;
904 dname_labeldec(hbuf, sizeof(hbuf),
905 dna->da_dom);
906 printf("\t %s (ltime=%s)\n",
907 hbuf, sec2str(ltime, ssbuf));
908 p += sizeof(*dna);
909 }
910 }
911 }
912
913 return (0);
914 }
915
916 static void
action_show_pref64(void * msg)917 action_show_pref64(void *msg)
918 {
919 struct pref64 *prf64;
920 uint16_t *prf64_cnt;
921 char ntopbuf[INET6_ADDRSTRLEN];
922 char ssbuf[SSBUFLEN];
923 char *p;
924 int i;
925 uint16_t prf64len;
926
927 p = msg;
928 prf64_cnt = (uint16_t *)p;
929 p += sizeof(*prf64_cnt);
930
931 for (i = 0; i < *prf64_cnt; i++) {
932 prf64 = (struct pref64 *)p;
933
934 /* RFC 8781 Section 4: Map PLC values to prefix lengths */
935 prf64len = (prf64->p64_plc == 0) ? 96 : 72 - (8 * prf64->p64_plc);
936 printf("\t %s/%d (ltime: %s)\n",
937 inet_ntop(AF_INET6, &prf64->p64_prefix,
938 ntopbuf, sizeof(ntopbuf)),
939 prf64len, sec2str(prf64->p64_sl, ssbuf));
940
941 p += sizeof(*prf64);
942 }
943 }
944
945 /* Decode domain name label encoding in RFC 1035 Section 3.1 */
946 static size_t
dname_labeldec(char * dst,size_t dlen,const char * src)947 dname_labeldec(char *dst, size_t dlen, const char *src)
948 {
949 size_t len;
950 const char *src_origin;
951 const char *src_last;
952 const char *dst_origin;
953
954 src_origin = src;
955 src_last = strchr(src, '\0');
956 dst_origin = dst;
957 memset(dst, '\0', dlen);
958 while (src && (len = (uint8_t)(*src++) & 0x3f) &&
959 (src + len) <= src_last) {
960 if (dst != dst_origin)
961 *dst++ = '.';
962 mysyslog(LOG_DEBUG, "<%s> labellen = %zd", __func__, len);
963 memcpy(dst, src, len);
964 src += len;
965 dst += len;
966 }
967 *dst = '\0';
968
969 return (src - src_origin);
970 }
971