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