ndp.c revision 253970
1/* $FreeBSD: head/usr.sbin/ndp/ndp.c 253970 2013-08-05 20:13:02Z hrs $ */ 2/* $KAME: ndp.c,v 1.104 2003/06/27 07:48:39 itojun Exp $ */ 3 4/* 5 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32/* 33 * Copyright (c) 1984, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * This code is derived from software contributed to Berkeley by 37 * Sun Microsystems, Inc. 38 * 39 * Redistribution and use in source and binary forms, with or without 40 * modification, are permitted provided that the following conditions 41 * are met: 42 * 1. Redistributions of source code must retain the above copyright 43 * notice, this list of conditions and the following disclaimer. 44 * 2. Redistributions in binary form must reproduce the above copyright 45 * notice, this list of conditions and the following disclaimer in the 46 * documentation and/or other materials provided with the distribution. 47 * 4. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 */ 63 64/* 65 * Based on: 66 * "@(#) Copyright (c) 1984, 1993\n\ 67 * The Regents of the University of California. All rights reserved.\n"; 68 * 69 * "@(#)arp.c 8.2 (Berkeley) 1/2/94"; 70 */ 71 72/* 73 * ndp - display, set, delete and flush neighbor cache 74 */ 75 76 77#include <sys/param.h> 78#include <sys/file.h> 79#include <sys/ioctl.h> 80#include <sys/socket.h> 81#include <sys/sysctl.h> 82#include <sys/queue.h> 83 84#include <net/if.h> 85#include <net/if_var.h> 86#include <net/if_dl.h> 87#include <net/if_types.h> 88#include <net/route.h> 89 90#include <netinet/in.h> 91#include <netinet/if_ether.h> 92 93#include <netinet/icmp6.h> 94#include <netinet6/in6_var.h> 95#include <netinet6/nd6.h> 96 97#include <arpa/inet.h> 98 99#include <netdb.h> 100#include <errno.h> 101#include <nlist.h> 102#include <stdio.h> 103#include <string.h> 104#include <paths.h> 105#include <err.h> 106#include <stdlib.h> 107#include <time.h> 108#include <fcntl.h> 109#include <unistd.h> 110#include "gmt2local.h" 111 112/* packing rule for routing socket */ 113#define ROUNDUP(a) \ 114 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 115#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 116 117#define NEXTADDR(w, s) \ 118 if (rtm->rtm_addrs & (w)) { \ 119 bcopy((char *)&s, cp, sizeof(s)); cp += SA_SIZE(&s);} 120 121 122static pid_t pid; 123static int nflag; 124static int tflag; 125static int32_t thiszone; /* time difference with gmt */ 126static int s = -1; 127static int repeat = 0; 128static struct timespec ts, ts0; 129 130char ntop_buf[INET6_ADDRSTRLEN]; /* inet_ntop() */ 131char host_buf[NI_MAXHOST]; /* getnameinfo() */ 132char ifix_buf[IFNAMSIZ]; /* if_indextoname() */ 133 134int main(int, char **); 135int file(char *); 136void getsocket(void); 137int set(int, char **); 138void get(char *); 139int delete(char *); 140void dump(struct in6_addr *, int); 141static struct in6_nbrinfo *getnbrinfo(struct in6_addr *, int, int); 142static char *ether_str(struct sockaddr_dl *); 143int ndp_ether_aton(char *, u_char *); 144void usage(void); 145int rtmsg(int); 146void ifinfo(char *, int, char **); 147void rtrlist(void); 148void plist(void); 149void pfx_flush(void); 150void rtr_flush(void); 151void harmonize_rtr(void); 152#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 153static void getdefif(void); 154static void setdefif(char *); 155#endif 156static char *sec2str(time_t); 157static void ts_print(const struct timespec *); 158 159#ifdef ICMPV6CTL_ND6_DRLIST 160static char *rtpref_str[] = { 161 "medium", /* 00 */ 162 "high", /* 01 */ 163 "rsv", /* 10 */ 164 "low" /* 11 */ 165}; 166#endif 167 168#define TS_SUB(tsp, usp, vsp) \ 169 do { \ 170 (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ 171 (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ 172 if ((vsp)->tv_nsec < 0) { \ 173 (vsp)->tv_sec--; \ 174 (vsp)->tv_nsec += 1000000000L; \ 175 } \ 176 } while (0) 177 178int mode = 0; 179char *arg = NULL; 180 181int 182main(argc, argv) 183 int argc; 184 char **argv; 185{ 186 struct timespec now; 187 int ch; 188 189 pid = getpid(); 190 thiszone = gmt2local(0); 191 clock_gettime(CLOCK_REALTIME_FAST, &now); 192 clock_gettime(CLOCK_MONOTONIC_FAST, &ts); 193 TS_SUB(&now, &ts, &ts0); 194 while ((ch = getopt(argc, argv, "acd:f:Ii:nprstA:HPR")) != -1) 195 switch (ch) { 196 case 'a': 197 case 'c': 198 case 'p': 199 case 'r': 200 case 'H': 201 case 'P': 202 case 'R': 203 case 's': 204 case 'I': 205 if (mode) { 206 usage(); 207 /*NOTREACHED*/ 208 } 209 mode = ch; 210 arg = NULL; 211 break; 212 case 'd': 213 case 'f': 214 case 'i' : 215 if (mode) { 216 usage(); 217 /*NOTREACHED*/ 218 } 219 mode = ch; 220 arg = optarg; 221 break; 222 case 'n': 223 nflag = 1; 224 break; 225 case 't': 226 tflag = 1; 227 break; 228 case 'A': 229 if (mode) { 230 usage(); 231 /*NOTREACHED*/ 232 } 233 mode = 'a'; 234 repeat = atoi(optarg); 235 if (repeat < 0) { 236 usage(); 237 /*NOTREACHED*/ 238 } 239 break; 240 default: 241 usage(); 242 } 243 244 argc -= optind; 245 argv += optind; 246 247 switch (mode) { 248 case 'a': 249 case 'c': 250 if (argc != 0) { 251 usage(); 252 /*NOTREACHED*/ 253 } 254 dump(0, mode == 'c'); 255 break; 256 case 'd': 257 if (argc != 0) { 258 usage(); 259 /*NOTREACHED*/ 260 } 261 delete(arg); 262 break; 263 case 'I': 264#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 265 if (argc > 1) { 266 usage(); 267 /*NOTREACHED*/ 268 } else if (argc == 1) { 269 if (strcmp(*argv, "delete") == 0 || 270 if_nametoindex(*argv)) 271 setdefif(*argv); 272 else 273 errx(1, "invalid interface %s", *argv); 274 } 275 getdefif(); /* always call it to print the result */ 276 break; 277#else 278 errx(1, "not supported yet"); 279 /*NOTREACHED*/ 280#endif 281 case 'p': 282 if (argc != 0) { 283 usage(); 284 /*NOTREACHED*/ 285 } 286 plist(); 287 break; 288 case 'i': 289 ifinfo(arg, argc, argv); 290 break; 291 case 'r': 292 if (argc != 0) { 293 usage(); 294 /*NOTREACHED*/ 295 } 296 rtrlist(); 297 break; 298 case 's': 299 if (argc < 2 || argc > 4) 300 usage(); 301 exit(set(argc, argv) ? 1 : 0); 302 case 'H': 303 if (argc != 0) { 304 usage(); 305 /*NOTREACHED*/ 306 } 307 harmonize_rtr(); 308 break; 309 case 'P': 310 if (argc != 0) { 311 usage(); 312 /*NOTREACHED*/ 313 } 314 pfx_flush(); 315 break; 316 case 'R': 317 if (argc != 0) { 318 usage(); 319 /*NOTREACHED*/ 320 } 321 rtr_flush(); 322 break; 323 case 0: 324 if (argc != 1) { 325 usage(); 326 /*NOTREACHED*/ 327 } 328 get(argv[0]); 329 break; 330 } 331 exit(0); 332} 333 334/* 335 * Process a file to set standard ndp entries 336 */ 337int 338file(name) 339 char *name; 340{ 341 FILE *fp; 342 int i, retval; 343 char line[100], arg[5][50], *args[5]; 344 345 if ((fp = fopen(name, "r")) == NULL) { 346 fprintf(stderr, "ndp: cannot open %s\n", name); 347 exit(1); 348 } 349 args[0] = &arg[0][0]; 350 args[1] = &arg[1][0]; 351 args[2] = &arg[2][0]; 352 args[3] = &arg[3][0]; 353 args[4] = &arg[4][0]; 354 retval = 0; 355 while (fgets(line, sizeof(line), fp) != NULL) { 356 i = sscanf(line, "%49s %49s %49s %49s %49s", 357 arg[0], arg[1], arg[2], arg[3], arg[4]); 358 if (i < 2) { 359 fprintf(stderr, "ndp: bad line: %s\n", line); 360 retval = 1; 361 continue; 362 } 363 if (set(i, args)) 364 retval = 1; 365 } 366 fclose(fp); 367 return (retval); 368} 369 370void 371getsocket() 372{ 373 if (s < 0) { 374 s = socket(PF_ROUTE, SOCK_RAW, 0); 375 if (s < 0) { 376 err(1, "socket"); 377 /* NOTREACHED */ 378 } 379 } 380} 381 382struct sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 }; 383struct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m; 384struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; 385static time_t expire_time; 386static int flags, found_entry; 387struct { 388 struct rt_msghdr m_rtm; 389 char m_space[512]; 390} m_rtmsg; 391 392/* 393 * Set an individual neighbor cache entry 394 */ 395int 396set(argc, argv) 397 int argc; 398 char **argv; 399{ 400 register struct sockaddr_in6 *sin = &sin_m; 401 register struct sockaddr_dl *sdl; 402 register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); 403 struct addrinfo hints, *res; 404 int gai_error; 405 u_char *ea; 406 char *host = argv[0], *eaddr = argv[1]; 407 408 getsocket(); 409 argc -= 2; 410 argv += 2; 411 sdl_m = blank_sdl; 412 sin_m = blank_sin; 413 414 bzero(&hints, sizeof(hints)); 415 hints.ai_family = AF_INET6; 416 gai_error = getaddrinfo(host, NULL, &hints, &res); 417 if (gai_error) { 418 fprintf(stderr, "ndp: %s: %s\n", host, 419 gai_strerror(gai_error)); 420 return 1; 421 } 422 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 423 sin->sin6_scope_id = 424 ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 425 ea = (u_char *)LLADDR(&sdl_m); 426 if (ndp_ether_aton(eaddr, ea) == 0) 427 sdl_m.sdl_alen = 6; 428 flags = expire_time = 0; 429 while (argc-- > 0) { 430 if (strncmp(argv[0], "temp", 4) == 0) { 431 struct timespec now; 432 433 clock_gettime(CLOCK_MONOTONIC_FAST, &now); 434 expire_time = now.tv_sec + 20 * 60; 435 } else if (strncmp(argv[0], "proxy", 5) == 0) 436 flags |= RTF_ANNOUNCE; 437 argv++; 438 } 439 if (rtmsg(RTM_GET) < 0) { 440 errx(1, "RTM_GET(%s) failed", host); 441 /* NOTREACHED */ 442 } 443 sin = (struct sockaddr_in6 *)(rtm + 1); 444 sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); 445 if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { 446 if (sdl->sdl_family == AF_LINK && 447 !(rtm->rtm_flags & RTF_GATEWAY)) { 448 switch (sdl->sdl_type) { 449 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 450 case IFT_ISO88024: case IFT_ISO88025: 451 case IFT_L2VLAN: case IFT_BRIDGE: 452 goto overwrite; 453 } 454 } 455 fprintf(stderr, "set: cannot configure a new entry\n"); 456 return 1; 457 } 458 459overwrite: 460 if (sdl->sdl_family != AF_LINK) { 461 printf("cannot intuit interface index and type for %s\n", host); 462 return (1); 463 } 464 sdl_m.sdl_type = sdl->sdl_type; 465 sdl_m.sdl_index = sdl->sdl_index; 466 return (rtmsg(RTM_ADD)); 467} 468 469/* 470 * Display an individual neighbor cache entry 471 */ 472void 473get(host) 474 char *host; 475{ 476 struct sockaddr_in6 *sin = &sin_m; 477 struct addrinfo hints, *res; 478 int gai_error; 479 480 sin_m = blank_sin; 481 bzero(&hints, sizeof(hints)); 482 hints.ai_family = AF_INET6; 483 gai_error = getaddrinfo(host, NULL, &hints, &res); 484 if (gai_error) { 485 fprintf(stderr, "ndp: %s: %s\n", host, 486 gai_strerror(gai_error)); 487 return; 488 } 489 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 490 dump(&sin->sin6_addr, 0); 491 if (found_entry == 0) { 492 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 493 sizeof(host_buf), NULL ,0, 494 (nflag ? NI_NUMERICHOST : 0)); 495 printf("%s (%s) -- no entry\n", host, host_buf); 496 exit(1); 497 } 498} 499 500/* 501 * Delete a neighbor cache entry 502 */ 503int 504delete(host) 505 char *host; 506{ 507 struct sockaddr_in6 *sin = &sin_m; 508 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 509 register char *cp = m_rtmsg.m_space; 510 struct sockaddr_dl *sdl; 511 struct addrinfo hints, *res; 512 int gai_error; 513 514 getsocket(); 515 sin_m = blank_sin; 516 517 bzero(&hints, sizeof(hints)); 518 hints.ai_family = AF_INET6; 519 gai_error = getaddrinfo(host, NULL, &hints, &res); 520 if (gai_error) { 521 fprintf(stderr, "ndp: %s: %s\n", host, 522 gai_strerror(gai_error)); 523 return 1; 524 } 525 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 526 sin->sin6_scope_id = 527 ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 528 if (rtmsg(RTM_GET) < 0) { 529 errx(1, "RTM_GET(%s) failed", host); 530 /* NOTREACHED */ 531 } 532 sin = (struct sockaddr_in6 *)(rtm + 1); 533 sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); 534 if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { 535 if (sdl->sdl_family == AF_LINK && 536 !(rtm->rtm_flags & RTF_GATEWAY)) { 537 goto delete; 538 } 539 fprintf(stderr, "delete: cannot delete non-NDP entry\n"); 540 return 1; 541 } 542 543delete: 544 if (sdl->sdl_family != AF_LINK) { 545 printf("cannot locate %s\n", host); 546 return (1); 547 } 548 /* 549 * need to reinit the field because it has rt_key 550 * but we want the actual address 551 */ 552 NEXTADDR(RTA_DST, sin_m); 553 rtm->rtm_flags |= RTF_LLDATA; 554 if (rtmsg(RTM_DELETE) == 0) { 555 getnameinfo((struct sockaddr *)sin, 556 sin->sin6_len, host_buf, 557 sizeof(host_buf), NULL, 0, 558 (nflag ? NI_NUMERICHOST : 0)); 559 printf("%s (%s) deleted\n", host, host_buf); 560 } 561 562 return 0; 563} 564 565#define W_ADDR 36 566#define W_LL 17 567#define W_IF 6 568 569/* 570 * Dump the entire neighbor cache 571 */ 572void 573dump(addr, cflag) 574 struct in6_addr *addr; 575 int cflag; 576{ 577 int mib[6]; 578 size_t needed; 579 char *lim, *buf, *next; 580 struct rt_msghdr *rtm; 581 struct sockaddr_in6 *sin; 582 struct sockaddr_dl *sdl; 583 extern int h_errno; 584 struct in6_nbrinfo *nbi; 585 struct timespec now; 586 int addrwidth; 587 int llwidth; 588 int ifwidth; 589 char flgbuf[8]; 590 char *ifname; 591 592 /* Print header */ 593 if (!tflag && !cflag) 594 printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %5s\n", 595 W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address", 596 W_IF, W_IF, "Netif", "Expire", "S", "Flags"); 597 598again:; 599 mib[0] = CTL_NET; 600 mib[1] = PF_ROUTE; 601 mib[2] = 0; 602 mib[3] = AF_INET6; 603 mib[4] = NET_RT_FLAGS; 604#ifdef RTF_LLINFO 605 mib[5] = RTF_LLINFO; 606#else 607 mib[5] = 0; 608#endif 609 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 610 err(1, "sysctl(PF_ROUTE estimate)"); 611 if (needed > 0) { 612 if ((buf = malloc(needed)) == NULL) 613 err(1, "malloc"); 614 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 615 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)"); 616 lim = buf + needed; 617 } else 618 buf = lim = NULL; 619 620 for (next = buf; next && next < lim; next += rtm->rtm_msglen) { 621 int isrouter = 0, prbs = 0; 622 623 rtm = (struct rt_msghdr *)next; 624 sin = (struct sockaddr_in6 *)(rtm + 1); 625 sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len)); 626 627 /* 628 * Some OSes can produce a route that has the LINK flag but 629 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD 630 * and BSD/OS, where xx is not the interface identifier on 631 * lo0). Such routes entry would annoy getnbrinfo() below, 632 * so we skip them. 633 * XXX: such routes should have the GATEWAY flag, not the 634 * LINK flag. However, there is rotten routing software 635 * that advertises all routes that have the GATEWAY flag. 636 * Thus, KAME kernel intentionally does not set the LINK flag. 637 * What is to be fixed is not ndp, but such routing software 638 * (and the kernel workaround)... 639 */ 640 if (sdl->sdl_family != AF_LINK) 641 continue; 642 643 if (!(rtm->rtm_flags & RTF_HOST)) 644 continue; 645 646 if (addr) { 647 if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr)) 648 continue; 649 found_entry = 1; 650 } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) 651 continue; 652 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) || 653 IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) { 654 /* XXX: should scope id be filled in the kernel? */ 655 if (sin->sin6_scope_id == 0) 656 sin->sin6_scope_id = sdl->sdl_index; 657 } 658 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 659 sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0)); 660 if (cflag) { 661#ifdef RTF_WASCLONED 662 if (rtm->rtm_flags & RTF_WASCLONED) 663 delete(host_buf); 664#elif defined(RTF_CLONED) 665 if (rtm->rtm_flags & RTF_CLONED) 666 delete(host_buf); 667#else 668 delete(host_buf); 669#endif 670 continue; 671 } 672 clock_gettime(CLOCK_MONOTONIC_FAST, &now); 673 if (tflag) 674 ts_print(&now); 675 676 addrwidth = strlen(host_buf); 677 if (addrwidth < W_ADDR) 678 addrwidth = W_ADDR; 679 llwidth = strlen(ether_str(sdl)); 680 if (W_ADDR + W_LL - addrwidth > llwidth) 681 llwidth = W_ADDR + W_LL - addrwidth; 682 ifname = if_indextoname(sdl->sdl_index, ifix_buf); 683 if (!ifname) 684 ifname = "?"; 685 ifwidth = strlen(ifname); 686 if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth) 687 ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth; 688 689 printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf, 690 llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname); 691 692 /* Print neighbor discovery specific informations */ 693 nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1); 694 if (nbi) { 695 if (nbi->expire > now.tv_sec) { 696 printf(" %-9.9s", 697 sec2str(nbi->expire - now.tv_sec)); 698 } else if (nbi->expire == 0) 699 printf(" %-9.9s", "permanent"); 700 else 701 printf(" %-9.9s", "expired"); 702 703 switch (nbi->state) { 704 case ND6_LLINFO_NOSTATE: 705 printf(" N"); 706 break; 707#ifdef ND6_LLINFO_WAITDELETE 708 case ND6_LLINFO_WAITDELETE: 709 printf(" W"); 710 break; 711#endif 712 case ND6_LLINFO_INCOMPLETE: 713 printf(" I"); 714 break; 715 case ND6_LLINFO_REACHABLE: 716 printf(" R"); 717 break; 718 case ND6_LLINFO_STALE: 719 printf(" S"); 720 break; 721 case ND6_LLINFO_DELAY: 722 printf(" D"); 723 break; 724 case ND6_LLINFO_PROBE: 725 printf(" P"); 726 break; 727 default: 728 printf(" ?"); 729 break; 730 } 731 732 isrouter = nbi->isrouter; 733 prbs = nbi->asked; 734 } else { 735 warnx("failed to get neighbor information"); 736 printf(" "); 737 } 738 739 /* 740 * other flags. R: router, P: proxy, W: ?? 741 */ 742 if ((rtm->rtm_addrs & RTA_NETMASK) == 0) { 743 snprintf(flgbuf, sizeof(flgbuf), "%s%s", 744 isrouter ? "R" : "", 745 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 746 } else { 747 sin = (struct sockaddr_in6 *) 748 (sdl->sdl_len + (char *)sdl); 749#if 0 /* W and P are mystery even for us */ 750 snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s", 751 isrouter ? "R" : "", 752 !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "P" : "", 753 (sin->sin6_len != sizeof(struct sockaddr_in6)) ? "W" : "", 754 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 755#else 756 snprintf(flgbuf, sizeof(flgbuf), "%s%s", 757 isrouter ? "R" : "", 758 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 759#endif 760 } 761 printf(" %s", flgbuf); 762 763 if (prbs) 764 printf(" %d", prbs); 765 766 printf("\n"); 767 } 768 if (buf != NULL) 769 free(buf); 770 771 if (repeat) { 772 printf("\n"); 773 fflush(stdout); 774 sleep(repeat); 775 goto again; 776 } 777} 778 779static struct in6_nbrinfo * 780getnbrinfo(addr, ifindex, warning) 781 struct in6_addr *addr; 782 int ifindex; 783 int warning; 784{ 785 static struct in6_nbrinfo nbi; 786 int s; 787 788 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 789 err(1, "socket"); 790 791 bzero(&nbi, sizeof(nbi)); 792 if_indextoname(ifindex, nbi.ifname); 793 nbi.addr = *addr; 794 if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) { 795 if (warning) 796 warn("ioctl(SIOCGNBRINFO_IN6)"); 797 close(s); 798 return(NULL); 799 } 800 801 close(s); 802 return(&nbi); 803} 804 805static char * 806ether_str(struct sockaddr_dl *sdl) 807{ 808 static char hbuf[NI_MAXHOST]; 809 char *cp; 810 811 if (sdl->sdl_alen == ETHER_ADDR_LEN) { 812 strlcpy(hbuf, ether_ntoa((struct ether_addr *)LLADDR(sdl)), 813 sizeof(hbuf)); 814 } else if (sdl->sdl_alen) { 815 int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0; 816 snprintf(hbuf, sizeof(hbuf), "%s", link_ntoa(sdl) + n); 817 } else 818 snprintf(hbuf, sizeof(hbuf), "(incomplete)"); 819 820 return(hbuf); 821} 822 823int 824ndp_ether_aton(a, n) 825 char *a; 826 u_char *n; 827{ 828 int i, o[6]; 829 830 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 831 &o[3], &o[4], &o[5]); 832 if (i != 6) { 833 fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a); 834 return (1); 835 } 836 for (i = 0; i < 6; i++) 837 n[i] = o[i]; 838 return (0); 839} 840 841void 842usage() 843{ 844 printf("usage: ndp [-nt] hostname\n"); 845 printf(" ndp [-nt] -a | -c | -p | -r | -H | -P | -R\n"); 846 printf(" ndp [-nt] -A wait\n"); 847 printf(" ndp [-nt] -d hostname\n"); 848 printf(" ndp [-nt] -f filename\n"); 849 printf(" ndp [-nt] -i interface [flags...]\n"); 850#ifdef SIOCSDEFIFACE_IN6 851 printf(" ndp [-nt] -I [interface|delete]\n"); 852#endif 853 printf(" ndp [-nt] -s nodename etheraddr [temp] [proxy]\n"); 854 exit(1); 855} 856 857int 858rtmsg(cmd) 859 int cmd; 860{ 861 static int seq; 862 int rlen; 863 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 864 register char *cp = m_rtmsg.m_space; 865 register int l; 866 867 errno = 0; 868 if (cmd == RTM_DELETE) 869 goto doit; 870 bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 871 rtm->rtm_flags = flags; 872 rtm->rtm_version = RTM_VERSION; 873 874 switch (cmd) { 875 default: 876 fprintf(stderr, "ndp: internal wrong cmd\n"); 877 exit(1); 878 case RTM_ADD: 879 rtm->rtm_addrs |= RTA_GATEWAY; 880 if (expire_time) { 881 rtm->rtm_rmx.rmx_expire = expire_time; 882 rtm->rtm_inits = RTV_EXPIRE; 883 } 884 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA); 885#if 0 /* we don't support ipv6addr/128 type proxying */ 886 if (rtm->rtm_flags & RTF_ANNOUNCE) { 887 rtm->rtm_flags &= ~RTF_HOST; 888 rtm->rtm_addrs |= RTA_NETMASK; 889 } 890#endif 891 /* FALLTHROUGH */ 892 case RTM_GET: 893 rtm->rtm_addrs |= RTA_DST; 894 } 895 896 NEXTADDR(RTA_DST, sin_m); 897 NEXTADDR(RTA_GATEWAY, sdl_m); 898#if 0 /* we don't support ipv6addr/128 type proxying */ 899 memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr)); 900 NEXTADDR(RTA_NETMASK, so_mask); 901#endif 902 903 rtm->rtm_msglen = cp - (char *)&m_rtmsg; 904doit: 905 l = rtm->rtm_msglen; 906 rtm->rtm_seq = ++seq; 907 rtm->rtm_type = cmd; 908 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 909 if (errno != ESRCH || cmd != RTM_DELETE) { 910 err(1, "writing to routing socket"); 911 /* NOTREACHED */ 912 } 913 } 914 do { 915 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 916 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 917 if (l < 0) 918 (void) fprintf(stderr, "ndp: read from routing socket: %s\n", 919 strerror(errno)); 920 return (0); 921} 922 923void 924ifinfo(ifname, argc, argv) 925 char *ifname; 926 int argc; 927 char **argv; 928{ 929 struct in6_ndireq nd; 930 int i, s; 931 u_int32_t newflags; 932#ifdef IPV6CTL_USETEMPADDR 933 u_int8_t nullbuf[8]; 934#endif 935 936 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 937 err(1, "socket"); 938 /* NOTREACHED */ 939 } 940 bzero(&nd, sizeof(nd)); 941 strlcpy(nd.ifname, ifname, sizeof(nd.ifname)); 942 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 943 err(1, "ioctl(SIOCGIFINFO_IN6)"); 944 /* NOTREACHED */ 945 } 946#define ND nd.ndi 947 newflags = ND.flags; 948 for (i = 0; i < argc; i++) { 949 int clear = 0; 950 char *cp = argv[i]; 951 952 if (*cp == '-') { 953 clear = 1; 954 cp++; 955 } 956 957#define SETFLAG(s, f) \ 958 do {\ 959 if (strcmp(cp, (s)) == 0) {\ 960 if (clear)\ 961 newflags &= ~(f);\ 962 else\ 963 newflags |= (f);\ 964 }\ 965 } while (0) 966/* 967 * XXX: this macro is not 100% correct, in that it matches "nud" against 968 * "nudbogus". But we just let it go since this is minor. 969 */ 970#define SETVALUE(f, v) \ 971 do { \ 972 char *valptr; \ 973 unsigned long newval; \ 974 v = 0; /* unspecified */ \ 975 if (strncmp(cp, f, strlen(f)) == 0) { \ 976 valptr = strchr(cp, '='); \ 977 if (valptr == NULL) \ 978 err(1, "syntax error in %s field", (f)); \ 979 errno = 0; \ 980 newval = strtoul(++valptr, NULL, 0); \ 981 if (errno) \ 982 err(1, "syntax error in %s's value", (f)); \ 983 v = newval; \ 984 } \ 985 } while (0) 986 987 SETFLAG("disabled", ND6_IFF_IFDISABLED); 988 SETFLAG("nud", ND6_IFF_PERFORMNUD); 989#ifdef ND6_IFF_ACCEPT_RTADV 990 SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV); 991#endif 992#ifdef ND6_IFF_AUTO_LINKLOCAL 993 SETFLAG("auto_linklocal", ND6_IFF_AUTO_LINKLOCAL); 994#endif 995#ifdef ND6_IFF_NO_PREFER_IFACE 996 SETFLAG("no_prefer_iface", ND6_IFF_NO_PREFER_IFACE); 997#endif 998 SETVALUE("basereachable", ND.basereachable); 999 SETVALUE("retrans", ND.retrans); 1000 SETVALUE("curhlim", ND.chlim); 1001 1002 ND.flags = newflags; 1003 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) { 1004 err(1, "ioctl(SIOCSIFINFO_IN6)"); 1005 /* NOTREACHED */ 1006 } 1007#undef SETFLAG 1008#undef SETVALUE 1009 } 1010 1011 if (!ND.initialized) { 1012 errx(1, "%s: not initialized yet", ifname); 1013 /* NOTREACHED */ 1014 } 1015 1016 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 1017 err(1, "ioctl(SIOCGIFINFO_IN6)"); 1018 /* NOTREACHED */ 1019 } 1020 printf("linkmtu=%d", ND.linkmtu); 1021 printf(", maxmtu=%d", ND.maxmtu); 1022 printf(", curhlim=%d", ND.chlim); 1023 printf(", basereachable=%ds%dms", 1024 ND.basereachable / 1000, ND.basereachable % 1000); 1025 printf(", reachable=%ds", ND.reachable); 1026 printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000); 1027#ifdef IPV6CTL_USETEMPADDR 1028 memset(nullbuf, 0, sizeof(nullbuf)); 1029 if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) { 1030 int j; 1031 u_int8_t *rbuf; 1032 1033 for (i = 0; i < 3; i++) { 1034 switch (i) { 1035 case 0: 1036 printf("\nRandom seed(0): "); 1037 rbuf = ND.randomseed0; 1038 break; 1039 case 1: 1040 printf("\nRandom seed(1): "); 1041 rbuf = ND.randomseed1; 1042 break; 1043 case 2: 1044 printf("\nRandom ID: "); 1045 rbuf = ND.randomid; 1046 break; 1047 default: 1048 errx(1, "impossible case for tempaddr display"); 1049 } 1050 for (j = 0; j < 8; j++) 1051 printf("%02x", rbuf[j]); 1052 } 1053 } 1054#endif 1055 if (ND.flags) { 1056 printf("\nFlags: "); 1057#ifdef ND6_IFF_IFDISABLED 1058 if ((ND.flags & ND6_IFF_IFDISABLED)) 1059 printf("disabled "); 1060#endif 1061 if ((ND.flags & ND6_IFF_PERFORMNUD)) 1062 printf("nud "); 1063#ifdef ND6_IFF_ACCEPT_RTADV 1064 if ((ND.flags & ND6_IFF_ACCEPT_RTADV)) 1065 printf("accept_rtadv "); 1066#endif 1067#ifdef ND6_IFF_AUTO_LINKLOCAL 1068 if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL)) 1069 printf("auto_linklocal "); 1070#endif 1071#ifdef ND6_IFF_NO_PREFER_IFACE 1072 if ((ND.flags & ND6_IFF_NO_PREFER_IFACE)) 1073 printf("no_prefer_iface "); 1074#endif 1075 } 1076 putc('\n', stdout); 1077#undef ND 1078 1079 close(s); 1080} 1081 1082#ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */ 1083#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 1084#endif 1085 1086void 1087rtrlist() 1088{ 1089#ifdef ICMPV6CTL_ND6_DRLIST 1090 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST }; 1091 char *buf; 1092 struct in6_defrouter *p, *ep; 1093 size_t l; 1094 struct timespec now; 1095 1096 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { 1097 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); 1098 /*NOTREACHED*/ 1099 } 1100 if (l == 0) 1101 return; 1102 buf = malloc(l); 1103 if (!buf) { 1104 err(1, "malloc"); 1105 /*NOTREACHED*/ 1106 } 1107 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 1108 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); 1109 /*NOTREACHED*/ 1110 } 1111 1112 ep = (struct in6_defrouter *)(buf + l); 1113 for (p = (struct in6_defrouter *)buf; p < ep; p++) { 1114 int rtpref; 1115 1116 if (getnameinfo((struct sockaddr *)&p->rtaddr, 1117 p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0, 1118 (nflag ? NI_NUMERICHOST : 0)) != 0) 1119 strlcpy(host_buf, "?", sizeof(host_buf)); 1120 1121 printf("%s if=%s", host_buf, 1122 if_indextoname(p->if_index, ifix_buf)); 1123 printf(", flags=%s%s", 1124 p->flags & ND_RA_FLAG_MANAGED ? "M" : "", 1125 p->flags & ND_RA_FLAG_OTHER ? "O" : ""); 1126 rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff; 1127 printf(", pref=%s", rtpref_str[rtpref]); 1128 1129 clock_gettime(CLOCK_MONOTONIC_FAST, &now); 1130 if (p->expire == 0) 1131 printf(", expire=Never\n"); 1132 else 1133 printf(", expire=%s\n", 1134 sec2str(p->expire - now.tv_sec)); 1135 } 1136 free(buf); 1137#else 1138 struct in6_drlist dr; 1139 int s, i; 1140 struct timespec now; 1141 1142 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1143 err(1, "socket"); 1144 /* NOTREACHED */ 1145 } 1146 bzero(&dr, sizeof(dr)); 1147 strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */ 1148 if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 1149 err(1, "ioctl(SIOCGDRLST_IN6)"); 1150 /* NOTREACHED */ 1151 } 1152#define DR dr.defrouter[i] 1153 for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) { 1154 struct sockaddr_in6 sin6; 1155 1156 bzero(&sin6, sizeof(sin6)); 1157 sin6.sin6_family = AF_INET6; 1158 sin6.sin6_len = sizeof(sin6); 1159 sin6.sin6_addr = DR.rtaddr; 1160 getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf, 1161 sizeof(host_buf), NULL, 0, 1162 (nflag ? NI_NUMERICHOST : 0)); 1163 1164 printf("%s if=%s", host_buf, 1165 if_indextoname(DR.if_index, ifix_buf)); 1166 printf(", flags=%s%s", 1167 DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", 1168 DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); 1169 clock_gettime(CLOCK_MONOTONIC_FAST, &now); 1170 if (DR.expire == 0) 1171 printf(", expire=Never\n"); 1172 else 1173 printf(", expire=%s\n", 1174 sec2str(DR.expire - now.tv_sec)); 1175 } 1176#undef DR 1177 close(s); 1178#endif 1179} 1180 1181void 1182plist() 1183{ 1184#ifdef ICMPV6CTL_ND6_PRLIST 1185 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST }; 1186 char *buf; 1187 struct in6_prefix *p, *ep, *n; 1188 struct sockaddr_in6 *advrtr; 1189 size_t l; 1190 struct timespec now; 1191 const int niflags = NI_NUMERICHOST; 1192 int ninflags = nflag ? NI_NUMERICHOST : 0; 1193 char namebuf[NI_MAXHOST]; 1194 1195 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { 1196 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); 1197 /*NOTREACHED*/ 1198 } 1199 buf = malloc(l); 1200 if (!buf) { 1201 err(1, "malloc"); 1202 /*NOTREACHED*/ 1203 } 1204 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 1205 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); 1206 /*NOTREACHED*/ 1207 } 1208 1209 ep = (struct in6_prefix *)(buf + l); 1210 for (p = (struct in6_prefix *)buf; p < ep; p = n) { 1211 advrtr = (struct sockaddr_in6 *)(p + 1); 1212 n = (struct in6_prefix *)&advrtr[p->advrtrs]; 1213 1214 if (getnameinfo((struct sockaddr *)&p->prefix, 1215 p->prefix.sin6_len, namebuf, sizeof(namebuf), 1216 NULL, 0, niflags) != 0) 1217 strlcpy(namebuf, "?", sizeof(namebuf)); 1218 printf("%s/%d if=%s\n", namebuf, p->prefixlen, 1219 if_indextoname(p->if_index, ifix_buf)); 1220 1221 clock_gettime(CLOCK_MONOTONIC_FAST, &now); 1222 /* 1223 * meaning of fields, especially flags, is very different 1224 * by origin. notify the difference to the users. 1225 */ 1226 printf("flags=%s%s%s%s%s", 1227 p->raflags.onlink ? "L" : "", 1228 p->raflags.autonomous ? "A" : "", 1229 (p->flags & NDPRF_ONLINK) != 0 ? "O" : "", 1230 (p->flags & NDPRF_DETACHED) != 0 ? "D" : "", 1231#ifdef NDPRF_HOME 1232 (p->flags & NDPRF_HOME) != 0 ? "H" : "" 1233#else 1234 "" 1235#endif 1236 ); 1237 if (p->vltime == ND6_INFINITE_LIFETIME) 1238 printf(" vltime=infinity"); 1239 else 1240 printf(" vltime=%lu", (unsigned long)p->vltime); 1241 if (p->pltime == ND6_INFINITE_LIFETIME) 1242 printf(", pltime=infinity"); 1243 else 1244 printf(", pltime=%lu", (unsigned long)p->pltime); 1245 if (p->expire == 0) 1246 printf(", expire=Never"); 1247 else if (p->expire >= now.tv_sec) 1248 printf(", expire=%s", 1249 sec2str(p->expire - now.tv_sec)); 1250 else 1251 printf(", expired"); 1252 printf(", ref=%d", p->refcnt); 1253 printf("\n"); 1254 /* 1255 * "advertising router" list is meaningful only if the prefix 1256 * information is from RA. 1257 */ 1258 if (p->advrtrs) { 1259 int j; 1260 struct sockaddr_in6 *sin6; 1261 1262 sin6 = advrtr; 1263 printf(" advertised by\n"); 1264 for (j = 0; j < p->advrtrs; j++) { 1265 struct in6_nbrinfo *nbi; 1266 1267 if (getnameinfo((struct sockaddr *)sin6, 1268 sin6->sin6_len, namebuf, sizeof(namebuf), 1269 NULL, 0, ninflags) != 0) 1270 strlcpy(namebuf, "?", sizeof(namebuf)); 1271 printf(" %s", namebuf); 1272 1273 nbi = getnbrinfo(&sin6->sin6_addr, 1274 p->if_index, 0); 1275 if (nbi) { 1276 switch (nbi->state) { 1277 case ND6_LLINFO_REACHABLE: 1278 case ND6_LLINFO_STALE: 1279 case ND6_LLINFO_DELAY: 1280 case ND6_LLINFO_PROBE: 1281 printf(" (reachable)\n"); 1282 break; 1283 default: 1284 printf(" (unreachable)\n"); 1285 } 1286 } else 1287 printf(" (no neighbor state)\n"); 1288 sin6++; 1289 } 1290 } else 1291 printf(" No advertising router\n"); 1292 } 1293 free(buf); 1294#else 1295 struct in6_prlist pr; 1296 int s, i; 1297 struct timespec now; 1298 1299 clock_gettime(CLOCK_MONOTONIC_FAST, &now); 1300 1301 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1302 err(1, "socket"); 1303 /* NOTREACHED */ 1304 } 1305 bzero(&pr, sizeof(pr)); 1306 strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */ 1307 if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { 1308 err(1, "ioctl(SIOCGPRLST_IN6)"); 1309 /* NOTREACHED */ 1310 } 1311#define PR pr.prefix[i] 1312 for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { 1313 struct sockaddr_in6 p6; 1314 char namebuf[NI_MAXHOST]; 1315 int niflags; 1316 1317#ifdef NDPRF_ONLINK 1318 p6 = PR.prefix; 1319#else 1320 memset(&p6, 0, sizeof(p6)); 1321 p6.sin6_family = AF_INET6; 1322 p6.sin6_len = sizeof(p6); 1323 p6.sin6_addr = PR.prefix; 1324#endif 1325 niflags = NI_NUMERICHOST; 1326 if (getnameinfo((struct sockaddr *)&p6, 1327 sizeof(p6), namebuf, sizeof(namebuf), 1328 NULL, 0, niflags)) { 1329 warnx("getnameinfo failed"); 1330 continue; 1331 } 1332 printf("%s/%d if=%s\n", namebuf, PR.prefixlen, 1333 if_indextoname(PR.if_index, ifix_buf)); 1334 1335 clock_gettime(CLOCK_MONOTONIC_FAST, &now); 1336 /* 1337 * meaning of fields, especially flags, is very different 1338 * by origin. notify the difference to the users. 1339 */ 1340#if 0 1341 printf(" %s", 1342 PR.origin == PR_ORIG_RA ? "" : "advertise: "); 1343#endif 1344#ifdef NDPRF_ONLINK 1345 printf("flags=%s%s%s%s%s", 1346 PR.raflags.onlink ? "L" : "", 1347 PR.raflags.autonomous ? "A" : "", 1348 (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "", 1349 (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "", 1350#ifdef NDPRF_HOME 1351 (PR.flags & NDPRF_HOME) != 0 ? "H" : "" 1352#else 1353 "" 1354#endif 1355 ); 1356#else 1357 printf("flags=%s%s", 1358 PR.raflags.onlink ? "L" : "", 1359 PR.raflags.autonomous ? "A" : ""); 1360#endif 1361 if (PR.vltime == ND6_INFINITE_LIFETIME) 1362 printf(" vltime=infinity"); 1363 else 1364 printf(" vltime=%lu", PR.vltime); 1365 if (PR.pltime == ND6_INFINITE_LIFETIME) 1366 printf(", pltime=infinity"); 1367 else 1368 printf(", pltime=%lu", PR.pltime); 1369 if (PR.expire == 0) 1370 printf(", expire=Never"); 1371 else if (PR.expire >= now.tv_sec) 1372 printf(", expire=%s", 1373 sec2str(PR.expire - now.tv_sec)); 1374 else 1375 printf(", expired"); 1376#ifdef NDPRF_ONLINK 1377 printf(", ref=%d", PR.refcnt); 1378#endif 1379#if 0 1380 switch (PR.origin) { 1381 case PR_ORIG_RA: 1382 printf(", origin=RA"); 1383 break; 1384 case PR_ORIG_RR: 1385 printf(", origin=RR"); 1386 break; 1387 case PR_ORIG_STATIC: 1388 printf(", origin=static"); 1389 break; 1390 case PR_ORIG_KERNEL: 1391 printf(", origin=kernel"); 1392 break; 1393 default: 1394 printf(", origin=?"); 1395 break; 1396 } 1397#endif 1398 printf("\n"); 1399 /* 1400 * "advertising router" list is meaningful only if the prefix 1401 * information is from RA. 1402 */ 1403 if (0 && /* prefix origin is almost obsolted */ 1404 PR.origin != PR_ORIG_RA) 1405 ; 1406 else if (PR.advrtrs) { 1407 int j; 1408 printf(" advertised by\n"); 1409 for (j = 0; j < PR.advrtrs; j++) { 1410 struct sockaddr_in6 sin6; 1411 struct in6_nbrinfo *nbi; 1412 1413 bzero(&sin6, sizeof(sin6)); 1414 sin6.sin6_family = AF_INET6; 1415 sin6.sin6_len = sizeof(sin6); 1416 sin6.sin6_addr = PR.advrtr[j]; 1417 sin6.sin6_scope_id = PR.if_index; /* XXX */ 1418 getnameinfo((struct sockaddr *)&sin6, 1419 sin6.sin6_len, host_buf, 1420 sizeof(host_buf), NULL, 0, 1421 (nflag ? NI_NUMERICHOST : 0)); 1422 printf(" %s", host_buf); 1423 1424 nbi = getnbrinfo(&sin6.sin6_addr, 1425 PR.if_index, 0); 1426 if (nbi) { 1427 switch (nbi->state) { 1428 case ND6_LLINFO_REACHABLE: 1429 case ND6_LLINFO_STALE: 1430 case ND6_LLINFO_DELAY: 1431 case ND6_LLINFO_PROBE: 1432 printf(" (reachable)\n"); 1433 break; 1434 default: 1435 printf(" (unreachable)\n"); 1436 } 1437 } else 1438 printf(" (no neighbor state)\n"); 1439 } 1440 if (PR.advrtrs > DRLSTSIZ) 1441 printf(" and %d routers\n", 1442 PR.advrtrs - DRLSTSIZ); 1443 } else 1444 printf(" No advertising router\n"); 1445 } 1446#undef PR 1447 close(s); 1448#endif 1449} 1450 1451void 1452pfx_flush() 1453{ 1454 char dummyif[IFNAMSIZ+8]; 1455 int s; 1456 1457 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1458 err(1, "socket"); 1459 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 1460 if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0) 1461 err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); 1462} 1463 1464void 1465rtr_flush() 1466{ 1467 char dummyif[IFNAMSIZ+8]; 1468 int s; 1469 1470 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1471 err(1, "socket"); 1472 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 1473 if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0) 1474 err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); 1475 1476 close(s); 1477} 1478 1479void 1480harmonize_rtr() 1481{ 1482 char dummyif[IFNAMSIZ+8]; 1483 int s; 1484 1485 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1486 err(1, "socket"); 1487 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 1488 if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) 1489 err(1, "ioctl(SIOCSNDFLUSH_IN6)"); 1490 1491 close(s); 1492} 1493 1494#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 1495static void 1496setdefif(ifname) 1497 char *ifname; 1498{ 1499 struct in6_ndifreq ndifreq; 1500 unsigned int ifindex; 1501 1502 if (strcasecmp(ifname, "delete") == 0) 1503 ifindex = 0; 1504 else { 1505 if ((ifindex = if_nametoindex(ifname)) == 0) 1506 err(1, "failed to resolve i/f index for %s", ifname); 1507 } 1508 1509 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1510 err(1, "socket"); 1511 1512 strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */ 1513 ndifreq.ifindex = ifindex; 1514 1515 if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1516 err(1, "ioctl(SIOCSDEFIFACE_IN6)"); 1517 1518 close(s); 1519} 1520 1521static void 1522getdefif() 1523{ 1524 struct in6_ndifreq ndifreq; 1525 char ifname[IFNAMSIZ+8]; 1526 1527 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1528 err(1, "socket"); 1529 1530 memset(&ndifreq, 0, sizeof(ndifreq)); 1531 strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */ 1532 1533 if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1534 err(1, "ioctl(SIOCGDEFIFACE_IN6)"); 1535 1536 if (ndifreq.ifindex == 0) 1537 printf("No default interface.\n"); 1538 else { 1539 if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL) 1540 err(1, "failed to resolve ifname for index %lu", 1541 ndifreq.ifindex); 1542 printf("ND default interface = %s\n", ifname); 1543 } 1544 1545 close(s); 1546} 1547#endif 1548 1549static char * 1550sec2str(total) 1551 time_t total; 1552{ 1553 static char result[256]; 1554 int days, hours, mins, secs; 1555 int first = 1; 1556 char *p = result; 1557 char *ep = &result[sizeof(result)]; 1558 int n; 1559 1560 days = total / 3600 / 24; 1561 hours = (total / 3600) % 24; 1562 mins = (total / 60) % 60; 1563 secs = total % 60; 1564 1565 if (days) { 1566 first = 0; 1567 n = snprintf(p, ep - p, "%dd", days); 1568 if (n < 0 || n >= ep - p) 1569 return "?"; 1570 p += n; 1571 } 1572 if (!first || hours) { 1573 first = 0; 1574 n = snprintf(p, ep - p, "%dh", hours); 1575 if (n < 0 || n >= ep - p) 1576 return "?"; 1577 p += n; 1578 } 1579 if (!first || mins) { 1580 first = 0; 1581 n = snprintf(p, ep - p, "%dm", mins); 1582 if (n < 0 || n >= ep - p) 1583 return "?"; 1584 p += n; 1585 } 1586 snprintf(p, ep - p, "%ds", secs); 1587 1588 return(result); 1589} 1590 1591/* 1592 * Print the timestamp 1593 * from tcpdump/util.c 1594 */ 1595static void 1596ts_print(tsp) 1597 const struct timespec *tsp; 1598{ 1599 int s; 1600 1601 /* Default */ 1602 s = (tsp->tv_sec + thiszone + ts0.tv_sec) % 86400; 1603 (void)printf("%02d:%02d:%02d.%06u ", 1604 s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tsp->tv_nsec / 1000); 1605} 1606 1607#undef NEXTADDR 1608