1 /*- 2 * Copyright (C) 2011 Hiroki Sato <hrs@FreeBSD.org> 3 * All rights reserved. 4 * 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. 13 * 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. 25 * 26 * $FreeBSD$ 27 * 28 */ 29 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/if_var.h> 40 #include <net/ethernet.h> 41 #include <netinet/in.h> 42 #include <netinet/ip6.h> 43 #include <netinet/icmp6.h> 44 #include <netinet6/in6_var.h> 45 #include <netinet6/nd6.h> 46 #include <arpa/inet.h> 47 #include <fcntl.h> 48 #include <errno.h> 49 #include <inttypes.h> 50 #include <netdb.h> 51 #include <unistd.h> 52 #include <string.h> 53 #include <stdarg.h> 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <stdarg.h> 57 #include <syslog.h> 58 #include <time.h> 59 #include <err.h> 60 61 #include "pathnames.h" 62 #include "rtadvd.h" 63 #include "if.h" 64 #include "timer_subr.h" 65 #include "timer.h" 66 #include "control.h" 67 #include "control_client.h" 68 69 #define RA_IFSTATUS_INACTIVE 0 70 #define RA_IFSTATUS_RA_RECV 1 71 #define RA_IFSTATUS_RA_SEND 2 72 73 static int vflag = LOG_ERR; 74 75 static void usage(void); 76 77 static int action_propset(char *); 78 static int action_propget(char *, struct ctrl_msg_pl *); 79 static int action_plgeneric(int, char *, char *); 80 81 static int action_enable(int, char **); 82 static int action_disable(int, char **); 83 static int action_reload(int, char **); 84 static int action_echo(int, char **); 85 static int action_version(int, char **); 86 static int action_shutdown(int, char **); 87 88 static int action_show(int, char **); 89 static int action_show_prefix(struct prefix *); 90 static int action_show_rtinfo(struct rtinfo *); 91 static int action_show_rdnss(void *); 92 static int action_show_dnssl(void *); 93 94 static int csock_client_open(struct sockinfo *); 95 static size_t dname_labeldec(char *, size_t, const char *); 96 static void mysyslog(int, const char *, ...); 97 98 static const char *rtpref_str[] = { 99 "medium", /* 00 */ 100 "high", /* 01 */ 101 "rsv", /* 10 */ 102 "low" /* 11 */ 103 }; 104 105 static struct dispatch_table { 106 const char *dt_comm; 107 int (*dt_act)(int, char **); 108 } dtable[] = { 109 { "show", action_show }, 110 { "reload", action_reload }, 111 { "shutdown", action_shutdown }, 112 { "enable", action_enable }, 113 { "disable", action_disable }, 114 { NULL, NULL }, 115 { "echo", action_echo }, 116 { "version", action_version }, 117 { NULL, NULL }, 118 }; 119 120 static char errmsgbuf[1024]; 121 static char *errmsg = NULL; 122 123 static void 124 mysyslog(int priority, const char * restrict fmt, ...) 125 { 126 va_list ap; 127 128 if (vflag >= priority) { 129 va_start(ap, fmt); 130 vfprintf(stderr, fmt, ap); 131 fprintf(stderr, "\n"); 132 va_end(ap); 133 } 134 } 135 136 static void 137 usage(void) 138 { 139 int i; 140 141 for (i = 0; (size_t)i < sizeof(dtable)/sizeof(dtable[0]); i++) { 142 if (dtable[i].dt_comm == NULL) 143 break; 144 printf("%s\n", dtable[i].dt_comm); 145 } 146 147 exit(1); 148 } 149 150 int 151 main(int argc, char *argv[]) 152 { 153 int i; 154 int ch; 155 int (*action)(int, char **) = NULL; 156 int error; 157 158 while ((ch = getopt(argc, argv, "Dv")) != -1) { 159 switch (ch) { 160 case 'D': 161 vflag = LOG_DEBUG; 162 break; 163 case 'v': 164 vflag++; 165 break; 166 default: 167 usage(); 168 } 169 } 170 argc -= optind; 171 argv += optind; 172 173 if (argc == 0) 174 usage(); 175 176 for (i = 0; (size_t)i < sizeof(dtable)/sizeof(dtable[0]); i++) { 177 if (dtable[i].dt_comm == NULL || 178 strcmp(dtable[i].dt_comm, argv[0]) == 0) { 179 action = dtable[i].dt_act; 180 break; 181 } 182 } 183 184 if (action == NULL) 185 usage(); 186 187 error = (dtable[i].dt_act)(--argc, ++argv); 188 if (error) { 189 fprintf(stderr, "%s failed", dtable[i].dt_comm); 190 if (errmsg != NULL) 191 fprintf(stderr, ": %s", errmsg); 192 fprintf(stderr, ".\n"); 193 } 194 195 return (error); 196 } 197 198 static int 199 csock_client_open(struct sockinfo *s) 200 { 201 struct sockaddr_un sun; 202 203 if ((s->si_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) 204 err(1, "cannot open control socket."); 205 206 memset(&sun, 0, sizeof(sun)); 207 sun.sun_family = AF_UNIX; 208 sun.sun_len = sizeof(sun); 209 strlcpy(sun.sun_path, s->si_name, sizeof(sun.sun_path)); 210 211 if (connect(s->si_fd, (struct sockaddr *)&sun, sizeof(sun)) == -1) 212 err(1, "connect: %s", s->si_name); 213 214 mysyslog(LOG_DEBUG, 215 "<%s> connected to %s", __func__, sun.sun_path); 216 217 return (0); 218 } 219 220 static int 221 action_plgeneric(int action, char *plstr, char *buf) 222 { 223 struct ctrl_msg_hdr *cm; 224 struct ctrl_msg_pl cp; 225 struct sockinfo *s; 226 char *msg; 227 char *p; 228 char *q; 229 230 s = &ctrlsock; 231 csock_client_open(s); 232 233 cm = (struct ctrl_msg_hdr *)buf; 234 msg = (char *)buf + sizeof(*cm); 235 236 cm->cm_version = CM_VERSION; 237 cm->cm_type = action; 238 cm->cm_len = sizeof(*cm); 239 240 if (plstr != NULL) { 241 memset(&cp, 0, sizeof(cp)); 242 p = strchr(plstr, ':'); 243 q = strchr(plstr, '='); 244 if (p != NULL && q != NULL && p > q) 245 return (1); 246 247 if (p == NULL) { /* No : */ 248 cp.cp_ifname = NULL; 249 cp.cp_key = plstr; 250 } else if (p == plstr) { /* empty */ 251 cp.cp_ifname = NULL; 252 cp.cp_key = plstr + 1; 253 } else { 254 *p++ = '\0'; 255 cp.cp_ifname = plstr; 256 cp.cp_key = p; 257 } 258 if (q == NULL) 259 cp.cp_val = NULL; 260 else { 261 *q++ = '\0'; 262 cp.cp_val = q; 263 } 264 cm->cm_len += cm_pl2bin(msg, &cp); 265 266 mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s", 267 __func__,cp.cp_key, cp.cp_val_len, cp.cp_ifname); 268 } 269 270 return (cm_handler_client(s->si_fd, CM_STATE_MSG_DISPATCH, buf)); 271 } 272 273 static int 274 action_propget(char *argv, struct ctrl_msg_pl *cp) 275 { 276 int error; 277 struct ctrl_msg_hdr *cm; 278 char buf[CM_MSG_MAXLEN]; 279 char *msg; 280 281 memset(cp, 0, sizeof(*cp)); 282 cm = (struct ctrl_msg_hdr *)buf; 283 msg = (char *)buf + sizeof(*cm); 284 285 error = action_plgeneric(CM_TYPE_REQ_GET_PROP, argv, buf); 286 if (error || cm->cm_len <= sizeof(*cm)) 287 return (1); 288 289 cm_bin2pl(msg, cp); 290 mysyslog(LOG_DEBUG, "<%s> type=%d, len=%d", 291 __func__, cm->cm_type, cm->cm_len); 292 mysyslog(LOG_DEBUG, "<%s> key=%s, val_len=%d, ifname=%s", 293 __func__,cp->cp_key, cp->cp_val_len, cp->cp_ifname); 294 295 return (0); 296 } 297 298 static int 299 action_propset(char *argv) 300 { 301 char buf[CM_MSG_MAXLEN]; 302 303 return (action_plgeneric(CM_TYPE_REQ_SET_PROP, argv, buf)); 304 } 305 306 static int 307 action_disable(int argc, char **argv) 308 { 309 char *action_argv; 310 char argv_disable[IFNAMSIZ + sizeof(":disable=")]; 311 int i; 312 int error; 313 314 if (argc < 1) 315 return (1); 316 317 error = 0; 318 for (i = 0; i < argc; i++) { 319 sprintf(argv_disable, "%s:disable=", argv[i]); 320 action_argv = argv_disable; 321 error += action_propset(action_argv); 322 } 323 324 return (error); 325 } 326 327 static int 328 action_enable(int argc, char **argv) 329 { 330 char *action_argv; 331 char argv_enable[IFNAMSIZ + sizeof(":enable=")]; 332 int i; 333 int error; 334 335 if (argc < 1) 336 return (1); 337 338 error = 0; 339 for (i = 0; i < argc; i++) { 340 sprintf(argv_enable, "%s:enable=", argv[i]); 341 action_argv = argv_enable; 342 error += action_propset(action_argv); 343 } 344 345 return (error); 346 } 347 348 static int 349 action_reload(int argc, char **argv) 350 { 351 char *action_argv; 352 char argv_reload[IFNAMSIZ + sizeof(":reload=")]; 353 int i; 354 int error; 355 356 if (argc == 0) { 357 action_argv = strdup(":reload="); 358 return (action_propset(action_argv)); 359 } 360 361 error = 0; 362 for (i = 0; i < argc; i++) { 363 sprintf(argv_reload, "%s:reload=", argv[i]); 364 action_argv = argv_reload; 365 error += action_propset(action_argv); 366 } 367 368 return (error); 369 } 370 371 static int 372 action_echo(int argc __unused, char **argv __unused) 373 { 374 char *action_argv; 375 376 action_argv = strdup("echo"); 377 return (action_propset(action_argv)); 378 } 379 380 static int 381 action_shutdown(int argc __unused, char **argv __unused) 382 { 383 char *action_argv; 384 385 action_argv = strdup("shutdown"); 386 return (action_propset(action_argv)); 387 } 388 389 /* XXX */ 390 static int 391 action_version(int argc __unused, char **argv __unused) 392 { 393 char *action_argv; 394 struct ctrl_msg_pl cp; 395 int error; 396 397 action_argv = strdup(":version="); 398 error = action_propget(action_argv, &cp); 399 if (error) 400 return (error); 401 402 printf("version=%s\n", cp.cp_val); 403 return (0); 404 } 405 406 static int 407 action_show(int argc, char **argv) 408 { 409 char *action_argv; 410 char argv_ifilist[sizeof(":ifilist=")] = ":ifilist="; 411 char argv_ifi[IFNAMSIZ + sizeof(":ifi=")]; 412 char argv_rai[IFNAMSIZ + sizeof(":rai=")]; 413 char argv_rti[IFNAMSIZ + sizeof(":rti=")]; 414 char argv_pfx[IFNAMSIZ + sizeof(":pfx=")]; 415 char argv_ifi_ra_timer[IFNAMSIZ + sizeof(":ifi_ra_timer=")]; 416 char argv_rdnss[IFNAMSIZ + sizeof(":rdnss=")]; 417 char argv_dnssl[IFNAMSIZ + sizeof(":dnssl=")]; 418 char ssbuf[SSBUFLEN]; 419 420 struct timespec now, ts0, ts; 421 struct ctrl_msg_pl cp; 422 struct ifinfo *ifi; 423 TAILQ_HEAD(, ifinfo) ifl = TAILQ_HEAD_INITIALIZER(ifl); 424 char *endp; 425 char *p; 426 int error; 427 int i; 428 int len; 429 430 if (argc == 0) { 431 action_argv = argv_ifilist; 432 error = action_propget(action_argv, &cp); 433 if (error) 434 return (error); 435 436 p = cp.cp_val; 437 endp = p + cp.cp_val_len; 438 while (p < endp) { 439 ifi = malloc(sizeof(*ifi)); 440 if (ifi == NULL) 441 return (1); 442 memset(ifi, 0, sizeof(*ifi)); 443 444 strcpy(ifi->ifi_ifname, p); 445 ifi->ifi_ifindex = if_nametoindex(ifi->ifi_ifname); 446 TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next); 447 p += strlen(ifi->ifi_ifname) + 1; 448 } 449 } else { 450 for (i = 0; i < argc; i++) { 451 ifi = malloc(sizeof(*ifi)); 452 if (ifi == NULL) 453 return (1); 454 memset(ifi, 0, sizeof(*ifi)); 455 456 strcpy(ifi->ifi_ifname, argv[i]); 457 ifi->ifi_ifindex = if_nametoindex(ifi->ifi_ifname); 458 if (ifi->ifi_ifindex == 0) { 459 sprintf(errmsgbuf, "invalid interface %s", 460 ifi->ifi_ifname); 461 errmsg = errmsgbuf; 462 return (1); 463 } 464 465 TAILQ_INSERT_TAIL(&ifl, ifi, ifi_next); 466 } 467 } 468 469 clock_gettime(CLOCK_REALTIME_FAST, &now); 470 clock_gettime(CLOCK_MONOTONIC_FAST, &ts); 471 TS_SUB(&now, &ts, &ts0); 472 473 TAILQ_FOREACH(ifi, &ifl, ifi_next) { 474 struct ifinfo *ifi_s; 475 struct rtadvd_timer *rat; 476 struct rainfo *rai; 477 struct rtinfo *rti; 478 struct prefix *pfx; 479 int c; 480 int ra_ifstatus; 481 482 sprintf(argv_ifi, "%s:ifi=", ifi->ifi_ifname); 483 action_argv = argv_ifi; 484 error = action_propget(action_argv, &cp); 485 if (error) 486 return (error); 487 ifi_s = (struct ifinfo *)cp.cp_val; 488 489 if (!(ifi_s->ifi_persist) && vflag < LOG_NOTICE) 490 continue; 491 492 printf("%s: flags=<", ifi->ifi_ifname); 493 494 c = 0; 495 if (ifi_s->ifi_ifindex == 0) 496 c += printf("NONEXISTENT"); 497 else 498 c += printf("%s", (ifi_s->ifi_flags & IFF_UP) ? 499 "UP" : "DOWN"); 500 switch (ifi_s->ifi_state) { 501 case IFI_STATE_CONFIGURED: 502 c += printf("%s%s", (c) ? "," : "", "CONFIGURED"); 503 break; 504 case IFI_STATE_TRANSITIVE: 505 c += printf("%s%s", (c) ? "," : "", "TRANSITIVE"); 506 break; 507 } 508 if (ifi_s->ifi_persist) 509 c += printf("%s%s", (c) ? "," : "", "PERSIST"); 510 printf(">"); 511 512 ra_ifstatus = RA_IFSTATUS_INACTIVE; 513 if ((ifi_s->ifi_flags & IFF_UP) && 514 ((ifi_s->ifi_state == IFI_STATE_CONFIGURED) || 515 (ifi_s->ifi_state == IFI_STATE_TRANSITIVE))) { 516 #if (__FreeBSD_version < 900000) 517 /* 518 * RA_RECV: !ip6.forwarding && ip6.accept_rtadv 519 * RA_SEND: ip6.forwarding 520 */ 521 if (getinet6sysctl(IPV6CTL_FORWARDING) == 0) { 522 if (getinet6sysctl(IPV6CTL_ACCEPT_RTADV)) 523 ra_ifstatus = RA_IFSTATUS_RA_RECV; 524 else 525 ra_ifstatus = RA_IFSTATUS_INACTIVE; 526 } else 527 ra_ifstatus = RA_IFSTATUS_RA_SEND; 528 #else 529 /* 530 * RA_RECV: ND6_IFF_ACCEPT_RTADV 531 * RA_SEND: ip6.forwarding 532 */ 533 if (ifi_s->ifi_nd_flags & ND6_IFF_ACCEPT_RTADV) 534 ra_ifstatus = RA_IFSTATUS_RA_RECV; 535 else if (getinet6sysctl(IPV6CTL_FORWARDING)) 536 ra_ifstatus = RA_IFSTATUS_RA_SEND; 537 else 538 ra_ifstatus = RA_IFSTATUS_INACTIVE; 539 #endif 540 } 541 542 c = 0; 543 printf(" status=<"); 544 if (ra_ifstatus == RA_IFSTATUS_INACTIVE) 545 printf("%s%s", (c) ? "," : "", "INACTIVE"); 546 else if (ra_ifstatus == RA_IFSTATUS_RA_RECV) 547 printf("%s%s", (c) ? "," : "", "RA_RECV"); 548 else if (ra_ifstatus == RA_IFSTATUS_RA_SEND) 549 printf("%s%s", (c) ? "," : "", "RA_SEND"); 550 printf("> "); 551 552 switch (ifi_s->ifi_state) { 553 case IFI_STATE_CONFIGURED: 554 case IFI_STATE_TRANSITIVE: 555 break; 556 default: 557 printf("\n"); 558 continue; 559 } 560 561 printf("mtu %d\n", ifi_s->ifi_phymtu); 562 563 sprintf(argv_rai, "%s:rai=", ifi->ifi_ifname); 564 action_argv = argv_rai; 565 566 error = action_propget(action_argv, &cp); 567 if (error) 568 continue; 569 570 rai = (struct rainfo *)cp.cp_val; 571 572 printf("\tDefaultLifetime: %s", 573 sec2str(rai->rai_lifetime, ssbuf)); 574 if (ra_ifstatus != RA_IFSTATUS_RA_SEND && 575 rai->rai_lifetime == 0) 576 printf(" (RAs will be sent with zero lifetime)"); 577 578 printf("\n"); 579 580 printf("\tMinAdvInterval/MaxAdvInterval: "); 581 printf("%s/", sec2str(rai->rai_mininterval, ssbuf)); 582 printf("%s\n", sec2str(rai->rai_maxinterval, ssbuf)); 583 if (rai->rai_linkmtu) 584 printf("\tAdvLinkMTU: %d", rai->rai_linkmtu); 585 else 586 printf("\tAdvLinkMTU: <none>"); 587 588 printf(", "); 589 590 printf("Flags: "); 591 if (rai->rai_managedflg || rai->rai_otherflg) { 592 printf("%s", rai->rai_managedflg ? "M" : ""); 593 printf("%s", rai->rai_otherflg ? "O" : ""); 594 } else 595 printf("<none>"); 596 597 printf(", "); 598 599 printf("Preference: %s\n", 600 rtpref_str[(rai->rai_rtpref >> 3) & 0xff]); 601 602 printf("\tReachableTime: %s, ", 603 sec2str(rai->rai_reachabletime, ssbuf)); 604 printf("RetransTimer: %s, " 605 "CurHopLimit: %d\n", 606 sec2str(rai->rai_retranstimer, ssbuf), 607 rai->rai_hoplimit); 608 printf("\tAdvIfPrefixes: %s\n", 609 rai->rai_advifprefix ? "yes" : "no"); 610 611 /* RA timer */ 612 rat = NULL; 613 if (ifi_s->ifi_ra_timer != NULL) { 614 sprintf(argv_ifi_ra_timer, "%s:ifi_ra_timer=", 615 ifi->ifi_ifname); 616 action_argv = argv_ifi_ra_timer; 617 618 error = action_propget(action_argv, &cp); 619 if (error) 620 return (error); 621 622 rat = (struct rtadvd_timer *)cp.cp_val; 623 } 624 printf("\tNext RA send: "); 625 if (rat == NULL) 626 printf("never\n"); 627 else { 628 ts.tv_sec = rat->rat_tm.tv_sec + ts0.tv_sec; 629 printf("%s", ctime(&ts.tv_sec)); 630 } 631 printf("\tLast RA send: "); 632 if (ifi_s->ifi_ra_lastsent.tv_sec == 0) 633 printf("never\n"); 634 else { 635 ts.tv_sec = ifi_s->ifi_ra_lastsent.tv_sec + ts0.tv_sec; 636 printf("%s", ctime(&ts.tv_sec)); 637 } 638 if (rai->rai_clockskew) 639 printf("\tClock skew: %" PRIu16 "sec\n", 640 rai->rai_clockskew); 641 642 if (vflag < LOG_WARNING) 643 continue; 644 645 /* route information */ 646 sprintf(argv_rti, "%s:rti=", ifi->ifi_ifname); 647 action_argv = argv_rti; 648 error = action_propget(action_argv, &cp); 649 if (error) 650 return (error); 651 652 rti = (struct rtinfo *)cp.cp_val; 653 len = cp.cp_val_len / sizeof(*rti); 654 if (len > 0) { 655 printf("\tRoute Info:\n"); 656 657 for (i = 0; i < len; i++) 658 action_show_rtinfo(&rti[i]); 659 } 660 661 /* prefix information */ 662 sprintf(argv_pfx, "%s:pfx=", ifi->ifi_ifname); 663 action_argv = argv_pfx; 664 665 error = action_propget(action_argv, &cp); 666 if (error) 667 continue; 668 669 pfx = (struct prefix *)cp.cp_val; 670 len = cp.cp_val_len / sizeof(*pfx); 671 672 if (len > 0) { 673 printf("\tPrefixes (%d):\n", len); 674 675 for (i = 0; i < len; i++) 676 action_show_prefix(&pfx[i]); 677 } 678 679 /* RDNSS information */ 680 sprintf(argv_rdnss, "%s:rdnss=", ifi->ifi_ifname); 681 action_argv = argv_rdnss; 682 683 error = action_propget(action_argv, &cp); 684 if (error) 685 continue; 686 687 len = *((uint16_t *)cp.cp_val); 688 689 if (len > 0) { 690 printf("\tRDNSS entries:\n"); 691 action_show_rdnss(cp.cp_val); 692 } 693 694 /* DNSSL information */ 695 sprintf(argv_dnssl, "%s:dnssl=", ifi->ifi_ifname); 696 action_argv = argv_dnssl; 697 698 error = action_propget(action_argv, &cp); 699 if (error) 700 continue; 701 702 len = *((uint16_t *)cp.cp_val); 703 704 if (len > 0) { 705 printf("\tDNSSL entries:\n"); 706 action_show_dnssl(cp.cp_val); 707 } 708 709 if (vflag < LOG_NOTICE) 710 continue; 711 712 printf("\n"); 713 714 printf("\tCounters\n" 715 "\t RA burst counts: %" PRIu16 " (interval: %s)\n" 716 "\t RS wait counts: %" PRIu16 "\n", 717 ifi_s->ifi_burstcount, 718 sec2str(ifi_s->ifi_burstinterval, ssbuf), 719 ifi_s->ifi_rs_waitcount); 720 721 printf("\tOutputs\n" 722 "\t RA: %" PRIu64 "\n", ifi_s->ifi_raoutput); 723 724 printf("\tInputs\n" 725 "\t RA: %" PRIu64 " (normal)\n" 726 "\t RA: %" PRIu64 " (inconsistent)\n" 727 "\t RS: %" PRIu64 "\n", 728 ifi_s->ifi_rainput, 729 ifi_s->ifi_rainconsistent, 730 ifi_s->ifi_rsinput); 731 732 printf("\n"); 733 734 #if 0 /* Not implemented yet */ 735 printf("\tReceived RAs:\n"); 736 #endif 737 } 738 739 return (0); 740 } 741 742 static int 743 action_show_rtinfo(struct rtinfo *rti) 744 { 745 char ntopbuf[INET6_ADDRSTRLEN]; 746 char ssbuf[SSBUFLEN]; 747 748 printf("\t %s/%d (pref: %s, ltime: %s)\n", 749 inet_ntop(AF_INET6, &rti->rti_prefix, 750 ntopbuf, sizeof(ntopbuf)), 751 rti->rti_prefixlen, 752 rtpref_str[0xff & (rti->rti_rtpref >> 3)], 753 (rti->rti_ltime == ND6_INFINITE_LIFETIME) ? 754 "infinity" : sec2str(rti->rti_ltime, ssbuf)); 755 756 return (0); 757 } 758 759 static int 760 action_show_prefix(struct prefix *pfx) 761 { 762 char ntopbuf[INET6_ADDRSTRLEN]; 763 char ssbuf[SSBUFLEN]; 764 struct timespec now; 765 766 clock_gettime(CLOCK_MONOTONIC_FAST, &now); 767 printf("\t %s/%d", inet_ntop(AF_INET6, &pfx->pfx_prefix, 768 ntopbuf, sizeof(ntopbuf)), pfx->pfx_prefixlen); 769 770 printf(" ("); 771 switch (pfx->pfx_origin) { 772 case PREFIX_FROM_KERNEL: 773 printf("KERNEL"); 774 break; 775 case PREFIX_FROM_CONFIG: 776 printf("CONFIG"); 777 break; 778 case PREFIX_FROM_DYNAMIC: 779 printf("DYNAMIC"); 780 break; 781 } 782 783 printf(","); 784 785 printf(" vltime=%s", 786 (pfx->pfx_validlifetime == ND6_INFINITE_LIFETIME) ? 787 "infinity" : sec2str(pfx->pfx_validlifetime, ssbuf)); 788 789 if (pfx->pfx_vltimeexpire > 0) 790 printf("(expire: %s)", 791 ((long)pfx->pfx_vltimeexpire > now.tv_sec) ? 792 sec2str(pfx->pfx_vltimeexpire - now.tv_sec, ssbuf) : 793 "0"); 794 795 printf(","); 796 797 printf(" pltime=%s", 798 (pfx->pfx_preflifetime == ND6_INFINITE_LIFETIME) ? 799 "infinity" : sec2str(pfx->pfx_preflifetime, ssbuf)); 800 801 if (pfx->pfx_pltimeexpire > 0) 802 printf("(expire %s)", 803 ((long)pfx->pfx_pltimeexpire > now.tv_sec) ? 804 sec2str(pfx->pfx_pltimeexpire - now.tv_sec, ssbuf) : 805 "0"); 806 807 printf(","); 808 809 printf(" flags="); 810 if (pfx->pfx_onlinkflg || pfx->pfx_autoconfflg) { 811 printf("%s", pfx->pfx_onlinkflg ? "L" : ""); 812 printf("%s", pfx->pfx_autoconfflg ? "A" : ""); 813 } else 814 printf("<none>"); 815 816 if (pfx->pfx_timer) { 817 struct timespec *rest; 818 819 rest = rtadvd_timer_rest(pfx->pfx_timer); 820 if (rest) { /* XXX: what if not? */ 821 printf(" expire=%s", sec2str(rest->tv_sec, ssbuf)); 822 } 823 } 824 825 printf(")\n"); 826 827 return (0); 828 } 829 830 static int 831 action_show_rdnss(void *msg) 832 { 833 struct rdnss *rdn; 834 struct rdnss_addr *rda; 835 uint16_t *rdn_cnt; 836 uint16_t *rda_cnt; 837 int i; 838 int j; 839 char *p; 840 uint32_t ltime; 841 char ntopbuf[INET6_ADDRSTRLEN]; 842 char ssbuf[SSBUFLEN]; 843 844 p = msg; 845 rdn_cnt = (uint16_t *)p; 846 p += sizeof(*rdn_cnt); 847 848 if (*rdn_cnt > 0) { 849 for (i = 0; i < *rdn_cnt; i++) { 850 rdn = (struct rdnss *)p; 851 ltime = rdn->rd_ltime; 852 p += sizeof(*rdn); 853 854 rda_cnt = (uint16_t *)p; 855 p += sizeof(*rda_cnt); 856 if (*rda_cnt > 0) 857 for (j = 0; j < *rda_cnt; j++) { 858 rda = (struct rdnss_addr *)p; 859 printf("\t %s (ltime=%s)\n", 860 inet_ntop(AF_INET6, 861 &rda->ra_dns, 862 ntopbuf, 863 sizeof(ntopbuf)), 864 sec2str(ltime, ssbuf)); 865 p += sizeof(*rda); 866 } 867 } 868 } 869 870 return (0); 871 } 872 873 static int 874 action_show_dnssl(void *msg) 875 { 876 struct dnssl *dns; 877 struct dnssl_addr *dna; 878 uint16_t *dns_cnt; 879 uint16_t *dna_cnt; 880 int i; 881 int j; 882 char *p; 883 uint32_t ltime; 884 char hbuf[NI_MAXHOST]; 885 char ssbuf[SSBUFLEN]; 886 887 p = msg; 888 dns_cnt = (uint16_t *)p; 889 p += sizeof(*dns_cnt); 890 891 if (*dns_cnt > 0) { 892 for (i = 0; i < *dns_cnt; i++) { 893 dns = (struct dnssl *)p; 894 ltime = dns->dn_ltime; 895 p += sizeof(*dns); 896 897 dna_cnt = (uint16_t *)p; 898 p += sizeof(*dna_cnt); 899 if (*dna_cnt > 0) 900 for (j = 0; j < *dna_cnt; j++) { 901 dna = (struct dnssl_addr *)p; 902 dname_labeldec(hbuf, sizeof(hbuf), 903 dna->da_dom); 904 printf("\t %s (ltime=%s)\n", 905 hbuf, sec2str(ltime, ssbuf)); 906 p += sizeof(*dna); 907 } 908 } 909 } 910 911 return (0); 912 } 913 914 /* Decode domain name label encoding in RFC 1035 Section 3.1 */ 915 static size_t 916 dname_labeldec(char *dst, size_t dlen, const char *src) 917 { 918 size_t len; 919 const char *src_origin; 920 const char *src_last; 921 const char *dst_origin; 922 923 src_origin = src; 924 src_last = strchr(src, '\0'); 925 dst_origin = dst; 926 memset(dst, '\0', dlen); 927 while (src && (len = (uint8_t)(*src++) & 0x3f) && 928 (src + len) <= src_last) { 929 if (dst != dst_origin) 930 *dst++ = '.'; 931 mysyslog(LOG_DEBUG, "<%s> labellen = %zd", __func__, len); 932 memcpy(dst, src, len); 933 src += len; 934 dst += len; 935 } 936 *dst = '\0'; 937 938 return (src - src_origin); 939 } 940