arm64 libc: hide .cerror, .curbrk, .minbrk for WITHOUT_SYMVER
[freebsd-src.git] / usr.sbin / rtadvctl / rtadvctl.c
blobf1657d799cb747031057520814bf8fab6c430e8d
1 /*-
2 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
3 * All rights reserved.
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.
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.
26 * $FreeBSD$
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/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>
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"
68 #define RA_IFSTATUS_INACTIVE 0
69 #define RA_IFSTATUS_RA_RECV 1
70 #define RA_IFSTATUS_RA_SEND 2
72 static int vflag = LOG_ERR;
74 static void usage(void);
76 static int action_propset(char *);
77 static int action_propget(char *, struct ctrl_msg_pl *);
78 static int action_plgeneric(int, char *, char *);
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 **);
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 *);
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 *, ...);
97 static const char *rtpref_str[] = {
98 "medium", /* 00 */
99 "high", /* 01 */
100 "rsv", /* 10 */
101 "low" /* 11 */
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 },
119 static char errmsgbuf[1024];
120 static char *errmsg = NULL;
122 static void
123 mysyslog(int priority, const char * restrict fmt, ...)
125 va_list ap;
127 if (vflag >= priority) {
128 va_start(ap, fmt);
129 vfprintf(stderr, fmt, ap);
130 fprintf(stderr, "\n");
131 va_end(ap);
135 static void
136 usage(void)
138 int i;
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);
146 exit(1);
150 main(int argc, char *argv[])
152 int i;
153 int ch;
154 int (*action)(int, char **) = NULL;
155 int error;
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();
169 argc -= optind;
170 argv += optind;
172 if (argc == 0)
173 usage();
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;
183 if (action == NULL)
184 usage();
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");
194 return (error);
197 static int
198 csock_client_open(struct sockinfo *s)
200 struct sockaddr_un sun;
202 if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
203 err(1, "cannot open control socket.");
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));
210 if (connect(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
211 err(1, "connect: %s", s->si_name);
213 mysyslog(LOG_DEBUG,
214 "<%s> connected to %s", __func__, sun.sun_path);
216 return (0);
219 static int
220 action_plgeneric(int action, char *plstr, char *buf)
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;
229 s = &ctrlsock;
230 csock_client_open(s);
232 cm = (struct ctrl_msg_hdr *)buf;
233 msg = (char *)buf + sizeof(*cm);
235 cm->cm_version = CM_VERSION;
236 cm->cm_type = action;
237 cm->cm_len = sizeof(*cm);
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);
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;
257 if (q == NULL)
258 cp.cp_val = NULL;
259 else {
260 *q++ = '\0';
261 cp.cp_val = q;
263 cm->cm_len += cm_pl2bin(msg, &cp);
265 mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s",
266 __func__,cp.cp_key, cp.cp_val_len, cp.cp_ifname);
269 return (cm_handler_client(s->si_fd, CM_STATE_MSG_DISPATCH, buf));
272 static int
273 action_propget(char *argv, struct ctrl_msg_pl *cp)
275 int error;
276 struct ctrl_msg_hdr *cm;
277 char buf[CM_MSG_MAXLEN];
278 char *msg;
280 memset(cp, 0, sizeof(*cp));
281 cm = (struct ctrl_msg_hdr *)buf;
282 msg = (char *)buf + sizeof(*cm);
284 error = action_plgeneric(CM_TYPE_REQ_GET_PROP, argv, buf);
285 if (error || cm->cm_len <= sizeof(*cm))
286 return (1);
288 cm_bin2pl(msg, cp);
289 mysyslog(LOG_DEBUG, "<%s> type=%d, len=%d",
290 __func__, cm->cm_type, cm->cm_len);
291 mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s",
292 __func__,cp->cp_key, cp->cp_val_len, cp->cp_ifname);
294 return (0);
297 static int
298 action_propset(char *argv)
300 char buf[CM_MSG_MAXLEN];
302 return (action_plgeneric(CM_TYPE_REQ_SET_PROP, argv, buf));
305 static int
306 action_disable(int argc, char **argv)
308 char *action_argv;
309 char argv_disable[IFNAMSIZ + sizeof(":disable=")];
310 int i;
311 int error;
313 if (argc < 1)
314 return (1);
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);
323 return (error);
326 static int
327 action_enable(int argc, char **argv)
329 char *action_argv;
330 char argv_enable[IFNAMSIZ + sizeof(":enable=")];
331 int i;
332 int error;
334 if (argc < 1)
335 return (1);
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);
344 return (error);
347 static int
348 action_reload(int argc, char **argv)
350 char *action_argv;
351 char argv_reload[IFNAMSIZ + sizeof(":reload=")];
352 int i;
353 int error;
355 if (argc == 0) {
356 action_argv = strdup(":reload=");
357 return (action_propset(action_argv));
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);
367 return (error);
370 static int
371 action_echo(int argc __unused, char **argv __unused)
373 char *action_argv;
375 action_argv = strdup("echo");
376 return (action_propset(action_argv));
379 static int
380 action_shutdown(int argc __unused, char **argv __unused)
382 char *action_argv;
384 action_argv = strdup("shutdown");
385 return (action_propset(action_argv));
388 /* XXX */
389 static int
390 action_version(int argc __unused, char **argv __unused)
392 char *action_argv;
393 struct ctrl_msg_pl cp;
394 int error;
396 action_argv = strdup(":version=");
397 error = action_propget(action_argv, &cp);
398 if (error)
399 return (error);
401 printf("version=%s\n", cp.cp_val);
402 return (0);
405 static int
406 action_show(int argc, char **argv)
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];
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;
429 if (argc == 0) {
430 action_argv = argv_ifilist;
431 error = action_propget(action_argv, &cp);
432 if (error)
433 return (error);
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));
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;
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));
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);
464 TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next);
468 clock_gettime(CLOCK_REALTIME_FAST, &now);
469 clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
470 TS_SUB(&now, &ts, &ts0);
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;
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;
488 if (!(ifi_s->ifi_persist) && vflag < LOG_NOTICE)
489 continue;
491 printf("%s: flags=<", ifi->ifi_ifname);
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;
507 if (ifi_s->ifi_persist)
508 c += printf("%s%s", (c) ? "," : "", "PERSIST");
509 printf(">");
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 #if (__FreeBSD_version < 900000)
517 * RA_RECV: !ip6.forwarding && ip6.accept_rtadv
518 * RA_SEND: ip6.forwarding
520 if (getinet6sysctl(IPV6CTL_FORWARDING) == 0) {
521 if (getinet6sysctl(IPV6CTL_ACCEPT_RTADV))
522 ra_ifstatus = RA_IFSTATUS_RA_RECV;
523 else
524 ra_ifstatus = RA_IFSTATUS_INACTIVE;
525 } else
526 ra_ifstatus = RA_IFSTATUS_RA_SEND;
527 #else
529 * RA_RECV: ND6_IFF_ACCEPT_RTADV
530 * RA_SEND: ip6.forwarding
532 if (ifi_s->ifi_nd_flags & ND6_IFF_ACCEPT_RTADV)
533 ra_ifstatus = RA_IFSTATUS_RA_RECV;
534 else if (getinet6sysctl(IPV6CTL_FORWARDING))
535 ra_ifstatus = RA_IFSTATUS_RA_SEND;
536 else
537 ra_ifstatus = RA_IFSTATUS_INACTIVE;
538 #endif
541 c = 0;
542 printf(" status=<");
543 if (ra_ifstatus == RA_IFSTATUS_INACTIVE)
544 printf("%s%s", (c) ? "," : "", "INACTIVE");
545 else if (ra_ifstatus == RA_IFSTATUS_RA_RECV)
546 printf("%s%s", (c) ? "," : "", "RA_RECV");
547 else if (ra_ifstatus == RA_IFSTATUS_RA_SEND)
548 printf("%s%s", (c) ? "," : "", "RA_SEND");
549 printf("> ");
551 switch (ifi_s->ifi_state) {
552 case IFI_STATE_CONFIGURED:
553 case IFI_STATE_TRANSITIVE:
554 break;
555 default:
556 printf("\n");
557 continue;
560 printf("mtu %d\n", ifi_s->ifi_phymtu);
562 sprintf(argv_rai, "%s:rai=", ifi->ifi_ifname);
563 action_argv = argv_rai;
565 error = action_propget(action_argv, &cp);
566 if (error)
567 continue;
569 rai = (struct rainfo *)cp.cp_val;
571 printf("\tDefaultLifetime: %s",
572 sec2str(rai->rai_lifetime, ssbuf));
573 if (ra_ifstatus != RA_IFSTATUS_RA_SEND &&
574 rai->rai_lifetime == 0)
575 printf(" (RAs will be sent with zero lifetime)");
577 printf("\n");
579 printf("\tMinAdvInterval/MaxAdvInterval: ");
580 printf("%s/", sec2str(rai->rai_mininterval, ssbuf));
581 printf("%s\n", sec2str(rai->rai_maxinterval, ssbuf));
582 if (rai->rai_linkmtu)
583 printf("\tAdvLinkMTU: %d", rai->rai_linkmtu);
584 else
585 printf("\tAdvLinkMTU: <none>");
587 printf(", ");
589 printf("Flags: ");
590 if (rai->rai_managedflg || rai->rai_otherflg) {
591 printf("%s", rai->rai_managedflg ? "M" : "");
592 printf("%s", rai->rai_otherflg ? "O" : "");
593 } else
594 printf("<none>");
596 printf(", ");
598 printf("Preference: %s\n",
599 rtpref_str[(rai->rai_rtpref >> 3) & 0xff]);
601 printf("\tReachableTime: %s, ",
602 sec2str(rai->rai_reachabletime, ssbuf));
603 printf("RetransTimer: %s, "
604 "CurHopLimit: %d\n",
605 sec2str(rai->rai_retranstimer, ssbuf),
606 rai->rai_hoplimit);
607 printf("\tAdvIfPrefixes: %s\n",
608 rai->rai_advifprefix ? "yes" : "no");
610 /* RA timer */
611 rat = NULL;
612 if (ifi_s->ifi_ra_timer != NULL) {
613 sprintf(argv_ifi_ra_timer, "%s:ifi_ra_timer=",
614 ifi->ifi_ifname);
615 action_argv = argv_ifi_ra_timer;
617 error = action_propget(action_argv, &cp);
618 if (error)
619 return (error);
621 rat = (struct rtadvd_timer *)cp.cp_val;
623 printf("\tNext RA send: ");
624 if (rat == NULL)
625 printf("never\n");
626 else {
627 ts.tv_sec = rat->rat_tm.tv_sec + ts0.tv_sec;
628 printf("%s", ctime(&ts.tv_sec));
630 printf("\tLast RA send: ");
631 if (ifi_s->ifi_ra_lastsent.tv_sec == 0)
632 printf("never\n");
633 else {
634 ts.tv_sec = ifi_s->ifi_ra_lastsent.tv_sec + ts0.tv_sec;
635 printf("%s", ctime(&ts.tv_sec));
637 if (rai->rai_clockskew)
638 printf("\tClock skew: %" PRIu16 "sec\n",
639 rai->rai_clockskew);
641 if (vflag < LOG_WARNING)
642 continue;
644 /* route information */
645 sprintf(argv_rti, "%s:rti=", ifi->ifi_ifname);
646 action_argv = argv_rti;
647 error = action_propget(action_argv, &cp);
648 if (error)
649 return (error);
651 rti = (struct rtinfo *)cp.cp_val;
652 len = cp.cp_val_len / sizeof(*rti);
653 if (len > 0) {
654 printf("\tRoute Info:\n");
656 for (i = 0; i < len; i++)
657 action_show_rtinfo(&rti[i]);
660 /* prefix information */
661 sprintf(argv_pfx, "%s:pfx=", ifi->ifi_ifname);
662 action_argv = argv_pfx;
664 error = action_propget(action_argv, &cp);
665 if (error)
666 continue;
668 pfx = (struct prefix *)cp.cp_val;
669 len = cp.cp_val_len / sizeof(*pfx);
671 if (len > 0) {
672 printf("\tPrefixes (%d):\n", len);
674 for (i = 0; i < len; i++)
675 action_show_prefix(&pfx[i]);
678 /* RDNSS information */
679 sprintf(argv_rdnss, "%s:rdnss=", ifi->ifi_ifname);
680 action_argv = argv_rdnss;
682 error = action_propget(action_argv, &cp);
683 if (error)
684 continue;
686 len = *((uint16_t *)cp.cp_val);
688 if (len > 0) {
689 printf("\tRDNSS entries:\n");
690 action_show_rdnss(cp.cp_val);
693 /* DNSSL information */
694 sprintf(argv_dnssl, "%s:dnssl=", ifi->ifi_ifname);
695 action_argv = argv_dnssl;
697 error = action_propget(action_argv, &cp);
698 if (error)
699 continue;
701 len = *((uint16_t *)cp.cp_val);
703 if (len > 0) {
704 printf("\tDNSSL entries:\n");
705 action_show_dnssl(cp.cp_val);
708 if (vflag < LOG_NOTICE)
709 continue;
711 printf("\n");
713 printf("\tCounters\n"
714 "\t RA burst counts: %" PRIu16 " (interval: %s)\n"
715 "\t RS wait counts: %" PRIu16 "\n",
716 ifi_s->ifi_burstcount,
717 sec2str(ifi_s->ifi_burstinterval, ssbuf),
718 ifi_s->ifi_rs_waitcount);
720 printf("\tOutputs\n"
721 "\t RA: %" PRIu64 "\n", ifi_s->ifi_raoutput);
723 printf("\tInputs\n"
724 "\t RA: %" PRIu64 " (normal)\n"
725 "\t RA: %" PRIu64 " (inconsistent)\n"
726 "\t RS: %" PRIu64 "\n",
727 ifi_s->ifi_rainput,
728 ifi_s->ifi_rainconsistent,
729 ifi_s->ifi_rsinput);
731 printf("\n");
733 #if 0 /* Not implemented yet */
734 printf("\tReceived RAs:\n");
735 #endif
738 return (0);
741 static int
742 action_show_rtinfo(struct rtinfo *rti)
744 char ntopbuf[INET6_ADDRSTRLEN];
745 char ssbuf[SSBUFLEN];
747 printf("\t %s/%d (pref: %s, ltime: %s)\n",
748 inet_ntop(AF_INET6, &rti->rti_prefix,
749 ntopbuf, sizeof(ntopbuf)),
750 rti->rti_prefixlen,
751 rtpref_str[0xff & (rti->rti_rtpref >> 3)],
752 (rti->rti_ltime == ND6_INFINITE_LIFETIME) ?
753 "infinity" : sec2str(rti->rti_ltime, ssbuf));
755 return (0);
758 static int
759 action_show_prefix(struct prefix *pfx)
761 char ntopbuf[INET6_ADDRSTRLEN];
762 char ssbuf[SSBUFLEN];
763 struct timespec now;
765 clock_gettime(CLOCK_MONOTONIC_FAST, &now);
766 printf("\t %s/%d", inet_ntop(AF_INET6, &pfx->pfx_prefix,
767 ntopbuf, sizeof(ntopbuf)), pfx->pfx_prefixlen);
769 printf(" (");
770 switch (pfx->pfx_origin) {
771 case PREFIX_FROM_KERNEL:
772 printf("KERNEL");
773 break;
774 case PREFIX_FROM_CONFIG:
775 printf("CONFIG");
776 break;
777 case PREFIX_FROM_DYNAMIC:
778 printf("DYNAMIC");
779 break;
782 printf(",");
784 printf(" vltime=%s",
785 (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME) ?
786 "infinity" : sec2str(pfx->pfx_validlifetime, ssbuf));
788 if (pfx->pfx_vltimeexpire > 0)
789 printf("(expire: %s)",
790 ((long)pfx->pfx_vltimeexpire > now.tv_sec) ?
791 sec2str(pfx->pfx_vltimeexpire - now.tv_sec, ssbuf) :
792 "0");
794 printf(",");
796 printf(" pltime=%s",
797 (pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME) ?
798 "infinity" : sec2str(pfx->pfx_preflifetime, ssbuf));
800 if (pfx->pfx_pltimeexpire > 0)
801 printf("(expire %s)",
802 ((long)pfx->pfx_pltimeexpire > now.tv_sec) ?
803 sec2str(pfx->pfx_pltimeexpire - now.tv_sec, ssbuf) :
804 "0");
806 printf(",");
808 printf(" flags=");
809 if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) {
810 printf("%s", pfx->pfx_onlinkflg ? "L" : "");
811 printf("%s", pfx->pfx_autoconfflg ? "A" : "");
812 } else
813 printf("<none>");
815 if (pfx->pfx_timer) {
816 struct timespec *rest;
818 rest = rtadvd_timer_rest(pfx->pfx_timer);
819 if (rest) { /* XXX: what if not? */
820 printf(" expire=%s", sec2str(rest->tv_sec, ssbuf));
824 printf(")\n");
826 return (0);
829 static int
830 action_show_rdnss(void *msg)
832 struct rdnss *rdn;
833 struct rdnss_addr *rda;
834 uint16_t *rdn_cnt;
835 uint16_t *rda_cnt;
836 int i;
837 int j;
838 char *p;
839 uint32_t ltime;
840 char ntopbuf[INET6_ADDRSTRLEN];
841 char ssbuf[SSBUFLEN];
843 p = msg;
844 rdn_cnt = (uint16_t *)p;
845 p += sizeof(*rdn_cnt);
847 if (*rdn_cnt > 0) {
848 for (i = 0; i < *rdn_cnt; i++) {
849 rdn = (struct rdnss *)p;
850 ltime = rdn->rd_ltime;
851 p += sizeof(*rdn);
853 rda_cnt = (uint16_t *)p;
854 p += sizeof(*rda_cnt);
855 if (*rda_cnt > 0)
856 for (j = 0; j < *rda_cnt; j++) {
857 rda = (struct rdnss_addr *)p;
858 printf("\t %s (ltime=%s)\n",
859 inet_ntop(AF_INET6,
860 &rda->ra_dns,
861 ntopbuf,
862 sizeof(ntopbuf)),
863 sec2str(ltime, ssbuf));
864 p += sizeof(*rda);
869 return (0);
872 static int
873 action_show_dnssl(void *msg)
875 struct dnssl *dns;
876 struct dnssl_addr *dna;
877 uint16_t *dns_cnt;
878 uint16_t *dna_cnt;
879 int i;
880 int j;
881 char *p;
882 uint32_t ltime;
883 char hbuf[NI_MAXHOST];
884 char ssbuf[SSBUFLEN];
886 p = msg;
887 dns_cnt = (uint16_t *)p;
888 p += sizeof(*dns_cnt);
890 if (*dns_cnt > 0) {
891 for (i = 0; i < *dns_cnt; i++) {
892 dns = (struct dnssl *)p;
893 ltime = dns->dn_ltime;
894 p += sizeof(*dns);
896 dna_cnt = (uint16_t *)p;
897 p += sizeof(*dna_cnt);
898 if (*dna_cnt > 0)
899 for (j = 0; j < *dna_cnt; j++) {
900 dna = (struct dnssl_addr *)p;
901 dname_labeldec(hbuf, sizeof(hbuf),
902 dna->da_dom);
903 printf("\t %s (ltime=%s)\n",
904 hbuf, sec2str(ltime, ssbuf));
905 p += sizeof(*dna);
910 return (0);
913 /* Decode domain name label encoding in RFC 1035 Section 3.1 */
914 static size_t
915 dname_labeldec(char *dst, size_t dlen, const char *src)
917 size_t len;
918 const char *src_origin;
919 const char *src_last;
920 const char *dst_origin;
922 src_origin = src;
923 src_last = strchr(src, '\0');
924 dst_origin = dst;
925 memset(dst, '\0', dlen);
926 while (src && (len = (uint8_t)(*src++) & 0x3f) &&
927 (src + len) <= src_last) {
928 if (dst != dst_origin)
929 *dst++ = '.';
930 mysyslog(LOG_DEBUG, "<%s> labellen = %zd", __func__, len);
931 memcpy(dst, src, len);
932 src += len;
933 dst += len;
935 *dst = '\0';
937 return (src - src_origin);