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 * $FreeBSD$ 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 #include <net/if_var.h> 89 #include <net/if_dl.h> 90 #include <net/if_types.h> 91 #include <net/route.h> 92 93 #include <netinet/in.h> 94 #include <netinet/if_ether.h> 95 96 #include <netinet/icmp6.h> 97 #include <netinet6/in6_var.h> 98 #include <netinet6/nd6.h> 99 100 #include <arpa/inet.h> 101 102 #include <netdb.h> 103 #include <errno.h> 104 #include <nlist.h> 105 #include <stdio.h> 106 #include <string.h> 107 #include <paths.h> 108 #include <err.h> 109 #include <stdlib.h> 110 #include <fcntl.h> 111 #include <unistd.h> 112 #include "gmt2local.h" 113 114 /* packing rule for routing socket */ 115 #define ROUNDUP(a) \ 116 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 117 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 118 119 extern int errno; 120 static int pid; 121 static int fflag; 122 static int nflag; 123 static int tflag; 124 static int32_t thiszone; /* time difference with gmt */ 125 static int s = -1; 126 static int repeat = 0; 127 static int lflag = 0; 128 129 char ntop_buf[INET6_ADDRSTRLEN]; /* inet_ntop() */ 130 char host_buf[NI_MAXHOST]; /* getnameinfo() */ 131 char ifix_buf[IFNAMSIZ]; /* if_indextoname() */ 132 133 int main __P((int, char **)); 134 int file __P((char *)); 135 void getsocket __P((void)); 136 int set __P((int, char **)); 137 void get __P((char *)); 138 int delete __P((char *)); 139 void dump __P((struct in6_addr *)); 140 static struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *addr, int ifindex)); 141 static char *ether_str __P((struct sockaddr_dl *)); 142 int ndp_ether_aton __P((char *, u_char *)); 143 void usage __P((void)); 144 int rtmsg __P((int)); 145 void ifinfo __P((char *)); 146 void list __P((void)); 147 void plist __P((void)); 148 void pfx_flush __P((void)); 149 void rtr_flush __P((void)); 150 void harmonize_rtr __P((void)); 151 static char *sec2str __P((time_t t)); 152 static char *ether_str __P((struct sockaddr_dl *sdl)); 153 static void ts_print __P((const struct timeval *)); 154 155 int 156 main(argc, argv) 157 int argc; 158 char **argv; 159 { 160 int ch; 161 int aflag = 0, cflag = 0, dflag = 0, sflag = 0, Hflag = 0, 162 pflag = 0, rflag = 0, Pflag = 0, Rflag = 0; 163 extern char *optarg; 164 extern int optind; 165 166 pid = getpid(); 167 thiszone = gmt2local(0); 168 while ((ch = getopt(argc, argv, "acndfilprstA:HPR")) != EOF) 169 switch ((char)ch) { 170 case 'a': 171 aflag = 1; 172 break; 173 case 'c': 174 fflag = 1; 175 cflag = 1; 176 break; 177 case 'd': 178 dflag = 1; 179 break; 180 case 'i' : 181 if (argc != 3) 182 usage(); 183 ifinfo(argv[2]); 184 exit(0); 185 case 'n': 186 nflag = 1; 187 continue; 188 case 'p': 189 pflag = 1; 190 break; 191 case 'f' : 192 if (argc != 3) 193 usage(); 194 file(argv[2]); 195 exit(0); 196 case 'l' : 197 lflag = 1; 198 break; 199 case 'r' : 200 rflag = 1; 201 break; 202 case 's': 203 sflag = 1; 204 break; 205 case 't': 206 tflag = 1; 207 break; 208 case 'A': 209 aflag = 1; 210 repeat = atoi(optarg); 211 if (repeat < 0) 212 usage(); 213 break; 214 case 'H' : 215 Hflag = 1; 216 break; 217 case 'P': 218 Pflag = 1; 219 break; 220 case 'R': 221 Rflag = 1; 222 break; 223 default: 224 usage(); 225 } 226 227 argc -= optind; 228 argv += optind; 229 230 if (aflag || cflag) { 231 dump(0); 232 exit(0); 233 } 234 if (dflag) { 235 if (argc != 1) 236 usage(); 237 delete(argv[0]); 238 } 239 if (pflag) { 240 plist(); 241 exit(0); 242 } 243 if (rflag) { 244 rtrlist(); 245 exit(0); 246 } 247 if (sflag) { 248 if (argc < 2 || argc > 4) 249 usage(); 250 exit(set(argc, argv) ? 1 : 0); 251 } 252 if (Hflag) { 253 harmonize_rtr(); 254 exit(0); 255 } 256 if (Pflag) { 257 pfx_flush(); 258 exit(0); 259 } 260 if (Rflag) { 261 rtr_flush(); 262 exit(0); 263 } 264 265 if (argc != 1) 266 usage(); 267 get(argv[0]); 268 exit(0); 269 } 270 271 /* 272 * Process a file to set standard ndp entries 273 */ 274 int 275 file(name) 276 char *name; 277 { 278 FILE *fp; 279 int i, retval; 280 char line[100], arg[5][50], *args[5]; 281 282 if ((fp = fopen(name, "r")) == NULL) { 283 fprintf(stderr, "ndp: cannot open %s\n", name); 284 exit(1); 285 } 286 args[0] = &arg[0][0]; 287 args[1] = &arg[1][0]; 288 args[2] = &arg[2][0]; 289 args[3] = &arg[3][0]; 290 args[4] = &arg[4][0]; 291 retval = 0; 292 while(fgets(line, 100, fp) != NULL) { 293 i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2], 294 arg[3], arg[4]); 295 if (i < 2) { 296 fprintf(stderr, "ndp: bad line: %s\n", line); 297 retval = 1; 298 continue; 299 } 300 if (set(i, args)) 301 retval = 1; 302 } 303 fclose(fp); 304 return (retval); 305 } 306 307 void 308 getsocket() 309 { 310 if (s < 0) { 311 s = socket(PF_ROUTE, SOCK_RAW, 0); 312 if (s < 0) { 313 perror("ndp: socket"); 314 exit(1); 315 } 316 } 317 } 318 319 struct sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}}; 320 struct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m; 321 struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; 322 int expire_time, flags, found_entry; 323 struct { 324 struct rt_msghdr m_rtm; 325 char m_space[512]; 326 } m_rtmsg; 327 328 /* 329 * Set an individual neighbor cache entry 330 */ 331 int 332 set(argc, argv) 333 int argc; 334 char **argv; 335 { 336 register struct sockaddr_in6 *sin = &sin_m; 337 register struct sockaddr_dl *sdl; 338 register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); 339 struct addrinfo hints, *res; 340 int gai_error; 341 u_char *ea; 342 char *host = argv[0], *eaddr = argv[1]; 343 344 getsocket(); 345 argc -= 2; 346 argv += 2; 347 sdl_m = blank_sdl; 348 sin_m = blank_sin; 349 350 bzero(&hints, sizeof(hints)); 351 hints.ai_family = AF_INET6; 352 gai_error = getaddrinfo(host, NULL, &hints, &res); 353 if (gai_error) { 354 fprintf(stderr, "ndp: %s: %s\n", host, 355 gai_strerror(gai_error)); 356 return 1; 357 } 358 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 359 ea = (u_char *)LLADDR(&sdl_m); 360 if (ndp_ether_aton(eaddr, ea) == 0) 361 sdl_m.sdl_alen = 6; 362 flags = expire_time = 0; 363 while (argc-- > 0) { 364 if (strncmp(argv[0], "temp", 4) == 0) { 365 struct timeval time; 366 gettimeofday(&time, 0); 367 expire_time = time.tv_sec + 20 * 60; 368 } 369 argv++; 370 } 371 tryagain: 372 if (rtmsg(RTM_GET) < 0) { 373 perror(host); 374 return (1); 375 } 376 sin = (struct sockaddr_in6 *)(rtm + 1); 377 sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); 378 if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { 379 if (sdl->sdl_family == AF_LINK && 380 (rtm->rtm_flags & RTF_LLINFO) && 381 !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { 382 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 383 case IFT_ISO88024: case IFT_ISO88025: 384 goto overwrite; 385 } 386 goto tryagain; 387 } 388 overwrite: 389 if (sdl->sdl_family != AF_LINK) { 390 printf("cannot intuit interface index and type for %s\n", host); 391 return (1); 392 } 393 sdl_m.sdl_type = sdl->sdl_type; 394 sdl_m.sdl_index = sdl->sdl_index; 395 return (rtmsg(RTM_ADD)); 396 } 397 398 /* 399 * Display an individual neighbor cache entry 400 */ 401 void 402 get(host) 403 char *host; 404 { 405 struct sockaddr_in6 *sin = &sin_m; 406 struct addrinfo hints, *res; 407 int gai_error; 408 409 sin_m = blank_sin; 410 bzero(&hints, sizeof(hints)); 411 hints.ai_family = AF_INET6; 412 gai_error = getaddrinfo(host, NULL, &hints, &res); 413 if (gai_error) { 414 fprintf(stderr, "ndp: %s: %s\n", host, 415 gai_strerror(gai_error)); 416 return; 417 } 418 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 419 dump(&sin->sin6_addr); 420 if (found_entry == 0) { 421 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 422 sizeof(host_buf), NULL ,0, 423 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 424 printf("%s (%s) -- no entry\n", host, host_buf); 425 exit(1); 426 } 427 } 428 429 /* 430 * Delete a neighbor cache entry 431 */ 432 int 433 delete(host) 434 char *host; 435 { 436 struct sockaddr_in6 *sin = &sin_m; 437 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 438 struct sockaddr_dl *sdl; 439 struct addrinfo hints, *res; 440 int gai_error; 441 442 getsocket(); 443 sin_m = blank_sin; 444 445 bzero(&hints, sizeof(hints)); 446 hints.ai_family = AF_INET6; 447 gai_error = getaddrinfo(host, NULL, &hints, &res); 448 if (gai_error) { 449 fprintf(stderr, "ndp: %s: %s\n", host, 450 gai_strerror(gai_error)); 451 return 1; 452 } 453 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 454 /*tryagain:*/ 455 if (rtmsg(RTM_GET) < 0) { 456 perror(host); 457 return (1); 458 } 459 sin = (struct sockaddr_in6 *)(rtm + 1); 460 sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); 461 if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { 462 if (sdl->sdl_family == AF_LINK && 463 (rtm->rtm_flags & RTF_LLINFO) && 464 !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { 465 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 466 case IFT_ISO88024: case IFT_ISO88025: 467 goto delete; 468 } 469 } 470 delete: 471 if (sdl->sdl_family != AF_LINK) { 472 printf("cannot locate %s\n", host); 473 return (1); 474 } 475 if (rtmsg(RTM_DELETE) == 0) { 476 getnameinfo((struct sockaddr *)sin, 477 sin->sin6_len, host_buf, 478 sizeof(host_buf), NULL, 0, 479 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 480 printf("%s (%s) deleted\n", host, host_buf); 481 } 482 483 return 0; 484 } 485 486 /* 487 * Dump the entire neighbor cache 488 */ 489 void 490 dump(addr) 491 struct in6_addr *addr; 492 { 493 int mib[6]; 494 size_t needed; 495 char *host, *lim, *buf, *next; 496 struct rt_msghdr *rtm; 497 struct sockaddr_in6 *sin; 498 struct sockaddr_dl *sdl; 499 extern int h_errno; 500 struct hostent *hp; 501 struct in6_nbrinfo *nbi; 502 struct timeval time; 503 int addrwidth; 504 505 /* Print header */ 506 if (!tflag) 507 printf("%-29.29s %-18.18s %6.6s %-9.9s %2s %4s %4s\n", 508 "Neighbor", "Linklayer Address", "Netif", "Expire", 509 "St", "Flgs", "Prbs"); 510 511 again:; 512 mib[0] = CTL_NET; 513 mib[1] = PF_ROUTE; 514 mib[2] = 0; 515 mib[3] = AF_INET6; 516 mib[4] = NET_RT_FLAGS; 517 mib[5] = RTF_LLINFO; 518 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 519 err(1, "sysctl(PF_ROUTE estimate)"); 520 if (needed > 0) { 521 if ((buf = malloc(needed)) == NULL) 522 errx(1, "malloc"); 523 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 524 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)"); 525 lim = buf + needed; 526 } else 527 buf = lim = NULL; 528 529 for (next = buf; next && next < lim; next += rtm->rtm_msglen) { 530 int isrouter = 0, prbs = 0; 531 532 rtm = (struct rt_msghdr *)next; 533 sin = (struct sockaddr_in6 *)(rtm + 1); 534 sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len)); 535 if (addr) { 536 if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr)) 537 continue; 538 found_entry = 1; 539 } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) 540 continue; 541 if (fflag == 1) { 542 delete((char *)inet_ntop(AF_INET6, &sin->sin6_addr, 543 ntop_buf, sizeof(ntop_buf))); 544 continue; 545 } 546 547 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) || 548 IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) { 549 /* XXX: should scope id be filled in the kernel? */ 550 if (sin->sin6_scope_id == 0) 551 sin->sin6_scope_id = sdl->sdl_index; 552 553 /* XXX: KAME specific hack; removed the embedded id */ 554 *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0; 555 } 556 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 557 sizeof(host_buf), NULL, 0, 558 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 559 gettimeofday(&time, 0); 560 if (tflag) 561 ts_print(&time); 562 563 if (lflag) { 564 addrwidth = strlen(host_buf); 565 if (addrwidth < 29) 566 addrwidth = 29; 567 } else 568 addrwidth = 29; 569 570 printf("%-*.*s %-18.18s %6.6s", addrwidth, addrwidth, host_buf, 571 ether_str(sdl), 572 if_indextoname(sdl->sdl_index, ifix_buf)); 573 574 /* Print neighbor discovery specific informations */ 575 putchar(' '); 576 nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index); 577 if (nbi) { 578 if (nbi->expire > time.tv_sec) { 579 printf(" %-9.9s", 580 sec2str(nbi->expire - time.tv_sec)); 581 } 582 else if (nbi->expire == 0) 583 printf(" %-9.9s", "permanent"); 584 else 585 printf(" %-9.9s", "expired"); 586 587 switch(nbi->state) { 588 case ND6_LLINFO_NOSTATE: 589 printf(" N"); 590 break; 591 case ND6_LLINFO_WAITDELETE: 592 printf(" W"); 593 break; 594 case ND6_LLINFO_INCOMPLETE: 595 printf(" I"); 596 break; 597 case ND6_LLINFO_REACHABLE: 598 printf(" R"); 599 break; 600 case ND6_LLINFO_STALE: 601 printf(" S"); 602 break; 603 case ND6_LLINFO_DELAY: 604 printf(" D"); 605 break; 606 case ND6_LLINFO_PROBE: 607 printf(" P"); 608 break; 609 default: 610 printf(" ?"); 611 break; 612 } 613 614 isrouter = nbi->isrouter; 615 prbs = nbi->asked; 616 } 617 else { 618 warnx("failed to get neighbor information"); 619 printf(" "); 620 } 621 622 /* other flags */ 623 putchar(' '); 624 { 625 u_char flgbuf[8], *p = flgbuf; 626 627 flgbuf[0] = '\0'; 628 if (isrouter) 629 p += sprintf((char *)p, "R"); 630 #ifndef RADISH 631 if (rtm->rtm_addrs & RTA_NETMASK) { 632 sin = (struct sockaddr_in6 *) 633 (sdl->sdl_len + (char *)sdl); 634 if (!IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)) 635 p += sprintf((char *)p, "P"); 636 if (sin->sin6_len != sizeof(struct sockaddr_in6)) 637 p += sprintf((char *)p, "W"); 638 } 639 #endif /*RADISH*/ 640 printf("%4s", flgbuf); 641 } 642 643 putchar(' '); 644 if (prbs) 645 printf("% 4d", prbs); 646 647 printf("\n"); 648 } 649 650 if (repeat) { 651 printf("\n"); 652 sleep(repeat); 653 goto again; 654 } 655 } 656 657 static struct in6_nbrinfo * 658 getnbrinfo(addr, ifindex) 659 struct in6_addr *addr; 660 int ifindex; 661 { 662 static struct in6_nbrinfo nbi; 663 int s; 664 665 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 666 err(1, "socket"); 667 668 bzero(&nbi, sizeof(nbi)); 669 if_indextoname(ifindex, nbi.ifname); 670 nbi.addr = *addr; 671 if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) { 672 warn("ioctl"); 673 close(s); 674 return(NULL); 675 } 676 677 close(s); 678 return(&nbi); 679 } 680 681 static char * 682 ether_str(sdl) 683 struct sockaddr_dl *sdl; 684 { 685 static char ebuf[32]; 686 u_char *cp; 687 688 if (sdl->sdl_alen) { 689 cp = (u_char *)LLADDR(sdl); 690 sprintf(ebuf, "%x:%x:%x:%x:%x:%x", 691 cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); 692 } 693 else { 694 sprintf(ebuf, "(incomplete)"); 695 } 696 697 return(ebuf); 698 } 699 700 int 701 ndp_ether_aton(a, n) 702 char *a; 703 u_char *n; 704 { 705 int i, o[6]; 706 707 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 708 &o[3], &o[4], &o[5]); 709 if (i != 6) { 710 fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a); 711 return (1); 712 } 713 for (i=0; i<6; i++) 714 n[i] = o[i]; 715 return (0); 716 } 717 718 void 719 usage() 720 { 721 printf("usage: ndp hostname\n"); 722 printf(" ndp -a[ntl]\n"); 723 printf(" ndp [-ntl] -A wait\n"); 724 printf(" ndp -c[nt]\n"); 725 printf(" ndp -d[nt] hostname\n"); 726 printf(" ndp -f[nt] filename\n"); 727 printf(" ndp -i interface\n"); 728 printf(" ndp -p\n"); 729 printf(" ndp -r\n"); 730 printf(" ndp -s hostname ether_addr [temp]\n"); 731 printf(" ndp -H\n"); 732 printf(" ndp -P\n"); 733 printf(" ndp -R\n"); 734 exit(1); 735 } 736 737 int 738 rtmsg(cmd) 739 int cmd; 740 { 741 static int seq; 742 int rlen; 743 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 744 register char *cp = m_rtmsg.m_space; 745 register int l; 746 747 errno = 0; 748 if (cmd == RTM_DELETE) 749 goto doit; 750 bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 751 rtm->rtm_flags = flags; 752 rtm->rtm_version = RTM_VERSION; 753 754 switch (cmd) { 755 default: 756 fprintf(stderr, "ndp: internal wrong cmd\n"); 757 exit(1); 758 case RTM_ADD: 759 rtm->rtm_addrs |= RTA_GATEWAY; 760 rtm->rtm_rmx.rmx_expire = expire_time; 761 rtm->rtm_inits = RTV_EXPIRE; 762 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); 763 /* FALLTHROUGH */ 764 case RTM_GET: 765 rtm->rtm_addrs |= RTA_DST; 766 } 767 #define NEXTADDR(w, s) \ 768 if (rtm->rtm_addrs & (w)) { \ 769 bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);} 770 771 NEXTADDR(RTA_DST, sin_m); 772 NEXTADDR(RTA_GATEWAY, sdl_m); 773 NEXTADDR(RTA_NETMASK, so_mask); 774 775 rtm->rtm_msglen = cp - (char *)&m_rtmsg; 776 doit: 777 l = rtm->rtm_msglen; 778 rtm->rtm_seq = ++seq; 779 rtm->rtm_type = cmd; 780 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 781 if (errno != ESRCH || cmd != RTM_DELETE) { 782 perror("writing to routing socket"); 783 return (-1); 784 } 785 } 786 do { 787 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 788 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 789 if (l < 0) 790 (void) fprintf(stderr, "ndp: read from routing socket: %s\n", 791 strerror(errno)); 792 return (0); 793 } 794 795 void 796 ifinfo(ifname) 797 char *ifname; 798 { 799 struct in6_ndireq nd; 800 int s; 801 802 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 803 perror("ndp: socket"); 804 exit(1); 805 } 806 bzero(&nd, sizeof(nd)); 807 strcpy(nd.ifname, ifname); 808 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 809 perror("ioctl (SIOCGIFINFO_IN6)"); 810 exit(1); 811 } 812 #define ND nd.ndi 813 printf("linkmtu=%d", ND.linkmtu); 814 printf(", curhlim=%d", ND.chlim); 815 printf(", basereachable=%ds%dms", 816 ND.basereachable / 1000, ND.basereachable % 1000); 817 printf(", reachable=%ds", ND.reachable); 818 printf(", retrans=%ds%dms\n", ND.retrans / 1000, ND.retrans % 1000); 819 #undef ND 820 close(s); 821 } 822 823 void 824 rtrlist() 825 { 826 struct in6_drlist dr; 827 int s, i; 828 struct timeval time; 829 830 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 831 perror("ndp: socket"); 832 exit(1); 833 } 834 bzero(&dr, sizeof(dr)); 835 strcpy(dr.ifname, "lo0"); /* dummy */ 836 if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 837 perror("ioctl (SIOCGDRLST_IN6)"); 838 exit(1); 839 } 840 #define DR dr.defrouter[i] 841 for (i = 0 ; DR.if_index && i < PRLSTSIZ ; i++) { 842 struct sockaddr_in6 sin6; 843 844 bzero(&sin6, sizeof(sin6)); 845 sin6.sin6_family = AF_INET6; 846 sin6.sin6_len = sizeof(sin6); 847 sin6.sin6_addr = DR.rtaddr; 848 getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf, 849 sizeof(host_buf), NULL, 0, 850 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 851 852 printf("%s if=%s", host_buf, 853 if_indextoname(DR.if_index, ifix_buf)); 854 printf(", flags=%s%s", 855 DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", 856 DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); 857 gettimeofday(&time, 0); 858 if (DR.expire == 0) 859 printf(", expire=Never\n"); 860 else 861 printf(", expire=%s\n", 862 sec2str(DR.expire - time.tv_sec)); 863 } 864 #undef DR 865 close(s); 866 } 867 868 void 869 plist() 870 { 871 struct in6_prlist pr; 872 int s, i; 873 struct timeval time; 874 875 gettimeofday(&time, 0); 876 877 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 878 perror("ndp: socket"); 879 exit(1); 880 } 881 bzero(&pr, sizeof(pr)); 882 strcpy(pr.ifname, "lo0"); /* dummy */ 883 if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { 884 perror("ioctl (SIOCGPRLST_IN6)"); 885 exit(1); 886 } 887 #define PR pr.prefix[i] 888 for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { 889 printf("%s/%d if=%s\n", 890 inet_ntop(AF_INET6, &PR.prefix, ntop_buf, 891 sizeof(ntop_buf)), PR.prefixlen, 892 if_indextoname(PR.if_index, ifix_buf)); 893 gettimeofday(&time, 0); 894 printf(" flags=%s%s", 895 PR.raflags.onlink ? "L" : "", 896 PR.raflags.autonomous ? "A" : ""); 897 if (PR.vltime == ND6_INFINITE_LIFETIME) 898 printf(" vltime=infinity"); 899 else 900 printf(" vltime=%ld", (long)PR.vltime); 901 if (PR.pltime == ND6_INFINITE_LIFETIME) 902 printf(", pltime=infinity"); 903 else 904 printf(", pltime=%ld", (long)PR.pltime); 905 if (PR.expire == 0) 906 printf(", expire=Never\n"); 907 else if (PR.expire >= time.tv_sec) 908 printf(", expire=%s\n", 909 sec2str(PR.expire - time.tv_sec)); 910 else 911 printf(", expired\n"); 912 if (PR.advrtrs) { 913 int j; 914 printf(" advertised by\n"); 915 for (j = 0; j < PR.advrtrs; j++) { 916 struct sockaddr_in6 sin6; 917 918 bzero(&sin6, sizeof(sin6)); 919 sin6.sin6_family = AF_INET6; 920 sin6.sin6_len = sizeof(sin6); 921 sin6.sin6_addr = PR.advrtr[j]; 922 getnameinfo((struct sockaddr *)&sin6, 923 sin6.sin6_len, host_buf, 924 sizeof(host_buf), NULL, 0, 925 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 926 927 printf(" %s\n", host_buf); 928 } 929 if (PR.advrtrs > DRLSTSIZ) 930 printf(" and %d routers\n", 931 PR.advrtrs - DRLSTSIZ); 932 } 933 else 934 printf(" No advertising router\n"); 935 } 936 #undef PR 937 close(s); 938 } 939 940 void 941 pfx_flush() 942 { 943 char dummyif[IFNAMSIZ+8]; 944 int s; 945 946 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 947 err(1, "socket"); 948 strcpy(dummyif, "lo0"); /* dummy */ 949 if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0) 950 err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); 951 } 952 953 void 954 rtr_flush() 955 { 956 char dummyif[IFNAMSIZ+8]; 957 int s; 958 959 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 960 err(1, "socket"); 961 strcpy(dummyif, "lo0"); /* dummy */ 962 if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0) 963 err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); 964 } 965 966 void 967 harmonize_rtr() 968 { 969 char dummyif[IFNAMSIZ+8]; 970 int s; 971 972 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 973 perror("ndp: socket"); 974 exit(1); 975 } 976 strcpy(dummyif, "lo0"); /* dummy */ 977 if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) { 978 perror("ioctl (SIOCSNDFLUSH_IN6)"); 979 exit(1); 980 } 981 } 982 983 static char * 984 sec2str(total) 985 time_t total; 986 { 987 static char result[256]; 988 int days, hours, mins, secs; 989 int first = 1; 990 char *p = result; 991 992 days = total / 3600 / 24; 993 hours = (total / 3600) % 24; 994 mins = (total / 60) % 60; 995 secs = total % 60; 996 997 if (days) { 998 first = 0; 999 p += sprintf(p, "%dd", days); 1000 } 1001 if (!first || hours) { 1002 first = 0; 1003 p += sprintf(p, "%dh", hours); 1004 } 1005 if (!first || mins) { 1006 first = 0; 1007 p += sprintf(p, "%dm", mins); 1008 } 1009 sprintf(p, "%ds", secs); 1010 1011 return(result); 1012 } 1013 1014 /* 1015 * Print the timestamp 1016 * from tcpdump/util.c 1017 */ 1018 static void 1019 ts_print(tvp) 1020 const struct timeval *tvp; 1021 { 1022 int s; 1023 1024 /* Default */ 1025 s = (tvp->tv_sec + thiszone) % 86400; 1026 (void)printf("%02d:%02d:%02d.%06u ", 1027 s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec); 1028 } 1029