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