137241896SHiroki Sato /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni *
437241896SHiroki Sato * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org>
537241896SHiroki Sato * All rights reserved.
637241896SHiroki Sato *
737241896SHiroki Sato * Redistribution and use in source and binary forms, with or without
837241896SHiroki Sato * modification, are permitted provided that the following conditions
937241896SHiroki Sato * are met:
1037241896SHiroki Sato * 1. Redistributions of source code must retain the above copyright
1137241896SHiroki Sato * notice, this list of conditions and the following disclaimer.
1237241896SHiroki Sato * 2. Redistributions in binary form must reproduce the above copyright
1337241896SHiroki Sato * notice, this list of conditions and the following disclaimer in the
1437241896SHiroki Sato * documentation and/or other materials provided with the distribution.
1537241896SHiroki Sato *
1637241896SHiroki Sato * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
1737241896SHiroki Sato * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1837241896SHiroki Sato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
1937241896SHiroki Sato * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS
2037241896SHiroki Sato * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2137241896SHiroki Sato * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2237241896SHiroki Sato * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
2337241896SHiroki Sato * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
2437241896SHiroki Sato * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
2537241896SHiroki Sato * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
2637241896SHiroki Sato * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2737241896SHiroki Sato *
2837241896SHiroki Sato */
2937241896SHiroki Sato
30*d1d652c0SElyes Haouas #include <sys/param.h>
3137241896SHiroki Sato #include <sys/queue.h>
3237241896SHiroki Sato #include <sys/socket.h>
3337241896SHiroki Sato #include <sys/stat.h>
3437241896SHiroki Sato #include <sys/un.h>
3537241896SHiroki Sato #include <sys/uio.h>
3637241896SHiroki Sato #include <net/if.h>
3737241896SHiroki Sato #include <net/if_dl.h>
3837241896SHiroki Sato #include <net/if_types.h>
3937241896SHiroki Sato #include <net/ethernet.h>
4037241896SHiroki Sato #include <netinet/in.h>
4137241896SHiroki Sato #include <netinet/ip6.h>
4237241896SHiroki Sato #include <netinet/icmp6.h>
4337241896SHiroki Sato #include <netinet6/in6_var.h>
4437241896SHiroki Sato #include <netinet6/nd6.h>
4537241896SHiroki Sato #include <arpa/inet.h>
4637241896SHiroki Sato #include <fcntl.h>
4737241896SHiroki Sato #include <errno.h>
4837241896SHiroki Sato #include <inttypes.h>
4937241896SHiroki Sato #include <netdb.h>
5037241896SHiroki Sato #include <unistd.h>
5137241896SHiroki Sato #include <string.h>
5237241896SHiroki Sato #include <stdarg.h>
5337241896SHiroki Sato #include <stdio.h>
5437241896SHiroki Sato #include <stdlib.h>
5537241896SHiroki Sato #include <stdarg.h>
5637241896SHiroki Sato #include <syslog.h>
577d26db17SHiroki Sato #include <time.h>
5837241896SHiroki Sato #include <err.h>
5937241896SHiroki Sato
6037241896SHiroki Sato #include "pathnames.h"
6137241896SHiroki Sato #include "rtadvd.h"
6237241896SHiroki Sato #include "if.h"
6337241896SHiroki Sato #include "timer_subr.h"
6437241896SHiroki Sato #include "timer.h"
6537241896SHiroki Sato #include "control.h"
6637241896SHiroki Sato #include "control_client.h"
6737241896SHiroki Sato
6837241896SHiroki Sato #define RA_IFSTATUS_INACTIVE 0
6937241896SHiroki Sato #define RA_IFSTATUS_RA_RECV 1
7037241896SHiroki Sato #define RA_IFSTATUS_RA_SEND 2
7137241896SHiroki Sato
7237241896SHiroki Sato static int vflag = LOG_ERR;
7337241896SHiroki Sato
7437241896SHiroki Sato static void usage(void);
7537241896SHiroki Sato
7637241896SHiroki Sato static int action_propset(char *);
7737241896SHiroki Sato static int action_propget(char *, struct ctrl_msg_pl *);
7837241896SHiroki Sato static int action_plgeneric(int, char *, char *);
7937241896SHiroki Sato
8037241896SHiroki Sato static int action_enable(int, char **);
8137241896SHiroki Sato static int action_disable(int, char **);
8237241896SHiroki Sato static int action_reload(int, char **);
8337241896SHiroki Sato static int action_echo(int, char **);
8437241896SHiroki Sato static int action_version(int, char **);
8537241896SHiroki Sato static int action_shutdown(int, char **);
8637241896SHiroki Sato
8737241896SHiroki Sato static int action_show(int, char **);
8837241896SHiroki Sato static int action_show_prefix(struct prefix *);
8937241896SHiroki Sato static int action_show_rtinfo(struct rtinfo *);
9037241896SHiroki Sato static int action_show_rdnss(void *);
9137241896SHiroki Sato static int action_show_dnssl(void *);
9237241896SHiroki Sato
9337241896SHiroki Sato static int csock_client_open(struct sockinfo *);
9437241896SHiroki Sato static size_t dname_labeldec(char *, size_t, const char *);
9537241896SHiroki Sato static void mysyslog(int, const char *, ...);
9637241896SHiroki Sato
9737241896SHiroki Sato static const char *rtpref_str[] = {
9837241896SHiroki Sato "medium", /* 00 */
9937241896SHiroki Sato "high", /* 01 */
10037241896SHiroki Sato "rsv", /* 10 */
10137241896SHiroki Sato "low" /* 11 */
10237241896SHiroki Sato };
10337241896SHiroki Sato
10437241896SHiroki Sato static struct dispatch_table {
10537241896SHiroki Sato const char *dt_comm;
10637241896SHiroki Sato int (*dt_act)(int, char **);
10737241896SHiroki Sato } dtable[] = {
10837241896SHiroki Sato { "show", action_show },
10937241896SHiroki Sato { "reload", action_reload },
11037241896SHiroki Sato { "shutdown", action_shutdown },
11137241896SHiroki Sato { "enable", action_enable },
11237241896SHiroki Sato { "disable", action_disable },
11337241896SHiroki Sato { NULL, NULL },
11437241896SHiroki Sato { "echo", action_echo },
11537241896SHiroki Sato { "version", action_version },
11637241896SHiroki Sato { NULL, NULL },
11737241896SHiroki Sato };
11837241896SHiroki Sato
11937241896SHiroki Sato static char errmsgbuf[1024];
12037241896SHiroki Sato static char *errmsg = NULL;
12137241896SHiroki Sato
12237241896SHiroki Sato static void
mysyslog(int priority,const char * restrict fmt,...)12337241896SHiroki Sato mysyslog(int priority, const char * restrict fmt, ...)
12437241896SHiroki Sato {
12537241896SHiroki Sato va_list ap;
12637241896SHiroki Sato
12737241896SHiroki Sato if (vflag >= priority) {
12837241896SHiroki Sato va_start(ap, fmt);
12937241896SHiroki Sato vfprintf(stderr, fmt, ap);
13037241896SHiroki Sato fprintf(stderr, "\n");
13137241896SHiroki Sato va_end(ap);
13237241896SHiroki Sato }
13337241896SHiroki Sato }
13437241896SHiroki Sato
13537241896SHiroki Sato static void
usage(void)13637241896SHiroki Sato usage(void)
13737241896SHiroki Sato {
13837241896SHiroki Sato int i;
13937241896SHiroki Sato
140*d1d652c0SElyes Haouas for (i = 0; (size_t)i < nitems(dtable); i++) {
14137241896SHiroki Sato if (dtable[i].dt_comm == NULL)
14237241896SHiroki Sato break;
14337241896SHiroki Sato printf("%s\n", dtable[i].dt_comm);
14437241896SHiroki Sato }
14537241896SHiroki Sato
14637241896SHiroki Sato exit(1);
14737241896SHiroki Sato }
14837241896SHiroki Sato
14937241896SHiroki Sato int
main(int argc,char * argv[])15037241896SHiroki Sato main(int argc, char *argv[])
15137241896SHiroki Sato {
15237241896SHiroki Sato int i;
15337241896SHiroki Sato int ch;
15437241896SHiroki Sato int (*action)(int, char **) = NULL;
15537241896SHiroki Sato int error;
15637241896SHiroki Sato
15737241896SHiroki Sato while ((ch = getopt(argc, argv, "Dv")) != -1) {
15837241896SHiroki Sato switch (ch) {
15937241896SHiroki Sato case 'D':
16037241896SHiroki Sato vflag = LOG_DEBUG;
16137241896SHiroki Sato break;
16237241896SHiroki Sato case 'v':
16337241896SHiroki Sato vflag++;
16437241896SHiroki Sato break;
16537241896SHiroki Sato default:
16637241896SHiroki Sato usage();
16737241896SHiroki Sato }
16837241896SHiroki Sato }
16937241896SHiroki Sato argc -= optind;
17037241896SHiroki Sato argv += optind;
17137241896SHiroki Sato
17237241896SHiroki Sato if (argc == 0)
17337241896SHiroki Sato usage();
17437241896SHiroki Sato
175*d1d652c0SElyes Haouas for (i = 0; (size_t)i < nitems(dtable); i++) {
17637241896SHiroki Sato if (dtable[i].dt_comm == NULL ||
17737241896SHiroki Sato strcmp(dtable[i].dt_comm, argv[0]) == 0) {
17837241896SHiroki Sato action = dtable[i].dt_act;
17937241896SHiroki Sato break;
18037241896SHiroki Sato }
18137241896SHiroki Sato }
18237241896SHiroki Sato
18337241896SHiroki Sato if (action == NULL)
18437241896SHiroki Sato usage();
18537241896SHiroki Sato
18637241896SHiroki Sato error = (dtable[i].dt_act)(--argc, ++argv);
18737241896SHiroki Sato if (error) {
18837241896SHiroki Sato fprintf(stderr, "%s failed", dtable[i].dt_comm);
18937241896SHiroki Sato if (errmsg != NULL)
19037241896SHiroki Sato fprintf(stderr, ": %s", errmsg);
19137241896SHiroki Sato fprintf(stderr, ".\n");
19237241896SHiroki Sato }
19337241896SHiroki Sato
19437241896SHiroki Sato return (error);
19537241896SHiroki Sato }
19637241896SHiroki Sato
19737241896SHiroki Sato static int
csock_client_open(struct sockinfo * s)19837241896SHiroki Sato csock_client_open(struct sockinfo *s)
19937241896SHiroki Sato {
20037241896SHiroki Sato struct sockaddr_un sun;
20137241896SHiroki Sato
20237241896SHiroki Sato if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
20337241896SHiroki Sato err(1, "cannot open control socket.");
20437241896SHiroki Sato
20537241896SHiroki Sato memset(&sun, 0, sizeof(sun));
20637241896SHiroki Sato sun.sun_family = AF_UNIX;
20737241896SHiroki Sato sun.sun_len = sizeof(sun);
20837241896SHiroki Sato strlcpy(sun.sun_path, s->si_name, sizeof(sun.sun_path));
20937241896SHiroki Sato
21037241896SHiroki Sato if (connect(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
21137241896SHiroki Sato err(1, "connect: %s", s->si_name);
21237241896SHiroki Sato
21337241896SHiroki Sato mysyslog(LOG_DEBUG,
21437241896SHiroki Sato "<%s> connected to %s", __func__, sun.sun_path);
21537241896SHiroki Sato
21637241896SHiroki Sato return (0);
21737241896SHiroki Sato }
21837241896SHiroki Sato
21937241896SHiroki Sato static int
action_plgeneric(int action,char * plstr,char * buf)22037241896SHiroki Sato action_plgeneric(int action, char *plstr, char *buf)
22137241896SHiroki Sato {
22237241896SHiroki Sato struct ctrl_msg_hdr *cm;
22337241896SHiroki Sato struct ctrl_msg_pl cp;
22437241896SHiroki Sato struct sockinfo *s;
22537241896SHiroki Sato char *msg;
22637241896SHiroki Sato char *p;
22737241896SHiroki Sato char *q;
22837241896SHiroki Sato
22937241896SHiroki Sato s = &ctrlsock;
23037241896SHiroki Sato csock_client_open(s);
23137241896SHiroki Sato
23237241896SHiroki Sato cm = (struct ctrl_msg_hdr *)buf;
23337241896SHiroki Sato msg = (char *)buf + sizeof(*cm);
23437241896SHiroki Sato
23537241896SHiroki Sato cm->cm_version = CM_VERSION;
23637241896SHiroki Sato cm->cm_type = action;
23737241896SHiroki Sato cm->cm_len = sizeof(*cm);
23837241896SHiroki Sato
23937241896SHiroki Sato if (plstr != NULL) {
24037241896SHiroki Sato memset(&cp, 0, sizeof(cp));
24137241896SHiroki Sato p = strchr(plstr, ':');
24237241896SHiroki Sato q = strchr(plstr, '=');
24337241896SHiroki Sato if (p != NULL && q != NULL && p > q)
24437241896SHiroki Sato return (1);
24537241896SHiroki Sato
24637241896SHiroki Sato if (p == NULL) { /* No : */
24737241896SHiroki Sato cp.cp_ifname = NULL;
24837241896SHiroki Sato cp.cp_key = plstr;
24937241896SHiroki Sato } else if (p == plstr) { /* empty */
25037241896SHiroki Sato cp.cp_ifname = NULL;
25137241896SHiroki Sato cp.cp_key = plstr + 1;
25237241896SHiroki Sato } else {
25337241896SHiroki Sato *p++ = '\0';
25437241896SHiroki Sato cp.cp_ifname = plstr;
25537241896SHiroki Sato cp.cp_key = p;
25637241896SHiroki Sato }
25737241896SHiroki Sato if (q == NULL)
25837241896SHiroki Sato cp.cp_val = NULL;
25937241896SHiroki Sato else {
26037241896SHiroki Sato *q++ = '\0';
26137241896SHiroki Sato cp.cp_val = q;
26237241896SHiroki Sato }
263aed37872SHiroki Sato cm->cm_len += cm_pl2bin(msg, &cp);
26437241896SHiroki Sato
26537241896SHiroki Sato mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s",
26637241896SHiroki Sato __func__,cp.cp_key, cp.cp_val_len, cp.cp_ifname);
26737241896SHiroki Sato }
26837241896SHiroki Sato
269aed37872SHiroki Sato return (cm_handler_client(s->si_fd, CM_STATE_MSG_DISPATCH, buf));
27037241896SHiroki Sato }
27137241896SHiroki Sato
27237241896SHiroki Sato static int
action_propget(char * argv,struct ctrl_msg_pl * cp)27337241896SHiroki Sato action_propget(char *argv, struct ctrl_msg_pl *cp)
27437241896SHiroki Sato {
27537241896SHiroki Sato int error;
27637241896SHiroki Sato struct ctrl_msg_hdr *cm;
27737241896SHiroki Sato char buf[CM_MSG_MAXLEN];
27837241896SHiroki Sato char *msg;
27937241896SHiroki Sato
28037241896SHiroki Sato memset(cp, 0, sizeof(*cp));
28137241896SHiroki Sato cm = (struct ctrl_msg_hdr *)buf;
28237241896SHiroki Sato msg = (char *)buf + sizeof(*cm);
28337241896SHiroki Sato
28437241896SHiroki Sato error = action_plgeneric(CM_TYPE_REQ_GET_PROP, argv, buf);
28537241896SHiroki Sato if (error || cm->cm_len <= sizeof(*cm))
28637241896SHiroki Sato return (1);
28737241896SHiroki Sato
288aed37872SHiroki Sato cm_bin2pl(msg, cp);
28937241896SHiroki Sato mysyslog(LOG_DEBUG, "<%s> type=%d, len=%d",
29037241896SHiroki Sato __func__, cm->cm_type, cm->cm_len);
29137241896SHiroki Sato mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s",
29237241896SHiroki Sato __func__,cp->cp_key, cp->cp_val_len, cp->cp_ifname);
29337241896SHiroki Sato
29437241896SHiroki Sato return (0);
29537241896SHiroki Sato }
29637241896SHiroki Sato
29737241896SHiroki Sato static int
action_propset(char * argv)29837241896SHiroki Sato action_propset(char *argv)
29937241896SHiroki Sato {
30037241896SHiroki Sato char buf[CM_MSG_MAXLEN];
30137241896SHiroki Sato
30237241896SHiroki Sato return (action_plgeneric(CM_TYPE_REQ_SET_PROP, argv, buf));
30337241896SHiroki Sato }
30437241896SHiroki Sato
30537241896SHiroki Sato static int
action_disable(int argc,char ** argv)30637241896SHiroki Sato action_disable(int argc, char **argv)
30737241896SHiroki Sato {
30837241896SHiroki Sato char *action_argv;
30937241896SHiroki Sato char argv_disable[IFNAMSIZ + sizeof(":disable=")];
31037241896SHiroki Sato int i;
31137241896SHiroki Sato int error;
31237241896SHiroki Sato
31337241896SHiroki Sato if (argc < 1)
31437241896SHiroki Sato return (1);
31537241896SHiroki Sato
31637241896SHiroki Sato error = 0;
31737241896SHiroki Sato for (i = 0; i < argc; i++) {
31837241896SHiroki Sato sprintf(argv_disable, "%s:disable=", argv[i]);
31937241896SHiroki Sato action_argv = argv_disable;
32037241896SHiroki Sato error += action_propset(action_argv);
32137241896SHiroki Sato }
32237241896SHiroki Sato
32337241896SHiroki Sato return (error);
32437241896SHiroki Sato }
32537241896SHiroki Sato
32637241896SHiroki Sato static int
action_enable(int argc,char ** argv)32737241896SHiroki Sato action_enable(int argc, char **argv)
32837241896SHiroki Sato {
32937241896SHiroki Sato char *action_argv;
33037241896SHiroki Sato char argv_enable[IFNAMSIZ + sizeof(":enable=")];
33137241896SHiroki Sato int i;
33237241896SHiroki Sato int error;
33337241896SHiroki Sato
33437241896SHiroki Sato if (argc < 1)
33537241896SHiroki Sato return (1);
33637241896SHiroki Sato
33737241896SHiroki Sato error = 0;
33837241896SHiroki Sato for (i = 0; i < argc; i++) {
33937241896SHiroki Sato sprintf(argv_enable, "%s:enable=", argv[i]);
34037241896SHiroki Sato action_argv = argv_enable;
34137241896SHiroki Sato error += action_propset(action_argv);
34237241896SHiroki Sato }
34337241896SHiroki Sato
34437241896SHiroki Sato return (error);
34537241896SHiroki Sato }
34637241896SHiroki Sato
34737241896SHiroki Sato static int
action_reload(int argc,char ** argv)34837241896SHiroki Sato action_reload(int argc, char **argv)
34937241896SHiroki Sato {
35037241896SHiroki Sato char *action_argv;
35137241896SHiroki Sato char argv_reload[IFNAMSIZ + sizeof(":reload=")];
35237241896SHiroki Sato int i;
35337241896SHiroki Sato int error;
35437241896SHiroki Sato
35537241896SHiroki Sato if (argc == 0) {
35637241896SHiroki Sato action_argv = strdup(":reload=");
35737241896SHiroki Sato return (action_propset(action_argv));
35837241896SHiroki Sato }
35937241896SHiroki Sato
36037241896SHiroki Sato error = 0;
36137241896SHiroki Sato for (i = 0; i < argc; i++) {
36237241896SHiroki Sato sprintf(argv_reload, "%s:reload=", argv[i]);
36337241896SHiroki Sato action_argv = argv_reload;
36437241896SHiroki Sato error += action_propset(action_argv);
36537241896SHiroki Sato }
36637241896SHiroki Sato
36737241896SHiroki Sato return (error);
36837241896SHiroki Sato }
36937241896SHiroki Sato
37037241896SHiroki Sato static int
action_echo(int argc __unused,char ** argv __unused)37137241896SHiroki Sato action_echo(int argc __unused, char **argv __unused)
37237241896SHiroki Sato {
37337241896SHiroki Sato char *action_argv;
37437241896SHiroki Sato
37537241896SHiroki Sato action_argv = strdup("echo");
37637241896SHiroki Sato return (action_propset(action_argv));
37737241896SHiroki Sato }
37837241896SHiroki Sato
37937241896SHiroki Sato static int
action_shutdown(int argc __unused,char ** argv __unused)38037241896SHiroki Sato action_shutdown(int argc __unused, char **argv __unused)
38137241896SHiroki Sato {
38237241896SHiroki Sato char *action_argv;
38337241896SHiroki Sato
38437241896SHiroki Sato action_argv = strdup("shutdown");
38537241896SHiroki Sato return (action_propset(action_argv));
38637241896SHiroki Sato }
38737241896SHiroki Sato
38837241896SHiroki Sato /* XXX */
38937241896SHiroki Sato static int
action_version(int argc __unused,char ** argv __unused)39037241896SHiroki Sato action_version(int argc __unused, char **argv __unused)
39137241896SHiroki Sato {
39237241896SHiroki Sato char *action_argv;
39337241896SHiroki Sato struct ctrl_msg_pl cp;
39437241896SHiroki Sato int error;
39537241896SHiroki Sato
39637241896SHiroki Sato action_argv = strdup(":version=");
39737241896SHiroki Sato error = action_propget(action_argv, &cp);
39837241896SHiroki Sato if (error)
39937241896SHiroki Sato return (error);
40037241896SHiroki Sato
40137241896SHiroki Sato printf("version=%s\n", cp.cp_val);
40237241896SHiroki Sato return (0);
40337241896SHiroki Sato }
40437241896SHiroki Sato
40537241896SHiroki Sato static int
action_show(int argc,char ** argv)40637241896SHiroki Sato action_show(int argc, char **argv)
40737241896SHiroki Sato {
40837241896SHiroki Sato char *action_argv;
40937241896SHiroki Sato char argv_ifilist[sizeof(":ifilist=")] = ":ifilist=";
41037241896SHiroki Sato char argv_ifi[IFNAMSIZ + sizeof(":ifi=")];
41137241896SHiroki Sato char argv_rai[IFNAMSIZ + sizeof(":rai=")];
41237241896SHiroki Sato char argv_rti[IFNAMSIZ + sizeof(":rti=")];
41337241896SHiroki Sato char argv_pfx[IFNAMSIZ + sizeof(":pfx=")];
41437241896SHiroki Sato char argv_ifi_ra_timer[IFNAMSIZ + sizeof(":ifi_ra_timer=")];
41537241896SHiroki Sato char argv_rdnss[IFNAMSIZ + sizeof(":rdnss=")];
41637241896SHiroki Sato char argv_dnssl[IFNAMSIZ + sizeof(":dnssl=")];
41737241896SHiroki Sato char ssbuf[SSBUFLEN];
41837241896SHiroki Sato
4197d26db17SHiroki Sato struct timespec now, ts0, ts;
42037241896SHiroki Sato struct ctrl_msg_pl cp;
42137241896SHiroki Sato struct ifinfo *ifi;
42237241896SHiroki Sato TAILQ_HEAD(, ifinfo) ifl = TAILQ_HEAD_INITIALIZER(ifl);
42337241896SHiroki Sato char *endp;
42437241896SHiroki Sato char *p;
42537241896SHiroki Sato int error;
42637241896SHiroki Sato int i;
42737241896SHiroki Sato int len;
42837241896SHiroki Sato
42937241896SHiroki Sato if (argc == 0) {
43037241896SHiroki Sato action_argv = argv_ifilist;
43137241896SHiroki Sato error = action_propget(action_argv, &cp);
43237241896SHiroki Sato if (error)
43337241896SHiroki Sato return (error);
43437241896SHiroki Sato
43537241896SHiroki Sato p = cp.cp_val;
43637241896SHiroki Sato endp = p + cp.cp_val_len;
43737241896SHiroki Sato while (p < endp) {
43837241896SHiroki Sato ifi = malloc(sizeof(*ifi));
43937241896SHiroki Sato if (ifi == NULL)
44037241896SHiroki Sato return (1);
44137241896SHiroki Sato memset(ifi, 0, sizeof(*ifi));
44237241896SHiroki Sato
44337241896SHiroki Sato strcpy(ifi->ifi_ifname, p);
44437241896SHiroki Sato ifi->ifi_ifindex = if_nametoindex(ifi->ifi_ifname);
44537241896SHiroki Sato TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next);
44637241896SHiroki Sato p += strlen(ifi->ifi_ifname) + 1;
44737241896SHiroki Sato }
44837241896SHiroki Sato } else {
44937241896SHiroki Sato for (i = 0; i < argc; i++) {
45037241896SHiroki Sato ifi = malloc(sizeof(*ifi));
45137241896SHiroki Sato if (ifi == NULL)
45237241896SHiroki Sato return (1);
45337241896SHiroki Sato memset(ifi, 0, sizeof(*ifi));
45437241896SHiroki Sato
45537241896SHiroki Sato strcpy(ifi->ifi_ifname, argv[i]);
45637241896SHiroki Sato ifi->ifi_ifindex = if_nametoindex(ifi->ifi_ifname);
45737241896SHiroki Sato if (ifi->ifi_ifindex == 0) {
45837241896SHiroki Sato sprintf(errmsgbuf, "invalid interface %s",
45937241896SHiroki Sato ifi->ifi_ifname);
46037241896SHiroki Sato errmsg = errmsgbuf;
46137241896SHiroki Sato return (1);
46237241896SHiroki Sato }
46337241896SHiroki Sato
46437241896SHiroki Sato TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next);
46537241896SHiroki Sato }
46637241896SHiroki Sato }
46737241896SHiroki Sato
4687d26db17SHiroki Sato clock_gettime(CLOCK_REALTIME_FAST, &now);
4697d26db17SHiroki Sato clock_gettime(CLOCK_MONOTONIC_FAST, &ts);
4707d26db17SHiroki Sato TS_SUB(&now, &ts, &ts0);
4717d26db17SHiroki Sato
47237241896SHiroki Sato TAILQ_FOREACH(ifi, &ifl, ifi_next) {
47337241896SHiroki Sato struct ifinfo *ifi_s;
47437241896SHiroki Sato struct rtadvd_timer *rat;
47537241896SHiroki Sato struct rainfo *rai;
47637241896SHiroki Sato struct rtinfo *rti;
47737241896SHiroki Sato struct prefix *pfx;
47837241896SHiroki Sato int c;
47937241896SHiroki Sato int ra_ifstatus;
48037241896SHiroki Sato
48137241896SHiroki Sato sprintf(argv_ifi, "%s:ifi=", ifi->ifi_ifname);
48237241896SHiroki Sato action_argv = argv_ifi;
48337241896SHiroki Sato error = action_propget(action_argv, &cp);
48437241896SHiroki Sato if (error)
48537241896SHiroki Sato return (error);
48637241896SHiroki Sato ifi_s = (struct ifinfo *)cp.cp_val;
48737241896SHiroki Sato
48837241896SHiroki Sato if (!(ifi_s->ifi_persist) && vflag < LOG_NOTICE)
48937241896SHiroki Sato continue;
49037241896SHiroki Sato
49137241896SHiroki Sato printf("%s: flags=<", ifi->ifi_ifname);
49237241896SHiroki Sato
49337241896SHiroki Sato c = 0;
49437241896SHiroki Sato if (ifi_s->ifi_ifindex == 0)
49537241896SHiroki Sato c += printf("NONEXISTENT");
49637241896SHiroki Sato else
49737241896SHiroki Sato c += printf("%s", (ifi_s->ifi_flags & IFF_UP) ?
49837241896SHiroki Sato "UP" : "DOWN");
49937241896SHiroki Sato switch (ifi_s->ifi_state) {
50037241896SHiroki Sato case IFI_STATE_CONFIGURED:
50137241896SHiroki Sato c += printf("%s%s", (c) ? "," : "", "CONFIGURED");
50237241896SHiroki Sato break;
50337241896SHiroki Sato case IFI_STATE_TRANSITIVE:
50437241896SHiroki Sato c += printf("%s%s", (c) ? "," : "", "TRANSITIVE");
50537241896SHiroki Sato break;
50637241896SHiroki Sato }
50737241896SHiroki Sato if (ifi_s->ifi_persist)
50837241896SHiroki Sato c += printf("%s%s", (c) ? "," : "", "PERSIST");
50937241896SHiroki Sato printf(">");
51037241896SHiroki Sato
51137241896SHiroki Sato ra_ifstatus = RA_IFSTATUS_INACTIVE;
51237241896SHiroki Sato if ((ifi_s->ifi_flags & IFF_UP) &&
51337241896SHiroki Sato ((ifi_s->ifi_state == IFI_STATE_CONFIGURED) ||
51437241896SHiroki Sato (ifi_s->ifi_state == IFI_STATE_TRANSITIVE))) {
51537241896SHiroki Sato /*
51637241896SHiroki Sato * RA_RECV: ND6_IFF_ACCEPT_RTADV
51737241896SHiroki Sato * RA_SEND: ip6.forwarding
51837241896SHiroki Sato */
51937241896SHiroki Sato if (ifi_s->ifi_nd_flags & ND6_IFF_ACCEPT_RTADV)
52037241896SHiroki Sato ra_ifstatus = RA_IFSTATUS_RA_RECV;
52137241896SHiroki Sato else if (getinet6sysctl(IPV6CTL_FORWARDING))
52237241896SHiroki Sato ra_ifstatus = RA_IFSTATUS_RA_SEND;
52337241896SHiroki Sato else
52437241896SHiroki Sato ra_ifstatus = RA_IFSTATUS_INACTIVE;
52537241896SHiroki Sato }
52637241896SHiroki Sato
52737241896SHiroki Sato c = 0;
52837241896SHiroki Sato printf(" status=<");
52937241896SHiroki Sato if (ra_ifstatus == RA_IFSTATUS_INACTIVE)
53037241896SHiroki Sato printf("%s%s", (c) ? "," : "", "INACTIVE");
53137241896SHiroki Sato else if (ra_ifstatus == RA_IFSTATUS_RA_RECV)
53237241896SHiroki Sato printf("%s%s", (c) ? "," : "", "RA_RECV");
53337241896SHiroki Sato else if (ra_ifstatus == RA_IFSTATUS_RA_SEND)
53437241896SHiroki Sato printf("%s%s", (c) ? "," : "", "RA_SEND");
53537241896SHiroki Sato printf("> ");
53637241896SHiroki Sato
53737241896SHiroki Sato switch (ifi_s->ifi_state) {
53837241896SHiroki Sato case IFI_STATE_CONFIGURED:
53937241896SHiroki Sato case IFI_STATE_TRANSITIVE:
54037241896SHiroki Sato break;
54137241896SHiroki Sato default:
54237241896SHiroki Sato printf("\n");
54337241896SHiroki Sato continue;
54437241896SHiroki Sato }
54537241896SHiroki Sato
54637241896SHiroki Sato printf("mtu %d\n", ifi_s->ifi_phymtu);
54737241896SHiroki Sato
54837241896SHiroki Sato sprintf(argv_rai, "%s:rai=", ifi->ifi_ifname);
54937241896SHiroki Sato action_argv = argv_rai;
55037241896SHiroki Sato
55137241896SHiroki Sato error = action_propget(action_argv, &cp);
55237241896SHiroki Sato if (error)
55337241896SHiroki Sato continue;
55437241896SHiroki Sato
55537241896SHiroki Sato rai = (struct rainfo *)cp.cp_val;
55637241896SHiroki Sato
55737241896SHiroki Sato printf("\tDefaultLifetime: %s",
55837241896SHiroki Sato sec2str(rai->rai_lifetime, ssbuf));
55937241896SHiroki Sato if (ra_ifstatus != RA_IFSTATUS_RA_SEND &&
56037241896SHiroki Sato rai->rai_lifetime == 0)
56137241896SHiroki Sato printf(" (RAs will be sent with zero lifetime)");
56237241896SHiroki Sato
56337241896SHiroki Sato printf("\n");
56437241896SHiroki Sato
565aed37872SHiroki Sato printf("\tMinAdvInterval/MaxAdvInterval: ");
566aed37872SHiroki Sato printf("%s/", sec2str(rai->rai_mininterval, ssbuf));
567aed37872SHiroki Sato printf("%s\n", sec2str(rai->rai_maxinterval, ssbuf));
56837241896SHiroki Sato if (rai->rai_linkmtu)
56937241896SHiroki Sato printf("\tAdvLinkMTU: %d", rai->rai_linkmtu);
57037241896SHiroki Sato else
57137241896SHiroki Sato printf("\tAdvLinkMTU: <none>");
57237241896SHiroki Sato
57337241896SHiroki Sato printf(", ");
57437241896SHiroki Sato
57537241896SHiroki Sato printf("Flags: ");
57637241896SHiroki Sato if (rai->rai_managedflg || rai->rai_otherflg) {
57737241896SHiroki Sato printf("%s", rai->rai_managedflg ? "M" : "");
57837241896SHiroki Sato printf("%s", rai->rai_otherflg ? "O" : "");
57937241896SHiroki Sato } else
58037241896SHiroki Sato printf("<none>");
58137241896SHiroki Sato
58237241896SHiroki Sato printf(", ");
58337241896SHiroki Sato
58437241896SHiroki Sato printf("Preference: %s\n",
58537241896SHiroki Sato rtpref_str[(rai->rai_rtpref >> 3) & 0xff]);
58637241896SHiroki Sato
587aed37872SHiroki Sato printf("\tReachableTime: %s, ",
588aed37872SHiroki Sato sec2str(rai->rai_reachabletime, ssbuf));
589aed37872SHiroki Sato printf("RetransTimer: %s, "
59037241896SHiroki Sato "CurHopLimit: %d\n",
59137241896SHiroki Sato sec2str(rai->rai_retranstimer, ssbuf),
59237241896SHiroki Sato rai->rai_hoplimit);
59337241896SHiroki Sato printf("\tAdvIfPrefixes: %s\n",
59437241896SHiroki Sato rai->rai_advifprefix ? "yes" : "no");
59537241896SHiroki Sato
59637241896SHiroki Sato /* RA timer */
59737241896SHiroki Sato rat = NULL;
59837241896SHiroki Sato if (ifi_s->ifi_ra_timer != NULL) {
59937241896SHiroki Sato sprintf(argv_ifi_ra_timer, "%s:ifi_ra_timer=",
60037241896SHiroki Sato ifi->ifi_ifname);
60137241896SHiroki Sato action_argv = argv_ifi_ra_timer;
60237241896SHiroki Sato
60337241896SHiroki Sato error = action_propget(action_argv, &cp);
60437241896SHiroki Sato if (error)
60537241896SHiroki Sato return (error);
60637241896SHiroki Sato
60737241896SHiroki Sato rat = (struct rtadvd_timer *)cp.cp_val;
60837241896SHiroki Sato }
6097d26db17SHiroki Sato printf("\tNext RA send: ");
6107d26db17SHiroki Sato if (rat == NULL)
6117d26db17SHiroki Sato printf("never\n");
6127d26db17SHiroki Sato else {
6137d26db17SHiroki Sato ts.tv_sec = rat->rat_tm.tv_sec + ts0.tv_sec;
6147d26db17SHiroki Sato printf("%s", ctime(&ts.tv_sec));
6157d26db17SHiroki Sato }
6167d26db17SHiroki Sato printf("\tLast RA send: ");
6177d26db17SHiroki Sato if (ifi_s->ifi_ra_lastsent.tv_sec == 0)
6187d26db17SHiroki Sato printf("never\n");
6197d26db17SHiroki Sato else {
6207d26db17SHiroki Sato ts.tv_sec = ifi_s->ifi_ra_lastsent.tv_sec + ts0.tv_sec;
6217d26db17SHiroki Sato printf("%s", ctime(&ts.tv_sec));
6227d26db17SHiroki Sato }
62337241896SHiroki Sato if (rai->rai_clockskew)
62437241896SHiroki Sato printf("\tClock skew: %" PRIu16 "sec\n",
62537241896SHiroki Sato rai->rai_clockskew);
62637241896SHiroki Sato
62737241896SHiroki Sato if (vflag < LOG_WARNING)
62837241896SHiroki Sato continue;
62937241896SHiroki Sato
63037241896SHiroki Sato /* route information */
63137241896SHiroki Sato sprintf(argv_rti, "%s:rti=", ifi->ifi_ifname);
63237241896SHiroki Sato action_argv = argv_rti;
63337241896SHiroki Sato error = action_propget(action_argv, &cp);
63437241896SHiroki Sato if (error)
63537241896SHiroki Sato return (error);
63637241896SHiroki Sato
63737241896SHiroki Sato rti = (struct rtinfo *)cp.cp_val;
63837241896SHiroki Sato len = cp.cp_val_len / sizeof(*rti);
63937241896SHiroki Sato if (len > 0) {
64037241896SHiroki Sato printf("\tRoute Info:\n");
64137241896SHiroki Sato
64237241896SHiroki Sato for (i = 0; i < len; i++)
64337241896SHiroki Sato action_show_rtinfo(&rti[i]);
64437241896SHiroki Sato }
64537241896SHiroki Sato
64637241896SHiroki Sato /* prefix information */
64737241896SHiroki Sato sprintf(argv_pfx, "%s:pfx=", ifi->ifi_ifname);
64837241896SHiroki Sato action_argv = argv_pfx;
64937241896SHiroki Sato
65037241896SHiroki Sato error = action_propget(action_argv, &cp);
65137241896SHiroki Sato if (error)
65237241896SHiroki Sato continue;
65337241896SHiroki Sato
65437241896SHiroki Sato pfx = (struct prefix *)cp.cp_val;
65537241896SHiroki Sato len = cp.cp_val_len / sizeof(*pfx);
65637241896SHiroki Sato
65737241896SHiroki Sato if (len > 0) {
65837241896SHiroki Sato printf("\tPrefixes (%d):\n", len);
65937241896SHiroki Sato
66037241896SHiroki Sato for (i = 0; i < len; i++)
66137241896SHiroki Sato action_show_prefix(&pfx[i]);
66237241896SHiroki Sato }
66337241896SHiroki Sato
66437241896SHiroki Sato /* RDNSS information */
66537241896SHiroki Sato sprintf(argv_rdnss, "%s:rdnss=", ifi->ifi_ifname);
66637241896SHiroki Sato action_argv = argv_rdnss;
66737241896SHiroki Sato
66837241896SHiroki Sato error = action_propget(action_argv, &cp);
66937241896SHiroki Sato if (error)
67037241896SHiroki Sato continue;
67137241896SHiroki Sato
67237241896SHiroki Sato len = *((uint16_t *)cp.cp_val);
67337241896SHiroki Sato
67437241896SHiroki Sato if (len > 0) {
67537241896SHiroki Sato printf("\tRDNSS entries:\n");
67637241896SHiroki Sato action_show_rdnss(cp.cp_val);
67737241896SHiroki Sato }
67837241896SHiroki Sato
67937241896SHiroki Sato /* DNSSL information */
68037241896SHiroki Sato sprintf(argv_dnssl, "%s:dnssl=", ifi->ifi_ifname);
68137241896SHiroki Sato action_argv = argv_dnssl;
68237241896SHiroki Sato
68337241896SHiroki Sato error = action_propget(action_argv, &cp);
68437241896SHiroki Sato if (error)
68537241896SHiroki Sato continue;
68637241896SHiroki Sato
68737241896SHiroki Sato len = *((uint16_t *)cp.cp_val);
68837241896SHiroki Sato
68937241896SHiroki Sato if (len > 0) {
69037241896SHiroki Sato printf("\tDNSSL entries:\n");
69137241896SHiroki Sato action_show_dnssl(cp.cp_val);
69237241896SHiroki Sato }
69337241896SHiroki Sato
69437241896SHiroki Sato if (vflag < LOG_NOTICE)
69537241896SHiroki Sato continue;
69637241896SHiroki Sato
69737241896SHiroki Sato printf("\n");
69837241896SHiroki Sato
69937241896SHiroki Sato printf("\tCounters\n"
70037241896SHiroki Sato "\t RA burst counts: %" PRIu16 " (interval: %s)\n"
70137241896SHiroki Sato "\t RS wait counts: %" PRIu16 "\n",
70237241896SHiroki Sato ifi_s->ifi_burstcount,
70337241896SHiroki Sato sec2str(ifi_s->ifi_burstinterval, ssbuf),
70437241896SHiroki Sato ifi_s->ifi_rs_waitcount);
70537241896SHiroki Sato
70637241896SHiroki Sato printf("\tOutputs\n"
70737241896SHiroki Sato "\t RA: %" PRIu64 "\n", ifi_s->ifi_raoutput);
70837241896SHiroki Sato
70937241896SHiroki Sato printf("\tInputs\n"
71037241896SHiroki Sato "\t RA: %" PRIu64 " (normal)\n"
71137241896SHiroki Sato "\t RA: %" PRIu64 " (inconsistent)\n"
71237241896SHiroki Sato "\t RS: %" PRIu64 "\n",
71337241896SHiroki Sato ifi_s->ifi_rainput,
71437241896SHiroki Sato ifi_s->ifi_rainconsistent,
71537241896SHiroki Sato ifi_s->ifi_rsinput);
71637241896SHiroki Sato
71737241896SHiroki Sato printf("\n");
71837241896SHiroki Sato
71937241896SHiroki Sato #if 0 /* Not implemented yet */
72037241896SHiroki Sato printf("\tReceived RAs:\n");
72137241896SHiroki Sato #endif
72237241896SHiroki Sato }
72337241896SHiroki Sato
72437241896SHiroki Sato return (0);
72537241896SHiroki Sato }
72637241896SHiroki Sato
72737241896SHiroki Sato static int
action_show_rtinfo(struct rtinfo * rti)72837241896SHiroki Sato action_show_rtinfo(struct rtinfo *rti)
72937241896SHiroki Sato {
73037241896SHiroki Sato char ntopbuf[INET6_ADDRSTRLEN];
73137241896SHiroki Sato char ssbuf[SSBUFLEN];
73237241896SHiroki Sato
73337241896SHiroki Sato printf("\t %s/%d (pref: %s, ltime: %s)\n",
73437241896SHiroki Sato inet_ntop(AF_INET6, &rti->rti_prefix,
73537241896SHiroki Sato ntopbuf, sizeof(ntopbuf)),
73637241896SHiroki Sato rti->rti_prefixlen,
73737241896SHiroki Sato rtpref_str[0xff & (rti->rti_rtpref >> 3)],
73837241896SHiroki Sato (rti->rti_ltime == ND6_INFINITE_LIFETIME) ?
73937241896SHiroki Sato "infinity" : sec2str(rti->rti_ltime, ssbuf));
74037241896SHiroki Sato
74137241896SHiroki Sato return (0);
74237241896SHiroki Sato }
74337241896SHiroki Sato
74437241896SHiroki Sato static int
action_show_prefix(struct prefix * pfx)74537241896SHiroki Sato action_show_prefix(struct prefix *pfx)
74637241896SHiroki Sato {
74737241896SHiroki Sato char ntopbuf[INET6_ADDRSTRLEN];
74837241896SHiroki Sato char ssbuf[SSBUFLEN];
7497d26db17SHiroki Sato struct timespec now;
75037241896SHiroki Sato
7517d26db17SHiroki Sato clock_gettime(CLOCK_MONOTONIC_FAST, &now);
75237241896SHiroki Sato printf("\t %s/%d", inet_ntop(AF_INET6, &pfx->pfx_prefix,
75337241896SHiroki Sato ntopbuf, sizeof(ntopbuf)), pfx->pfx_prefixlen);
75437241896SHiroki Sato
75537241896SHiroki Sato printf(" (");
75637241896SHiroki Sato switch (pfx->pfx_origin) {
75737241896SHiroki Sato case PREFIX_FROM_KERNEL:
75837241896SHiroki Sato printf("KERNEL");
75937241896SHiroki Sato break;
76037241896SHiroki Sato case PREFIX_FROM_CONFIG:
76137241896SHiroki Sato printf("CONFIG");
76237241896SHiroki Sato break;
76337241896SHiroki Sato case PREFIX_FROM_DYNAMIC:
76437241896SHiroki Sato printf("DYNAMIC");
76537241896SHiroki Sato break;
76637241896SHiroki Sato }
76737241896SHiroki Sato
76837241896SHiroki Sato printf(",");
76937241896SHiroki Sato
77037241896SHiroki Sato printf(" vltime=%s",
77137241896SHiroki Sato (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME) ?
77237241896SHiroki Sato "infinity" : sec2str(pfx->pfx_validlifetime, ssbuf));
77337241896SHiroki Sato
77437241896SHiroki Sato if (pfx->pfx_vltimeexpire > 0)
77537241896SHiroki Sato printf("(expire: %s)",
77637241896SHiroki Sato ((long)pfx->pfx_vltimeexpire > now.tv_sec) ?
77737241896SHiroki Sato sec2str(pfx->pfx_vltimeexpire - now.tv_sec, ssbuf) :
77837241896SHiroki Sato "0");
77937241896SHiroki Sato
78037241896SHiroki Sato printf(",");
78137241896SHiroki Sato
78237241896SHiroki Sato printf(" pltime=%s",
78337241896SHiroki Sato (pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME) ?
78437241896SHiroki Sato "infinity" : sec2str(pfx->pfx_preflifetime, ssbuf));
78537241896SHiroki Sato
78637241896SHiroki Sato if (pfx->pfx_pltimeexpire > 0)
78737241896SHiroki Sato printf("(expire %s)",
78837241896SHiroki Sato ((long)pfx->pfx_pltimeexpire > now.tv_sec) ?
78937241896SHiroki Sato sec2str(pfx->pfx_pltimeexpire - now.tv_sec, ssbuf) :
79037241896SHiroki Sato "0");
79137241896SHiroki Sato
79237241896SHiroki Sato printf(",");
79337241896SHiroki Sato
79437241896SHiroki Sato printf(" flags=");
79537241896SHiroki Sato if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) {
79637241896SHiroki Sato printf("%s", pfx->pfx_onlinkflg ? "L" : "");
79737241896SHiroki Sato printf("%s", pfx->pfx_autoconfflg ? "A" : "");
79837241896SHiroki Sato } else
79937241896SHiroki Sato printf("<none>");
80037241896SHiroki Sato
80137241896SHiroki Sato if (pfx->pfx_timer) {
8027d26db17SHiroki Sato struct timespec *rest;
80337241896SHiroki Sato
80437241896SHiroki Sato rest = rtadvd_timer_rest(pfx->pfx_timer);
80537241896SHiroki Sato if (rest) { /* XXX: what if not? */
80637241896SHiroki Sato printf(" expire=%s", sec2str(rest->tv_sec, ssbuf));
80737241896SHiroki Sato }
80837241896SHiroki Sato }
80937241896SHiroki Sato
81037241896SHiroki Sato printf(")\n");
81137241896SHiroki Sato
81237241896SHiroki Sato return (0);
81337241896SHiroki Sato }
81437241896SHiroki Sato
81537241896SHiroki Sato static int
action_show_rdnss(void * msg)81637241896SHiroki Sato action_show_rdnss(void *msg)
81737241896SHiroki Sato {
81837241896SHiroki Sato struct rdnss *rdn;
81937241896SHiroki Sato struct rdnss_addr *rda;
82037241896SHiroki Sato uint16_t *rdn_cnt;
82137241896SHiroki Sato uint16_t *rda_cnt;
82237241896SHiroki Sato int i;
82337241896SHiroki Sato int j;
82437241896SHiroki Sato char *p;
82537241896SHiroki Sato uint32_t ltime;
82637241896SHiroki Sato char ntopbuf[INET6_ADDRSTRLEN];
82737241896SHiroki Sato char ssbuf[SSBUFLEN];
82837241896SHiroki Sato
82937241896SHiroki Sato p = msg;
83037241896SHiroki Sato rdn_cnt = (uint16_t *)p;
83137241896SHiroki Sato p += sizeof(*rdn_cnt);
83237241896SHiroki Sato
83337241896SHiroki Sato if (*rdn_cnt > 0) {
83437241896SHiroki Sato for (i = 0; i < *rdn_cnt; i++) {
83537241896SHiroki Sato rdn = (struct rdnss *)p;
83637241896SHiroki Sato ltime = rdn->rd_ltime;
83737241896SHiroki Sato p += sizeof(*rdn);
83837241896SHiroki Sato
83937241896SHiroki Sato rda_cnt = (uint16_t *)p;
84037241896SHiroki Sato p += sizeof(*rda_cnt);
84137241896SHiroki Sato if (*rda_cnt > 0)
84237241896SHiroki Sato for (j = 0; j < *rda_cnt; j++) {
84337241896SHiroki Sato rda = (struct rdnss_addr *)p;
84437241896SHiroki Sato printf("\t %s (ltime=%s)\n",
84537241896SHiroki Sato inet_ntop(AF_INET6,
84637241896SHiroki Sato &rda->ra_dns,
84737241896SHiroki Sato ntopbuf,
84837241896SHiroki Sato sizeof(ntopbuf)),
84937241896SHiroki Sato sec2str(ltime, ssbuf));
85037241896SHiroki Sato p += sizeof(*rda);
85137241896SHiroki Sato }
85237241896SHiroki Sato }
85337241896SHiroki Sato }
85437241896SHiroki Sato
85537241896SHiroki Sato return (0);
85637241896SHiroki Sato }
85737241896SHiroki Sato
85837241896SHiroki Sato static int
action_show_dnssl(void * msg)85937241896SHiroki Sato action_show_dnssl(void *msg)
86037241896SHiroki Sato {
86137241896SHiroki Sato struct dnssl *dns;
86237241896SHiroki Sato struct dnssl_addr *dna;
86337241896SHiroki Sato uint16_t *dns_cnt;
86437241896SHiroki Sato uint16_t *dna_cnt;
86537241896SHiroki Sato int i;
86637241896SHiroki Sato int j;
86737241896SHiroki Sato char *p;
86837241896SHiroki Sato uint32_t ltime;
86937241896SHiroki Sato char hbuf[NI_MAXHOST];
87037241896SHiroki Sato char ssbuf[SSBUFLEN];
87137241896SHiroki Sato
87237241896SHiroki Sato p = msg;
87337241896SHiroki Sato dns_cnt = (uint16_t *)p;
87437241896SHiroki Sato p += sizeof(*dns_cnt);
87537241896SHiroki Sato
87637241896SHiroki Sato if (*dns_cnt > 0) {
87737241896SHiroki Sato for (i = 0; i < *dns_cnt; i++) {
87837241896SHiroki Sato dns = (struct dnssl *)p;
87937241896SHiroki Sato ltime = dns->dn_ltime;
88037241896SHiroki Sato p += sizeof(*dns);
88137241896SHiroki Sato
88237241896SHiroki Sato dna_cnt = (uint16_t *)p;
88337241896SHiroki Sato p += sizeof(*dna_cnt);
88437241896SHiroki Sato if (*dna_cnt > 0)
88537241896SHiroki Sato for (j = 0; j < *dna_cnt; j++) {
88637241896SHiroki Sato dna = (struct dnssl_addr *)p;
88737241896SHiroki Sato dname_labeldec(hbuf, sizeof(hbuf),
88837241896SHiroki Sato dna->da_dom);
88937241896SHiroki Sato printf("\t %s (ltime=%s)\n",
89037241896SHiroki Sato hbuf, sec2str(ltime, ssbuf));
89137241896SHiroki Sato p += sizeof(*dna);
89237241896SHiroki Sato }
89337241896SHiroki Sato }
89437241896SHiroki Sato }
89537241896SHiroki Sato
89637241896SHiroki Sato return (0);
89737241896SHiroki Sato }
89837241896SHiroki Sato
89937241896SHiroki Sato /* Decode domain name label encoding in RFC 1035 Section 3.1 */
90037241896SHiroki Sato static size_t
dname_labeldec(char * dst,size_t dlen,const char * src)90137241896SHiroki Sato dname_labeldec(char *dst, size_t dlen, const char *src)
90237241896SHiroki Sato {
90337241896SHiroki Sato size_t len;
90437241896SHiroki Sato const char *src_origin;
90537241896SHiroki Sato const char *src_last;
90637241896SHiroki Sato const char *dst_origin;
90737241896SHiroki Sato
90837241896SHiroki Sato src_origin = src;
90937241896SHiroki Sato src_last = strchr(src, '\0');
91037241896SHiroki Sato dst_origin = dst;
91137241896SHiroki Sato memset(dst, '\0', dlen);
91237241896SHiroki Sato while (src && (len = (uint8_t)(*src++) & 0x3f) &&
91337241896SHiroki Sato (src + len) <= src_last) {
91437241896SHiroki Sato if (dst != dst_origin)
91537241896SHiroki Sato *dst++ = '.';
91637241896SHiroki Sato mysyslog(LOG_DEBUG, "<%s> labellen = %zd", __func__, len);
91737241896SHiroki Sato memcpy(dst, src, len);
91837241896SHiroki Sato src += len;
91937241896SHiroki Sato dst += len;
92037241896SHiroki Sato }
92137241896SHiroki Sato *dst = '\0';
92237241896SHiroki Sato
92337241896SHiroki Sato return (src - src_origin);
92437241896SHiroki Sato }
925