1 /* $NetBSD: ndp.c,v 1.55 2018/12/16 08:47:43 roy Exp $ */ 2 /* $KAME: ndp.c,v 1.121 2005/07/13 11:30:13 keiichi Exp $ */ 3 4 /* 5 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 /* 33 * Copyright (c) 1984, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * This code is derived from software contributed to Berkeley by 37 * Sun Microsystems, Inc. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 3. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 */ 63 64 /* 65 * Based on: 66 * "@(#) Copyright (c) 1984, 1993\n\ 67 * The Regents of the University of California. All rights reserved.\n"; 68 * 69 * "@(#)arp.c 8.2 (Berkeley) 1/2/94"; 70 */ 71 72 /* 73 * ndp - display, set, delete and flush neighbor cache 74 */ 75 76 77 #include <sys/param.h> 78 #include <sys/file.h> 79 #include <sys/ioctl.h> 80 #include <sys/socket.h> 81 #include <sys/sysctl.h> 82 #include <sys/time.h> 83 84 #include <net/if.h> 85 #include <net/if_dl.h> 86 #include <net/if_types.h> 87 #include <net/route.h> 88 89 #include <netinet/in.h> 90 91 #include <netinet/icmp6.h> 92 #include <netinet6/in6_var.h> 93 #include <netinet6/nd6.h> 94 95 #include <arpa/inet.h> 96 97 #include <netdb.h> 98 #include <errno.h> 99 #include <nlist.h> 100 #include <stdio.h> 101 #include <string.h> 102 #include <paths.h> 103 #include <err.h> 104 #include <stdlib.h> 105 #include <fcntl.h> 106 #include <unistd.h> 107 108 #include "gmt2local.h" 109 #include "prog_ops.h" 110 111 static pid_t pid; 112 static int nflag; 113 static int tflag; 114 static int32_t thiszone; /* time difference with gmt */ 115 static int my_s = -1; 116 static unsigned int repeat = 0; 117 118 119 static char host_buf[NI_MAXHOST]; /* getnameinfo() */ 120 static char ifix_buf[IFNAMSIZ]; /* if_indextoname() */ 121 122 static void getsocket(void); 123 static int set(int, char **); 124 static void get(char *); 125 static int delete(struct rt_msghdr *, char *); 126 static void delete_one(char *); 127 static void do_foreach(struct in6_addr *, char *, int); 128 static struct in6_nbrinfo *getnbrinfo(struct in6_addr *, unsigned int, int); 129 static char *ether_str(struct sockaddr_dl *); 130 static int ndp_ether_aton(char *, u_char *); 131 __dead static void usage(void); 132 static int rtmsg(int, struct rt_msghdr *); 133 static void ifinfo(char *, int, char **); 134 static void rtrlist(void); 135 static void plist(void); 136 static void pfx_flush(void); 137 static void rtr_flush(void); 138 static void harmonize_rtr(void); 139 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 140 static void getdefif(void); 141 static void setdefif(char *); 142 #endif 143 static const char *sec2str(time_t); 144 static char *ether_str(struct sockaddr_dl *); 145 static void ts_print(const struct timeval *); 146 147 #define NDP_F_CLEAR 1 148 #define NDP_F_DELETE 2 149 150 #ifdef ICMPV6CTL_ND6_DRLIST 151 static const char *rtpref_str[] = { 152 "medium", /* 00 */ 153 "high", /* 01 */ 154 "rsv", /* 10 */ 155 "low" /* 11 */ 156 }; 157 #endif 158 159 static int mode = 0; 160 static char *arg = NULL; 161 162 int 163 main(int argc, char **argv) 164 { 165 int ch; 166 167 while ((ch = getopt(argc, argv, "acd:f:Ii:nprstA:HPR")) != -1) 168 switch (ch) { 169 case 'a': 170 case 'c': 171 case 'p': 172 case 'r': 173 case 'H': 174 case 'P': 175 case 'R': 176 case 's': 177 case 'I': 178 if (mode) { 179 usage(); 180 /*NOTREACHED*/ 181 } 182 mode = ch; 183 arg = NULL; 184 break; 185 case 'd': 186 case 'f': 187 case 'i' : 188 if (mode) { 189 usage(); 190 /*NOTREACHED*/ 191 } 192 mode = ch; 193 arg = optarg; 194 break; 195 case 'n': 196 nflag = 1; 197 break; 198 case 't': 199 tflag = 1; 200 break; 201 case 'A': 202 if (mode) { 203 usage(); 204 /*NOTREACHED*/ 205 } 206 mode = 'a'; 207 repeat = atoi(optarg); 208 break; 209 default: 210 usage(); 211 } 212 213 argc -= optind; 214 argv += optind; 215 216 if (prog_init && prog_init() == -1) 217 err(1, "init failed"); 218 219 pid = prog_getpid(); 220 thiszone = gmt2local(0L); 221 222 switch (mode) { 223 case 'a': 224 case 'c': 225 if (argc != 0) { 226 usage(); 227 /*NOTREACHED*/ 228 } 229 do_foreach(0, NULL, mode == 'c' ? NDP_F_CLEAR : 0); 230 break; 231 case 'd': 232 if (argc != 0) { 233 usage(); 234 /*NOTREACHED*/ 235 } 236 delete_one(arg); 237 break; 238 case 'I': 239 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 240 if (argc > 1) { 241 usage(); 242 /*NOTREACHED*/ 243 } else if (argc == 1) { 244 if (strcmp(*argv, "delete") == 0 || 245 if_nametoindex(*argv)) 246 setdefif(*argv); 247 else 248 errx(1, "invalid interface %s", *argv); 249 } 250 getdefif(); /* always call it to print the result */ 251 break; 252 #else 253 errx(1, "not supported yet"); 254 /*NOTREACHED*/ 255 #endif 256 case 'p': 257 if (argc != 0) { 258 usage(); 259 /*NOTREACHED*/ 260 } 261 plist(); 262 break; 263 case 'i': 264 ifinfo(arg, argc, argv); 265 break; 266 case 'r': 267 if (argc != 0) { 268 usage(); 269 /*NOTREACHED*/ 270 } 271 rtrlist(); 272 break; 273 case 's': 274 if (argc < 2 || argc > 4) 275 usage(); 276 return(set(argc, argv) ? 1 : 0); 277 case 'H': 278 if (argc != 0) { 279 usage(); 280 /*NOTREACHED*/ 281 } 282 harmonize_rtr(); 283 break; 284 case 'P': 285 if (argc != 0) { 286 usage(); 287 /*NOTREACHED*/ 288 } 289 pfx_flush(); 290 break; 291 case 'R': 292 if (argc != 0) { 293 usage(); 294 /*NOTREACHED*/ 295 } 296 rtr_flush(); 297 break; 298 case 0: 299 if (argc != 1) { 300 usage(); 301 /*NOTREACHED*/ 302 } 303 get(argv[0]); 304 break; 305 } 306 return(0); 307 } 308 309 static void 310 makeaddr(struct sockaddr_in6 *mysin, const void *resp) 311 { 312 const struct sockaddr_in6 *res = resp; 313 mysin->sin6_addr = res->sin6_addr; 314 mysin->sin6_scope_id = res->sin6_scope_id; 315 inet6_putscopeid(mysin, INET6_IS_ADDR_LINKLOCAL); 316 } 317 318 static void 319 getsocket(void) 320 { 321 if (my_s < 0) { 322 my_s = prog_socket(PF_ROUTE, SOCK_RAW, 0); 323 if (my_s < 0) 324 err(1, "socket"); 325 } 326 } 327 328 #ifdef notdef 329 static struct sockaddr_in6 so_mask = { 330 .sin6_len = sizeof(so_mask), 331 .sin6_family = AF_INET6 332 }; 333 #endif 334 static struct sockaddr_in6 blank_sin = { 335 .sin6_len = sizeof(blank_sin), 336 .sin6_family = AF_INET6 337 }; 338 static struct sockaddr_in6 sin_m; 339 static struct sockaddr_dl blank_sdl = { 340 .sdl_len = sizeof(blank_sdl), 341 .sdl_family = AF_LINK, 342 }; 343 static struct sockaddr_dl sdl_m; 344 static int expire_time, flags, found_entry; 345 static struct { 346 struct rt_msghdr m_rtm; 347 char m_space[512]; 348 } m_rtmsg; 349 350 /* 351 * Set an individual neighbor cache entry 352 */ 353 static int 354 set(int argc, char **argv) 355 { 356 register struct sockaddr_in6 *mysin = &sin_m; 357 register struct sockaddr_dl *sdl; 358 register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); 359 struct addrinfo hints, *res; 360 int gai_error; 361 u_char *ea; 362 char *host = argv[0], *eaddr = argv[1]; 363 364 getsocket(); 365 argc -= 2; 366 argv += 2; 367 sdl_m = blank_sdl; 368 sin_m = blank_sin; 369 370 (void)memset(&hints, 0, sizeof(hints)); 371 hints.ai_family = AF_INET6; 372 gai_error = getaddrinfo(host, NULL, &hints, &res); 373 if (gai_error) { 374 warnx("%s: %s", host, gai_strerror(gai_error)); 375 return 1; 376 } 377 makeaddr(mysin, res->ai_addr); 378 freeaddrinfo(res); 379 ea = (u_char *)LLADDR(&sdl_m); 380 if (ndp_ether_aton(eaddr, ea) == 0) 381 sdl_m.sdl_alen = 6; 382 flags = expire_time = 0; 383 while (argc-- > 0) { 384 if (strncmp(argv[0], "temp", 4) == 0) { 385 struct timeval tim; 386 387 (void)gettimeofday(&tim, 0); 388 expire_time = tim.tv_sec + 20 * 60; 389 } else if (strncmp(argv[0], "proxy", 5) == 0) 390 flags |= RTF_ANNOUNCE; 391 argv++; 392 } 393 if (rtmsg(RTM_GET, NULL) < 0) { 394 errx(1, "RTM_GET(%s) failed", host); 395 /* NOTREACHED */ 396 } 397 mysin = (struct sockaddr_in6 *)(void *)(rtm + 1); 398 sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(mysin->sin6_len) + (char *)(void *)mysin); 399 if (IN6_ARE_ADDR_EQUAL(&mysin->sin6_addr, &sin_m.sin6_addr)) { 400 if (sdl->sdl_family == AF_LINK && 401 !(rtm->rtm_flags & RTF_GATEWAY)) { 402 switch (sdl->sdl_type) { 403 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 404 case IFT_ISO88024: case IFT_ISO88025: 405 goto overwrite; 406 } 407 } 408 /* 409 * IPv4 arp command retries with sin_other = SIN_PROXY here. 410 */ 411 (void)fprintf(stderr, "set: cannot configure a new entry\n"); 412 return 1; 413 } 414 415 overwrite: 416 if (sdl->sdl_family != AF_LINK) { 417 warnx("cannot intuit interface index and type for %s", host); 418 return (1); 419 } 420 sdl_m.sdl_type = sdl->sdl_type; 421 sdl_m.sdl_index = sdl->sdl_index; 422 return (rtmsg(RTM_ADD, NULL)); 423 } 424 425 /* 426 * Display an individual neighbor cache entry 427 */ 428 static void 429 get(char *host) 430 { 431 struct sockaddr_in6 *mysin = &sin_m; 432 struct addrinfo hints, *res; 433 int gai_error; 434 435 sin_m = blank_sin; 436 (void)memset(&hints, 0, sizeof(hints)); 437 hints.ai_family = AF_INET6; 438 gai_error = getaddrinfo(host, NULL, &hints, &res); 439 if (gai_error) { 440 warnx("%s: %s", host, gai_strerror(gai_error)); 441 return; 442 } 443 makeaddr(mysin, res->ai_addr); 444 freeaddrinfo(res); 445 do_foreach(&mysin->sin6_addr, host, 0); 446 if (found_entry == 0) { 447 (void)getnameinfo((struct sockaddr *)(void *)mysin, 448 (socklen_t)mysin->sin6_len, 449 host_buf, sizeof(host_buf), NULL ,0, 450 (nflag ? NI_NUMERICHOST : 0)); 451 errx(1, "%s (%s) -- no entry", host, host_buf); 452 } 453 } 454 455 static void 456 delete_one(char *host) 457 { 458 struct sockaddr_in6 *mysin = &sin_m; 459 struct addrinfo hints, *res; 460 int gai_error; 461 462 sin_m = blank_sin; 463 (void)memset(&hints, 0, sizeof(hints)); 464 hints.ai_family = AF_INET6; 465 gai_error = getaddrinfo(host, NULL, &hints, &res); 466 if (gai_error) { 467 warnx("%s: %s", host, gai_strerror(gai_error)); 468 return; 469 } 470 makeaddr(mysin, res->ai_addr); 471 freeaddrinfo(res); 472 do_foreach(&mysin->sin6_addr, host, NDP_F_DELETE); 473 } 474 475 /* 476 * Delete a neighbor cache entry 477 */ 478 static int 479 delete(struct rt_msghdr *rtm, char *host) 480 { 481 char delete_host_buf[NI_MAXHOST]; 482 struct sockaddr_in6 *mysin = &sin_m; 483 struct sockaddr_dl *sdl; 484 485 getsocket(); 486 mysin = (struct sockaddr_in6 *)(void *)(rtm + 1); 487 sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(mysin->sin6_len) + 488 (char *)(void *)mysin); 489 490 if (sdl->sdl_family != AF_LINK) { 491 (void)printf("cannot locate %s\n", host); 492 return (1); 493 } 494 if (rtmsg(RTM_DELETE, rtm) == 0) { 495 struct sockaddr_in6 s6 = *mysin; /* XXX: for safety */ 496 497 s6.sin6_scope_id = 0; 498 inet6_putscopeid(&s6, INET6_IS_ADDR_LINKLOCAL); 499 (void)getnameinfo((struct sockaddr *)(void *)&s6, 500 (socklen_t)s6.sin6_len, delete_host_buf, 501 sizeof(delete_host_buf), NULL, 0, 502 (nflag ? NI_NUMERICHOST : 0)); 503 (void)printf("%s (%s) deleted\n", host, delete_host_buf); 504 } 505 506 return 0; 507 } 508 509 #define W_ADDR (8 * 4 + 7) 510 #define W_LL 17 511 #define W_IF 6 512 513 /* 514 * Iterate on neighbor caches and do 515 * - dump all caches, 516 * - clear all caches (NDP_F_CLEAR) or 517 * - remove matched caches (NDP_F_DELETE) 518 */ 519 static void 520 do_foreach(struct in6_addr *addr, char *host, int _flags) 521 { 522 int mib[6]; 523 size_t needed; 524 char *lim, *buf, *next; 525 struct rt_msghdr *rtm; 526 struct sockaddr_in6 *mysin; 527 struct sockaddr_dl *sdl; 528 struct in6_nbrinfo *nbi; 529 struct timeval tim; 530 int addrwidth; 531 int llwidth; 532 int ifwidth; 533 char flgbuf[8], *fl; 534 const char *ifname; 535 int cflag = _flags == NDP_F_CLEAR; 536 int dflag = _flags == NDP_F_DELETE; 537 538 /* Print header */ 539 if (!tflag && !cflag) 540 (void)printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %2s\n", 541 W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address", 542 W_IF, W_IF, "Netif", "Expire", "S", "Fl"); 543 544 again:; 545 mib[0] = CTL_NET; 546 mib[1] = PF_ROUTE; 547 mib[2] = 0; 548 mib[3] = AF_INET6; 549 mib[4] = NET_RT_FLAGS; 550 mib[5] = RTF_LLDATA; 551 if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 552 err(1, "sysctl(PF_ROUTE estimate)"); 553 if (needed > 0) { 554 if ((buf = malloc(needed)) == NULL) 555 err(1, "malloc"); 556 if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 557 free(buf); 558 if (errno == ENOBUFS) 559 goto again; 560 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)"); 561 } 562 lim = buf + needed; 563 } else 564 buf = lim = NULL; 565 566 for (next = buf; next && next < lim; next += rtm->rtm_msglen) { 567 int isrouter = 0, prbs = 0; 568 569 rtm = (struct rt_msghdr *)(void *)next; 570 mysin = (struct sockaddr_in6 *)(void *)(rtm + 1); 571 sdl = (struct sockaddr_dl *)(void *)((char *)(void *)mysin + RT_ROUNDUP(mysin->sin6_len)); 572 573 /* 574 * Some OSes can produce a route that has the LINK flag but 575 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD 576 * and BSD/OS, where xx is not the interface identifier on 577 * lo0). Such routes entry would annoy getnbrinfo() below, 578 * so we skip them. 579 * XXX: such routes should have the GATEWAY flag, not the 580 * LINK flag. However, there is rotten routing software 581 * that advertises all routes that have the GATEWAY flag. 582 * Thus, KAME kernel intentionally does not set the LINK flag. 583 * What is to be fixed is not ndp, but such routing software 584 * (and the kernel workaround)... 585 */ 586 if (sdl->sdl_family != AF_LINK) 587 continue; 588 589 if (!(rtm->rtm_flags & RTF_HOST)) 590 continue; 591 592 if (addr) { 593 if (!IN6_ARE_ADDR_EQUAL(addr, &mysin->sin6_addr)) 594 continue; 595 found_entry = 1; 596 } else if (IN6_IS_ADDR_MULTICAST(&mysin->sin6_addr)) 597 continue; 598 if (dflag) { 599 (void)delete(rtm, host_buf); 600 continue; 601 } 602 if (IN6_IS_ADDR_LINKLOCAL(&mysin->sin6_addr) || 603 IN6_IS_ADDR_MC_LINKLOCAL(&mysin->sin6_addr)) { 604 uint16_t scopeid = mysin->sin6_scope_id; 605 inet6_getscopeid(mysin, INET6_IS_ADDR_LINKLOCAL| 606 INET6_IS_ADDR_MC_LINKLOCAL); 607 if (scopeid == 0) 608 mysin->sin6_scope_id = sdl->sdl_index; 609 } 610 (void)getnameinfo((struct sockaddr *)(void *)mysin, 611 (socklen_t)mysin->sin6_len, 612 host_buf, sizeof(host_buf), NULL, 0, 613 (nflag ? NI_NUMERICHOST : 0)); 614 if (cflag) { 615 /* Restore scopeid */ 616 if (IN6_IS_ADDR_LINKLOCAL(&mysin->sin6_addr) || 617 IN6_IS_ADDR_MC_LINKLOCAL(&mysin->sin6_addr)) 618 inet6_putscopeid(mysin, INET6_IS_ADDR_LINKLOCAL| 619 INET6_IS_ADDR_MC_LINKLOCAL); 620 if ((rtm->rtm_flags & RTF_STATIC) == 0) 621 (void)delete(rtm, host_buf); 622 continue; 623 } 624 (void)gettimeofday(&tim, 0); 625 if (tflag) 626 ts_print(&tim); 627 628 addrwidth = strlen(host_buf); 629 if (addrwidth < W_ADDR) 630 addrwidth = W_ADDR; 631 llwidth = strlen(ether_str(sdl)); 632 if (W_ADDR + W_LL - addrwidth > llwidth) 633 llwidth = W_ADDR + W_LL - addrwidth; 634 ifname = if_indextoname((unsigned int)sdl->sdl_index, ifix_buf); 635 if (!ifname) 636 ifname = "?"; 637 ifwidth = strlen(ifname); 638 if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth) 639 ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth; 640 641 (void)printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, 642 host_buf, llwidth, llwidth, ether_str(sdl), ifwidth, 643 ifwidth, ifname); 644 645 /* Print neighbor discovery specific informations */ 646 nbi = getnbrinfo(&mysin->sin6_addr, 647 (unsigned int)sdl->sdl_index, 1); 648 if (nbi) { 649 if (nbi->expire > tim.tv_sec) { 650 (void)printf(" %-9.9s", 651 sec2str(nbi->expire - tim.tv_sec)); 652 } else if (nbi->expire == 0) 653 (void)printf(" %-9.9s", "permanent"); 654 else 655 (void)printf(" %-9.9s", "expired"); 656 657 switch (nbi->state) { 658 case ND6_LLINFO_NOSTATE: 659 (void)printf(" N"); 660 break; 661 #ifdef ND6_LLINFO_WAITDELETE 662 case ND6_LLINFO_WAITDELETE: 663 (void)printf(" W"); 664 break; 665 #endif 666 case ND6_LLINFO_INCOMPLETE: 667 (void)printf(" I"); 668 break; 669 case ND6_LLINFO_REACHABLE: 670 (void)printf(" R"); 671 break; 672 case ND6_LLINFO_STALE: 673 (void)printf(" S"); 674 break; 675 case ND6_LLINFO_DELAY: 676 (void)printf(" D"); 677 break; 678 case ND6_LLINFO_PROBE: 679 (void)printf(" P"); 680 break; 681 default: 682 (void)printf(" ?"); 683 break; 684 } 685 686 isrouter = nbi->isrouter; 687 prbs = nbi->asked; 688 } else { 689 warnx("failed to get neighbor information"); 690 (void)printf(" "); 691 } 692 693 /* 694 * other flags. R: router, P: proxy, W: ?? 695 */ 696 fl = flgbuf; 697 if (isrouter) 698 *fl++ = 'R'; 699 if (rtm->rtm_flags & RTF_ANNOUNCE) 700 *fl++ = 'p'; 701 *fl++ = '\0'; 702 (void)printf(" %s", flgbuf); 703 704 if (prbs) 705 (void)printf(" %d", prbs); 706 707 (void)printf("\n"); 708 } 709 if (buf != NULL) 710 free(buf); 711 712 if (repeat) { 713 (void)printf("\n"); 714 (void)fflush(stdout); 715 (void)sleep(repeat); 716 goto again; 717 } 718 } 719 720 static struct in6_nbrinfo * 721 getnbrinfo(struct in6_addr *addr, unsigned int ifindex, int warning) 722 { 723 static struct in6_nbrinfo nbi; 724 int s; 725 726 if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 727 err(1, "socket"); 728 729 (void)memset(&nbi, 0, sizeof(nbi)); 730 (void)if_indextoname(ifindex, nbi.ifname); 731 nbi.addr = *addr; 732 if (prog_ioctl(s, SIOCGNBRINFO_IN6, &nbi) < 0) { 733 if (warning) 734 warn("ioctl(SIOCGNBRINFO_IN6)"); 735 (void)prog_close(s); 736 return(NULL); 737 } 738 739 (void)prog_close(s); 740 return(&nbi); 741 } 742 743 static char * 744 ether_str(struct sockaddr_dl *sdl) 745 { 746 static char hbuf[NI_MAXHOST]; 747 748 if (sdl->sdl_alen) { 749 if (getnameinfo((struct sockaddr *)(void *)sdl, 750 (socklen_t)sdl->sdl_len, 751 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 752 (void)snprintf(hbuf, sizeof(hbuf), "<invalid>"); 753 } else 754 (void)snprintf(hbuf, sizeof(hbuf), "(incomplete)"); 755 756 return(hbuf); 757 } 758 759 static int 760 ndp_ether_aton(char *a, u_char *n) 761 { 762 int i, o[6]; 763 764 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 765 &o[3], &o[4], &o[5]); 766 if (i != 6) { 767 warnx("invalid Ethernet address '%s'", a); 768 return (1); 769 } 770 for (i = 0; i < 6; i++) 771 n[i] = o[i]; 772 return (0); 773 } 774 775 static void 776 usage(void) 777 { 778 const char *pn = getprogname(); 779 780 (void)fprintf(stderr, "Usage: %s [-nt] hostname\n", pn); 781 (void)fprintf(stderr, 782 " %s [-nt] -a | -c | -p | -r | -H | -P | -R\n", pn); 783 (void)fprintf(stderr, " %s [-nt] -A wait\n", pn); 784 (void)fprintf(stderr, " %s [-nt] -d hostname\n", pn); 785 (void)fprintf(stderr, " %s [-nt] -f filename\n", pn); 786 (void)fprintf(stderr, " %s [-nt] -i interface [flags...]\n", pn); 787 #ifdef SIOCSDEFIFACE_IN6 788 (void)fprintf(stderr, " %s [-nt] -I [interface|delete]\n", pn); 789 #endif 790 (void)fprintf(stderr, 791 " %s [-nt] -s nodename etheraddr [temp] [proxy]\n", pn); 792 exit(1); 793 } 794 795 static int 796 rtmsg(int cmd, struct rt_msghdr *_rtm) 797 { 798 static int seq; 799 register struct rt_msghdr *rtm = _rtm; 800 register char *cp = m_rtmsg.m_space; 801 register int l; 802 803 errno = 0; 804 if (rtm != NULL) { 805 memcpy(&m_rtmsg, rtm, rtm->rtm_msglen); 806 rtm = &m_rtmsg.m_rtm; 807 goto doit; 808 } 809 (void)memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 810 rtm = &m_rtmsg.m_rtm; 811 rtm->rtm_flags = flags; 812 rtm->rtm_version = RTM_VERSION; 813 814 switch (cmd) { 815 default: 816 errx(1, "internal wrong cmd"); 817 /*NOTREACHED*/ 818 case RTM_ADD: 819 rtm->rtm_addrs |= RTA_GATEWAY; 820 if (expire_time) { 821 rtm->rtm_rmx.rmx_expire = expire_time; 822 rtm->rtm_inits = RTV_EXPIRE; 823 } 824 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA); 825 #ifdef notdef /* we don't support ipv6addr/128 type proxying. */ 826 if (rtm->rtm_flags & RTF_ANNOUNCE) { 827 rtm->rtm_flags &= ~RTF_HOST; 828 rtm->rtm_addrs |= RTA_NETMASK; 829 } 830 #endif 831 rtm->rtm_addrs |= RTA_DST; 832 break; 833 case RTM_GET: 834 rtm->rtm_flags |= RTF_LLDATA; 835 rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY; 836 } 837 #define NEXTADDR(w, s) \ 838 if (rtm->rtm_addrs & (w)) { \ 839 (void)memcpy(cp, &s, sizeof(s)); \ 840 RT_ADVANCE(cp, (struct sockaddr *)(void *)&s); \ 841 } 842 843 NEXTADDR(RTA_DST, sin_m); 844 NEXTADDR(RTA_GATEWAY, sdl_m); 845 #ifdef notdef /* we don't support ipv6addr/128 type proxying. */ 846 (void)memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr)); 847 NEXTADDR(RTA_NETMASK, so_mask); 848 #endif 849 850 rtm->rtm_msglen = cp - (char *)(void *)&m_rtmsg; 851 doit: 852 l = rtm->rtm_msglen; 853 rtm->rtm_seq = ++seq; 854 rtm->rtm_type = cmd; 855 if (prog_write(my_s, &m_rtmsg, (size_t)l) == -1) { 856 if (errno != ESRCH || cmd != RTM_DELETE) 857 err(1, "writing to routing socket"); 858 } 859 do { 860 l = prog_read(my_s, &m_rtmsg, sizeof(m_rtmsg)); 861 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 862 if (l < 0) 863 warn("read from routing socket"); 864 return (0); 865 } 866 867 static void 868 ifinfo(char *ifname, int argc, char **argv) 869 { 870 struct in6_ndireq nd; 871 int i, s; 872 u_int32_t newflags; 873 #ifdef IPV6CTL_USETEMPADDR 874 u_int8_t nullbuf[8]; 875 #endif 876 877 if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 878 err(1, "socket"); 879 (void)memset(&nd, 0, sizeof(nd)); 880 (void)strlcpy(nd.ifname, ifname, sizeof(nd.ifname)); 881 if (prog_ioctl(s, SIOCGIFINFO_IN6, &nd) < 0) 882 err(1, "ioctl(SIOCGIFINFO_IN6)"); 883 #define ND nd.ndi 884 newflags = ND.flags; 885 for (i = 0; i < argc; i++) { 886 int clear = 0; 887 char *cp = argv[i]; 888 889 if (*cp == '-') { 890 clear = 1; 891 cp++; 892 } 893 894 #define SETFLAG(s, f) \ 895 do {\ 896 if (strcmp(cp, (s)) == 0) {\ 897 if (clear)\ 898 newflags &= ~(f);\ 899 else\ 900 newflags |= (f);\ 901 }\ 902 } while (/*CONSTCOND*/0) 903 /* 904 * XXX: this macro is not 100% correct, in that it matches "nud" against 905 * "nudbogus". But we just let it go since this is minor. 906 */ 907 #define SETVALUE(f, v) \ 908 do { \ 909 char *valptr; \ 910 unsigned long newval; \ 911 v = 0; /* unspecified */ \ 912 if (strncmp(cp, f, strlen(f)) == 0) { \ 913 valptr = strchr(cp, '='); \ 914 if (valptr == NULL) \ 915 err(1, "syntax error in %s field", (f)); \ 916 errno = 0; \ 917 newval = strtoul(++valptr, NULL, 0); \ 918 if (errno) \ 919 err(1, "syntax error in %s's value", (f)); \ 920 v = newval; \ 921 } \ 922 } while (/*CONSTCOND*/0) 923 924 #ifdef ND6_IFF_IFDISABLED 925 SETFLAG("disabled", ND6_IFF_IFDISABLED); 926 #endif 927 SETFLAG("nud", ND6_IFF_PERFORMNUD); 928 #ifdef ND6_IFF_ACCEPT_RTADV 929 SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV); 930 #endif 931 #ifdef ND6_IFF_OVERRIDE_RTADV 932 SETFLAG("override_rtadv", ND6_IFF_OVERRIDE_RTADV); 933 #endif 934 #ifdef ND6_IFF_AUTO_LINKLOCAL 935 SETFLAG("auto_linklocal", ND6_IFF_AUTO_LINKLOCAL); 936 #endif 937 #ifdef ND6_IFF_PREFER_SOURCE 938 SETFLAG("prefer_source", ND6_IFF_PREFER_SOURCE); 939 #endif 940 #ifdef ND6_IFF_DONT_SET_IFROUTE 941 SETFLAG("dont_set_ifroute", ND6_IFF_DONT_SET_IFROUTE); 942 #endif 943 SETVALUE("basereachable", ND.basereachable); 944 SETVALUE("retrans", ND.retrans); 945 SETVALUE("curhlim", ND.chlim); 946 947 ND.flags = newflags; 948 #ifdef SIOCSIFINFO_IN6 949 if (prog_ioctl(s, SIOCSIFINFO_IN6, &nd) < 0) 950 err(1, "ioctl(SIOCSIFINFO_IN6)"); 951 #else 952 if (prog_ioctl(s, SIOCSIFINFO_FLAGS, &nd) < 0) 953 err(1, "ioctl(SIOCSIFINFO_FLAGS)"); 954 #endif 955 #undef SETFLAG 956 #undef SETVALUE 957 } 958 959 if (!ND.initialized) 960 errx(1, "%s: not initialized yet", ifname); 961 962 if (prog_ioctl(s, SIOCGIFINFO_IN6, &nd) < 0) 963 err(1, "ioctl(SIOCGIFINFO_IN6)"); 964 (void)printf("linkmtu=%d", ND.linkmtu); 965 (void)printf(", maxmtu=%d", ND.maxmtu); 966 (void)printf(", curhlim=%d", ND.chlim); 967 (void)printf(", basereachable=%ds%dms", 968 ND.basereachable / 1000, ND.basereachable % 1000); 969 (void)printf(", reachable=%ds", ND.reachable); 970 (void)printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000); 971 #ifdef IPV6CTL_USETEMPADDR 972 (void)memset(nullbuf, 0, sizeof(nullbuf)); 973 if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) { 974 int j; 975 u_int8_t *rbuf; 976 977 for (i = 0; i < 3; i++) { 978 switch (i) { 979 case 0: 980 (void)printf("\nRandom seed(0): "); 981 rbuf = ND.randomseed0; 982 break; 983 case 1: 984 (void)printf("\nRandom seed(1): "); 985 rbuf = ND.randomseed1; 986 break; 987 case 2: 988 (void)printf("\nRandom ID: "); 989 rbuf = ND.randomid; 990 break; 991 default: 992 errx(1, "impossible case for tempaddr display"); 993 } 994 for (j = 0; j < 8; j++) 995 (void)printf("%02x", rbuf[j]); 996 } 997 } 998 #endif 999 if (ND.flags) { 1000 (void)printf("\nFlags: "); 1001 if ((ND.flags & ND6_IFF_PERFORMNUD)) 1002 (void)printf("nud "); 1003 #ifdef ND6_IFF_IFDISABLED 1004 if ((ND.flags & ND6_IFF_IFDISABLED)) 1005 (void)printf("disabled "); 1006 #endif 1007 #ifdef ND6_IFF_ACCEPT_RTADV 1008 if ((ND.flags & ND6_IFF_ACCEPT_RTADV)) 1009 (void)printf("accept_rtadv "); 1010 #endif 1011 #ifdef ND6_IFF_OVERRIDE_RTADV 1012 if ((ND.flags & ND6_IFF_OVERRIDE_RTADV)) 1013 (void)printf("override_rtadv "); 1014 #endif 1015 #ifdef ND6_IFF_AUTO_LINKLOCAL 1016 if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL)) 1017 (void)printf("auto_linklocal "); 1018 #endif 1019 #ifdef ND6_IFF_PREFER_SOURCE 1020 if ((ND.flags & ND6_IFF_PREFER_SOURCE)) 1021 (void)printf("prefer_source "); 1022 #endif 1023 } 1024 (void)putc('\n', stdout); 1025 #undef ND 1026 1027 (void)prog_close(s); 1028 } 1029 1030 #ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */ 1031 #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 1032 #endif 1033 1034 static void 1035 rtrlist(void) 1036 { 1037 #ifdef ICMPV6CTL_ND6_DRLIST 1038 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST }; 1039 char *buf; 1040 struct in6_defrouter *p, *ep; 1041 size_t l; 1042 struct timeval tim; 1043 1044 if (prog_sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { 1045 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); 1046 /*NOTREACHED*/ 1047 } 1048 if (l == 0) 1049 return; 1050 buf = malloc(l); 1051 if (!buf) { 1052 err(1, "malloc"); 1053 /*NOTREACHED*/ 1054 } 1055 if (prog_sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 1056 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); 1057 /*NOTREACHED*/ 1058 } 1059 1060 ep = (struct in6_defrouter *)(void *)(buf + l); 1061 for (p = (struct in6_defrouter *)(void *)buf; p < ep; p++) { 1062 int rtpref; 1063 1064 if (getnameinfo((struct sockaddr *)(void *)&p->rtaddr, 1065 (socklen_t)p->rtaddr.sin6_len, host_buf, sizeof(host_buf), 1066 NULL, 0, (nflag ? NI_NUMERICHOST : 0)) != 0) 1067 (void)strlcpy(host_buf, "?", sizeof(host_buf)); 1068 1069 (void)printf("%s if=%s", host_buf, 1070 if_indextoname((unsigned int)p->if_index, ifix_buf)); 1071 (void)printf(", flags=%s%s", 1072 p->flags & ND_RA_FLAG_MANAGED ? "M" : "", 1073 p->flags & ND_RA_FLAG_OTHER ? "O" : ""); 1074 rtpref = ((uint32_t)(p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff; 1075 (void)printf(", pref=%s", rtpref_str[rtpref]); 1076 1077 (void)gettimeofday(&tim, 0); 1078 if (p->expire == 0) 1079 (void)printf(", expire=Never\n"); 1080 else 1081 (void)printf(", expire=%s\n", 1082 sec2str((time_t)(p->expire - tim.tv_sec))); 1083 } 1084 free(buf); 1085 #else 1086 struct in6_drlist dr; 1087 int s, i; 1088 struct timeval time; 1089 1090 if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1091 err(1, "socket"); 1092 /* NOTREACHED */ 1093 } 1094 (void)memset(&dr, 0, sizeof(dr)); 1095 (void)strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */ 1096 if (prog_ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 1097 err(1, "ioctl(SIOCGDRLST_IN6)"); 1098 /* NOTREACHED */ 1099 } 1100 #define DR dr.defrouter[i] 1101 for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) { 1102 struct sockaddr_in6 sin6; 1103 1104 (void)memset(&sin6, 0, sizeof(sin6)); 1105 sin6.sin6_family = AF_INET6; 1106 sin6.sin6_len = sizeof(sin6); 1107 sin6.sin6_addr = DR.rtaddr; 1108 (void)getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 1109 host_buf, sizeof(host_buf), NULL, 0, 1110 (nflag ? NI_NUMERICHOST : 0)); 1111 1112 (void)printf("%s if=%s", host_buf, 1113 if_indextoname(DR.if_index, ifix_buf)); 1114 (void)printf(", flags=%s%s", 1115 DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", 1116 DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); 1117 gettimeofday(&time, 0); 1118 if (DR.expire == 0) 1119 (void)printf(", expire=Never\n"); 1120 else 1121 (void)printf(", expire=%s\n", 1122 sec2str(DR.expire - time.tv_sec)); 1123 } 1124 #undef DR 1125 (void)prog_close(s); 1126 #endif 1127 } 1128 1129 static void 1130 plist(void) 1131 { 1132 #ifdef ICMPV6CTL_ND6_PRLIST 1133 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST }; 1134 char *buf, *p, *ep; 1135 struct in6_prefix pfx; 1136 size_t l; 1137 struct timeval tim; 1138 const int niflags = NI_NUMERICHOST; 1139 int ninflags = nflag ? NI_NUMERICHOST : 0; 1140 char namebuf[NI_MAXHOST]; 1141 1142 if (prog_sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { 1143 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); 1144 /*NOTREACHED*/ 1145 } 1146 buf = malloc(l); 1147 if (!buf) { 1148 err(1, "malloc"); 1149 /*NOTREACHED*/ 1150 } 1151 if (prog_sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 1152 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); 1153 /*NOTREACHED*/ 1154 } 1155 1156 ep = buf + l; 1157 for (p = buf; p < ep; ) { 1158 memcpy(&pfx, p, sizeof(pfx)); 1159 p += sizeof(pfx); 1160 1161 if (getnameinfo((struct sockaddr*)&pfx.prefix, 1162 (socklen_t)pfx.prefix.sin6_len, namebuf, sizeof(namebuf), 1163 NULL, 0, niflags) != 0) 1164 (void)strlcpy(namebuf, "?", sizeof(namebuf)); 1165 (void)printf("%s/%d if=%s\n", namebuf, pfx.prefixlen, 1166 if_indextoname((unsigned int)pfx.if_index, ifix_buf)); 1167 1168 (void)gettimeofday(&tim, 0); 1169 /* 1170 * meaning of fields, especially flags, is very different 1171 * by origin. notify the difference to the users. 1172 */ 1173 (void)printf("flags=%s%s%s%s%s", 1174 pfx.raflags.onlink ? "L" : "", 1175 pfx.raflags.autonomous ? "A" : "", 1176 (pfx.flags & NDPRF_ONLINK) != 0 ? "O" : "", 1177 (pfx.flags & NDPRF_DETACHED) != 0 ? "D" : "", 1178 #ifdef NDPRF_HOME 1179 (pfx.flags & NDPRF_HOME) != 0 ? "H" : "" 1180 #else 1181 "" 1182 #endif 1183 ); 1184 if (pfx.vltime == ND6_INFINITE_LIFETIME) 1185 (void)printf(" vltime=infinity"); 1186 else 1187 (void)printf(" vltime=%lu", (unsigned long)pfx.vltime); 1188 if (pfx.pltime == ND6_INFINITE_LIFETIME) 1189 (void)printf(", pltime=infinity"); 1190 else 1191 (void)printf(", pltime=%lu", (unsigned long)pfx.pltime); 1192 if (pfx.expire == 0) 1193 (void)printf(", expire=Never"); 1194 else if (pfx.expire >= tim.tv_sec) 1195 (void)printf(", expire=%s", 1196 sec2str(pfx.expire - tim.tv_sec)); 1197 else 1198 (void)printf(", expired"); 1199 (void)printf(", ref=%d", pfx.refcnt); 1200 (void)printf("\n"); 1201 /* 1202 * "advertising router" list is meaningful only if the prefix 1203 * information is from RA. 1204 */ 1205 if (pfx.advrtrs) { 1206 int j; 1207 struct sockaddr_in6 sin6; 1208 1209 (void)printf(" advertised by\n"); 1210 for (j = 0; j < pfx.advrtrs && p <= ep; j++) { 1211 struct in6_nbrinfo *nbi; 1212 1213 memcpy(&sin6, p, sizeof(sin6)); 1214 p += sizeof(sin6); 1215 1216 if (getnameinfo((struct sockaddr *)&sin6, 1217 (socklen_t)sin6.sin6_len, namebuf, 1218 sizeof(namebuf), NULL, 0, ninflags) != 0) 1219 (void)strlcpy(namebuf, "?", sizeof(namebuf)); 1220 (void)printf(" %s", namebuf); 1221 1222 nbi = getnbrinfo(&sin6.sin6_addr, 1223 (unsigned int)pfx.if_index, 0); 1224 if (nbi) { 1225 switch (nbi->state) { 1226 case ND6_LLINFO_REACHABLE: 1227 case ND6_LLINFO_STALE: 1228 case ND6_LLINFO_DELAY: 1229 case ND6_LLINFO_PROBE: 1230 (void)printf(" (reachable)\n"); 1231 break; 1232 default: 1233 (void)printf(" (unreachable)\n"); 1234 } 1235 } else 1236 (void)printf(" (no neighbor state)\n"); 1237 } 1238 } else 1239 (void)printf(" No advertising router\n"); 1240 } 1241 free(buf); 1242 #else 1243 struct in6_prlist pr; 1244 int s, i; 1245 struct timeval time; 1246 1247 (void)gettimeofday(&time, 0); 1248 1249 if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1250 err(1, "socket"); 1251 /* NOTREACHED */ 1252 } 1253 (void)memset(&pr, 0, sizeof(pr)); 1254 (void)strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */ 1255 if (prog_ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { 1256 err(1, "ioctl(SIOCGPRLST_IN6)"); 1257 /* NOTREACHED */ 1258 } 1259 #define PR pr.prefix[i] 1260 for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { 1261 struct sockaddr_in6 p6; 1262 char namebuf[NI_MAXHOST]; 1263 int niflags; 1264 1265 #ifdef NDPRF_ONLINK 1266 p6 = PR.prefix; 1267 #else 1268 (void)memset(&p6, 0, sizeof(p6)); 1269 p6.sin6_family = AF_INET6; 1270 p6.sin6_len = sizeof(p6); 1271 p6.sin6_addr = PR.prefix; 1272 #endif 1273 1274 niflags = NI_NUMERICHOST; 1275 if (getnameinfo((struct sockaddr *)&p6, 1276 sizeof(p6), namebuf, sizeof(namebuf), 1277 NULL, 0, niflags)) { 1278 warnx("getnameinfo failed"); 1279 continue; 1280 } 1281 (void)printf("%s/%d if=%s\n", namebuf, PR.prefixlen, 1282 if_indextoname(PR.if_index, ifix_buf)); 1283 1284 (void)gettimeofday(&time, 0); 1285 /* 1286 * meaning of fields, especially flags, is very different 1287 * by origin. notify the difference to the users. 1288 */ 1289 #if 0 1290 (void)printf(" %s", 1291 PR.origin == PR_ORIG_RA ? "" : "advertise: "); 1292 #endif 1293 #ifdef NDPRF_ONLINK 1294 (void)printf("flags=%s%s%s%s%s", 1295 PR.raflags.onlink ? "L" : "", 1296 PR.raflags.autonomous ? "A" : "", 1297 (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "", 1298 (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "", 1299 #ifdef NDPRF_HOME 1300 (PR.flags & NDPRF_HOME) != 0 ? "H" : "" 1301 #else 1302 "" 1303 #endif 1304 ); 1305 #else 1306 (void)printf("flags=%s%s", 1307 PR.raflags.onlink ? "L" : "", 1308 PR.raflags.autonomous ? "A" : ""); 1309 #endif 1310 if (PR.vltime == ND6_INFINITE_LIFETIME) 1311 (void)printf(" vltime=infinity"); 1312 else 1313 (void)printf(" vltime=%lu", PR.vltime); 1314 if (PR.pltime == ND6_INFINITE_LIFETIME) 1315 (void)printf(", pltime=infinity"); 1316 else 1317 (void)printf(", pltime=%lu", PR.pltime); 1318 if (PR.expire == 0) 1319 (void)printf(", expire=Never"); 1320 else if (PR.expire >= time.tv_sec) 1321 (void)printf(", expire=%s", 1322 sec2str(PR.expire - time.tv_sec)); 1323 else 1324 (void)printf(", expired"); 1325 #ifdef NDPRF_ONLINK 1326 (void)printf(", ref=%d", PR.refcnt); 1327 #endif 1328 #if 0 1329 switch (PR.origin) { 1330 case PR_ORIG_RA: 1331 (void)printf(", origin=RA"); 1332 break; 1333 case PR_ORIG_RR: 1334 (void)printf(", origin=RR"); 1335 break; 1336 case PR_ORIG_STATIC: 1337 (void)printf(", origin=static"); 1338 break; 1339 case PR_ORIG_KERNEL: 1340 (void)printf(", origin=kernel"); 1341 break; 1342 default: 1343 (void)printf(", origin=?"); 1344 break; 1345 } 1346 #endif 1347 (void)printf("\n"); 1348 /* 1349 * "advertising router" list is meaningful only if the prefix 1350 * information is from RA. 1351 */ 1352 if (0 && /* prefix origin is almost obsolted */ 1353 PR.origin != PR_ORIG_RA) 1354 ; 1355 else if (PR.advrtrs) { 1356 int j; 1357 (void)printf(" advertised by\n"); 1358 for (j = 0; j < PR.advrtrs; j++) { 1359 struct sockaddr_in6 sin6; 1360 struct in6_nbrinfo *nbi; 1361 1362 bzero(&sin6, sizeof(sin6)); 1363 sin6.sin6_family = AF_INET6; 1364 sin6.sin6_len = sizeof(sin6); 1365 sin6.sin6_addr = PR.advrtr[j]; 1366 sin6.sin6_scope_id = PR.if_index; /* XXX */ 1367 (void)getnameinfo((struct sockaddr *)&sin6, 1368 sin6.sin6_len, host_buf, 1369 sizeof(host_buf), NULL, 0, 1370 (nflag ? NI_NUMERICHOST : 0)); 1371 (void)printf(" %s", host_buf); 1372 1373 nbi = getnbrinfo(&sin6.sin6_addr, 1374 PR.if_index, 0); 1375 if (nbi) { 1376 switch (nbi->state) { 1377 case ND6_LLINFO_REACHABLE: 1378 case ND6_LLINFO_STALE: 1379 case ND6_LLINFO_DELAY: 1380 case ND6_LLINFO_PROBE: 1381 (void)printf(" (reachable)\n"); 1382 break; 1383 default: 1384 (void)printf(" (unreachable)\n"); 1385 } 1386 } else 1387 (void)printf(" (no neighbor state)\n"); 1388 } 1389 if (PR.advrtrs > DRLSTSIZ) 1390 (void)printf(" and %d routers\n", 1391 PR.advrtrs - DRLSTSIZ); 1392 } else 1393 (void)printf(" No advertising router\n"); 1394 } 1395 #undef PR 1396 (void)prog_close(s); 1397 #endif 1398 } 1399 1400 static void 1401 pfx_flush(void) 1402 { 1403 int s; 1404 struct in6_ifreq ifr; 1405 1406 if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1407 err(1, "socket"); 1408 memset(&ifr, 0, sizeof(ifr)); 1409 strcpy(ifr.ifr_name, "lo0"); 1410 if (prog_ioctl(s, SIOCSPFXFLUSH_IN6, &ifr) < 0) 1411 err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); 1412 (void)prog_close(s); 1413 } 1414 1415 static void 1416 rtr_flush(void) 1417 { 1418 int s; 1419 struct in6_ifreq ifr; 1420 1421 if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1422 err(1, "socket"); 1423 memset(&ifr, 0, sizeof(ifr)); 1424 strcpy(ifr.ifr_name, "lo0"); 1425 if (prog_ioctl(s, SIOCSRTRFLUSH_IN6, &ifr) < 0) 1426 err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); 1427 (void)prog_close(s); 1428 } 1429 1430 static void 1431 harmonize_rtr(void) 1432 { 1433 char dummyif[IFNAMSIZ+8]; 1434 int s; 1435 1436 if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1437 err(1, "socket"); 1438 (void)strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 1439 if (prog_ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) 1440 err(1, "ioctl(SIOCSNDFLUSH_IN6)"); 1441 1442 (void)prog_close(s); 1443 } 1444 1445 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 1446 static void 1447 setdefif(char *ifname) 1448 { 1449 struct in6_ndifreq ndifreq; 1450 unsigned int ifindex; 1451 int s; 1452 1453 if (strcasecmp(ifname, "delete") == 0) 1454 ifindex = 0; 1455 else { 1456 if ((ifindex = if_nametoindex(ifname)) == 0) 1457 err(1, "failed to resolve i/f index for %s", ifname); 1458 } 1459 1460 if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1461 err(1, "socket"); 1462 1463 (void)strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */ 1464 ndifreq.ifindex = ifindex; 1465 1466 if (prog_ioctl(s, SIOCSDEFIFACE_IN6, &ndifreq) < 0) 1467 err(1, "ioctl(SIOCSDEFIFACE_IN6)"); 1468 1469 (void)prog_close(s); 1470 } 1471 1472 static void 1473 getdefif(void) 1474 { 1475 struct in6_ndifreq ndifreq; 1476 char ifname[IFNAMSIZ+8]; 1477 int s; 1478 1479 if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1480 err(1, "socket"); 1481 1482 (void)memset(&ndifreq, 0, sizeof(ndifreq)); 1483 (void)strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */ 1484 1485 if (prog_ioctl(s, SIOCGDEFIFACE_IN6, &ndifreq) < 0) 1486 err(1, "ioctl(SIOCGDEFIFACE_IN6)"); 1487 1488 if (ndifreq.ifindex == 0) 1489 (void)printf("No default interface.\n"); 1490 else { 1491 if ((if_indextoname((unsigned int)ndifreq.ifindex, ifname)) == NULL) 1492 err(1, "failed to resolve ifname for index %lu", 1493 ndifreq.ifindex); 1494 (void)printf("ND default interface = %s\n", ifname); 1495 } 1496 1497 (void)prog_close(s); 1498 } 1499 #endif 1500 1501 static const char * 1502 sec2str(time_t total) 1503 { 1504 static char result[256]; 1505 int days, hours, mins, secs; 1506 int first = 1; 1507 char *p = result; 1508 char *ep = &result[sizeof(result)]; 1509 int n; 1510 1511 days = total / 3600 / 24; 1512 hours = (total / 3600) % 24; 1513 mins = (total / 60) % 60; 1514 secs = total % 60; 1515 1516 if (days) { 1517 first = 0; 1518 n = snprintf(p, (size_t)(ep - p), "%dd", days); 1519 if (n < 0 || n >= ep - p) 1520 return "?"; 1521 p += n; 1522 } 1523 if (!first || hours) { 1524 first = 0; 1525 n = snprintf(p, (size_t)(ep - p), "%dh", hours); 1526 if (n < 0 || n >= ep - p) 1527 return "?"; 1528 p += n; 1529 } 1530 if (!first || mins) { 1531 first = 0; 1532 n = snprintf(p, (size_t)(ep - p), "%dm", mins); 1533 if (n < 0 || n >= ep - p) 1534 return "?"; 1535 p += n; 1536 } 1537 (void)snprintf(p, (size_t)(ep - p), "%ds", secs); 1538 1539 return(result); 1540 } 1541 1542 /* 1543 * Print the timestamp 1544 * from tcpdump/util.c 1545 */ 1546 static void 1547 ts_print(const struct timeval *tvp) 1548 { 1549 int s; 1550 1551 /* Default */ 1552 s = (tvp->tv_sec + thiszone) % 86400; 1553 (void)printf("%02d:%02d:%02d.%06u ", 1554 s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec); 1555 } 1556