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 return 0; 471 delete: 472 if (sdl->sdl_family != AF_LINK) { 473 printf("cannot locate %s\n", host); 474 return (1); 475 } 476 if (rtmsg(RTM_DELETE) == 0) { 477 getnameinfo((struct sockaddr *)sin, 478 sin->sin6_len, host_buf, 479 sizeof(host_buf), NULL, 0, 480 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 481 printf("%s (%s) deleted\n", host, host_buf); 482 } 483 484 return 0; 485 } 486 487 /* 488 * Dump the entire neighbor cache 489 */ 490 void 491 dump(addr) 492 struct in6_addr *addr; 493 { 494 int mib[6]; 495 size_t needed; 496 char *host, *lim, *buf, *next; 497 struct rt_msghdr *rtm; 498 struct sockaddr_in6 *sin; 499 struct sockaddr_dl *sdl; 500 extern int h_errno; 501 struct hostent *hp; 502 struct in6_nbrinfo *nbi; 503 struct timeval time; 504 int addrwidth; 505 506 /* Print header */ 507 if (!tflag) 508 printf("%-29.29s %-18.18s %6.6s %-9.9s %2s %4s %4s\n", 509 "Neighbor", "Linklayer Address", "Netif", "Expire", 510 "St", "Flgs", "Prbs"); 511 512 again:; 513 mib[0] = CTL_NET; 514 mib[1] = PF_ROUTE; 515 mib[2] = 0; 516 mib[3] = AF_INET6; 517 mib[4] = NET_RT_FLAGS; 518 mib[5] = RTF_LLINFO; 519 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 520 err(1, "sysctl(PF_ROUTE estimate)"); 521 if (needed > 0) { 522 if ((buf = malloc(needed)) == NULL) 523 errx(1, "malloc"); 524 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 525 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)"); 526 lim = buf + needed; 527 } else 528 buf = lim = NULL; 529 530 for (next = buf; next && next < lim; next += rtm->rtm_msglen) { 531 int isrouter = 0, prbs = 0; 532 533 rtm = (struct rt_msghdr *)next; 534 sin = (struct sockaddr_in6 *)(rtm + 1); 535 sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len)); 536 if (addr) { 537 if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr)) 538 continue; 539 found_entry = 1; 540 } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) 541 continue; 542 if (fflag == 1) { 543 delete((char *)inet_ntop(AF_INET6, &sin->sin6_addr, 544 ntop_buf, sizeof(ntop_buf))); 545 continue; 546 } 547 548 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) || 549 IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) { 550 /* XXX: should scope id be filled in the kernel? */ 551 if (sin->sin6_scope_id == 0) 552 sin->sin6_scope_id = sdl->sdl_index; 553 554 /* XXX: KAME specific hack; removed the embedded id */ 555 *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0; 556 } 557 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 558 sizeof(host_buf), NULL, 0, 559 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 560 gettimeofday(&time, 0); 561 if (tflag) 562 ts_print(&time); 563 564 if (lflag) { 565 addrwidth = strlen(host_buf); 566 if (addrwidth < 29) 567 addrwidth = 29; 568 } else 569 addrwidth = 29; 570 571 printf("%-*.*s %-18.18s %6.6s", addrwidth, addrwidth, host_buf, 572 ether_str(sdl), 573 if_indextoname(sdl->sdl_index, ifix_buf)); 574 575 /* Print neighbor discovery specific informations */ 576 putchar(' '); 577 nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index); 578 if (nbi) { 579 if (nbi->expire > time.tv_sec) { 580 printf(" %-9.9s", 581 sec2str(nbi->expire - time.tv_sec)); 582 } 583 else if (nbi->expire == 0) 584 printf(" %-9.9s", "permanent"); 585 else 586 printf(" %-9.9s", "expired"); 587 588 switch(nbi->state) { 589 case ND6_LLINFO_NOSTATE: 590 printf(" N"); 591 break; 592 case ND6_LLINFO_WAITDELETE: 593 printf(" W"); 594 break; 595 case ND6_LLINFO_INCOMPLETE: 596 printf(" I"); 597 break; 598 case ND6_LLINFO_REACHABLE: 599 printf(" R"); 600 break; 601 case ND6_LLINFO_STALE: 602 printf(" S"); 603 break; 604 case ND6_LLINFO_DELAY: 605 printf(" D"); 606 break; 607 case ND6_LLINFO_PROBE: 608 printf(" P"); 609 break; 610 default: 611 printf(" ?"); 612 break; 613 } 614 615 isrouter = nbi->isrouter; 616 prbs = nbi->asked; 617 } 618 else { 619 warnx("failed to get neighbor information"); 620 printf(" "); 621 } 622 623 /* other flags */ 624 putchar(' '); 625 { 626 u_char flgbuf[8], *p = flgbuf; 627 628 flgbuf[0] = '\0'; 629 if (isrouter) 630 p += sprintf((char *)p, "R"); 631 #ifndef RADISH 632 if (rtm->rtm_addrs & RTA_NETMASK) { 633 sin = (struct sockaddr_in6 *) 634 (sdl->sdl_len + (char *)sdl); 635 if (!IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)) 636 p += sprintf((char *)p, "P"); 637 if (sin->sin6_len != sizeof(struct sockaddr_in6)) 638 p += sprintf((char *)p, "W"); 639 } 640 #endif /*RADISH*/ 641 printf("%4s", flgbuf); 642 } 643 644 putchar(' '); 645 if (prbs) 646 printf("% 4d", prbs); 647 648 printf("\n"); 649 } 650 651 if (repeat) { 652 printf("\n"); 653 sleep(repeat); 654 goto again; 655 } 656 } 657 658 static struct in6_nbrinfo * 659 getnbrinfo(addr, ifindex) 660 struct in6_addr *addr; 661 int ifindex; 662 { 663 static struct in6_nbrinfo nbi; 664 int s; 665 666 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 667 err(1, "socket"); 668 669 bzero(&nbi, sizeof(nbi)); 670 if_indextoname(ifindex, nbi.ifname); 671 nbi.addr = *addr; 672 if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) { 673 warn("ioctl"); 674 close(s); 675 return(NULL); 676 } 677 678 close(s); 679 return(&nbi); 680 } 681 682 static char * 683 ether_str(sdl) 684 struct sockaddr_dl *sdl; 685 { 686 static char ebuf[32]; 687 u_char *cp; 688 689 if (sdl->sdl_alen) { 690 cp = (u_char *)LLADDR(sdl); 691 sprintf(ebuf, "%x:%x:%x:%x:%x:%x", 692 cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); 693 } 694 else { 695 sprintf(ebuf, "(incomplete)"); 696 } 697 698 return(ebuf); 699 } 700 701 int 702 ndp_ether_aton(a, n) 703 char *a; 704 u_char *n; 705 { 706 int i, o[6]; 707 708 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 709 &o[3], &o[4], &o[5]); 710 if (i != 6) { 711 fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a); 712 return (1); 713 } 714 for (i=0; i<6; i++) 715 n[i] = o[i]; 716 return (0); 717 } 718 719 void 720 usage() 721 { 722 printf("usage: ndp hostname\n"); 723 printf(" ndp -a[ntl]\n"); 724 printf(" ndp [-ntl] -A wait\n"); 725 printf(" ndp -c[nt]\n"); 726 printf(" ndp -d[nt] hostname\n"); 727 printf(" ndp -f[nt] filename\n"); 728 printf(" ndp -i interface\n"); 729 printf(" ndp -p\n"); 730 printf(" ndp -r\n"); 731 printf(" ndp -s hostname ether_addr [temp]\n"); 732 printf(" ndp -H\n"); 733 printf(" ndp -P\n"); 734 printf(" ndp -R\n"); 735 exit(1); 736 } 737 738 int 739 rtmsg(cmd) 740 int cmd; 741 { 742 static int seq; 743 int rlen; 744 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 745 register char *cp = m_rtmsg.m_space; 746 register int l; 747 748 errno = 0; 749 if (cmd == RTM_DELETE) 750 goto doit; 751 bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 752 rtm->rtm_flags = flags; 753 rtm->rtm_version = RTM_VERSION; 754 755 switch (cmd) { 756 default: 757 fprintf(stderr, "ndp: internal wrong cmd\n"); 758 exit(1); 759 case RTM_ADD: 760 rtm->rtm_addrs |= RTA_GATEWAY; 761 rtm->rtm_rmx.rmx_expire = expire_time; 762 rtm->rtm_inits = RTV_EXPIRE; 763 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); 764 /* FALLTHROUGH */ 765 case RTM_GET: 766 rtm->rtm_addrs |= RTA_DST; 767 } 768 #define NEXTADDR(w, s) \ 769 if (rtm->rtm_addrs & (w)) { \ 770 bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);} 771 772 NEXTADDR(RTA_DST, sin_m); 773 NEXTADDR(RTA_GATEWAY, sdl_m); 774 NEXTADDR(RTA_NETMASK, so_mask); 775 776 rtm->rtm_msglen = cp - (char *)&m_rtmsg; 777 doit: 778 l = rtm->rtm_msglen; 779 rtm->rtm_seq = ++seq; 780 rtm->rtm_type = cmd; 781 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 782 if (errno != ESRCH || cmd != RTM_DELETE) { 783 perror("writing to routing socket"); 784 return (-1); 785 } 786 } 787 do { 788 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 789 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 790 if (l < 0) 791 (void) fprintf(stderr, "ndp: read from routing socket: %s\n", 792 strerror(errno)); 793 return (0); 794 } 795 796 void 797 ifinfo(ifname) 798 char *ifname; 799 { 800 struct in6_ndireq nd; 801 int s; 802 803 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 804 perror("ndp: socket"); 805 exit(1); 806 } 807 bzero(&nd, sizeof(nd)); 808 strcpy(nd.ifname, ifname); 809 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 810 perror("ioctl (SIOCGIFINFO_IN6)"); 811 exit(1); 812 } 813 #define ND nd.ndi 814 printf("linkmtu=%d", ND.linkmtu); 815 printf(", curhlim=%d", ND.chlim); 816 printf(", basereachable=%ds%dms", 817 ND.basereachable / 1000, ND.basereachable % 1000); 818 printf(", reachable=%ds", ND.reachable); 819 printf(", retrans=%ds%dms\n", ND.retrans / 1000, ND.retrans % 1000); 820 #undef ND 821 close(s); 822 } 823 824 void 825 rtrlist() 826 { 827 struct in6_drlist dr; 828 int s, i; 829 struct timeval time; 830 831 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 832 perror("ndp: socket"); 833 exit(1); 834 } 835 bzero(&dr, sizeof(dr)); 836 strcpy(dr.ifname, "lo0"); /* dummy */ 837 if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 838 perror("ioctl (SIOCGDRLST_IN6)"); 839 exit(1); 840 } 841 #define DR dr.defrouter[i] 842 for (i = 0 ; DR.if_index && i < PRLSTSIZ ; i++) { 843 struct sockaddr_in6 sin6; 844 845 bzero(&sin6, sizeof(sin6)); 846 sin6.sin6_family = AF_INET6; 847 sin6.sin6_len = sizeof(sin6); 848 sin6.sin6_addr = DR.rtaddr; 849 getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf, 850 sizeof(host_buf), NULL, 0, 851 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 852 853 printf("%s if=%s", host_buf, 854 if_indextoname(DR.if_index, ifix_buf)); 855 printf(", flags=%s%s", 856 DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", 857 DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); 858 gettimeofday(&time, 0); 859 if (DR.expire == 0) 860 printf(", expire=Never\n"); 861 else 862 printf(", expire=%s\n", 863 sec2str(DR.expire - time.tv_sec)); 864 } 865 #undef DR 866 close(s); 867 } 868 869 void 870 plist() 871 { 872 struct in6_prlist pr; 873 int s, i; 874 struct timeval time; 875 876 gettimeofday(&time, 0); 877 878 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 879 perror("ndp: socket"); 880 exit(1); 881 } 882 bzero(&pr, sizeof(pr)); 883 strcpy(pr.ifname, "lo0"); /* dummy */ 884 if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { 885 perror("ioctl (SIOCGPRLST_IN6)"); 886 exit(1); 887 } 888 #define PR pr.prefix[i] 889 for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { 890 printf("%s/%d if=%s\n", 891 inet_ntop(AF_INET6, &PR.prefix, ntop_buf, 892 sizeof(ntop_buf)), PR.prefixlen, 893 if_indextoname(PR.if_index, ifix_buf)); 894 gettimeofday(&time, 0); 895 printf(" flags=%s%s", 896 PR.raflags.onlink ? "L" : "", 897 PR.raflags.autonomous ? "A" : ""); 898 if (PR.vltime == ND6_INFINITE_LIFETIME) 899 printf(" vltime=infinity"); 900 else 901 printf(" vltime=%ld", (long)PR.vltime); 902 if (PR.pltime == ND6_INFINITE_LIFETIME) 903 printf(", pltime=infinity"); 904 else 905 printf(", pltime=%ld", (long)PR.pltime); 906 if (PR.expire == 0) 907 printf(", expire=Never\n"); 908 else if (PR.expire >= time.tv_sec) 909 printf(", expire=%s\n", 910 sec2str(PR.expire - time.tv_sec)); 911 else 912 printf(", expired\n"); 913 if (PR.advrtrs) { 914 int j; 915 printf(" advertised by\n"); 916 for (j = 0; j < PR.advrtrs; j++) { 917 struct sockaddr_in6 sin6; 918 919 bzero(&sin6, sizeof(sin6)); 920 sin6.sin6_family = AF_INET6; 921 sin6.sin6_len = sizeof(sin6); 922 sin6.sin6_addr = PR.advrtr[j]; 923 getnameinfo((struct sockaddr *)&sin6, 924 sin6.sin6_len, host_buf, 925 sizeof(host_buf), NULL, 0, 926 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 927 928 printf(" %s\n", host_buf); 929 } 930 if (PR.advrtrs > DRLSTSIZ) 931 printf(" and %d routers\n", 932 PR.advrtrs - DRLSTSIZ); 933 } 934 else 935 printf(" No advertising router\n"); 936 } 937 #undef PR 938 close(s); 939 } 940 941 void 942 pfx_flush() 943 { 944 char dummyif[IFNAMSIZ+8]; 945 int s; 946 947 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 948 err(1, "socket"); 949 strcpy(dummyif, "lo0"); /* dummy */ 950 if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0) 951 err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); 952 } 953 954 void 955 rtr_flush() 956 { 957 char dummyif[IFNAMSIZ+8]; 958 int s; 959 960 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 961 err(1, "socket"); 962 strcpy(dummyif, "lo0"); /* dummy */ 963 if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0) 964 err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); 965 } 966 967 void 968 harmonize_rtr() 969 { 970 char dummyif[IFNAMSIZ+8]; 971 int s; 972 973 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 974 perror("ndp: socket"); 975 exit(1); 976 } 977 strcpy(dummyif, "lo0"); /* dummy */ 978 if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) { 979 perror("ioctl (SIOCSNDFLUSH_IN6)"); 980 exit(1); 981 } 982 } 983 984 static char * 985 sec2str(total) 986 time_t total; 987 { 988 static char result[256]; 989 int days, hours, mins, secs; 990 int first = 1; 991 char *p = result; 992 993 days = total / 3600 / 24; 994 hours = (total / 3600) % 24; 995 mins = (total / 60) % 60; 996 secs = total % 60; 997 998 if (days) { 999 first = 0; 1000 p += sprintf(p, "%dd", days); 1001 } 1002 if (!first || hours) { 1003 first = 0; 1004 p += sprintf(p, "%dh", hours); 1005 } 1006 if (!first || mins) { 1007 first = 0; 1008 p += sprintf(p, "%dm", mins); 1009 } 1010 sprintf(p, "%ds", secs); 1011 1012 return(result); 1013 } 1014 1015 /* 1016 * Print the timestamp 1017 * from tcpdump/util.c 1018 */ 1019 static void 1020 ts_print(tvp) 1021 const struct timeval *tvp; 1022 { 1023 int s; 1024 1025 /* Default */ 1026 s = (tvp->tv_sec + thiszone) % 86400; 1027 (void)printf("%02d:%02d:%02d.%06u ", 1028 s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec); 1029 } 1030