1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 * $FreeBSD$ 29 * 30 */ 31 32 #include <sys/queue.h> 33 #include <sys/types.h> 34 #include <sys/socket.h> 35 #include <sys/stat.h> 36 #include <sys/un.h> 37 #include <sys/uio.h> 38 #include <net/if.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> 48 #include <fcntl.h> 49 #include <errno.h> 50 #include <inttypes.h> 51 #include <netdb.h> 52 #include <unistd.h> 53 #include <string.h> 54 #include <stdarg.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <stdarg.h> 58 #include <syslog.h> 59 #include <time.h> 60 #include <err.h> 61 62 #include "pathnames.h" 63 #include "rtadvd.h" 64 #include "if.h" 65 #include "timer_subr.h" 66 #include "timer.h" 67 #include "control.h" 68 #include "control_client.h" 69 70 #define RA_IFSTATUS_INACTIVE 0 71 #define RA_IFSTATUS_RA_RECV 1 72 #define RA_IFSTATUS_RA_SEND 2 73 74 static int vflag = LOG_ERR; 75 76 static void usage(void); 77 78 static int action_propset(char *); 79 static int action_propget(char *, struct ctrl_msg_pl *); 80 static int action_plgeneric(int, char *, char *); 81 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 **); 88 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 *); 94 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 *, ...); 98 99 static const char *rtpref_str[] = { 100 "medium", /* 00 */ 101 "high", /* 01 */ 102 "rsv", /* 10 */ 103 "low" /* 11 */ 104 }; 105 106 static struct dispatch_table { 107 const char *dt_comm; 108 int (*dt_act)(int, char **); 109 } dtable[] = { 110 { "show", action_show }, 111 { "reload", action_reload }, 112 { "shutdown", action_shutdown }, 113 { "enable", action_enable }, 114 { "disable", action_disable }, 115 { NULL, NULL }, 116 { "echo", action_echo }, 117 { "version", action_version }, 118 { NULL, NULL }, 119 }; 120 121 static char errmsgbuf[1024]; 122 static char *errmsg = NULL; 123 124 static void 125 mysyslog(int priority, const char * restrict fmt, ...) 126 { 127 va_list ap; 128 129 if (vflag >= priority) { 130 va_start(ap, fmt); 131 vfprintf(stderr, fmt, ap); 132 fprintf(stderr, "\n"); 133 va_end(ap); 134 } 135 } 136 137 static void 138 usage(void) 139 { 140 int i; 141 142 for (i = 0; (size_t)i < sizeof(dtable)/sizeof(dtable[0]); i++) { 143 if (dtable[i].dt_comm == NULL) 144 break; 145 printf("%s\n", dtable[i].dt_comm); 146 } 147 148 exit(1); 149 } 150 151 int 152 main(int argc, char *argv[]) 153 { 154 int i; 155 int ch; 156 int (*action)(int, char **) = NULL; 157 int error; 158 159 while ((ch = getopt(argc, argv, "Dv")) != -1) { 160 switch (ch) { 161 case 'D': 162 vflag = LOG_DEBUG; 163 break; 164 case 'v': 165 vflag++; 166 break; 167 default: 168 usage(); 169 } 170 } 171 argc -= optind; 172 argv += optind; 173 174 if (argc == 0) 175 usage(); 176 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; 181 break; 182 } 183 } 184 185 if (action == NULL) 186 usage(); 187 188 error = (dtable[i].dt_act)(--argc, ++argv); 189 if (error) { 190 fprintf(stderr, "%s failed", dtable[i].dt_comm); 191 if (errmsg != NULL) 192 fprintf(stderr, ": %s", errmsg); 193 fprintf(stderr, ".\n"); 194 } 195 196 return (error); 197 } 198 199 static int 200 csock_client_open(struct sockinfo *s) 201 { 202 struct sockaddr_un sun; 203 204 if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 205 err(1, "cannot open control socket."); 206 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)); 211 212 if (connect(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) 213 err(1, "connect: %s", s->si_name); 214 215 mysyslog(LOG_DEBUG, 216 "<%s> connected to %s", __func__, sun.sun_path); 217 218 return (0); 219 } 220 221 static int 222 action_plgeneric(int action, char *plstr, char *buf) 223 { 224 struct ctrl_msg_hdr *cm; 225 struct ctrl_msg_pl cp; 226 struct sockinfo *s; 227 char *msg; 228 char *p; 229 char *q; 230 231 s = &ctrlsock; 232 csock_client_open(s); 233 234 cm = (struct ctrl_msg_hdr *)buf; 235 msg = (char *)buf + sizeof(*cm); 236 237 cm->cm_version = CM_VERSION; 238 cm->cm_type = action; 239 cm->cm_len = sizeof(*cm); 240 241 if (plstr != NULL) { 242 memset(&cp, 0, sizeof(cp)); 243 p = strchr(plstr, ':'); 244 q = strchr(plstr, '='); 245 if (p != NULL && q != NULL && p > q) 246 return (1); 247 248 if (p == NULL) { /* No : */ 249 cp.cp_ifname = NULL; 250 cp.cp_key = plstr; 251 } else if (p == plstr) { /* empty */ 252 cp.cp_ifname = NULL; 253 cp.cp_key = plstr + 1; 254 } else { 255 *p++ = '\0'; 256 cp.cp_ifname = plstr; 257 cp.cp_key = p; 258 } 259 if (q == NULL) 260 cp.cp_val = NULL; 261 else { 262 *q++ = '\0'; 263 cp.cp_val = q; 264 } 265 cm->cm_len += cm_pl2bin(msg, &cp); 266 267 mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s", 268 __func__,cp.cp_key, cp.cp_val_len, cp.cp_ifname); 269 } 270 271 return (cm_handler_client(s->si_fd, CM_STATE_MSG_DISPATCH, buf)); 272 } 273 274 static int 275 action_propget(char *argv, struct ctrl_msg_pl *cp) 276 { 277 int error; 278 struct ctrl_msg_hdr *cm; 279 char buf[CM_MSG_MAXLEN]; 280 char *msg; 281 282 memset(cp, 0, sizeof(*cp)); 283 cm = (struct ctrl_msg_hdr *)buf; 284 msg = (char *)buf + sizeof(*cm); 285 286 error = action_plgeneric(CM_TYPE_REQ_GET_PROP, argv, buf); 287 if (error || cm->cm_len <= sizeof(*cm)) 288 return (1); 289 290 cm_bin2pl(msg, cp); 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); 295 296 return (0); 297 } 298 299 static int 300 action_propset(char *argv) 301 { 302 char buf[CM_MSG_MAXLEN]; 303 304 return (action_plgeneric(CM_TYPE_REQ_SET_PROP, argv, buf)); 305 } 306 307 static int 308 action_disable(int argc, char **argv) 309 { 310 char *action_argv; 311 char argv_disable[IFNAMSIZ + sizeof(":disable=")]; 312 int i; 313 int error; 314 315 if (argc < 1) 316 return (1); 317 318 error = 0; 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); 323 } 324 325 return (error); 326 } 327 328 static int 329 action_enable(int argc, char **argv) 330 { 331 char *action_argv; 332 char argv_enable[IFNAMSIZ + sizeof(":enable=")]; 333 int i; 334 int error; 335 336 if (argc < 1) 337 return (1); 338 339 error = 0; 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); 344 } 345 346 return (error); 347 } 348 349 static int 350 action_reload(int argc, char **argv) 351 { 352 char *action_argv; 353 char argv_reload[IFNAMSIZ + sizeof(":reload=")]; 354 int i; 355 int error; 356 357 if (argc == 0) { 358 action_argv = strdup(":reload="); 359 return (action_propset(action_argv)); 360 } 361 362 error = 0; 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); 367 } 368 369 return (error); 370 } 371 372 static int 373 action_echo(int argc __unused, char **argv __unused) 374 { 375 char *action_argv; 376 377 action_argv = strdup("echo"); 378 return (action_propset(action_argv)); 379 } 380 381 static int 382 action_shutdown(int argc __unused, char **argv __unused) 383 { 384 char *action_argv; 385 386 action_argv = strdup("shutdown"); 387 return (action_propset(action_argv)); 388 } 389 390 /* XXX */ 391 static int 392 action_version(int argc __unused, char **argv __unused) 393 { 394 char *action_argv; 395 struct ctrl_msg_pl cp; 396 int error; 397 398 action_argv = strdup(":version="); 399 error = action_propget(action_argv, &cp); 400 if (error) 401 return (error); 402 403 printf("version=%s\n", cp.cp_val); 404 return (0); 405 } 406 407 static int 408 action_show(int argc, char **argv) 409 { 410 char *action_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]; 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 #if (__FreeBSD_version < 900000) 518 /* 519 * RA_RECV: !ip6.forwarding && ip6.accept_rtadv 520 * RA_SEND: ip6.forwarding 521 */ 522 if (getinet6sysctl(IPV6CTL_FORWARDING) == 0) { 523 if (getinet6sysctl(IPV6CTL_ACCEPT_RTADV)) 524 ra_ifstatus = RA_IFSTATUS_RA_RECV; 525 else 526 ra_ifstatus = RA_IFSTATUS_INACTIVE; 527 } else 528 ra_ifstatus = RA_IFSTATUS_RA_SEND; 529 #else 530 /* 531 * RA_RECV: ND6_IFF_ACCEPT_RTADV 532 * RA_SEND: ip6.forwarding 533 */ 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; 538 else 539 ra_ifstatus = RA_IFSTATUS_INACTIVE; 540 #endif 541 } 542 543 c = 0; 544 printf(" status=<"); 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"); 551 printf("> "); 552 553 switch (ifi_s->ifi_state) { 554 case IFI_STATE_CONFIGURED: 555 case IFI_STATE_TRANSITIVE: 556 break; 557 default: 558 printf("\n"); 559 continue; 560 } 561 562 printf("mtu %d\n", ifi_s->ifi_phymtu); 563 564 sprintf(argv_rai, "%s:rai=", ifi->ifi_ifname); 565 action_argv = argv_rai; 566 567 error = action_propget(action_argv, &cp); 568 if (error) 569 continue; 570 571 rai = (struct rainfo *)cp.cp_val; 572 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)"); 578 579 printf("\n"); 580 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); 586 else 587 printf("\tAdvLinkMTU: <none>"); 588 589 printf(", "); 590 591 printf("Flags: "); 592 if (rai->rai_managedflg || rai->rai_otherflg) { 593 printf("%s", rai->rai_managedflg ? "M" : ""); 594 printf("%s", rai->rai_otherflg ? "O" : ""); 595 } else 596 printf("<none>"); 597 598 printf(", "); 599 600 printf("Preference: %s\n", 601 rtpref_str[(rai->rai_rtpref >> 3) & 0xff]); 602 603 printf("\tReachableTime: %s, ", 604 sec2str(rai->rai_reachabletime, ssbuf)); 605 printf("RetransTimer: %s, " 606 "CurHopLimit: %d\n", 607 sec2str(rai->rai_retranstimer, ssbuf), 608 rai->rai_hoplimit); 609 printf("\tAdvIfPrefixes: %s\n", 610 rai->rai_advifprefix ? "yes" : "no"); 611 612 /* RA timer */ 613 rat = NULL; 614 if (ifi_s->ifi_ra_timer != NULL) { 615 sprintf(argv_ifi_ra_timer, "%s:ifi_ra_timer=", 616 ifi->ifi_ifname); 617 action_argv = argv_ifi_ra_timer; 618 619 error = action_propget(action_argv, &cp); 620 if (error) 621 return (error); 622 623 rat = (struct rtadvd_timer *)cp.cp_val; 624 } 625 printf("\tNext RA send: "); 626 if (rat == NULL) 627 printf("never\n"); 628 else { 629 ts.tv_sec = rat->rat_tm.tv_sec + ts0.tv_sec; 630 printf("%s", ctime(&ts.tv_sec)); 631 } 632 printf("\tLast RA send: "); 633 if (ifi_s->ifi_ra_lastsent.tv_sec == 0) 634 printf("never\n"); 635 else { 636 ts.tv_sec = ifi_s->ifi_ra_lastsent.tv_sec + ts0.tv_sec; 637 printf("%s", ctime(&ts.tv_sec)); 638 } 639 if (rai->rai_clockskew) 640 printf("\tClock skew: %" PRIu16 "sec\n", 641 rai->rai_clockskew); 642 643 if (vflag < LOG_WARNING) 644 continue; 645 646 /* route information */ 647 sprintf(argv_rti, "%s:rti=", ifi->ifi_ifname); 648 action_argv = argv_rti; 649 error = action_propget(action_argv, &cp); 650 if (error) 651 return (error); 652 653 rti = (struct rtinfo *)cp.cp_val; 654 len = cp.cp_val_len / sizeof(*rti); 655 if (len > 0) { 656 printf("\tRoute Info:\n"); 657 658 for (i = 0; i < len; i++) 659 action_show_rtinfo(&rti[i]); 660 } 661 662 /* prefix information */ 663 sprintf(argv_pfx, "%s:pfx=", ifi->ifi_ifname); 664 action_argv = argv_pfx; 665 666 error = action_propget(action_argv, &cp); 667 if (error) 668 continue; 669 670 pfx = (struct prefix *)cp.cp_val; 671 len = cp.cp_val_len / sizeof(*pfx); 672 673 if (len > 0) { 674 printf("\tPrefixes (%d):\n", len); 675 676 for (i = 0; i < len; i++) 677 action_show_prefix(&pfx[i]); 678 } 679 680 /* RDNSS information */ 681 sprintf(argv_rdnss, "%s:rdnss=", ifi->ifi_ifname); 682 action_argv = argv_rdnss; 683 684 error = action_propget(action_argv, &cp); 685 if (error) 686 continue; 687 688 len = *((uint16_t *)cp.cp_val); 689 690 if (len > 0) { 691 printf("\tRDNSS entries:\n"); 692 action_show_rdnss(cp.cp_val); 693 } 694 695 /* DNSSL information */ 696 sprintf(argv_dnssl, "%s:dnssl=", ifi->ifi_ifname); 697 action_argv = argv_dnssl; 698 699 error = action_propget(action_argv, &cp); 700 if (error) 701 continue; 702 703 len = *((uint16_t *)cp.cp_val); 704 705 if (len > 0) { 706 printf("\tDNSSL entries:\n"); 707 action_show_dnssl(cp.cp_val); 708 } 709 710 if (vflag < LOG_NOTICE) 711 continue; 712 713 printf("\n"); 714 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); 721 722 printf("\tOutputs\n" 723 "\t RA: %" PRIu64 "\n", ifi_s->ifi_raoutput); 724 725 printf("\tInputs\n" 726 "\t RA: %" PRIu64 " (normal)\n" 727 "\t RA: %" PRIu64 " (inconsistent)\n" 728 "\t RS: %" PRIu64 "\n", 729 ifi_s->ifi_rainput, 730 ifi_s->ifi_rainconsistent, 731 ifi_s->ifi_rsinput); 732 733 printf("\n"); 734 735 #if 0 /* Not implemented yet */ 736 printf("\tReceived RAs:\n"); 737 #endif 738 } 739 740 return (0); 741 } 742 743 static int 744 action_show_rtinfo(struct rtinfo *rti) 745 { 746 char ntopbuf[INET6_ADDRSTRLEN]; 747 char ssbuf[SSBUFLEN]; 748 749 printf("\t %s/%d (pref: %s, ltime: %s)\n", 750 inet_ntop(AF_INET6, &rti->rti_prefix, 751 ntopbuf, sizeof(ntopbuf)), 752 rti->rti_prefixlen, 753 rtpref_str[0xff & (rti->rti_rtpref >> 3)], 754 (rti->rti_ltime == ND6_INFINITE_LIFETIME) ? 755 "infinity" : sec2str(rti->rti_ltime, ssbuf)); 756 757 return (0); 758 } 759 760 static int 761 action_show_prefix(struct prefix *pfx) 762 { 763 char ntopbuf[INET6_ADDRSTRLEN]; 764 char ssbuf[SSBUFLEN]; 765 struct timespec now; 766 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); 770 771 printf(" ("); 772 switch (pfx->pfx_origin) { 773 case PREFIX_FROM_KERNEL: 774 printf("KERNEL"); 775 break; 776 case PREFIX_FROM_CONFIG: 777 printf("CONFIG"); 778 break; 779 case PREFIX_FROM_DYNAMIC: 780 printf("DYNAMIC"); 781 break; 782 } 783 784 printf(","); 785 786 printf(" vltime=%s", 787 (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME) ? 788 "infinity" : sec2str(pfx->pfx_validlifetime, ssbuf)); 789 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) : 794 "0"); 795 796 printf(","); 797 798 printf(" pltime=%s", 799 (pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME) ? 800 "infinity" : sec2str(pfx->pfx_preflifetime, ssbuf)); 801 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) : 806 "0"); 807 808 printf(","); 809 810 printf(" flags="); 811 if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) { 812 printf("%s", pfx->pfx_onlinkflg ? "L" : ""); 813 printf("%s", pfx->pfx_autoconfflg ? "A" : ""); 814 } else 815 printf("<none>"); 816 817 if (pfx->pfx_timer) { 818 struct timespec *rest; 819 820 rest = rtadvd_timer_rest(pfx->pfx_timer); 821 if (rest) { /* XXX: what if not? */ 822 printf(" expire=%s", sec2str(rest->tv_sec, ssbuf)); 823 } 824 } 825 826 printf(")\n"); 827 828 return (0); 829 } 830 831 static int 832 action_show_rdnss(void *msg) 833 { 834 struct rdnss *rdn; 835 struct rdnss_addr *rda; 836 uint16_t *rdn_cnt; 837 uint16_t *rda_cnt; 838 int i; 839 int j; 840 char *p; 841 uint32_t ltime; 842 char ntopbuf[INET6_ADDRSTRLEN]; 843 char ssbuf[SSBUFLEN]; 844 845 p = msg; 846 rdn_cnt = (uint16_t *)p; 847 p += sizeof(*rdn_cnt); 848 849 if (*rdn_cnt > 0) { 850 for (i = 0; i < *rdn_cnt; i++) { 851 rdn = (struct rdnss *)p; 852 ltime = rdn->rd_ltime; 853 p += sizeof(*rdn); 854 855 rda_cnt = (uint16_t *)p; 856 p += sizeof(*rda_cnt); 857 if (*rda_cnt > 0) 858 for (j = 0; j < *rda_cnt; j++) { 859 rda = (struct rdnss_addr *)p; 860 printf("\t %s (ltime=%s)\n", 861 inet_ntop(AF_INET6, 862 &rda->ra_dns, 863 ntopbuf, 864 sizeof(ntopbuf)), 865 sec2str(ltime, ssbuf)); 866 p += sizeof(*rda); 867 } 868 } 869 } 870 871 return (0); 872 } 873 874 static int 875 action_show_dnssl(void *msg) 876 { 877 struct dnssl *dns; 878 struct dnssl_addr *dna; 879 uint16_t *dns_cnt; 880 uint16_t *dna_cnt; 881 int i; 882 int j; 883 char *p; 884 uint32_t ltime; 885 char hbuf[NI_MAXHOST]; 886 char ssbuf[SSBUFLEN]; 887 888 p = msg; 889 dns_cnt = (uint16_t *)p; 890 p += sizeof(*dns_cnt); 891 892 if (*dns_cnt > 0) { 893 for (i = 0; i < *dns_cnt; i++) { 894 dns = (struct dnssl *)p; 895 ltime = dns->dn_ltime; 896 p += sizeof(*dns); 897 898 dna_cnt = (uint16_t *)p; 899 p += sizeof(*dna_cnt); 900 if (*dna_cnt > 0) 901 for (j = 0; j < *dna_cnt; j++) { 902 dna = (struct dnssl_addr *)p; 903 dname_labeldec(hbuf, sizeof(hbuf), 904 dna->da_dom); 905 printf("\t %s (ltime=%s)\n", 906 hbuf, sec2str(ltime, ssbuf)); 907 p += sizeof(*dna); 908 } 909 } 910 } 911 912 return (0); 913 } 914 915 /* Decode domain name label encoding in RFC 1035 Section 3.1 */ 916 static size_t 917 dname_labeldec(char *dst, size_t dlen, const char *src) 918 { 919 size_t len; 920 const char *src_origin; 921 const char *src_last; 922 const char *dst_origin; 923 924 src_origin = src; 925 src_last = strchr(src, '\0'); 926 dst_origin = dst; 927 memset(dst, '\0', dlen); 928 while (src && (len = (uint8_t)(*src++) & 0x3f) && 929 (src + len) <= src_last) { 930 if (dst != dst_origin) 931 *dst++ = '.'; 932 mysyslog(LOG_DEBUG, "<%s> labellen = %zd", __func__, len); 933 memcpy(dst, src, len); 934 src += len; 935 dst += len; 936 } 937 *dst = '\0'; 938 939 return (src - src_origin); 940 } 941