1 /* $NetBSD: ndp.c,v 1.40 2011/08/31 13:32:38 joerg 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 #include "gmt2local.h" 108 109 static pid_t pid; 110 static int nflag; 111 static int tflag; 112 static int32_t thiszone; /* time difference with gmt */ 113 static int my_s = -1; 114 static unsigned int repeat = 0; 115 116 117 static char host_buf[NI_MAXHOST]; /* getnameinfo() */ 118 static char ifix_buf[IFNAMSIZ]; /* if_indextoname() */ 119 120 static void getsocket(void); 121 static int set(int, char **); 122 static void get(char *); 123 static int delete(char *); 124 static void dump(struct in6_addr *, int); 125 static struct in6_nbrinfo *getnbrinfo(struct in6_addr *, unsigned int, int); 126 static char *ether_str(struct sockaddr_dl *); 127 static int ndp_ether_aton(char *, u_char *); 128 __dead static void usage(void); 129 static int rtmsg(int); 130 static void ifinfo(char *, int, char **); 131 static void rtrlist(void); 132 static void plist(void); 133 static void pfx_flush(void); 134 static void rtrlist(void); 135 static void rtr_flush(void); 136 static void harmonize_rtr(void); 137 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 138 static void getdefif(void); 139 static void setdefif(char *); 140 #endif 141 static const char *sec2str(time_t); 142 static char *ether_str(struct sockaddr_dl *); 143 static void ts_print(const struct timeval *); 144 145 #ifdef ICMPV6CTL_ND6_DRLIST 146 static const char *rtpref_str[] = { 147 "medium", /* 00 */ 148 "high", /* 01 */ 149 "rsv", /* 10 */ 150 "low" /* 11 */ 151 }; 152 #endif 153 154 static int mode = 0; 155 static char *arg = NULL; 156 157 int 158 main(int argc, char **argv) 159 { 160 int ch; 161 162 pid = getpid(); 163 thiszone = gmt2local(0L); 164 while ((ch = getopt(argc, argv, "acd:f:Ii:nprstA:HPR")) != -1) 165 switch (ch) { 166 case 'a': 167 case 'c': 168 case 'p': 169 case 'r': 170 case 'H': 171 case 'P': 172 case 'R': 173 case 's': 174 case 'I': 175 if (mode) { 176 usage(); 177 /*NOTREACHED*/ 178 } 179 mode = ch; 180 arg = NULL; 181 break; 182 case 'd': 183 case 'f': 184 case 'i' : 185 if (mode) { 186 usage(); 187 /*NOTREACHED*/ 188 } 189 mode = ch; 190 arg = optarg; 191 break; 192 case 'n': 193 nflag = 1; 194 break; 195 case 't': 196 tflag = 1; 197 break; 198 case 'A': 199 if (mode) { 200 usage(); 201 /*NOTREACHED*/ 202 } 203 mode = 'a'; 204 repeat = atoi(optarg); 205 break; 206 default: 207 usage(); 208 } 209 210 argc -= optind; 211 argv += optind; 212 213 switch (mode) { 214 case 'a': 215 case 'c': 216 if (argc != 0) { 217 usage(); 218 /*NOTREACHED*/ 219 } 220 dump(0, mode == 'c'); 221 break; 222 case 'd': 223 if (argc != 0) { 224 usage(); 225 /*NOTREACHED*/ 226 } 227 (void)delete(arg); 228 break; 229 case 'I': 230 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 231 if (argc > 1) { 232 usage(); 233 /*NOTREACHED*/ 234 } else if (argc == 1) { 235 if (strcmp(*argv, "delete") == 0 || 236 if_nametoindex(*argv)) 237 setdefif(*argv); 238 else 239 errx(1, "invalid interface %s", *argv); 240 } 241 getdefif(); /* always call it to print the result */ 242 break; 243 #else 244 errx(1, "not supported yet"); 245 /*NOTREACHED*/ 246 #endif 247 case 'p': 248 if (argc != 0) { 249 usage(); 250 /*NOTREACHED*/ 251 } 252 plist(); 253 break; 254 case 'i': 255 ifinfo(arg, argc, argv); 256 break; 257 case 'r': 258 if (argc != 0) { 259 usage(); 260 /*NOTREACHED*/ 261 } 262 rtrlist(); 263 break; 264 case 's': 265 if (argc < 2 || argc > 4) 266 usage(); 267 return(set(argc, argv) ? 1 : 0); 268 case 'H': 269 if (argc != 0) { 270 usage(); 271 /*NOTREACHED*/ 272 } 273 harmonize_rtr(); 274 break; 275 case 'P': 276 if (argc != 0) { 277 usage(); 278 /*NOTREACHED*/ 279 } 280 pfx_flush(); 281 break; 282 case 'R': 283 if (argc != 0) { 284 usage(); 285 /*NOTREACHED*/ 286 } 287 rtr_flush(); 288 break; 289 case 0: 290 if (argc != 1) { 291 usage(); 292 /*NOTREACHED*/ 293 } 294 get(argv[0]); 295 break; 296 } 297 return(0); 298 } 299 300 static void 301 getsocket(void) 302 { 303 if (my_s < 0) { 304 my_s = socket(PF_ROUTE, SOCK_RAW, 0); 305 if (my_s < 0) 306 err(1, "socket"); 307 } 308 } 309 310 #ifdef notdef 311 static struct sockaddr_in6 so_mask = { 312 .sin6_len = sizeof(so_mask), 313 .sin6_family = AF_INET6 314 }; 315 #endif 316 static struct sockaddr_in6 blank_sin = { 317 .sin6_len = sizeof(blank_sin), 318 .sin6_family = AF_INET6 319 }; 320 static struct sockaddr_in6 sin_m; 321 static struct sockaddr_dl blank_sdl = { 322 .sdl_len = sizeof(blank_sdl), 323 .sdl_family = AF_LINK, 324 }; 325 static struct sockaddr_dl sdl_m; 326 static int expire_time, flags, found_entry; 327 static struct { 328 struct rt_msghdr m_rtm; 329 char m_space[512]; 330 } m_rtmsg; 331 332 /* 333 * Set an individual neighbor cache entry 334 */ 335 static int 336 set(int argc, char **argv) 337 { 338 register struct sockaddr_in6 *mysin = &sin_m; 339 register struct sockaddr_dl *sdl; 340 register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); 341 struct addrinfo hints, *res; 342 int gai_error; 343 u_char *ea; 344 char *host = argv[0], *eaddr = argv[1]; 345 346 getsocket(); 347 argc -= 2; 348 argv += 2; 349 sdl_m = blank_sdl; 350 sin_m = blank_sin; 351 352 (void)memset(&hints, 0, sizeof(hints)); 353 hints.ai_family = AF_INET6; 354 gai_error = getaddrinfo(host, NULL, &hints, &res); 355 if (gai_error) { 356 warnx("%s: %s\n", host, gai_strerror(gai_error)); 357 return 1; 358 } 359 mysin->sin6_addr = ((struct sockaddr_in6 *)(void *)res->ai_addr)->sin6_addr; 360 #ifdef __KAME__ 361 if (IN6_IS_ADDR_LINKLOCAL(&mysin->sin6_addr)) { 362 *(u_int16_t *)(void *)&mysin->sin6_addr.s6_addr[2] = 363 htons(((struct sockaddr_in6 *)(void *)res->ai_addr)->sin6_scope_id); 364 } 365 #endif 366 ea = (u_char *)LLADDR(&sdl_m); 367 if (ndp_ether_aton(eaddr, ea) == 0) 368 sdl_m.sdl_alen = 6; 369 flags = expire_time = 0; 370 while (argc-- > 0) { 371 if (strncmp(argv[0], "temp", 4) == 0) { 372 struct timeval tim; 373 374 (void)gettimeofday(&tim, 0); 375 expire_time = tim.tv_sec + 20 * 60; 376 } else if (strncmp(argv[0], "proxy", 5) == 0) 377 flags |= RTF_ANNOUNCE; 378 argv++; 379 } 380 if (rtmsg(RTM_GET) < 0) { 381 errx(1, "RTM_GET(%s) failed", host); 382 /* NOTREACHED */ 383 } 384 mysin = (struct sockaddr_in6 *)(void *)(rtm + 1); 385 sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(mysin->sin6_len) + (char *)(void *)mysin); 386 if (IN6_ARE_ADDR_EQUAL(&mysin->sin6_addr, &sin_m.sin6_addr)) { 387 if (sdl->sdl_family == AF_LINK && 388 (rtm->rtm_flags & RTF_LLINFO) && 389 !(rtm->rtm_flags & RTF_GATEWAY)) { 390 switch (sdl->sdl_type) { 391 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 392 case IFT_ISO88024: case IFT_ISO88025: 393 goto overwrite; 394 } 395 } 396 /* 397 * IPv4 arp command retries with sin_other = SIN_PROXY here. 398 */ 399 (void)fprintf(stderr, "set: cannot configure a new entry\n"); 400 return 1; 401 } 402 403 overwrite: 404 if (sdl->sdl_family != AF_LINK) { 405 warnx("cannot intuit interface index and type for %s", host); 406 return (1); 407 } 408 sdl_m.sdl_type = sdl->sdl_type; 409 sdl_m.sdl_index = sdl->sdl_index; 410 return (rtmsg(RTM_ADD)); 411 } 412 413 /* 414 * Display an individual neighbor cache entry 415 */ 416 static void 417 get(char *host) 418 { 419 struct sockaddr_in6 *mysin = &sin_m; 420 struct addrinfo hints, *res; 421 int gai_error; 422 423 sin_m = blank_sin; 424 (void)memset(&hints, 0, sizeof(hints)); 425 hints.ai_family = AF_INET6; 426 gai_error = getaddrinfo(host, NULL, &hints, &res); 427 if (gai_error) { 428 warnx("%s: %s\n", host, gai_strerror(gai_error)); 429 return; 430 } 431 mysin->sin6_addr = ((struct sockaddr_in6 *)(void *)res->ai_addr)->sin6_addr; 432 #ifdef __KAME__ 433 if (IN6_IS_ADDR_LINKLOCAL(&mysin->sin6_addr)) { 434 *(u_int16_t *)(void *)&mysin->sin6_addr.s6_addr[2] = 435 htons(((struct sockaddr_in6 *)(void *)res->ai_addr)->sin6_scope_id); 436 } 437 #endif 438 dump(&mysin->sin6_addr, 0); 439 if (found_entry == 0) { 440 (void)getnameinfo((struct sockaddr *)(void *)mysin, 441 (socklen_t)mysin->sin6_len, 442 host_buf, sizeof(host_buf), NULL ,0, 443 (nflag ? NI_NUMERICHOST : 0)); 444 errx(1, "%s (%s) -- no entry", host, host_buf); 445 } 446 } 447 448 /* 449 * Delete a neighbor cache entry 450 */ 451 static int 452 delete(char *host) 453 { 454 struct sockaddr_in6 *mysin = &sin_m; 455 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 456 struct sockaddr_dl *sdl; 457 struct addrinfo hints, *res; 458 int gai_error; 459 460 getsocket(); 461 sin_m = blank_sin; 462 463 bzero(&hints, sizeof(hints)); 464 hints.ai_family = AF_INET6; 465 gai_error = getaddrinfo(host, NULL, &hints, &res); 466 if (gai_error) { 467 warnx("%s: %s\n", host, gai_strerror(gai_error)); 468 return 1; 469 } 470 mysin->sin6_addr = ((struct sockaddr_in6 *)(void *)res->ai_addr)->sin6_addr; 471 #ifdef __KAME__ 472 if (IN6_IS_ADDR_LINKLOCAL(&mysin->sin6_addr)) { 473 *(u_int16_t *)(void *)&mysin->sin6_addr.s6_addr[2] = 474 htons(((struct sockaddr_in6 *)(void *)res->ai_addr)->sin6_scope_id); 475 } 476 #endif 477 if (rtmsg(RTM_GET) < 0) 478 errx(1, "RTM_GET(%s) failed", host); 479 mysin = (struct sockaddr_in6 *)(void *)(rtm + 1); 480 sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(mysin->sin6_len) + 481 (char *)(void *)mysin); 482 if (IN6_ARE_ADDR_EQUAL(&mysin->sin6_addr, &sin_m.sin6_addr)) { 483 if (sdl->sdl_family == AF_LINK && 484 (rtm->rtm_flags & RTF_LLINFO) && 485 !(rtm->rtm_flags & RTF_GATEWAY)) { 486 goto delete; 487 } 488 /* 489 * IPv4 arp command retries with sin_other = SIN_PROXY here. 490 */ 491 warnx("delete: cannot delete non-NDP entry"); 492 return 1; 493 } 494 495 delete: 496 if (sdl->sdl_family != AF_LINK) { 497 (void)printf("cannot locate %s\n", host); 498 return (1); 499 } 500 if (rtmsg(RTM_DELETE) == 0) { 501 struct sockaddr_in6 s6 = *mysin; /* XXX: for safety */ 502 503 #ifdef __KAME__ 504 if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) { 505 s6.sin6_scope_id = ntohs(*(u_int16_t *)(void *)&s6.sin6_addr.s6_addr[2]); 506 *(u_int16_t *)(void *)&s6.sin6_addr.s6_addr[2] = 0; 507 } 508 #endif 509 (void)getnameinfo((struct sockaddr *)(void *)&s6, 510 (socklen_t)s6.sin6_len, host_buf, 511 sizeof(host_buf), NULL, 0, 512 (nflag ? NI_NUMERICHOST : 0)); 513 (void)printf("%s (%s) deleted\n", host, host_buf); 514 } 515 516 return 0; 517 } 518 519 #define W_ADDR 36 520 #define W_LL 17 521 #define W_IF 6 522 523 /* 524 * Dump the entire neighbor cache 525 */ 526 static void 527 dump(struct in6_addr *addr, int cflag) 528 { 529 int mib[6]; 530 size_t needed; 531 char *lim, *buf, *next; 532 struct rt_msghdr *rtm; 533 struct sockaddr_in6 *mysin; 534 struct sockaddr_dl *sdl; 535 struct in6_nbrinfo *nbi; 536 struct timeval tim; 537 int addrwidth; 538 int llwidth; 539 int ifwidth; 540 char flgbuf[8]; 541 const char *ifname; 542 543 /* Print header */ 544 if (!tflag && !cflag) 545 (void)printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %5s\n", 546 W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address", 547 W_IF, W_IF, "Netif", "Expire", "S", "Flags"); 548 549 again:; 550 mib[0] = CTL_NET; 551 mib[1] = PF_ROUTE; 552 mib[2] = 0; 553 mib[3] = AF_INET6; 554 mib[4] = NET_RT_FLAGS; 555 mib[5] = RTF_LLINFO; 556 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 557 err(1, "sysctl(PF_ROUTE estimate)"); 558 if (needed > 0) { 559 if ((buf = malloc(needed)) == NULL) 560 err(1, "malloc"); 561 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 562 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)"); 563 lim = buf + needed; 564 } else 565 buf = lim = NULL; 566 567 for (next = buf; next && next < lim; next += rtm->rtm_msglen) { 568 int isrouter = 0, prbs = 0; 569 570 rtm = (struct rt_msghdr *)(void *)next; 571 mysin = (struct sockaddr_in6 *)(void *)(rtm + 1); 572 sdl = (struct sockaddr_dl *)(void *)((char *)(void *)mysin + RT_ROUNDUP(mysin->sin6_len)); 573 574 /* 575 * Some OSes can produce a route that has the LINK flag but 576 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD 577 * and BSD/OS, where xx is not the interface identifier on 578 * lo0). Such routes entry would annoy getnbrinfo() below, 579 * so we skip them. 580 * XXX: such routes should have the GATEWAY flag, not the 581 * LINK flag. However, there is rotten routing software 582 * that advertises all routes that have the GATEWAY flag. 583 * Thus, KAME kernel intentionally does not set the LINK flag. 584 * What is to be fixed is not ndp, but such routing software 585 * (and the kernel workaround)... 586 */ 587 if (sdl->sdl_family != AF_LINK) 588 continue; 589 590 if (!(rtm->rtm_flags & RTF_HOST)) 591 continue; 592 593 if (addr) { 594 if (!IN6_ARE_ADDR_EQUAL(addr, &mysin->sin6_addr)) 595 continue; 596 found_entry = 1; 597 } else if (IN6_IS_ADDR_MULTICAST(&mysin->sin6_addr)) 598 continue; 599 if (IN6_IS_ADDR_LINKLOCAL(&mysin->sin6_addr) || 600 IN6_IS_ADDR_MC_LINKLOCAL(&mysin->sin6_addr)) { 601 /* XXX: should scope id be filled in the kernel? */ 602 if (mysin->sin6_scope_id == 0) 603 mysin->sin6_scope_id = sdl->sdl_index; 604 #ifdef __KAME__ 605 /* KAME specific hack; removed the embedded id */ 606 *(u_int16_t *)(void *)&mysin->sin6_addr.s6_addr[2] = 0; 607 #endif 608 } 609 (void)getnameinfo((struct sockaddr *)(void *)mysin, 610 (socklen_t)mysin->sin6_len, 611 host_buf, sizeof(host_buf), NULL, 0, 612 (nflag ? NI_NUMERICHOST : 0)); 613 if (cflag) { 614 #ifdef RTF_WASCLONED 615 if (rtm->rtm_flags & RTF_WASCLONED) 616 (void)delete(host_buf); 617 #elif defined(RTF_CLONED) 618 if (rtm->rtm_flags & RTF_CLONED) 619 (void)delete(host_buf); 620 #else 621 (void)delete(host_buf); 622 #endif 623 continue; 624 } 625 (void)gettimeofday(&tim, 0); 626 if (tflag) 627 ts_print(&tim); 628 629 addrwidth = strlen(host_buf); 630 if (addrwidth < W_ADDR) 631 addrwidth = W_ADDR; 632 llwidth = strlen(ether_str(sdl)); 633 if (W_ADDR + W_LL - addrwidth > llwidth) 634 llwidth = W_ADDR + W_LL - addrwidth; 635 ifname = if_indextoname((unsigned int)sdl->sdl_index, ifix_buf); 636 if (!ifname) 637 ifname = "?"; 638 ifwidth = strlen(ifname); 639 if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth) 640 ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth; 641 642 (void)printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, 643 host_buf, llwidth, llwidth, ether_str(sdl), ifwidth, 644 ifwidth, ifname); 645 646 /* Print neighbor discovery specific informations */ 647 nbi = getnbrinfo(&mysin->sin6_addr, 648 (unsigned int)sdl->sdl_index, 1); 649 if (nbi) { 650 if (nbi->expire > tim.tv_sec) { 651 (void)printf(" %-9.9s", 652 sec2str(nbi->expire - tim.tv_sec)); 653 } else if (nbi->expire == 0) 654 (void)printf(" %-9.9s", "permanent"); 655 else 656 (void)printf(" %-9.9s", "expired"); 657 658 switch (nbi->state) { 659 case ND6_LLINFO_NOSTATE: 660 (void)printf(" N"); 661 break; 662 #ifdef ND6_LLINFO_WAITDELETE 663 case ND6_LLINFO_WAITDELETE: 664 (void)printf(" W"); 665 break; 666 #endif 667 case ND6_LLINFO_INCOMPLETE: 668 (void)printf(" I"); 669 break; 670 case ND6_LLINFO_REACHABLE: 671 (void)printf(" R"); 672 break; 673 case ND6_LLINFO_STALE: 674 (void)printf(" S"); 675 break; 676 case ND6_LLINFO_DELAY: 677 (void)printf(" D"); 678 break; 679 case ND6_LLINFO_PROBE: 680 (void)printf(" P"); 681 break; 682 default: 683 (void)printf(" ?"); 684 break; 685 } 686 687 isrouter = nbi->isrouter; 688 prbs = nbi->asked; 689 } else { 690 warnx("failed to get neighbor information"); 691 (void)printf(" "); 692 } 693 694 /* 695 * other flags. R: router, P: proxy, W: ?? 696 */ 697 if ((rtm->rtm_addrs & RTA_NETMASK) == 0) { 698 (void)snprintf(flgbuf, sizeof(flgbuf), "%s%s", 699 isrouter ? "R" : "", 700 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 701 } else { 702 mysin = (struct sockaddr_in6 *)(void *) 703 (sdl->sdl_len + (char *)(void *)sdl); 704 #if 0 /* W and P are mystery even for us */ 705 (void)snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s", 706 isrouter ? "R" : "", 707 !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "P" : "", 708 (sin->sin6_len != sizeof(struct sockaddr_in6)) ? "W" : "", 709 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 710 #else 711 (void)snprintf(flgbuf, sizeof(flgbuf), "%s%s", 712 isrouter ? "R" : "", 713 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 714 #endif 715 } 716 (void)printf(" %s", flgbuf); 717 718 if (prbs) 719 (void)printf(" %d", prbs); 720 721 (void)printf("\n"); 722 } 723 if (buf != NULL) 724 free(buf); 725 726 if (repeat) { 727 (void)printf("\n"); 728 (void)fflush(stdout); 729 (void)sleep(repeat); 730 goto again; 731 } 732 } 733 734 static struct in6_nbrinfo * 735 getnbrinfo(struct in6_addr *addr, unsigned int ifindex, int warning) 736 { 737 static struct in6_nbrinfo nbi; 738 int s; 739 740 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 741 err(1, "socket"); 742 743 (void)memset(&nbi, 0, sizeof(nbi)); 744 (void)if_indextoname(ifindex, nbi.ifname); 745 nbi.addr = *addr; 746 if (ioctl(s, SIOCGNBRINFO_IN6, &nbi) < 0) { 747 if (warning) 748 warn("ioctl(SIOCGNBRINFO_IN6)"); 749 (void)close(s); 750 return(NULL); 751 } 752 753 (void)close(s); 754 return(&nbi); 755 } 756 757 static char * 758 ether_str(struct sockaddr_dl *sdl) 759 { 760 static char hbuf[NI_MAXHOST]; 761 762 if (sdl->sdl_alen) { 763 if (getnameinfo((struct sockaddr *)(void *)sdl, 764 (socklen_t)sdl->sdl_len, 765 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 766 (void)snprintf(hbuf, sizeof(hbuf), "<invalid>"); 767 } else 768 (void)snprintf(hbuf, sizeof(hbuf), "(incomplete)"); 769 770 return(hbuf); 771 } 772 773 static int 774 ndp_ether_aton(char *a, u_char *n) 775 { 776 int i, o[6]; 777 778 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 779 &o[3], &o[4], &o[5]); 780 if (i != 6) { 781 warnx("invalid Ethernet address '%s'", a); 782 return (1); 783 } 784 for (i = 0; i < 6; i++) 785 n[i] = o[i]; 786 return (0); 787 } 788 789 static void 790 usage(void) 791 { 792 const char *pn = getprogname(); 793 794 (void)fprintf(stderr, "Usage: %s [-nt] hostname\n", pn); 795 (void)fprintf(stderr, 796 " %s [-nt] -a | -c | -p | -r | -H | -P | -R\n", pn); 797 (void)fprintf(stderr, " %s [-nt] -A wait\n", pn); 798 (void)fprintf(stderr, " %s [-nt] -d hostname\n", pn); 799 (void)fprintf(stderr, " %s [-nt] -f filename\n", pn); 800 (void)fprintf(stderr, " %s [-nt] -i interface [flags...]\n", pn); 801 #ifdef SIOCSDEFIFACE_IN6 802 (void)fprintf(stderr, " %s [-nt] -I [interface|delete]\n", pn); 803 #endif 804 (void)fprintf(stderr, 805 " %s [-nt] -s nodename etheraddr [temp] [proxy]\n", pn); 806 exit(1); 807 } 808 809 static int 810 rtmsg(int cmd) 811 { 812 static int seq; 813 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 814 register char *cp = m_rtmsg.m_space; 815 register int l; 816 817 errno = 0; 818 if (cmd == RTM_DELETE) 819 goto doit; 820 (void)memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 821 rtm->rtm_flags = flags; 822 rtm->rtm_version = RTM_VERSION; 823 824 switch (cmd) { 825 default: 826 errx(1, "internal wrong cmd"); 827 /*NOTREACHED*/ 828 case RTM_ADD: 829 rtm->rtm_addrs |= RTA_GATEWAY; 830 if (expire_time) { 831 rtm->rtm_rmx.rmx_expire = expire_time; 832 rtm->rtm_inits = RTV_EXPIRE; 833 } 834 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); 835 #ifdef notdef /* we don't support ipv6addr/128 type proxying. */ 836 if (rtm->rtm_flags & RTF_ANNOUNCE) { 837 rtm->rtm_flags &= ~RTF_HOST; 838 rtm->rtm_addrs |= RTA_NETMASK; 839 } 840 #endif 841 /* FALLTHROUGH */ 842 case RTM_GET: 843 rtm->rtm_addrs |= RTA_DST; 844 } 845 #define NEXTADDR(w, s) \ 846 if (rtm->rtm_addrs & (w)) { \ 847 (void)memcpy(cp, &s, sizeof(s)); \ 848 RT_ADVANCE(cp, (struct sockaddr *)(void *)&s); \ 849 } 850 851 NEXTADDR(RTA_DST, sin_m); 852 NEXTADDR(RTA_GATEWAY, sdl_m); 853 #ifdef notdef /* we don't support ipv6addr/128 type proxying. */ 854 (void)memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr)); 855 NEXTADDR(RTA_NETMASK, so_mask); 856 #endif 857 858 rtm->rtm_msglen = cp - (char *)(void *)&m_rtmsg; 859 doit: 860 l = rtm->rtm_msglen; 861 rtm->rtm_seq = ++seq; 862 rtm->rtm_type = cmd; 863 if (write(my_s, &m_rtmsg, (size_t)l) == -1) { 864 if (errno != ESRCH || cmd != RTM_DELETE) 865 err(1, "writing to routing socket"); 866 } 867 do { 868 l = read(my_s, &m_rtmsg, sizeof(m_rtmsg)); 869 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 870 if (l < 0) 871 warn("read from routing socket"); 872 return (0); 873 } 874 875 static void 876 ifinfo(char *ifname, int argc, char **argv) 877 { 878 struct in6_ndireq nd; 879 int i, s; 880 u_int32_t newflags; 881 #ifdef IPV6CTL_USETEMPADDR 882 u_int8_t nullbuf[8]; 883 #endif 884 885 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 886 err(1, "socket"); 887 (void)memset(&nd, 0, sizeof(nd)); 888 (void)strlcpy(nd.ifname, ifname, sizeof(nd.ifname)); 889 if (ioctl(s, SIOCGIFINFO_IN6, &nd) < 0) 890 err(1, "ioctl(SIOCGIFINFO_IN6)"); 891 #define ND nd.ndi 892 newflags = ND.flags; 893 for (i = 0; i < argc; i++) { 894 int clear = 0; 895 char *cp = argv[i]; 896 897 if (*cp == '-') { 898 clear = 1; 899 cp++; 900 } 901 902 #define SETFLAG(s, f) \ 903 do {\ 904 if (strcmp(cp, (s)) == 0) {\ 905 if (clear)\ 906 newflags &= ~(f);\ 907 else\ 908 newflags |= (f);\ 909 }\ 910 } while (/*CONSTCOND*/0) 911 /* 912 * XXX: this macro is not 100% correct, in that it matches "nud" against 913 * "nudbogus". But we just let it go since this is minor. 914 */ 915 #define SETVALUE(f, v) \ 916 do { \ 917 char *valptr; \ 918 unsigned long newval; \ 919 v = 0; /* unspecified */ \ 920 if (strncmp(cp, f, strlen(f)) == 0) { \ 921 valptr = strchr(cp, '='); \ 922 if (valptr == NULL) \ 923 err(1, "syntax error in %s field", (f)); \ 924 errno = 0; \ 925 newval = strtoul(++valptr, NULL, 0); \ 926 if (errno) \ 927 err(1, "syntax error in %s's value", (f)); \ 928 v = newval; \ 929 } \ 930 } while (/*CONSTCOND*/0) 931 932 #ifdef ND6_IFF_IFDISABLED 933 SETFLAG("disabled", ND6_IFF_IFDISABLED); 934 #endif 935 SETFLAG("nud", ND6_IFF_PERFORMNUD); 936 #ifdef ND6_IFF_ACCEPT_RTADV 937 SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV); 938 #endif 939 #ifdef ND6_IFF_OVERRIDE_RTADV 940 SETFLAG("override_rtadv", ND6_IFF_OVERRIDE_RTADV); 941 #endif 942 #ifdef ND6_IFF_PREFER_SOURCE 943 SETFLAG("prefer_source", ND6_IFF_PREFER_SOURCE); 944 #endif 945 #ifdef ND6_IFF_DONT_SET_IFROUTE 946 SETFLAG("dont_set_ifroute", ND6_IFF_DONT_SET_IFROUTE); 947 #endif 948 SETVALUE("basereachable", ND.basereachable); 949 SETVALUE("retrans", ND.retrans); 950 SETVALUE("curhlim", ND.chlim); 951 952 ND.flags = newflags; 953 #ifdef SIOCSIFINFO_IN6 954 if (ioctl(s, SIOCSIFINFO_IN6, &nd) < 0) 955 err(1, "ioctl(SIOCSIFINFO_IN6)"); 956 #else 957 if (ioctl(s, SIOCSIFINFO_FLAGS, &nd) < 0) 958 err(1, "ioctl(SIOCSIFINFO_FLAGS)"); 959 #endif 960 #undef SETFLAG 961 #undef SETVALUE 962 } 963 964 if (!ND.initialized) 965 errx(1, "%s: not initialized yet", ifname); 966 967 if (ioctl(s, SIOCGIFINFO_IN6, &nd) < 0) 968 err(1, "ioctl(SIOCGIFINFO_IN6)"); 969 (void)printf("linkmtu=%d", ND.linkmtu); 970 (void)printf(", maxmtu=%d", ND.maxmtu); 971 (void)printf(", curhlim=%d", ND.chlim); 972 (void)printf(", basereachable=%ds%dms", 973 ND.basereachable / 1000, ND.basereachable % 1000); 974 (void)printf(", reachable=%ds", ND.reachable); 975 (void)printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000); 976 #ifdef IPV6CTL_USETEMPADDR 977 (void)memset(nullbuf, 0, sizeof(nullbuf)); 978 if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) { 979 int j; 980 u_int8_t *rbuf; 981 982 for (i = 0; i < 3; i++) { 983 switch (i) { 984 case 0: 985 (void)printf("\nRandom seed(0): "); 986 rbuf = ND.randomseed0; 987 break; 988 case 1: 989 (void)printf("\nRandom seed(1): "); 990 rbuf = ND.randomseed1; 991 break; 992 case 2: 993 (void)printf("\nRandom ID: "); 994 rbuf = ND.randomid; 995 break; 996 default: 997 errx(1, "impossible case for tempaddr display"); 998 } 999 for (j = 0; j < 8; j++) 1000 (void)printf("%02x", rbuf[j]); 1001 } 1002 } 1003 #endif 1004 if (ND.flags) { 1005 (void)printf("\nFlags: "); 1006 if ((ND.flags & ND6_IFF_PERFORMNUD)) 1007 (void)printf("nud "); 1008 #ifdef ND6_IFF_IFDISABLED 1009 if ((ND.flags & ND6_IFF_IFDISABLED)) 1010 (void)printf("disabled "); 1011 #endif 1012 #ifdef ND6_IFF_ACCEPT_RTADV 1013 if ((ND.flags & ND6_IFF_ACCEPT_RTADV)) 1014 (void)printf("accept_rtadv "); 1015 #endif 1016 #ifdef ND6_IFF_OVERRIDE_RTADV 1017 if ((ND.flags & ND6_IFF_OVERRIDE_RTADV)) 1018 (void)printf("override_rtadv "); 1019 #endif 1020 #ifdef ND6_IFF_PREFER_SOURCE 1021 if ((ND.flags & ND6_IFF_PREFER_SOURCE)) 1022 (void)printf("prefer_source "); 1023 #endif 1024 } 1025 (void)putc('\n', stdout); 1026 #undef ND 1027 1028 (void)close(s); 1029 } 1030 1031 #ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */ 1032 #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 1033 #endif 1034 1035 static void 1036 rtrlist(void) 1037 { 1038 #ifdef ICMPV6CTL_ND6_DRLIST 1039 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST }; 1040 char *buf; 1041 struct in6_defrouter *p, *ep; 1042 size_t l; 1043 struct timeval tim; 1044 1045 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { 1046 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); 1047 /*NOTREACHED*/ 1048 } 1049 if (l == 0) 1050 return; 1051 buf = malloc(l); 1052 if (!buf) { 1053 err(1, "malloc"); 1054 /*NOTREACHED*/ 1055 } 1056 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 1057 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); 1058 /*NOTREACHED*/ 1059 } 1060 1061 ep = (struct in6_defrouter *)(void *)(buf + l); 1062 for (p = (struct in6_defrouter *)(void *)buf; p < ep; p++) { 1063 int rtpref; 1064 1065 if (getnameinfo((struct sockaddr *)(void *)&p->rtaddr, 1066 (socklen_t)p->rtaddr.sin6_len, host_buf, sizeof(host_buf), 1067 NULL, 0, (nflag ? NI_NUMERICHOST : 0)) != 0) 1068 (void)strlcpy(host_buf, "?", sizeof(host_buf)); 1069 1070 (void)printf("%s if=%s", host_buf, 1071 if_indextoname((unsigned int)p->if_index, ifix_buf)); 1072 (void)printf(", flags=%s%s", 1073 p->flags & ND_RA_FLAG_MANAGED ? "M" : "", 1074 p->flags & ND_RA_FLAG_OTHER ? "O" : ""); 1075 rtpref = ((uint32_t)(p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff; 1076 (void)printf(", pref=%s", rtpref_str[rtpref]); 1077 1078 (void)gettimeofday(&tim, 0); 1079 if (p->expire == 0) 1080 (void)printf(", expire=Never\n"); 1081 else 1082 (void)printf(", expire=%s\n", 1083 sec2str((time_t)(p->expire - tim.tv_sec))); 1084 } 1085 free(buf); 1086 #else 1087 struct in6_drlist dr; 1088 int s, i; 1089 struct timeval time; 1090 1091 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1092 err(1, "socket"); 1093 /* NOTREACHED */ 1094 } 1095 (void)memset(&dr, 0, sizeof(dr)); 1096 (void)strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */ 1097 if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 1098 err(1, "ioctl(SIOCGDRLST_IN6)"); 1099 /* NOTREACHED */ 1100 } 1101 #define DR dr.defrouter[i] 1102 for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) { 1103 struct sockaddr_in6 sin6; 1104 1105 (void)memset(&sin6, 0, sizeof(sin6)); 1106 sin6.sin6_family = AF_INET6; 1107 sin6.sin6_len = sizeof(sin6); 1108 sin6.sin6_addr = DR.rtaddr; 1109 (void)getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, 1110 host_buf, sizeof(host_buf), NULL, 0, 1111 (nflag ? NI_NUMERICHOST : 0)); 1112 1113 (void)printf("%s if=%s", host_buf, 1114 if_indextoname(DR.if_index, ifix_buf)); 1115 (void)printf(", flags=%s%s", 1116 DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", 1117 DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); 1118 gettimeofday(&time, 0); 1119 if (DR.expire == 0) 1120 (void)printf(", expire=Never\n"); 1121 else 1122 (void)printf(", expire=%s\n", 1123 sec2str(DR.expire - time.tv_sec)); 1124 } 1125 #undef DR 1126 (void)close(s); 1127 #endif 1128 } 1129 1130 static void 1131 plist(void) 1132 { 1133 #ifdef ICMPV6CTL_ND6_PRLIST 1134 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST }; 1135 char *buf; 1136 struct in6_prefix *p, *ep, *n; 1137 struct sockaddr_in6 *advrtr; 1138 size_t l; 1139 struct timeval tim; 1140 const int niflags = NI_NUMERICHOST; 1141 int ninflags = nflag ? NI_NUMERICHOST : 0; 1142 char namebuf[NI_MAXHOST]; 1143 1144 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { 1145 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); 1146 /*NOTREACHED*/ 1147 } 1148 buf = malloc(l); 1149 if (!buf) { 1150 err(1, "malloc"); 1151 /*NOTREACHED*/ 1152 } 1153 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 1154 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); 1155 /*NOTREACHED*/ 1156 } 1157 1158 ep = (struct in6_prefix *)(void *)(buf + l); 1159 for (p = (struct in6_prefix *)(void *)buf; p < ep; p = n) { 1160 advrtr = (struct sockaddr_in6 *)(void *)(p + 1); 1161 n = (struct in6_prefix *)(void *)&advrtr[p->advrtrs]; 1162 1163 if (getnameinfo((struct sockaddr *)(void *)&p->prefix, 1164 (socklen_t)p->prefix.sin6_len, namebuf, sizeof(namebuf), 1165 NULL, 0, niflags) != 0) 1166 (void)strlcpy(namebuf, "?", sizeof(namebuf)); 1167 (void)printf("%s/%d if=%s\n", namebuf, p->prefixlen, 1168 if_indextoname((unsigned int)p->if_index, ifix_buf)); 1169 1170 (void)gettimeofday(&tim, 0); 1171 /* 1172 * meaning of fields, especially flags, is very different 1173 * by origin. notify the difference to the users. 1174 */ 1175 (void)printf("flags=%s%s%s%s%s", 1176 p->raflags.onlink ? "L" : "", 1177 p->raflags.autonomous ? "A" : "", 1178 (p->flags & NDPRF_ONLINK) != 0 ? "O" : "", 1179 (p->flags & NDPRF_DETACHED) != 0 ? "D" : "", 1180 #ifdef NDPRF_HOME 1181 (p->flags & NDPRF_HOME) != 0 ? "H" : "" 1182 #else 1183 "" 1184 #endif 1185 ); 1186 if (p->vltime == ND6_INFINITE_LIFETIME) 1187 (void)printf(" vltime=infinity"); 1188 else 1189 (void)printf(" vltime=%lu", (unsigned long)p->vltime); 1190 if (p->pltime == ND6_INFINITE_LIFETIME) 1191 (void)printf(", pltime=infinity"); 1192 else 1193 (void)printf(", pltime=%lu", (unsigned long)p->pltime); 1194 if (p->expire == 0) 1195 (void)printf(", expire=Never"); 1196 else if (p->expire >= tim.tv_sec) 1197 (void)printf(", expire=%s", 1198 sec2str(p->expire - tim.tv_sec)); 1199 else 1200 (void)printf(", expired"); 1201 (void)printf(", ref=%d", p->refcnt); 1202 (void)printf("\n"); 1203 /* 1204 * "advertising router" list is meaningful only if the prefix 1205 * information is from RA. 1206 */ 1207 if (p->advrtrs) { 1208 int j; 1209 struct sockaddr_in6 *sin6; 1210 1211 sin6 = advrtr; 1212 (void)printf(" advertised by\n"); 1213 for (j = 0; j < p->advrtrs; j++) { 1214 struct in6_nbrinfo *nbi; 1215 1216 if (getnameinfo((struct sockaddr *)(void *)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)p->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 sin6++; 1238 } 1239 } else 1240 (void)printf(" No advertising router\n"); 1241 } 1242 free(buf); 1243 #else 1244 struct in6_prlist pr; 1245 int s, i; 1246 struct timeval time; 1247 1248 (void)gettimeofday(&time, 0); 1249 1250 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1251 err(1, "socket"); 1252 /* NOTREACHED */ 1253 } 1254 (void)memset(&pr, 0, sizeof(pr)); 1255 (void)strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */ 1256 if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { 1257 err(1, "ioctl(SIOCGPRLST_IN6)"); 1258 /* NOTREACHED */ 1259 } 1260 #define PR pr.prefix[i] 1261 for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { 1262 struct sockaddr_in6 p6; 1263 char namebuf[NI_MAXHOST]; 1264 int niflags; 1265 1266 #ifdef NDPRF_ONLINK 1267 p6 = PR.prefix; 1268 #else 1269 (void)memset(&p6, 0, sizeof(p6)); 1270 p6.sin6_family = AF_INET6; 1271 p6.sin6_len = sizeof(p6); 1272 p6.sin6_addr = PR.prefix; 1273 #endif 1274 1275 niflags = NI_NUMERICHOST; 1276 if (getnameinfo((struct sockaddr *)&p6, 1277 sizeof(p6), namebuf, sizeof(namebuf), 1278 NULL, 0, niflags)) { 1279 warnx("getnameinfo failed"); 1280 continue; 1281 } 1282 (void)printf("%s/%d if=%s\n", namebuf, PR.prefixlen, 1283 if_indextoname(PR.if_index, ifix_buf)); 1284 1285 (void)gettimeofday(&time, 0); 1286 /* 1287 * meaning of fields, especially flags, is very different 1288 * by origin. notify the difference to the users. 1289 */ 1290 #if 0 1291 (void)printf(" %s", 1292 PR.origin == PR_ORIG_RA ? "" : "advertise: "); 1293 #endif 1294 #ifdef NDPRF_ONLINK 1295 (void)printf("flags=%s%s%s%s%s", 1296 PR.raflags.onlink ? "L" : "", 1297 PR.raflags.autonomous ? "A" : "", 1298 (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "", 1299 (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "", 1300 #ifdef NDPRF_HOME 1301 (PR.flags & NDPRF_HOME) != 0 ? "H" : "" 1302 #else 1303 "" 1304 #endif 1305 ); 1306 #else 1307 (void)printf("flags=%s%s", 1308 PR.raflags.onlink ? "L" : "", 1309 PR.raflags.autonomous ? "A" : ""); 1310 #endif 1311 if (PR.vltime == ND6_INFINITE_LIFETIME) 1312 (void)printf(" vltime=infinity"); 1313 else 1314 (void)printf(" vltime=%lu", PR.vltime); 1315 if (PR.pltime == ND6_INFINITE_LIFETIME) 1316 (void)printf(", pltime=infinity"); 1317 else 1318 (void)printf(", pltime=%lu", PR.pltime); 1319 if (PR.expire == 0) 1320 (void)printf(", expire=Never"); 1321 else if (PR.expire >= time.tv_sec) 1322 (void)printf(", expire=%s", 1323 sec2str(PR.expire - time.tv_sec)); 1324 else 1325 (void)printf(", expired"); 1326 #ifdef NDPRF_ONLINK 1327 (void)printf(", ref=%d", PR.refcnt); 1328 #endif 1329 #if 0 1330 switch (PR.origin) { 1331 case PR_ORIG_RA: 1332 (void)printf(", origin=RA"); 1333 break; 1334 case PR_ORIG_RR: 1335 (void)printf(", origin=RR"); 1336 break; 1337 case PR_ORIG_STATIC: 1338 (void)printf(", origin=static"); 1339 break; 1340 case PR_ORIG_KERNEL: 1341 (void)printf(", origin=kernel"); 1342 break; 1343 default: 1344 (void)printf(", origin=?"); 1345 break; 1346 } 1347 #endif 1348 (void)printf("\n"); 1349 /* 1350 * "advertising router" list is meaningful only if the prefix 1351 * information is from RA. 1352 */ 1353 if (0 && /* prefix origin is almost obsolted */ 1354 PR.origin != PR_ORIG_RA) 1355 ; 1356 else if (PR.advrtrs) { 1357 int j; 1358 (void)printf(" advertised by\n"); 1359 for (j = 0; j < PR.advrtrs; j++) { 1360 struct sockaddr_in6 sin6; 1361 struct in6_nbrinfo *nbi; 1362 1363 bzero(&sin6, sizeof(sin6)); 1364 sin6.sin6_family = AF_INET6; 1365 sin6.sin6_len = sizeof(sin6); 1366 sin6.sin6_addr = PR.advrtr[j]; 1367 sin6.sin6_scope_id = PR.if_index; /* XXX */ 1368 (void)getnameinfo((struct sockaddr *)&sin6, 1369 sin6.sin6_len, host_buf, 1370 sizeof(host_buf), NULL, 0, 1371 (nflag ? NI_NUMERICHOST : 0)); 1372 (void)printf(" %s", host_buf); 1373 1374 nbi = getnbrinfo(&sin6.sin6_addr, 1375 PR.if_index, 0); 1376 if (nbi) { 1377 switch (nbi->state) { 1378 case ND6_LLINFO_REACHABLE: 1379 case ND6_LLINFO_STALE: 1380 case ND6_LLINFO_DELAY: 1381 case ND6_LLINFO_PROBE: 1382 (void)printf(" (reachable)\n"); 1383 break; 1384 default: 1385 (void)printf(" (unreachable)\n"); 1386 } 1387 } else 1388 (void)printf(" (no neighbor state)\n"); 1389 } 1390 if (PR.advrtrs > DRLSTSIZ) 1391 (void)printf(" and %d routers\n", 1392 PR.advrtrs - DRLSTSIZ); 1393 } else 1394 (void)printf(" No advertising router\n"); 1395 } 1396 #undef PR 1397 (void)close(s); 1398 #endif 1399 } 1400 1401 static void 1402 pfx_flush(void) 1403 { 1404 char dummyif[IFNAMSIZ+8]; 1405 int s; 1406 1407 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1408 err(1, "socket"); 1409 (void)strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 1410 if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0) 1411 err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); 1412 (void)close(s); 1413 } 1414 1415 static void 1416 rtr_flush(void) 1417 { 1418 char dummyif[IFNAMSIZ+8]; 1419 int s; 1420 1421 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1422 err(1, "socket"); 1423 (void)strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 1424 if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0) 1425 err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); 1426 1427 (void)close(s); 1428 } 1429 1430 static void 1431 harmonize_rtr(void) 1432 { 1433 char dummyif[IFNAMSIZ+8]; 1434 int s; 1435 1436 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1437 err(1, "socket"); 1438 (void)strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 1439 if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) 1440 err(1, "ioctl(SIOCSNDFLUSH_IN6)"); 1441 1442 (void)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 = 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 (ioctl(s, SIOCSDEFIFACE_IN6, &ndifreq) < 0) 1467 err(1, "ioctl(SIOCSDEFIFACE_IN6)"); 1468 1469 (void)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 = 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 (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)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