2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
32 #include <sys/queue.h>
33 #include <sys/types.h>
34 #include <sys/socket.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>
62 #include "pathnames.h"
65 #include "timer_subr.h"
68 #include "control_client.h"
70 #define RA_IFSTATUS_INACTIVE 0
71 #define RA_IFSTATUS_RA_RECV 1
72 #define RA_IFSTATUS_RA_SEND 2
74 static int vflag = LOG_ERR;
76 static void usage(void);
78 static int action_propset(char *);
79 static int action_propget(char *, struct ctrl_msg_pl *);
80 static int action_plgeneric(int, char *, char *);
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 **);
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 *);
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 *, ...);
99 static const char *rtpref_str[] = {
106 static struct dispatch_table {
108 int (*dt_act)(int, char **);
110 { "show", action_show },
111 { "reload", action_reload },
112 { "shutdown", action_shutdown },
113 { "enable", action_enable },
114 { "disable", action_disable },
116 { "echo", action_echo },
117 { "version", action_version },
121 static char errmsgbuf[1024];
122 static char *errmsg = NULL;
125 mysyslog(int priority, const char * restrict fmt, ...)
129 if (vflag >= priority) {
131 vfprintf(stderr, fmt, ap);
132 fprintf(stderr, "\n");
142 for (i = 0; (size_t)i < sizeof(dtable)/sizeof(dtable[0]); i++) {
143 if (dtable[i].dt_comm == NULL)
145 printf("%s\n", dtable[i].dt_comm);
152 main(int argc, char *argv[])
156 int (*action)(int, char **) = NULL;
159 while ((ch = getopt(argc, argv, "Dv")) != -1) {
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;
188 error = (dtable[i].dt_act)(--argc, ++argv);
190 fprintf(stderr, "%s failed", dtable[i].dt_comm);
192 fprintf(stderr, ": %s", errmsg);
193 fprintf(stderr, ".\n");
200 csock_client_open(struct sockinfo *s)
202 struct sockaddr_un sun;
204 if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
205 err(1, "cannot open control socket.");
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));
212 if (connect(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
213 err(1, "connect: %s", s->si_name);
216 "<%s> connected to %s", __func__, sun.sun_path);
222 action_plgeneric(int action, char *plstr, char *buf)
224 struct ctrl_msg_hdr *cm;
225 struct ctrl_msg_pl cp;
232 csock_client_open(s);
234 cm = (struct ctrl_msg_hdr *)buf;
235 msg = (char *)buf + sizeof(*cm);
237 cm->cm_version = CM_VERSION;
238 cm->cm_type = action;
239 cm->cm_len = sizeof(*cm);
242 memset(&cp, 0, sizeof(cp));
243 p = strchr(plstr, ':');
244 q = strchr(plstr, '=');
245 if (p != NULL && q != NULL && p > q)
248 if (p == NULL) { /* No : */
251 } else if (p == plstr) { /* empty */
253 cp.cp_key = plstr + 1;
256 cp.cp_ifname = plstr;
265 cm->cm_len += cm_pl2bin(msg, &cp);
267 mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s",
268 __func__,cp.cp_key, cp.cp_val_len, cp.cp_ifname);
271 return (cm_handler_client(s->si_fd, CM_STATE_MSG_DISPATCH, buf));
275 action_propget(char *argv, struct ctrl_msg_pl *cp)
278 struct ctrl_msg_hdr *cm;
279 char buf[CM_MSG_MAXLEN];
282 memset(cp, 0, sizeof(*cp));
283 cm = (struct ctrl_msg_hdr *)buf;
284 msg = (char *)buf + sizeof(*cm);
286 error = action_plgeneric(CM_TYPE_REQ_GET_PROP, argv, buf);
287 if (error || cm->cm_len <= sizeof(*cm))
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);
300 action_propset(char *argv)
302 char buf[CM_MSG_MAXLEN];
304 return (action_plgeneric(CM_TYPE_REQ_SET_PROP, argv, buf));
308 action_disable(int argc, char **argv)
311 char argv_disable[IFNAMSIZ + sizeof(":disable=")];
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);
329 action_enable(int argc, char **argv)
332 char argv_enable[IFNAMSIZ + sizeof(":enable=")];
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);
350 action_reload(int argc, char **argv)
353 char argv_reload[IFNAMSIZ + sizeof(":reload=")];
358 action_argv = strdup(":reload=");
359 return (action_propset(action_argv));
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);
373 action_echo(int argc __unused, char **argv __unused)
377 action_argv = strdup("echo");
378 return (action_propset(action_argv));
382 action_shutdown(int argc __unused, char **argv __unused)
386 action_argv = strdup("shutdown");
387 return (action_propset(action_argv));
392 action_version(int argc __unused, char **argv __unused)
395 struct ctrl_msg_pl cp;
398 action_argv = strdup(":version=");
399 error = action_propget(action_argv, &cp);
403 printf("version=%s\n", cp.cp_val);
408 action_show(int argc, char **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];
421 struct timespec now, ts0, ts;
422 struct ctrl_msg_pl cp;
424 TAILQ_HEAD(, ifinfo) ifl = TAILQ_HEAD_INITIALIZER(ifl);
432 action_argv = argv_ifilist;
433 error = action_propget(action_argv, &cp);
438 endp = p + cp.cp_val_len;
440 ifi = malloc(sizeof(*ifi));
443 memset(ifi, 0, sizeof(*ifi));
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;
451 for (i = 0; i < argc; i++) {
452 ifi = malloc(sizeof(*ifi));
455 memset(ifi, 0, sizeof(*ifi));
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",
466 TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next);
470 clock_gettime(CLOCK_REALTIME_FAST, &now);
471 clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
472 TS_SUB(&now, &ts, &ts0);
474 TAILQ_FOREACH(ifi, &ifl, ifi_next) {
475 struct ifinfo *ifi_s;
476 struct rtadvd_timer *rat;
483 sprintf(argv_ifi, "%s:ifi=", ifi->ifi_ifname);
484 action_argv = argv_ifi;
485 error = action_propget(action_argv, &cp);
488 ifi_s = (struct ifinfo *)cp.cp_val;
490 if (!(ifi_s->ifi_persist) && vflag < LOG_NOTICE)
493 printf("%s: flags=<", ifi->ifi_ifname);
496 if (ifi_s->ifi_ifindex == 0)
497 c += printf("NONEXISTENT");
499 c += printf("%s", (ifi_s->ifi_flags & IFF_UP) ?
501 switch (ifi_s->ifi_state) {
502 case IFI_STATE_CONFIGURED:
503 c += printf("%s%s", (c) ? "," : "", "CONFIGURED");
505 case IFI_STATE_TRANSITIVE:
506 c += printf("%s%s", (c) ? "," : "", "TRANSITIVE");
509 if (ifi_s->ifi_persist)
510 c += printf("%s%s", (c) ? "," : "", "PERSIST");
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)
519 * RA_RECV: !ip6.forwarding && ip6.accept_rtadv
520 * RA_SEND: ip6.forwarding
522 if (getinet6sysctl(IPV6CTL_FORWARDING) == 0) {
523 if (getinet6sysctl(IPV6CTL_ACCEPT_RTADV))
524 ra_ifstatus = RA_IFSTATUS_RA_RECV;
526 ra_ifstatus = RA_IFSTATUS_INACTIVE;
528 ra_ifstatus = RA_IFSTATUS_RA_SEND;
531 * RA_RECV: ND6_IFF_ACCEPT_RTADV
532 * RA_SEND: ip6.forwarding
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;
539 ra_ifstatus = RA_IFSTATUS_INACTIVE;
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");
553 switch (ifi_s->ifi_state) {
554 case IFI_STATE_CONFIGURED:
555 case IFI_STATE_TRANSITIVE:
562 printf("mtu %d\n", ifi_s->ifi_phymtu);
564 sprintf(argv_rai, "%s:rai=", ifi->ifi_ifname);
565 action_argv = argv_rai;
567 error = action_propget(action_argv, &cp);
571 rai = (struct rainfo *)cp.cp_val;
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)");
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);
587 printf("\tAdvLinkMTU: <none>");
592 if (rai->rai_managedflg || rai->rai_otherflg) {
593 printf("%s", rai->rai_managedflg ? "M" : "");
594 printf("%s", rai->rai_otherflg ? "O" : "");
600 printf("Preference: %s\n",
601 rtpref_str[(rai->rai_rtpref >> 3) & 0xff]);
603 printf("\tReachableTime: %s, ",
604 sec2str(rai->rai_reachabletime, ssbuf));
605 printf("RetransTimer: %s, "
607 sec2str(rai->rai_retranstimer, ssbuf),
609 printf("\tAdvIfPrefixes: %s\n",
610 rai->rai_advifprefix ? "yes" : "no");
614 if (ifi_s->ifi_ra_timer != NULL) {
615 sprintf(argv_ifi_ra_timer, "%s:ifi_ra_timer=",
617 action_argv = argv_ifi_ra_timer;
619 error = action_propget(action_argv, &cp);
623 rat = (struct rtadvd_timer *)cp.cp_val;
625 printf("\tNext RA send: ");
629 ts.tv_sec = rat->rat_tm.tv_sec + ts0.tv_sec;
630 printf("%s", ctime(&ts.tv_sec));
632 printf("\tLast RA send: ");
633 if (ifi_s->ifi_ra_lastsent.tv_sec == 0)
636 ts.tv_sec = ifi_s->ifi_ra_lastsent.tv_sec + ts0.tv_sec;
637 printf("%s", ctime(&ts.tv_sec));
639 if (rai->rai_clockskew)
640 printf("\tClock skew: %" PRIu16 "sec\n",
643 if (vflag < LOG_WARNING)
646 /* route information */
647 sprintf(argv_rti, "%s:rti=", ifi->ifi_ifname);
648 action_argv = argv_rti;
649 error = action_propget(action_argv, &cp);
653 rti = (struct rtinfo *)cp.cp_val;
654 len = cp.cp_val_len / sizeof(*rti);
656 printf("\tRoute Info:\n");
658 for (i = 0; i < len; i++)
659 action_show_rtinfo(&rti[i]);
662 /* prefix information */
663 sprintf(argv_pfx, "%s:pfx=", ifi->ifi_ifname);
664 action_argv = argv_pfx;
666 error = action_propget(action_argv, &cp);
670 pfx = (struct prefix *)cp.cp_val;
671 len = cp.cp_val_len / sizeof(*pfx);
674 printf("\tPrefixes (%d):\n", len);
676 for (i = 0; i < len; i++)
677 action_show_prefix(&pfx[i]);
680 /* RDNSS information */
681 sprintf(argv_rdnss, "%s:rdnss=", ifi->ifi_ifname);
682 action_argv = argv_rdnss;
684 error = action_propget(action_argv, &cp);
688 len = *((uint16_t *)cp.cp_val);
691 printf("\tRDNSS entries:\n");
692 action_show_rdnss(cp.cp_val);
695 /* DNSSL information */
696 sprintf(argv_dnssl, "%s:dnssl=", ifi->ifi_ifname);
697 action_argv = argv_dnssl;
699 error = action_propget(action_argv, &cp);
703 len = *((uint16_t *)cp.cp_val);
706 printf("\tDNSSL entries:\n");
707 action_show_dnssl(cp.cp_val);
710 if (vflag < LOG_NOTICE)
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);
723 "\t RA: %" PRIu64 "\n", ifi_s->ifi_raoutput);
726 "\t RA: %" PRIu64 " (normal)\n"
727 "\t RA: %" PRIu64 " (inconsistent)\n"
728 "\t RS: %" PRIu64 "\n",
730 ifi_s->ifi_rainconsistent,
735 #if 0 /* Not implemented yet */
736 printf("\tReceived RAs:\n");
744 action_show_rtinfo(struct rtinfo *rti)
746 char ntopbuf[INET6_ADDRSTRLEN];
747 char ssbuf[SSBUFLEN];
749 printf("\t %s/%d (pref: %s, ltime: %s)\n",
750 inet_ntop(AF_INET6, &rti->rti_prefix,
751 ntopbuf, sizeof(ntopbuf)),
753 rtpref_str[0xff & (rti->rti_rtpref >> 3)],
754 (rti->rti_ltime == ND6_INFINITE_LIFETIME) ?
755 "infinity" : sec2str(rti->rti_ltime, ssbuf));
761 action_show_prefix(struct prefix *pfx)
763 char ntopbuf[INET6_ADDRSTRLEN];
764 char ssbuf[SSBUFLEN];
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);
772 switch (pfx->pfx_origin) {
773 case PREFIX_FROM_KERNEL:
776 case PREFIX_FROM_CONFIG:
779 case PREFIX_FROM_DYNAMIC:
787 (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME) ?
788 "infinity" : sec2str(pfx->pfx_validlifetime, ssbuf));
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) :
799 (pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME) ?
800 "infinity" : sec2str(pfx->pfx_preflifetime, ssbuf));
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) :
811 if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) {
812 printf("%s", pfx->pfx_onlinkflg ? "L" : "");
813 printf("%s", pfx->pfx_autoconfflg ? "A" : "");
817 if (pfx->pfx_timer) {
818 struct timespec *rest;
820 rest = rtadvd_timer_rest(pfx->pfx_timer);
821 if (rest) { /* XXX: what if not? */
822 printf(" expire=%s", sec2str(rest->tv_sec, ssbuf));
832 action_show_rdnss(void *msg)
835 struct rdnss_addr *rda;
842 char ntopbuf[INET6_ADDRSTRLEN];
843 char ssbuf[SSBUFLEN];
846 rdn_cnt = (uint16_t *)p;
847 p += sizeof(*rdn_cnt);
850 for (i = 0; i < *rdn_cnt; i++) {
851 rdn = (struct rdnss *)p;
852 ltime = rdn->rd_ltime;
855 rda_cnt = (uint16_t *)p;
856 p += sizeof(*rda_cnt);
858 for (j = 0; j < *rda_cnt; j++) {
859 rda = (struct rdnss_addr *)p;
860 printf("\t %s (ltime=%s)\n",
865 sec2str(ltime, ssbuf));
875 action_show_dnssl(void *msg)
878 struct dnssl_addr *dna;
885 char hbuf[NI_MAXHOST];
886 char ssbuf[SSBUFLEN];
889 dns_cnt = (uint16_t *)p;
890 p += sizeof(*dns_cnt);
893 for (i = 0; i < *dns_cnt; i++) {
894 dns = (struct dnssl *)p;
895 ltime = dns->dn_ltime;
898 dna_cnt = (uint16_t *)p;
899 p += sizeof(*dna_cnt);
901 for (j = 0; j < *dna_cnt; j++) {
902 dna = (struct dnssl_addr *)p;
903 dname_labeldec(hbuf, sizeof(hbuf),
905 printf("\t %s (ltime=%s)\n",
906 hbuf, sec2str(ltime, ssbuf));
915 /* Decode domain name label encoding in RFC 1035 Section 3.1 */
917 dname_labeldec(char *dst, size_t dlen, const char *src)
920 const char *src_origin;
921 const char *src_last;
922 const char *dst_origin;
925 src_last = strchr(src, '\0');
927 memset(dst, '\0', dlen);
928 while (src && (len = (uint8_t)(*src++) & 0x3f) &&
929 (src + len) <= src_last) {
930 if (dst != dst_origin)
932 mysyslog(LOG_DEBUG, "<%s> labellen = %zd", __func__, len);
933 memcpy(dst, src, len);
939 return (src - src_origin);