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 #ifdef ND6_IFF_AUTO_LINKLOCAL 954 SETFLAG("auto_linklocal", ND6_IFF_AUTO_LINKLOCAL); 955 #endif 956 ND.flags = newflags; 957 if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) { 958 perror("ioctl(SIOCSIFINFO_FLAGS)"); 959 exit(1); 960 } 961 #undef SETFLAG 962 } 963 964 printf("linkmtu=%d", ND.linkmtu); 965 printf(", curhlim=%d", ND.chlim); 966 printf(", basereachable=%ds%dms", 967 ND.basereachable / 1000, ND.basereachable % 1000); 968 printf(", reachable=%ds", ND.reachable); 969 printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000); 970 #ifdef IPV6CTL_USETEMPADDR 971 memset(nullbuf, 0, sizeof(nullbuf)); 972 if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) { 973 int j; 974 u_int8_t *rbuf; 975 976 for (i = 0; i < 3; i++) { 977 switch(i) { 978 case 0: 979 printf("\nRandom seed(0): "); 980 rbuf = ND.randomseed0; 981 break; 982 case 1: 983 printf("\nRandom seed(1): "); 984 rbuf = ND.randomseed1; 985 break; 986 case 2: 987 printf("\nRandom ID: "); 988 rbuf = ND.randomid; 989 break; 990 } 991 for (j = 0; j < 8; j++) 992 printf("%02x", rbuf[j]); 993 } 994 } 995 #endif 996 if (ND.flags) { 997 printf("\nFlags: "); 998 if ((ND.flags & ND6_IFF_PERFORMNUD)) 999 printf("nud "); 1000 #ifdef ND6_IFF_ACCEPT_RTADV 1001 if ((ND.flags & ND6_IFF_ACCEPT_RTADV)) 1002 printf("accept_rtadv "); 1003 #endif 1004 #ifdef ND6_IFF_AUTO_LINKLOCAL 1005 if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL)) 1006 printf("auto_linklocal "); 1007 #endif 1008 } 1009 putc('\n', stdout); 1010 #undef ND 1011 1012 close(s); 1013 } 1014 1015 #ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */ 1016 #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 1017 #endif 1018 1019 void 1020 rtrlist(void) 1021 { 1022 #ifdef ICMPV6CTL_ND6_DRLIST 1023 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST }; 1024 char *buf; 1025 struct in6_defrouter *p, *ep; 1026 size_t l; 1027 struct timeval time; 1028 1029 if (sysctl(mib, NELEM(mib), NULL, &l, NULL, 0) < 0) { 1030 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); 1031 /*NOTREACHED*/ 1032 } 1033 buf = malloc(l); 1034 if (!buf) { 1035 errx(1, "not enough core"); 1036 /*NOTREACHED*/ 1037 } 1038 if (sysctl(mib, NELEM(mib), buf, &l, NULL, 0) < 0) { 1039 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); 1040 /*NOTREACHED*/ 1041 } 1042 1043 ep = (struct in6_defrouter *)(buf + l); 1044 for (p = (struct in6_defrouter *)buf; p < ep; p++) { 1045 int rtpref; 1046 1047 if (getnameinfo((struct sockaddr *)&p->rtaddr, 1048 p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0, 1049 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)) != 0) 1050 strlcpy(host_buf, "?", sizeof(host_buf)); 1051 1052 printf("%s if=%s", host_buf, 1053 if_indextoname(p->if_index, ifix_buf)); 1054 printf(", flags=%s%s", 1055 p->flags & ND_RA_FLAG_MANAGED ? "M" : "", 1056 p->flags & ND_RA_FLAG_OTHER ? "O" : ""); 1057 rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff; 1058 printf(", pref=%s", rtpref_str[rtpref]); 1059 1060 gettimeofday(&time, 0); 1061 if (p->expire == 0) 1062 printf(", expire=Never\n"); 1063 else 1064 printf(", expire=%s\n", 1065 sec2str(p->expire - time.tv_sec)); 1066 } 1067 free(buf); 1068 #else 1069 struct in6_drlist dr; 1070 int s, i; 1071 struct timeval time; 1072 1073 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1074 perror("ndp: socket"); 1075 exit(1); 1076 } 1077 bzero(&dr, sizeof(dr)); 1078 strcpy(dr.ifname, "lo0"); /* dummy */ 1079 if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 1080 perror("ioctl (SIOCGDRLST_IN6)"); 1081 exit(1); 1082 } 1083 #define DR dr.defrouter[i] 1084 for (i = 0 ; i < DRLSTSIZ && DR.if_index ; i++) { 1085 struct sockaddr_in6 sin6; 1086 1087 bzero(&sin6, sizeof(sin6)); 1088 sin6.sin6_family = AF_INET6; 1089 sin6.sin6_len = sizeof(sin6); 1090 sin6.sin6_addr = DR.rtaddr; 1091 getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf, 1092 sizeof(host_buf), NULL, 0, 1093 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 1094 1095 printf("%s if=%s", host_buf, 1096 if_indextoname(DR.if_index, ifix_buf)); 1097 printf(", flags=%s%s", 1098 DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", 1099 DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); 1100 gettimeofday(&time, 0); 1101 if (DR.expire == 0) 1102 printf(", expire=Never\n"); 1103 else 1104 printf(", expire=%s\n", 1105 sec2str(DR.expire - time.tv_sec)); 1106 } 1107 #undef DR 1108 close(s); 1109 #endif 1110 } 1111 1112 void 1113 plist(void) 1114 { 1115 #ifdef ICMPV6CTL_ND6_PRLIST 1116 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST }; 1117 char *buf; 1118 struct in6_prefix *p, *ep, *n; 1119 struct sockaddr_in6 *advrtr; 1120 size_t l; 1121 struct timeval time; 1122 #ifdef NI_WITHSCOPEID 1123 const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; 1124 int ninflags = (nflag ? NI_NUMERICHOST : 0) | NI_WITHSCOPEID; 1125 #else 1126 const int niflags = NI_NUMERICHOST; 1127 int ninflags = nflag ? NI_NUMERICHOST : 0; 1128 #endif 1129 char namebuf[NI_MAXHOST]; 1130 1131 if (sysctl(mib, NELEM(mib), NULL, &l, NULL, 0) < 0) { 1132 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); 1133 /*NOTREACHED*/ 1134 } 1135 buf = malloc(l); 1136 if (!buf) { 1137 errx(1, "not enough core"); 1138 /*NOTREACHED*/ 1139 } 1140 if (sysctl(mib, NELEM(mib), buf, &l, NULL, 0) < 0) { 1141 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); 1142 /*NOTREACHED*/ 1143 } 1144 1145 ep = (struct in6_prefix *)(buf + l); 1146 for (p = (struct in6_prefix *)buf; p < ep; p = n) { 1147 advrtr = (struct sockaddr_in6 *)(p + 1); 1148 n = (struct in6_prefix *)&advrtr[p->advrtrs]; 1149 1150 if (getnameinfo((struct sockaddr *)&p->prefix, 1151 p->prefix.sin6_len, namebuf, sizeof(namebuf), 1152 NULL, 0, niflags) != 0) 1153 strlcpy(namebuf, "?", sizeof(namebuf)); 1154 printf("%s/%d if=%s\n", namebuf, p->prefixlen, 1155 if_indextoname(p->if_index, ifix_buf)); 1156 1157 gettimeofday(&time, 0); 1158 /* 1159 * meaning of fields, especially flags, is very different 1160 * by origin. notify the difference to the users. 1161 */ 1162 printf("flags=%s%s%s%s%s", 1163 p->raflags.onlink ? "L" : "", 1164 p->raflags.autonomous ? "A" : "", 1165 (p->flags & NDPRF_ONLINK) != 0 ? "O" : "", 1166 (p->flags & NDPRF_DETACHED) != 0 ? "D" : "", 1167 #ifdef NDPRF_HOME 1168 (p->flags & NDPRF_HOME) != 0 ? "H" : "" 1169 #else 1170 "" 1171 #endif 1172 ); 1173 if (p->vltime == ND6_INFINITE_LIFETIME) 1174 printf(" vltime=infinity"); 1175 else 1176 printf(" vltime=%ld", (long)p->vltime); 1177 if (p->pltime == ND6_INFINITE_LIFETIME) 1178 printf(", pltime=infinity"); 1179 else 1180 printf(", pltime=%ld", (long)p->pltime); 1181 if (p->expire == 0) 1182 printf(", expire=Never"); 1183 else if (p->expire >= time.tv_sec) 1184 printf(", expire=%s", 1185 sec2str(p->expire - time.tv_sec)); 1186 else 1187 printf(", expired"); 1188 printf(", ref=%d", p->refcnt); 1189 printf("\n"); 1190 /* 1191 * "advertising router" list is meaningful only if the prefix 1192 * information is from RA. 1193 */ 1194 if (p->advrtrs) { 1195 int j; 1196 struct sockaddr_in6 *sin6; 1197 1198 sin6 = (struct sockaddr_in6 *)(p + 1); 1199 printf(" advertised by\n"); 1200 for (j = 0; j < p->advrtrs; j++) { 1201 struct in6_nbrinfo *nbi; 1202 1203 if (getnameinfo((struct sockaddr *)sin6, 1204 sin6->sin6_len, namebuf, sizeof(namebuf), 1205 NULL, 0, ninflags) != 0) 1206 strlcpy(namebuf, "?", sizeof(namebuf)); 1207 printf(" %s", namebuf); 1208 1209 nbi = getnbrinfo(&sin6->sin6_addr, p->if_index, 1210 0); 1211 if (nbi) { 1212 switch(nbi->state) { 1213 case ND6_LLINFO_REACHABLE: 1214 case ND6_LLINFO_STALE: 1215 case ND6_LLINFO_DELAY: 1216 case ND6_LLINFO_PROBE: 1217 printf(" (reachable)\n"); 1218 break; 1219 default: 1220 printf(" (unreachable)\n"); 1221 } 1222 } else 1223 printf(" (no neighbor state)\n"); 1224 sin6++; 1225 } 1226 } else 1227 printf(" No advertising router\n"); 1228 } 1229 free(buf); 1230 #else 1231 struct in6_prlist pr; 1232 int s, i; 1233 struct timeval time; 1234 1235 gettimeofday(&time, 0); 1236 1237 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1238 perror("ndp: socket"); 1239 exit(1); 1240 } 1241 bzero(&pr, sizeof(pr)); 1242 strcpy(pr.ifname, "lo0"); /* dummy */ 1243 if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { 1244 perror("ioctl (SIOCGPRLST_IN6)"); 1245 exit(1); 1246 } 1247 #define PR pr.prefix[i] 1248 for (i = 0; i < PRLSTSIZ && PR.if_index ; i++) { 1249 struct sockaddr_in6 p6; 1250 char namebuf[NI_MAXHOST]; 1251 int niflags; 1252 1253 #ifdef NDPRF_ONLINK 1254 p6 = PR.prefix; 1255 #else 1256 memset(&p6, 0, sizeof(p6)); 1257 p6.sin6_family = AF_INET6; 1258 p6.sin6_len = sizeof(p6); 1259 p6.sin6_addr = PR.prefix; 1260 #endif 1261 1262 /* 1263 * copy link index to sin6_scope_id field. 1264 * XXX: KAME specific. 1265 */ 1266 if (IN6_IS_ADDR_LINKLOCAL(&p6.sin6_addr)) { 1267 u_int16_t linkid; 1268 1269 memcpy(&linkid, &p6.sin6_addr.s6_addr[2], 1270 sizeof(linkid)); 1271 linkid = ntohs(linkid); 1272 p6.sin6_scope_id = linkid; 1273 p6.sin6_addr.s6_addr[2] = 0; 1274 p6.sin6_addr.s6_addr[3] = 0; 1275 } 1276 1277 niflags = NI_NUMERICHOST; 1278 #ifdef __KAME__ 1279 niflags |= NI_WITHSCOPEID; 1280 #endif 1281 if (getnameinfo((struct sockaddr *)&p6, 1282 sizeof(p6), namebuf, sizeof(namebuf), 1283 NULL, 0, niflags)) { 1284 warnx("getnameinfo failed"); 1285 continue; 1286 } 1287 printf("%s/%d if=%s\n", namebuf, PR.prefixlen, 1288 if_indextoname(PR.if_index, ifix_buf)); 1289 1290 gettimeofday(&time, 0); 1291 /* 1292 * meaning of fields, especially flags, is very different 1293 * by origin. notify the difference to the users. 1294 */ 1295 #if 0 1296 printf(" %s", 1297 PR.origin == PR_ORIG_RA ? "" : "advertise: "); 1298 #endif 1299 #ifdef NDPRF_ONLINK 1300 printf("flags=%s%s%s%s%s", 1301 PR.raflags.onlink ? "L" : "", 1302 PR.raflags.autonomous ? "A" : "", 1303 (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "", 1304 (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "", 1305 #ifdef NDPRF_HOME 1306 (PR.flags & NDPRF_HOME) != 0 ? "H" : "" 1307 #else 1308 "" 1309 #endif 1310 ); 1311 #else 1312 printf("flags=%s%s", 1313 PR.raflags.onlink ? "L" : "", 1314 PR.raflags.autonomous ? "A" : ""); 1315 #endif 1316 if (PR.vltime == ND6_INFINITE_LIFETIME) 1317 printf(" vltime=infinity"); 1318 else 1319 printf(" vltime=%ld", (long)PR.vltime); 1320 if (PR.pltime == ND6_INFINITE_LIFETIME) 1321 printf(", pltime=infinity"); 1322 else 1323 printf(", pltime=%ld", (long)PR.pltime); 1324 if (PR.expire == 0) 1325 printf(", expire=Never"); 1326 else if (PR.expire >= time.tv_sec) 1327 printf(", expire=%s", 1328 sec2str(PR.expire - time.tv_sec)); 1329 else 1330 printf(", expired"); 1331 #ifdef NDPRF_ONLINK 1332 printf(", ref=%d", PR.refcnt); 1333 #endif 1334 #if 0 1335 switch (PR.origin) { 1336 case PR_ORIG_RA: 1337 printf(", origin=RA"); 1338 break; 1339 case PR_ORIG_RR: 1340 printf(", origin=RR"); 1341 break; 1342 case PR_ORIG_STATIC: 1343 printf(", origin=static"); 1344 break; 1345 case PR_ORIG_KERNEL: 1346 printf(", origin=kernel"); 1347 break; 1348 default: 1349 printf(", origin=?"); 1350 break; 1351 } 1352 #endif 1353 printf("\n"); 1354 /* 1355 * "advertising router" list is meaningful only if the prefix 1356 * information is from RA. 1357 */ 1358 if (0 && /* prefix origin is almost obsolted */ 1359 PR.origin != PR_ORIG_RA) 1360 ; 1361 else if (PR.advrtrs) { 1362 int j; 1363 printf(" advertised by\n"); 1364 for (j = 0; j < PR.advrtrs; j++) { 1365 struct sockaddr_in6 sin6; 1366 struct in6_nbrinfo *nbi; 1367 1368 bzero(&sin6, sizeof(sin6)); 1369 sin6.sin6_family = AF_INET6; 1370 sin6.sin6_len = sizeof(sin6); 1371 sin6.sin6_addr = PR.advrtr[j]; 1372 sin6.sin6_scope_id = PR.if_index; /* XXX */ 1373 getnameinfo((struct sockaddr *)&sin6, 1374 sin6.sin6_len, host_buf, 1375 sizeof(host_buf), NULL, 0, 1376 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 1377 printf(" %s", host_buf); 1378 1379 nbi = getnbrinfo(&sin6.sin6_addr, PR.if_index, 1380 0); 1381 if (nbi) { 1382 switch(nbi->state) { 1383 case ND6_LLINFO_REACHABLE: 1384 case ND6_LLINFO_STALE: 1385 case ND6_LLINFO_DELAY: 1386 case ND6_LLINFO_PROBE: 1387 printf(" (reachable)\n"); 1388 break; 1389 default: 1390 printf(" (unreachable)\n"); 1391 } 1392 } else 1393 printf(" (no neighbor state)\n"); 1394 } 1395 if (PR.advrtrs > DRLSTSIZ) 1396 printf(" and %d routers\n", 1397 PR.advrtrs - DRLSTSIZ); 1398 } else 1399 printf(" No advertising router\n"); 1400 } 1401 #undef PR 1402 close(s); 1403 #endif 1404 } 1405 1406 void 1407 pfx_flush(void) 1408 { 1409 char dummyif[IFNAMSIZ+8]; 1410 int s; 1411 1412 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1413 err(1, "socket"); 1414 strcpy(dummyif, "lo0"); /* dummy */ 1415 if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0) 1416 err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); 1417 } 1418 1419 void 1420 rtr_flush(void) 1421 { 1422 char dummyif[IFNAMSIZ+8]; 1423 int s; 1424 1425 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1426 err(1, "socket"); 1427 strcpy(dummyif, "lo0"); /* dummy */ 1428 if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0) 1429 err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); 1430 1431 close(s); 1432 } 1433 1434 void 1435 harmonize_rtr(void) 1436 { 1437 char dummyif[IFNAMSIZ+8]; 1438 int s; 1439 1440 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1441 err(1, "socket"); 1442 strcpy(dummyif, "lo0"); /* dummy */ 1443 if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) 1444 err(1, "ioctl (SIOCSNDFLUSH_IN6)"); 1445 1446 close(s); 1447 } 1448 1449 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 1450 static void 1451 setdefif(char *ifname) 1452 { 1453 struct in6_ndifreq ndifreq; 1454 unsigned int ifindex; 1455 1456 if (strcasecmp(ifname, "delete") == 0) 1457 ifindex = 0; 1458 else { 1459 if ((ifindex = if_nametoindex(ifname)) == 0) 1460 err(1, "failed to resolve i/f index for %s", ifname); 1461 } 1462 1463 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1464 err(1, "socket"); 1465 1466 strcpy(ndifreq.ifname, "lo0"); /* dummy */ 1467 ndifreq.ifindex = ifindex; 1468 1469 if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1470 err(1, "ioctl (SIOCSDEFIFACE_IN6)"); 1471 1472 close(s); 1473 } 1474 1475 static void 1476 getdefif(void) 1477 { 1478 struct in6_ndifreq ndifreq; 1479 char ifname[IFNAMSIZ+8]; 1480 1481 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1482 err(1, "socket"); 1483 1484 memset(&ndifreq, 0, sizeof(ndifreq)); 1485 strcpy(ndifreq.ifname, "lo0"); /* dummy */ 1486 1487 if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1488 err(1, "ioctl (SIOCGDEFIFACE_IN6)"); 1489 1490 if (ndifreq.ifindex == 0) 1491 printf("No default interface.\n"); 1492 else { 1493 if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL) 1494 err(1, "failed to resolve ifname for index %lu", 1495 ndifreq.ifindex); 1496 printf("ND default interface = %s\n", ifname); 1497 } 1498 1499 close(s); 1500 } 1501 #endif 1502 1503 static char * 1504 sec2str(time_t total) 1505 { 1506 static char result[256]; 1507 int days, hours, mins, secs; 1508 int first = 1; 1509 char *p = result; 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 p += sprintf(p, "%dd", days); 1519 } 1520 if (!first || hours) { 1521 first = 0; 1522 p += sprintf(p, "%dh", hours); 1523 } 1524 if (!first || mins) { 1525 first = 0; 1526 p += sprintf(p, "%dm", mins); 1527 } 1528 sprintf(p, "%ds", secs); 1529 1530 return(result); 1531 } 1532 1533 /* 1534 * Print the timestamp 1535 * from tcpdump/util.c 1536 */ 1537 static void 1538 ts_print(const struct timespec *sp) 1539 { 1540 int s; 1541 1542 /* Default */ 1543 s = (sp->tv_sec + thiszone) % 86400; 1544 printf("%02d:%02d:%02d.%06u ", 1545 s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)(sp->tv_nsec / 1000)); 1546 } 1547