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((int, 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 174 pid = getpid(); 175 thiszone = gmt2local(0); 176 while ((ch = getopt(argc, argv, "acndfIilprstA:HPR")) != EOF) 177 switch ((char)ch) { 178 case 'a': 179 aflag = 1; 180 break; 181 case 'c': 182 fflag = 1; 183 cflag = 1; 184 break; 185 case 'd': 186 dflag = 1; 187 break; 188 case 'I': 189 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 190 if (argc > 2) 191 setdefif(argv[2]); 192 getdefif(); /* always call it to print the result */ 193 exit(0); 194 #else 195 errx(1, "not supported yet"); 196 /*NOTREACHED*/ 197 #endif 198 case 'i' : 199 argc -= optind; 200 argv += optind; 201 if (argc < 1) 202 usage(); 203 ifinfo(argc, argv); 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)) { 486 switch (sdl->sdl_type) { 487 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 488 case IFT_ISO88024: case IFT_ISO88025: 489 goto delete; 490 } 491 } 492 } 493 return 0; 494 495 delete: 496 if (sdl->sdl_family != AF_LINK) { 497 printf("cannot locate %s\n", host); 498 return (1); 499 } 500 if (rtmsg(RTM_DELETE) == 0) { 501 getnameinfo((struct sockaddr *)sin, 502 sin->sin6_len, host_buf, 503 sizeof(host_buf), NULL, 0, 504 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 505 printf("%s (%s) deleted\n", host, host_buf); 506 } 507 508 return 0; 509 } 510 511 /* 512 * Dump the entire neighbor cache 513 */ 514 void 515 dump(addr) 516 struct in6_addr *addr; 517 { 518 int mib[6]; 519 size_t needed; 520 char *lim, *buf, *next; 521 struct rt_msghdr *rtm; 522 struct sockaddr_in6 *sin; 523 struct sockaddr_dl *sdl; 524 struct in6_nbrinfo *nbi; 525 struct timeval time; 526 int addrwidth; 527 char flgbuf[8]; 528 529 /* Print header */ 530 if (!tflag) 531 printf("%-31.31s %-17.17s %6.6s %-9.9s %2s %4s %4s\n", 532 "Neighbor", "Linklayer Address", "Netif", "Expire", 533 "St", "Flgs", "Prbs"); 534 535 again:; 536 mib[0] = CTL_NET; 537 mib[1] = PF_ROUTE; 538 mib[2] = 0; 539 mib[3] = AF_INET6; 540 mib[4] = NET_RT_FLAGS; 541 mib[5] = RTF_LLINFO; 542 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 543 err(1, "sysctl(PF_ROUTE estimate)"); 544 if (needed > 0) { 545 if ((buf = malloc(needed)) == NULL) 546 errx(1, "malloc"); 547 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 548 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)"); 549 lim = buf + needed; 550 } else 551 buf = lim = NULL; 552 553 for (next = buf; next && next < lim; next += rtm->rtm_msglen) { 554 int isrouter = 0, prbs = 0; 555 556 rtm = (struct rt_msghdr *)next; 557 sin = (struct sockaddr_in6 *)(rtm + 1); 558 sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len)); 559 if (addr) { 560 if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr)) 561 continue; 562 found_entry = 1; 563 } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) 564 continue; 565 if (fflag == 1) { 566 delete((char *)inet_ntop(AF_INET6, &sin->sin6_addr, 567 ntop_buf, sizeof(ntop_buf))); 568 continue; 569 } 570 571 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) || 572 IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) { 573 /* XXX: should scope id be filled in the kernel? */ 574 if (sin->sin6_scope_id == 0) 575 sin->sin6_scope_id = sdl->sdl_index; 576 577 /* XXX: KAME specific hack; removed the embedded id */ 578 *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0; 579 } 580 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 581 sizeof(host_buf), NULL, 0, 582 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 583 gettimeofday(&time, 0); 584 if (tflag) 585 ts_print(&time); 586 587 if (lflag) { 588 addrwidth = strlen(host_buf); 589 if (addrwidth < 31) 590 addrwidth = 31; 591 } else 592 addrwidth = 31; 593 594 printf("%-*.*s %-17.17s %6.6s", addrwidth, addrwidth, host_buf, 595 ether_str(sdl), 596 if_indextoname(sdl->sdl_index, ifix_buf)); 597 598 /* Print neighbor discovery specific informations */ 599 nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1); 600 if (nbi) { 601 if (nbi->expire > time.tv_sec) { 602 printf(" %-9.9s", 603 sec2str(nbi->expire - time.tv_sec)); 604 } 605 else if (nbi->expire == 0) 606 printf(" %-9.9s", "permanent"); 607 else 608 printf(" %-9.9s", "expired"); 609 610 switch(nbi->state) { 611 case ND6_LLINFO_NOSTATE: 612 printf(" N"); 613 break; 614 case ND6_LLINFO_WAITDELETE: 615 printf(" W"); 616 break; 617 case ND6_LLINFO_INCOMPLETE: 618 printf(" I"); 619 break; 620 case ND6_LLINFO_REACHABLE: 621 printf(" R"); 622 break; 623 case ND6_LLINFO_STALE: 624 printf(" S"); 625 break; 626 case ND6_LLINFO_DELAY: 627 printf(" D"); 628 break; 629 case ND6_LLINFO_PROBE: 630 printf(" P"); 631 break; 632 default: 633 printf(" ?"); 634 break; 635 } 636 637 isrouter = nbi->isrouter; 638 prbs = nbi->asked; 639 } 640 else { 641 warnx("failed to get neighbor information"); 642 printf(" "); 643 } 644 putchar(' '); 645 646 /* 647 * other flags. R: router, P: proxy, W: ?? 648 */ 649 if ((rtm->rtm_addrs & RTA_NETMASK) == 0) { 650 snprintf(flgbuf, sizeof(flgbuf), "%s%s", 651 isrouter ? "R" : "", 652 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 653 } else { 654 sin = (struct sockaddr_in6 *) 655 (sdl->sdl_len + (char *)sdl); 656 snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s", 657 isrouter ? "R" : "", 658 !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) 659 ? "P" : "", 660 (sin->sin6_len != sizeof(struct sockaddr_in6)) 661 ? "W" : "", 662 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 663 } 664 printf(" %-4.4s", flgbuf); 665 666 if (prbs) 667 printf(" %4d", prbs); 668 669 printf("\n"); 670 } 671 672 if (repeat) { 673 printf("\n"); 674 sleep(repeat); 675 goto again; 676 } 677 } 678 679 static struct in6_nbrinfo * 680 getnbrinfo(addr, ifindex, warning) 681 struct in6_addr *addr; 682 int ifindex; 683 int warning; 684 { 685 static struct in6_nbrinfo nbi; 686 int s; 687 688 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 689 err(1, "socket"); 690 691 bzero(&nbi, sizeof(nbi)); 692 if_indextoname(ifindex, nbi.ifname); 693 nbi.addr = *addr; 694 if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) { 695 if (warning) 696 warn("ioctl(SIOCGNBRINFO_IN6)"); 697 close(s); 698 return(NULL); 699 } 700 701 close(s); 702 return(&nbi); 703 } 704 705 static char * 706 ether_str(sdl) 707 struct sockaddr_dl *sdl; 708 { 709 static char ebuf[32]; 710 u_char *cp; 711 712 if (sdl->sdl_alen) { 713 cp = (u_char *)LLADDR(sdl); 714 sprintf(ebuf, "%x:%x:%x:%x:%x:%x", 715 cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); 716 } 717 else { 718 sprintf(ebuf, "(incomplete)"); 719 } 720 721 return(ebuf); 722 } 723 724 int 725 ndp_ether_aton(a, n) 726 char *a; 727 u_char *n; 728 { 729 int i, o[6]; 730 731 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 732 &o[3], &o[4], &o[5]); 733 if (i != 6) { 734 fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a); 735 return (1); 736 } 737 for (i=0; i<6; i++) 738 n[i] = o[i]; 739 return (0); 740 } 741 742 void 743 usage() 744 { 745 printf("usage: ndp hostname\n"); 746 printf(" ndp -a[ntl]\n"); 747 printf(" ndp [-ntl] -A wait\n"); 748 printf(" ndp -c[nt]\n"); 749 printf(" ndp -d[nt] hostname\n"); 750 printf(" ndp -f[nt] filename\n"); 751 printf(" ndp -i interface [flags...]\n"); 752 #ifdef SIOCSDEFIFACE_IN6 753 printf(" ndp -I [interface|delete]\n"); 754 #endif 755 printf(" ndp -p\n"); 756 printf(" ndp -r\n"); 757 printf(" ndp -s hostname ether_addr [temp] [proxy]\n"); 758 printf(" ndp -H\n"); 759 printf(" ndp -P\n"); 760 printf(" ndp -R\n"); 761 exit(1); 762 } 763 764 int 765 rtmsg(cmd) 766 int cmd; 767 { 768 static int seq; 769 int rlen; 770 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 771 register char *cp = m_rtmsg.m_space; 772 register int l; 773 774 errno = 0; 775 if (cmd == RTM_DELETE) 776 goto doit; 777 bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 778 rtm->rtm_flags = flags; 779 rtm->rtm_version = RTM_VERSION; 780 781 switch (cmd) { 782 default: 783 fprintf(stderr, "ndp: internal wrong cmd\n"); 784 exit(1); 785 case RTM_ADD: 786 rtm->rtm_addrs |= RTA_GATEWAY; 787 rtm->rtm_rmx.rmx_expire = expire_time; 788 rtm->rtm_inits = RTV_EXPIRE; 789 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); 790 if (rtm->rtm_flags & RTF_ANNOUNCE) { 791 rtm->rtm_flags &= ~RTF_HOST; 792 rtm->rtm_flags |= RTA_NETMASK; 793 } 794 /* FALLTHROUGH */ 795 case RTM_GET: 796 rtm->rtm_addrs |= RTA_DST; 797 } 798 #define NEXTADDR(w, s) \ 799 if (rtm->rtm_addrs & (w)) { \ 800 bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);} 801 802 NEXTADDR(RTA_DST, sin_m); 803 NEXTADDR(RTA_GATEWAY, sdl_m); 804 memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr)); 805 NEXTADDR(RTA_NETMASK, so_mask); 806 807 rtm->rtm_msglen = cp - (char *)&m_rtmsg; 808 doit: 809 l = rtm->rtm_msglen; 810 rtm->rtm_seq = ++seq; 811 rtm->rtm_type = cmd; 812 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 813 if (errno != ESRCH || cmd != RTM_DELETE) { 814 perror("writing to routing socket"); 815 return (-1); 816 } 817 } 818 do { 819 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 820 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 821 if (l < 0) 822 (void) fprintf(stderr, "ndp: read from routing socket: %s\n", 823 strerror(errno)); 824 return (0); 825 } 826 827 void 828 ifinfo(argc, argv) 829 int argc; 830 char **argv; 831 { 832 struct in6_ndireq nd; 833 int i, s; 834 char *ifname = argv[0]; 835 u_int32_t newflags; 836 837 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 838 perror("ndp: socket"); 839 exit(1); 840 } 841 bzero(&nd, sizeof(nd)); 842 strcpy(nd.ifname, ifname); 843 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 844 perror("ioctl (SIOCGIFINFO_IN6)"); 845 exit(1); 846 } 847 #define ND nd.ndi 848 newflags = ND.flags; 849 for (i = 1; i < argc; i++) { 850 int clear = 0; 851 char *cp = argv[i]; 852 853 if (*cp == '-') { 854 clear = 1; 855 cp++; 856 } 857 858 #define SETFLAG(s, f) \ 859 do {\ 860 if (strcmp(cp, (s)) == 0) {\ 861 if (clear)\ 862 newflags &= ~(f);\ 863 else\ 864 newflags |= (f);\ 865 }\ 866 } while (0) 867 SETFLAG("nud", ND6_IFF_PERFORMNUD); 868 869 ND.flags = newflags; 870 if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) { 871 perror("ioctl(SIOCSIFINFO_FLAGS)"); 872 exit(1); 873 } 874 #undef SETFLAG 875 } 876 877 printf("linkmtu=%d", ND.linkmtu); 878 printf(", curhlim=%d", ND.chlim); 879 printf(", basereachable=%ds%dms", 880 ND.basereachable / 1000, ND.basereachable % 1000); 881 printf(", reachable=%ds", ND.reachable); 882 printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000); 883 if (ND.flags) { 884 printf("\nFlags: "); 885 if ((ND.flags & ND6_IFF_PERFORMNUD) != 0) 886 printf("PERFORMNUD "); 887 } 888 putc('\n', stdout); 889 #undef ND 890 891 close(s); 892 } 893 894 void 895 rtrlist() 896 { 897 struct in6_drlist dr; 898 int s, i; 899 struct timeval time; 900 901 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 902 perror("ndp: socket"); 903 exit(1); 904 } 905 bzero(&dr, sizeof(dr)); 906 strcpy(dr.ifname, "lo0"); /* dummy */ 907 if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 908 perror("ioctl (SIOCGDRLST_IN6)"); 909 exit(1); 910 } 911 #define DR dr.defrouter[i] 912 for (i = 0 ; DR.if_index && i < PRLSTSIZ ; i++) { 913 struct sockaddr_in6 sin6; 914 915 bzero(&sin6, sizeof(sin6)); 916 sin6.sin6_family = AF_INET6; 917 sin6.sin6_len = sizeof(sin6); 918 sin6.sin6_addr = DR.rtaddr; 919 getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf, 920 sizeof(host_buf), NULL, 0, 921 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 922 923 printf("%s if=%s", host_buf, 924 if_indextoname(DR.if_index, ifix_buf)); 925 printf(", flags=%s%s", 926 DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", 927 DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); 928 gettimeofday(&time, 0); 929 if (DR.expire == 0) 930 printf(", expire=Never\n"); 931 else 932 printf(", expire=%s\n", 933 sec2str(DR.expire - time.tv_sec)); 934 } 935 #undef DR 936 close(s); 937 } 938 939 void 940 plist() 941 { 942 struct in6_prlist pr; 943 int s, i; 944 struct timeval time; 945 946 gettimeofday(&time, 0); 947 948 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 949 perror("ndp: socket"); 950 exit(1); 951 } 952 bzero(&pr, sizeof(pr)); 953 strcpy(pr.ifname, "lo0"); /* dummy */ 954 if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { 955 perror("ioctl (SIOCGPRLST_IN6)"); 956 exit(1); 957 } 958 #define PR pr.prefix[i] 959 for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { 960 printf("%s/%d if=%s\n", 961 inet_ntop(AF_INET6, &PR.prefix, ntop_buf, 962 sizeof(ntop_buf)), PR.prefixlen, 963 if_indextoname(PR.if_index, ifix_buf)); 964 gettimeofday(&time, 0); 965 /* 966 * meaning of fields, especially flags, is very different 967 * by origin. notify the difference to the users. 968 */ 969 printf(" %s", PR.origin == PR_ORIG_RA ? "" : "advertise: "); 970 printf("flags=%s%s", 971 PR.raflags.onlink ? "L" : "", 972 PR.raflags.autonomous ? "A" : ""); 973 if (PR.vltime == ND6_INFINITE_LIFETIME) 974 printf(" vltime=infinity"); 975 else 976 printf(" vltime=%ld", (long)PR.vltime); 977 if (PR.pltime == ND6_INFINITE_LIFETIME) 978 printf(", pltime=infinity"); 979 else 980 printf(", pltime=%ld", (long)PR.pltime); 981 if (PR.expire == 0) 982 printf(", expire=Never"); 983 else if (PR.expire >= time.tv_sec) 984 printf(", expire=%s", 985 sec2str(PR.expire - time.tv_sec)); 986 else 987 printf(", expired"); 988 switch (PR.origin) { 989 case PR_ORIG_RA: 990 printf(", origin=RA"); 991 break; 992 case PR_ORIG_RR: 993 printf(", origin=RR"); 994 break; 995 case PR_ORIG_STATIC: 996 printf(", origin=static"); 997 break; 998 case PR_ORIG_KERNEL: 999 printf(", origin=kernel"); 1000 break; 1001 default: 1002 printf(", origin=?"); 1003 break; 1004 } 1005 printf("\n"); 1006 /* 1007 * "advertising router" list is meaningful only if the prefix 1008 * information is from RA. 1009 */ 1010 if (PR.origin != PR_ORIG_RA) 1011 ; 1012 else if (PR.advrtrs) { 1013 int j; 1014 printf(" advertised by\n"); 1015 for (j = 0; j < PR.advrtrs; j++) { 1016 struct sockaddr_in6 sin6; 1017 struct in6_nbrinfo *nbi; 1018 1019 bzero(&sin6, sizeof(sin6)); 1020 sin6.sin6_family = AF_INET6; 1021 sin6.sin6_len = sizeof(sin6); 1022 sin6.sin6_addr = PR.advrtr[j]; 1023 sin6.sin6_scope_id = PR.if_index; /* XXX */ 1024 getnameinfo((struct sockaddr *)&sin6, 1025 sin6.sin6_len, host_buf, 1026 sizeof(host_buf), NULL, 0, 1027 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 1028 printf(" %s", host_buf); 1029 1030 nbi = getnbrinfo(&sin6.sin6_addr, PR.if_index, 1031 0); 1032 if (nbi) { 1033 switch(nbi->state) { 1034 case ND6_LLINFO_REACHABLE: 1035 case ND6_LLINFO_STALE: 1036 case ND6_LLINFO_DELAY: 1037 case ND6_LLINFO_PROBE: 1038 printf(" (reachable)\n"); 1039 break; 1040 default: 1041 printf(" (unreachable)\n"); 1042 } 1043 } 1044 else 1045 printf(" (no neighbor state)\n"); 1046 } 1047 if (PR.advrtrs > DRLSTSIZ) 1048 printf(" and %d routers\n", 1049 PR.advrtrs - DRLSTSIZ); 1050 } else 1051 printf(" No advertising router\n"); 1052 } 1053 #undef PR 1054 close(s); 1055 } 1056 1057 void 1058 pfx_flush() 1059 { 1060 char dummyif[IFNAMSIZ+8]; 1061 int s; 1062 1063 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1064 err(1, "socket"); 1065 strcpy(dummyif, "lo0"); /* dummy */ 1066 if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0) 1067 err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); 1068 } 1069 1070 void 1071 rtr_flush() 1072 { 1073 char dummyif[IFNAMSIZ+8]; 1074 int s; 1075 1076 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1077 err(1, "socket"); 1078 strcpy(dummyif, "lo0"); /* dummy */ 1079 if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0) 1080 err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); 1081 1082 close(s); 1083 } 1084 1085 void 1086 harmonize_rtr() 1087 { 1088 char dummyif[IFNAMSIZ+8]; 1089 int s; 1090 1091 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1092 err(1, "socket"); 1093 strcpy(dummyif, "lo0"); /* dummy */ 1094 if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) 1095 err(1, "ioctl (SIOCSNDFLUSH_IN6)"); 1096 1097 close(s); 1098 } 1099 1100 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 1101 static void 1102 setdefif(ifname) 1103 char *ifname; 1104 { 1105 struct in6_ndifreq ndifreq; 1106 unsigned int ifindex; 1107 1108 if (strcasecmp(ifname, "delete") == 0) 1109 ifindex = 0; 1110 else { 1111 if ((ifindex = if_nametoindex(ifname)) == 0) 1112 err(1, "failed to resolve i/f index for %s", ifname); 1113 } 1114 1115 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1116 err(1, "socket"); 1117 1118 strcpy(ndifreq.ifname, "lo0"); /* dummy */ 1119 ndifreq.ifindex = ifindex; 1120 1121 if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1122 err(1, "ioctl (SIOCSDEFIFACE_IN6)"); 1123 1124 close(s); 1125 } 1126 1127 static void 1128 getdefif() 1129 { 1130 struct in6_ndifreq ndifreq; 1131 char ifname[IFNAMSIZ+8]; 1132 1133 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1134 err(1, "socket"); 1135 1136 memset(&ndifreq, 0, sizeof(ndifreq)); 1137 strcpy(ndifreq.ifname, "lo0"); /* dummy */ 1138 1139 if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1140 err(1, "ioctl (SIOCGDEFIFACE_IN6)"); 1141 1142 if (ndifreq.ifindex == 0) 1143 printf("No default interface.\n"); 1144 else { 1145 if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL) 1146 err(1, "failed to resolve ifname for index %lu", 1147 ndifreq.ifindex); 1148 printf("ND default interface = %s\n", ifname); 1149 } 1150 1151 close(s); 1152 } 1153 #endif 1154 1155 static char * 1156 sec2str(total) 1157 time_t total; 1158 { 1159 static char result[256]; 1160 int days, hours, mins, secs; 1161 int first = 1; 1162 char *p = result; 1163 1164 days = total / 3600 / 24; 1165 hours = (total / 3600) % 24; 1166 mins = (total / 60) % 60; 1167 secs = total % 60; 1168 1169 if (days) { 1170 first = 0; 1171 p += sprintf(p, "%dd", days); 1172 } 1173 if (!first || hours) { 1174 first = 0; 1175 p += sprintf(p, "%dh", hours); 1176 } 1177 if (!first || mins) { 1178 first = 0; 1179 p += sprintf(p, "%dm", mins); 1180 } 1181 sprintf(p, "%ds", secs); 1182 1183 return(result); 1184 } 1185 1186 /* 1187 * Print the timestamp 1188 * from tcpdump/util.c 1189 */ 1190 static void 1191 ts_print(tvp) 1192 const struct timeval *tvp; 1193 { 1194 int s; 1195 1196 /* Default */ 1197 s = (tvp->tv_sec + thiszone) % 86400; 1198 (void)printf("%02d:%02d:%02d.%06u ", 1199 s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec); 1200 } 1201