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