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