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