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