1 /* 2 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the project nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 /* 30 * Copyright (c) 1984, 1993 31 * The Regents of the University of California. All rights reserved. 32 * 33 * This code is derived from software contributed to Berkeley by 34 * Sun Microsystems, Inc. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. All advertising materials mentioning features or use of this software 45 * must display the following acknowledgement: 46 * This product includes software developed by the University of 47 * California, Berkeley and its contributors. 48 * 4. Neither the name of the University nor the names of its contributors 49 * may be used to endorse or promote products derived from this software 50 * without specific prior written permission. 51 * 52 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 53 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 54 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 55 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 56 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 57 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 58 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 59 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 60 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 61 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 62 * SUCH DAMAGE. 63 */ 64 65 /* 66 * Based on: 67 * "@(#) Copyright (c) 1984, 1993\n\ 68 * The Regents of the University of California. All rights reserved.\n"; 69 * 70 * "@(#)arp.c 8.2 (Berkeley) 1/2/94"; 71 */ 72 73 /* 74 * ndp - display, set, delete and flush neighbor cache 75 */ 76 77 78 #include <sys/param.h> 79 #include <sys/file.h> 80 #include <sys/ioctl.h> 81 #include <sys/socket.h> 82 #include <sys/sysctl.h> 83 #include <sys/time.h> 84 85 #include <net/if.h> 86 #if defined(__FreeBSD__) && __FreeBSD__ >= 3 87 #include <net/if_var.h> 88 #endif /* __FreeBSD__ >= 3 */ 89 #include <net/if_dl.h> 90 #include <net/if_types.h> 91 #include <net/route.h> 92 93 #include <netinet/in.h> 94 #ifndef __NetBSD__ 95 #include <netinet/if_ether.h> 96 #endif 97 98 #include <netinet/icmp6.h> 99 #include <netinet6/in6_var.h> 100 #include <netinet6/nd6.h> 101 102 #include <arpa/inet.h> 103 104 #include <netdb.h> 105 #include <errno.h> 106 #include <nlist.h> 107 #include <stdio.h> 108 #include <string.h> 109 #include <paths.h> 110 #include <err.h> 111 #include <stdlib.h> 112 #include <fcntl.h> 113 #include <unistd.h> 114 #include "gmt2local.h" 115 116 #ifndef NI_WITHSCOPEID 117 #define NI_WITHSCOPEID 0 118 #endif 119 120 /* packing rule for routing socket */ 121 #define ROUNDUP(a) \ 122 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 123 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 124 125 static int pid; 126 static int fflag; 127 static int nflag; 128 static int tflag; 129 static int32_t thiszone; /* time difference with gmt */ 130 static int s = -1; 131 static int repeat = 0; 132 static int lflag = 0; 133 134 char ntop_buf[INET6_ADDRSTRLEN]; /* inet_ntop() */ 135 char host_buf[NI_MAXHOST]; /* getnameinfo() */ 136 char ifix_buf[IFNAMSIZ]; /* if_indextoname() */ 137 138 int main __P((int, char **)); 139 int file __P((char *)); 140 void getsocket __P((void)); 141 int set __P((int, char **)); 142 void get __P((char *)); 143 int delete __P((char *)); 144 void dump __P((struct in6_addr *)); 145 static struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *addr, 146 int ifindex, int)); 147 static char *ether_str __P((struct sockaddr_dl *)); 148 int ndp_ether_aton __P((char *, u_char *)); 149 void usage __P((void)); 150 int rtmsg __P((int)); 151 void ifinfo __P((char *)); 152 void rtrlist __P((void)); 153 void plist __P((void)); 154 void pfx_flush __P((void)); 155 void rtr_flush __P((void)); 156 void harmonize_rtr __P((void)); 157 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 158 static void getdefif __P((void)); 159 static void setdefif __P((char *)); 160 #endif 161 static char *sec2str __P((time_t t)); 162 static char *ether_str __P((struct sockaddr_dl *sdl)); 163 static void ts_print __P((const struct timeval *)); 164 165 int 166 main(argc, argv) 167 int argc; 168 char **argv; 169 { 170 int ch; 171 int aflag = 0, cflag = 0, dflag = 0, sflag = 0, Hflag = 0, 172 pflag = 0, rflag = 0, Pflag = 0, Rflag = 0; 173 extern char *optarg; 174 extern int optind; 175 176 pid = getpid(); 177 thiszone = gmt2local(0); 178 while ((ch = getopt(argc, argv, "acndfIilprstA:HPR")) != EOF) 179 switch ((char)ch) { 180 case 'a': 181 aflag = 1; 182 break; 183 case 'c': 184 fflag = 1; 185 cflag = 1; 186 break; 187 case 'd': 188 dflag = 1; 189 break; 190 case 'I': 191 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 192 if (argc > 2) 193 setdefif(argv[2]); 194 getdefif(); /* always call it to print the result */ 195 exit(0); 196 #else 197 errx(1, "not supported yet"); 198 /*NOTREACHED*/ 199 #endif 200 case 'i' : 201 if (argc != 3) 202 usage(); 203 ifinfo(argv[2]); 204 exit(0); 205 case 'n': 206 nflag = 1; 207 continue; 208 case 'p': 209 pflag = 1; 210 break; 211 case 'f' : 212 if (argc != 3) 213 usage(); 214 file(argv[2]); 215 exit(0); 216 case 'l' : 217 lflag = 1; 218 break; 219 case 'r' : 220 rflag = 1; 221 break; 222 case 's': 223 sflag = 1; 224 break; 225 case 't': 226 tflag = 1; 227 break; 228 case 'A': 229 aflag = 1; 230 repeat = atoi(optarg); 231 if (repeat < 0) 232 usage(); 233 break; 234 case 'H' : 235 Hflag = 1; 236 break; 237 case 'P': 238 Pflag = 1; 239 break; 240 case 'R': 241 Rflag = 1; 242 break; 243 default: 244 usage(); 245 } 246 247 argc -= optind; 248 argv += optind; 249 250 if (aflag || cflag) { 251 dump(0); 252 exit(0); 253 } 254 if (dflag) { 255 if (argc != 1) 256 usage(); 257 delete(argv[0]); 258 } 259 if (pflag) { 260 plist(); 261 exit(0); 262 } 263 if (rflag) { 264 rtrlist(); 265 exit(0); 266 } 267 if (sflag) { 268 if (argc < 2 || argc > 4) 269 usage(); 270 exit(set(argc, argv) ? 1 : 0); 271 } 272 if (Hflag) { 273 harmonize_rtr(); 274 exit(0); 275 } 276 if (Pflag) { 277 pfx_flush(); 278 exit(0); 279 } 280 if (Rflag) { 281 rtr_flush(); 282 exit(0); 283 } 284 285 if (argc != 1) 286 usage(); 287 get(argv[0]); 288 exit(0); 289 } 290 291 /* 292 * Process a file to set standard ndp entries 293 */ 294 int 295 file(name) 296 char *name; 297 { 298 FILE *fp; 299 int i, retval; 300 char line[100], arg[5][50], *args[5]; 301 302 if ((fp = fopen(name, "r")) == NULL) { 303 fprintf(stderr, "ndp: cannot open %s\n", name); 304 exit(1); 305 } 306 args[0] = &arg[0][0]; 307 args[1] = &arg[1][0]; 308 args[2] = &arg[2][0]; 309 args[3] = &arg[3][0]; 310 args[4] = &arg[4][0]; 311 retval = 0; 312 while(fgets(line, 100, fp) != NULL) { 313 i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2], 314 arg[3], arg[4]); 315 if (i < 2) { 316 fprintf(stderr, "ndp: bad line: %s\n", line); 317 retval = 1; 318 continue; 319 } 320 if (set(i, args)) 321 retval = 1; 322 } 323 fclose(fp); 324 return (retval); 325 } 326 327 void 328 getsocket() 329 { 330 if (s < 0) { 331 s = socket(PF_ROUTE, SOCK_RAW, 0); 332 if (s < 0) { 333 perror("ndp: socket"); 334 exit(1); 335 } 336 } 337 } 338 339 struct sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 }; 340 struct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m; 341 struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; 342 int expire_time, flags, found_entry; 343 struct { 344 struct rt_msghdr m_rtm; 345 char m_space[512]; 346 } m_rtmsg; 347 348 /* 349 * Set an individual neighbor cache entry 350 */ 351 int 352 set(argc, argv) 353 int argc; 354 char **argv; 355 { 356 register struct sockaddr_in6 *sin = &sin_m; 357 register struct sockaddr_dl *sdl; 358 register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); 359 struct addrinfo hints, *res; 360 int gai_error; 361 u_char *ea; 362 char *host = argv[0], *eaddr = argv[1]; 363 364 getsocket(); 365 argc -= 2; 366 argv += 2; 367 sdl_m = blank_sdl; 368 sin_m = blank_sin; 369 370 bzero(&hints, sizeof(hints)); 371 hints.ai_family = AF_INET6; 372 gai_error = getaddrinfo(host, NULL, &hints, &res); 373 if (gai_error) { 374 fprintf(stderr, "ndp: %s: %s\n", host, 375 gai_strerror(gai_error)); 376 return 1; 377 } 378 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 379 ea = (u_char *)LLADDR(&sdl_m); 380 if (ndp_ether_aton(eaddr, ea) == 0) 381 sdl_m.sdl_alen = 6; 382 flags = expire_time = 0; 383 while (argc-- > 0) { 384 if (strncmp(argv[0], "temp", 4) == 0) { 385 struct timeval time; 386 gettimeofday(&time, 0); 387 expire_time = time.tv_sec + 20 * 60; 388 } else if (strncmp(argv[0], "proxy", 5) == 0) 389 flags |= RTF_ANNOUNCE; 390 argv++; 391 } 392 tryagain: 393 if (rtmsg(RTM_GET) < 0) { 394 perror(host); 395 return (1); 396 } 397 sin = (struct sockaddr_in6 *)(rtm + 1); 398 sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); 399 if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { 400 if (sdl->sdl_family == AF_LINK && 401 (rtm->rtm_flags & RTF_LLINFO) && 402 !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { 403 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 404 case IFT_ISO88024: case IFT_ISO88025: 405 goto overwrite; 406 } 407 goto tryagain; 408 } 409 overwrite: 410 if (sdl->sdl_family != AF_LINK) { 411 printf("cannot intuit interface index and type for %s\n", host); 412 return (1); 413 } 414 sdl_m.sdl_type = sdl->sdl_type; 415 sdl_m.sdl_index = sdl->sdl_index; 416 return (rtmsg(RTM_ADD)); 417 } 418 419 /* 420 * Display an individual neighbor cache entry 421 */ 422 void 423 get(host) 424 char *host; 425 { 426 struct sockaddr_in6 *sin = &sin_m; 427 struct addrinfo hints, *res; 428 int gai_error; 429 430 sin_m = blank_sin; 431 bzero(&hints, sizeof(hints)); 432 hints.ai_family = AF_INET6; 433 gai_error = getaddrinfo(host, NULL, &hints, &res); 434 if (gai_error) { 435 fprintf(stderr, "ndp: %s: %s\n", host, 436 gai_strerror(gai_error)); 437 return; 438 } 439 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 440 dump(&sin->sin6_addr); 441 if (found_entry == 0) { 442 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 443 sizeof(host_buf), NULL ,0, 444 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 445 printf("%s (%s) -- no entry\n", host, host_buf); 446 exit(1); 447 } 448 } 449 450 /* 451 * Delete a neighbor cache entry 452 */ 453 int 454 delete(host) 455 char *host; 456 { 457 struct sockaddr_in6 *sin = &sin_m; 458 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 459 struct sockaddr_dl *sdl; 460 struct addrinfo hints, *res; 461 int gai_error; 462 463 getsocket(); 464 sin_m = blank_sin; 465 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 1; 473 } 474 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 475 /*tryagain:*/ 476 if (rtmsg(RTM_GET) < 0) { 477 perror(host); 478 return (1); 479 } 480 sin = (struct sockaddr_in6 *)(rtm + 1); 481 sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); 482 if (IN6_ARE_ADDR_EQUAL(&sin->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)) switch (sdl->sdl_type) { 486 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 487 case IFT_ISO88024: case IFT_ISO88025: 488 goto delete; 489 } 490 } 491 delete: 492 if (sdl->sdl_family != AF_LINK) { 493 printf("cannot locate %s\n", host); 494 return (1); 495 } 496 if (rtmsg(RTM_DELETE) == 0) { 497 getnameinfo((struct sockaddr *)sin, 498 sin->sin6_len, host_buf, 499 sizeof(host_buf), NULL, 0, 500 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 501 printf("%s (%s) deleted\n", host, host_buf); 502 } 503 504 return 0; 505 } 506 507 /* 508 * Dump the entire neighbor cache 509 */ 510 void 511 dump(addr) 512 struct in6_addr *addr; 513 { 514 int mib[6]; 515 size_t needed; 516 char *lim, *buf, *next; 517 struct rt_msghdr *rtm; 518 struct sockaddr_in6 *sin; 519 struct sockaddr_dl *sdl; 520 extern int h_errno; 521 struct in6_nbrinfo *nbi; 522 struct timeval time; 523 int addrwidth; 524 char flgbuf[8]; 525 526 /* Print header */ 527 if (!tflag) 528 printf("%-31.31s %-17.17s %6.6s %-9.9s %2s %4s %4s\n", 529 "Neighbor", "Linklayer Address", "Netif", "Expire", 530 "St", "Flgs", "Prbs"); 531 532 again:; 533 mib[0] = CTL_NET; 534 mib[1] = PF_ROUTE; 535 mib[2] = 0; 536 mib[3] = AF_INET6; 537 mib[4] = NET_RT_FLAGS; 538 mib[5] = RTF_LLINFO; 539 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 540 err(1, "sysctl(PF_ROUTE estimate)"); 541 if (needed > 0) { 542 if ((buf = malloc(needed)) == NULL) 543 errx(1, "malloc"); 544 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 545 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)"); 546 lim = buf + needed; 547 } else 548 buf = lim = NULL; 549 550 for (next = buf; next && next < lim; next += rtm->rtm_msglen) { 551 int isrouter = 0, prbs = 0; 552 553 rtm = (struct rt_msghdr *)next; 554 sin = (struct sockaddr_in6 *)(rtm + 1); 555 sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len)); 556 if (addr) { 557 if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr)) 558 continue; 559 found_entry = 1; 560 } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) 561 continue; 562 if (fflag == 1) { 563 delete((char *)inet_ntop(AF_INET6, &sin->sin6_addr, 564 ntop_buf, sizeof(ntop_buf))); 565 continue; 566 } 567 568 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) || 569 IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) { 570 /* XXX: should scope id be filled in the kernel? */ 571 if (sin->sin6_scope_id == 0) 572 sin->sin6_scope_id = sdl->sdl_index; 573 574 /* XXX: KAME specific hack; removed the embedded id */ 575 *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0; 576 } 577 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 578 sizeof(host_buf), NULL, 0, 579 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 580 gettimeofday(&time, 0); 581 if (tflag) 582 ts_print(&time); 583 584 if (lflag) { 585 addrwidth = strlen(host_buf); 586 if (addrwidth < 31) 587 addrwidth = 31; 588 } else 589 addrwidth = 31; 590 591 printf("%-*.*s %-17.17s %6.6s", addrwidth, addrwidth, host_buf, 592 ether_str(sdl), 593 if_indextoname(sdl->sdl_index, ifix_buf)); 594 595 /* Print neighbor discovery specific informations */ 596 nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1); 597 if (nbi) { 598 if (nbi->expire > time.tv_sec) { 599 printf(" %-9.9s", 600 sec2str(nbi->expire - time.tv_sec)); 601 } 602 else if (nbi->expire == 0) 603 printf(" %-9.9s", "permanent"); 604 else 605 printf(" %-9.9s", "expired"); 606 607 switch(nbi->state) { 608 case ND6_LLINFO_NOSTATE: 609 printf(" N"); 610 break; 611 case ND6_LLINFO_WAITDELETE: 612 printf(" W"); 613 break; 614 case ND6_LLINFO_INCOMPLETE: 615 printf(" I"); 616 break; 617 case ND6_LLINFO_REACHABLE: 618 printf(" R"); 619 break; 620 case ND6_LLINFO_STALE: 621 printf(" S"); 622 break; 623 case ND6_LLINFO_DELAY: 624 printf(" D"); 625 break; 626 case ND6_LLINFO_PROBE: 627 printf(" P"); 628 break; 629 default: 630 printf(" ?"); 631 break; 632 } 633 634 isrouter = nbi->isrouter; 635 prbs = nbi->asked; 636 } 637 else { 638 warnx("failed to get neighbor information"); 639 printf(" "); 640 } 641 putchar(' '); 642 643 /* 644 * other flags. R: router, P: proxy, W: ?? 645 */ 646 if ((rtm->rtm_addrs & RTA_NETMASK) == 0) { 647 snprintf(flgbuf, sizeof(flgbuf), "%s%s", 648 isrouter ? "R" : "", 649 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 650 } else { 651 sin = (struct sockaddr_in6 *) 652 (sdl->sdl_len + (char *)sdl); 653 snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s", 654 isrouter ? "R" : "", 655 !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) 656 ? "P" : "", 657 (sin->sin6_len != sizeof(struct sockaddr_in6)) 658 ? "W" : "", 659 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 660 } 661 printf(" %-4.4s", flgbuf); 662 663 if (prbs) 664 printf(" %4d", prbs); 665 666 printf("\n"); 667 } 668 669 if (repeat) { 670 printf("\n"); 671 sleep(repeat); 672 goto again; 673 } 674 } 675 676 static struct in6_nbrinfo * 677 getnbrinfo(addr, ifindex, warning) 678 struct in6_addr *addr; 679 int ifindex; 680 int warning; 681 { 682 static struct in6_nbrinfo nbi; 683 int s; 684 685 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 686 err(1, "socket"); 687 688 bzero(&nbi, sizeof(nbi)); 689 if_indextoname(ifindex, nbi.ifname); 690 nbi.addr = *addr; 691 if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) { 692 if (warning) 693 warn("ioctl"); 694 close(s); 695 return(NULL); 696 } 697 698 close(s); 699 return(&nbi); 700 } 701 702 static char * 703 ether_str(sdl) 704 struct sockaddr_dl *sdl; 705 { 706 static char ebuf[32]; 707 u_char *cp; 708 709 if (sdl->sdl_alen) { 710 cp = (u_char *)LLADDR(sdl); 711 sprintf(ebuf, "%x:%x:%x:%x:%x:%x", 712 cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); 713 } 714 else { 715 sprintf(ebuf, "(incomplete)"); 716 } 717 718 return(ebuf); 719 } 720 721 int 722 ndp_ether_aton(a, n) 723 char *a; 724 u_char *n; 725 { 726 int i, o[6]; 727 728 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 729 &o[3], &o[4], &o[5]); 730 if (i != 6) { 731 fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a); 732 return (1); 733 } 734 for (i=0; i<6; i++) 735 n[i] = o[i]; 736 return (0); 737 } 738 739 void 740 usage() 741 { 742 printf("usage: ndp hostname\n"); 743 printf(" ndp -a[ntl]\n"); 744 printf(" ndp [-ntl] -A wait\n"); 745 printf(" ndp -c[nt]\n"); 746 printf(" ndp -d[nt] hostname\n"); 747 printf(" ndp -f[nt] filename\n"); 748 printf(" ndp -i interface\n"); 749 #ifdef SIOCSDEFIFACE_IN6 750 printf(" ndp -I [interface|delete]\n"); 751 #endif 752 printf(" ndp -p\n"); 753 printf(" ndp -r\n"); 754 printf(" ndp -s hostname ether_addr [temp] [proxy]\n"); 755 printf(" ndp -H\n"); 756 printf(" ndp -P\n"); 757 printf(" ndp -R\n"); 758 exit(1); 759 } 760 761 int 762 rtmsg(cmd) 763 int cmd; 764 { 765 static int seq; 766 int rlen; 767 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 768 register char *cp = m_rtmsg.m_space; 769 register int l; 770 771 errno = 0; 772 if (cmd == RTM_DELETE) 773 goto doit; 774 bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 775 rtm->rtm_flags = flags; 776 rtm->rtm_version = RTM_VERSION; 777 778 switch (cmd) { 779 default: 780 fprintf(stderr, "ndp: internal wrong cmd\n"); 781 exit(1); 782 case RTM_ADD: 783 rtm->rtm_addrs |= RTA_GATEWAY; 784 rtm->rtm_rmx.rmx_expire = expire_time; 785 rtm->rtm_inits = RTV_EXPIRE; 786 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); 787 if (rtm->rtm_flags & RTF_ANNOUNCE) { 788 rtm->rtm_flags &= ~RTF_HOST; 789 rtm->rtm_flags |= RTA_NETMASK; 790 } 791 /* FALLTHROUGH */ 792 case RTM_GET: 793 rtm->rtm_addrs |= RTA_DST; 794 } 795 #define NEXTADDR(w, s) \ 796 if (rtm->rtm_addrs & (w)) { \ 797 bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);} 798 799 NEXTADDR(RTA_DST, sin_m); 800 NEXTADDR(RTA_GATEWAY, sdl_m); 801 memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr)); 802 NEXTADDR(RTA_NETMASK, so_mask); 803 804 rtm->rtm_msglen = cp - (char *)&m_rtmsg; 805 doit: 806 l = rtm->rtm_msglen; 807 rtm->rtm_seq = ++seq; 808 rtm->rtm_type = cmd; 809 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 810 if (errno != ESRCH || cmd != RTM_DELETE) { 811 perror("writing to routing socket"); 812 return (-1); 813 } 814 } 815 do { 816 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 817 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 818 if (l < 0) 819 (void) fprintf(stderr, "ndp: read from routing socket: %s\n", 820 strerror(errno)); 821 return (0); 822 } 823 824 void 825 ifinfo(ifname) 826 char *ifname; 827 { 828 struct in6_ndireq nd; 829 int s; 830 831 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 832 perror("ndp: socket"); 833 exit(1); 834 } 835 bzero(&nd, sizeof(nd)); 836 strcpy(nd.ifname, ifname); 837 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 838 perror("ioctl (SIOCGIFINFO_IN6)"); 839 exit(1); 840 } 841 #define ND nd.ndi 842 printf("linkmtu=%d", ND.linkmtu); 843 printf(", curhlim=%d", ND.chlim); 844 printf(", basereachable=%ds%dms", 845 ND.basereachable / 1000, ND.basereachable % 1000); 846 printf(", reachable=%ds", ND.reachable); 847 printf(", retrans=%ds%dms\n", ND.retrans / 1000, ND.retrans % 1000); 848 #undef ND 849 close(s); 850 } 851 852 void 853 rtrlist() 854 { 855 struct in6_drlist dr; 856 int s, i; 857 struct timeval time; 858 859 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 860 perror("ndp: socket"); 861 exit(1); 862 } 863 bzero(&dr, sizeof(dr)); 864 strcpy(dr.ifname, "lo0"); /* dummy */ 865 if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 866 perror("ioctl (SIOCGDRLST_IN6)"); 867 exit(1); 868 } 869 #define DR dr.defrouter[i] 870 for (i = 0 ; DR.if_index && i < PRLSTSIZ ; i++) { 871 struct sockaddr_in6 sin6; 872 873 bzero(&sin6, sizeof(sin6)); 874 sin6.sin6_family = AF_INET6; 875 sin6.sin6_len = sizeof(sin6); 876 sin6.sin6_addr = DR.rtaddr; 877 getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf, 878 sizeof(host_buf), NULL, 0, 879 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 880 881 printf("%s if=%s", host_buf, 882 if_indextoname(DR.if_index, ifix_buf)); 883 printf(", flags=%s%s", 884 DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", 885 DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); 886 gettimeofday(&time, 0); 887 if (DR.expire == 0) 888 printf(", expire=Never\n"); 889 else 890 printf(", expire=%s\n", 891 sec2str(DR.expire - time.tv_sec)); 892 } 893 #undef DR 894 close(s); 895 } 896 897 void 898 plist() 899 { 900 struct in6_prlist pr; 901 int s, i; 902 struct timeval time; 903 904 gettimeofday(&time, 0); 905 906 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 907 perror("ndp: socket"); 908 exit(1); 909 } 910 bzero(&pr, sizeof(pr)); 911 strcpy(pr.ifname, "lo0"); /* dummy */ 912 if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { 913 perror("ioctl (SIOCGPRLST_IN6)"); 914 exit(1); 915 } 916 #define PR pr.prefix[i] 917 for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { 918 printf("%s/%d if=%s\n", 919 inet_ntop(AF_INET6, &PR.prefix, ntop_buf, 920 sizeof(ntop_buf)), PR.prefixlen, 921 if_indextoname(PR.if_index, ifix_buf)); 922 gettimeofday(&time, 0); 923 /* 924 * meaning of fields, especially flags, is very different 925 * by origin. notify the difference to the users. 926 */ 927 printf(" %s", PR.origin == PR_ORIG_RA ? "" : "advertise: "); 928 printf("flags=%s%s", 929 PR.raflags.onlink ? "L" : "", 930 PR.raflags.autonomous ? "A" : ""); 931 if (PR.vltime == ND6_INFINITE_LIFETIME) 932 printf(" vltime=infinity"); 933 else 934 printf(" vltime=%ld", (long)PR.vltime); 935 if (PR.pltime == ND6_INFINITE_LIFETIME) 936 printf(", pltime=infinity"); 937 else 938 printf(", pltime=%ld", (long)PR.pltime); 939 if (PR.expire == 0) 940 printf(", expire=Never"); 941 else if (PR.expire >= time.tv_sec) 942 printf(", expire=%s", 943 sec2str(PR.expire - time.tv_sec)); 944 else 945 printf(", expired"); 946 switch (PR.origin) { 947 case PR_ORIG_RA: 948 printf(", origin=RA"); 949 break; 950 case PR_ORIG_RR: 951 printf(", origin=RR"); 952 break; 953 case PR_ORIG_STATIC: 954 printf(", origin=static"); 955 break; 956 case PR_ORIG_KERNEL: 957 printf(", origin=kernel"); 958 break; 959 default: 960 printf(", origin=?"); 961 break; 962 } 963 printf("\n"); 964 /* 965 * "advertising router" list is meaningful only if the prefix 966 * information is from RA. 967 */ 968 if (PR.origin != PR_ORIG_RA) 969 ; 970 else if (PR.advrtrs) { 971 int j; 972 printf(" advertised by\n"); 973 for (j = 0; j < PR.advrtrs; j++) { 974 struct sockaddr_in6 sin6; 975 struct in6_nbrinfo *nbi; 976 977 bzero(&sin6, sizeof(sin6)); 978 sin6.sin6_family = AF_INET6; 979 sin6.sin6_len = sizeof(sin6); 980 sin6.sin6_addr = PR.advrtr[j]; 981 sin6.sin6_scope_id = PR.if_index; /* XXX */ 982 getnameinfo((struct sockaddr *)&sin6, 983 sin6.sin6_len, host_buf, 984 sizeof(host_buf), NULL, 0, 985 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 986 printf(" %s", host_buf); 987 988 nbi = getnbrinfo(&sin6.sin6_addr, PR.if_index, 989 0); 990 if (nbi) { 991 switch(nbi->state) { 992 case ND6_LLINFO_REACHABLE: 993 case ND6_LLINFO_STALE: 994 case ND6_LLINFO_DELAY: 995 case ND6_LLINFO_PROBE: 996 printf(" (reachable)\n"); 997 break; 998 default: 999 printf(" (unreachable)\n"); 1000 } 1001 } 1002 else 1003 printf(" (no neighbor state)\n"); 1004 } 1005 if (PR.advrtrs > DRLSTSIZ) 1006 printf(" and %d routers\n", 1007 PR.advrtrs - DRLSTSIZ); 1008 } else 1009 printf(" No advertising router\n"); 1010 } 1011 #undef PR 1012 close(s); 1013 } 1014 1015 void 1016 pfx_flush() 1017 { 1018 char dummyif[IFNAMSIZ+8]; 1019 int s; 1020 1021 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1022 err(1, "socket"); 1023 strcpy(dummyif, "lo0"); /* dummy */ 1024 if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0) 1025 err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); 1026 } 1027 1028 void 1029 rtr_flush() 1030 { 1031 char dummyif[IFNAMSIZ+8]; 1032 int s; 1033 1034 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1035 err(1, "socket"); 1036 strcpy(dummyif, "lo0"); /* dummy */ 1037 if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0) 1038 err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); 1039 1040 close(s); 1041 } 1042 1043 void 1044 harmonize_rtr() 1045 { 1046 char dummyif[IFNAMSIZ+8]; 1047 int s; 1048 1049 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1050 err(1, "socket"); 1051 strcpy(dummyif, "lo0"); /* dummy */ 1052 if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) 1053 err(1, "ioctl (SIOCSNDFLUSH_IN6)"); 1054 1055 close(s); 1056 } 1057 1058 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 1059 static void 1060 setdefif(ifname) 1061 char *ifname; 1062 { 1063 struct in6_ndifreq ndifreq; 1064 unsigned int ifindex; 1065 1066 if (strcasecmp(ifname, "delete") == 0) 1067 ifindex = 0; 1068 else { 1069 if ((ifindex = if_nametoindex(ifname)) == 0) 1070 err(1, "failed to resolve i/f index for %s", ifname); 1071 } 1072 1073 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1074 err(1, "socket"); 1075 1076 strcpy(ndifreq.ifname, "lo0"); /* dummy */ 1077 ndifreq.ifindex = ifindex; 1078 1079 if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1080 err(1, "ioctl (SIOCSDEFIFACE_IN6)"); 1081 1082 close(s); 1083 } 1084 1085 static void 1086 getdefif() 1087 { 1088 struct in6_ndifreq ndifreq; 1089 char ifname[IFNAMSIZ+8]; 1090 1091 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1092 err(1, "socket"); 1093 1094 memset(&ndifreq, 0, sizeof(ndifreq)); 1095 strcpy(ndifreq.ifname, "lo0"); /* dummy */ 1096 1097 if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1098 err(1, "ioctl (SIOCGDEFIFACE_IN6)"); 1099 1100 if (ndifreq.ifindex == 0) 1101 printf("No default interface.\n"); 1102 else { 1103 if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL) 1104 err(1, "failed to resolve ifname for index %lu", 1105 ndifreq.ifindex); 1106 printf("ND default interface = %s\n", ifname); 1107 } 1108 1109 close(s); 1110 } 1111 #endif 1112 1113 static char * 1114 sec2str(total) 1115 time_t total; 1116 { 1117 static char result[256]; 1118 int days, hours, mins, secs; 1119 int first = 1; 1120 char *p = result; 1121 1122 days = total / 3600 / 24; 1123 hours = (total / 3600) % 24; 1124 mins = (total / 60) % 60; 1125 secs = total % 60; 1126 1127 if (days) { 1128 first = 0; 1129 p += sprintf(p, "%dd", days); 1130 } 1131 if (!first || hours) { 1132 first = 0; 1133 p += sprintf(p, "%dh", hours); 1134 } 1135 if (!first || mins) { 1136 first = 0; 1137 p += sprintf(p, "%dm", mins); 1138 } 1139 sprintf(p, "%ds", secs); 1140 1141 return(result); 1142 } 1143 1144 /* 1145 * Print the timestamp 1146 * from tcpdump/util.c 1147 */ 1148 static void 1149 ts_print(tvp) 1150 const struct timeval *tvp; 1151 { 1152 int s; 1153 1154 /* Default */ 1155 s = (tvp->tv_sec + thiszone) % 86400; 1156 (void)printf("%02d:%02d:%02d.%06u ", 1157 s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec); 1158 } 1159