ndp.c revision 62590
138494Sobrien/* $FreeBSD: head/usr.sbin/ndp/ndp.c 62590 2000-07-04 16:43:14Z itojun $ */ 2174294Sobrien/* $KAME: ndp.c,v 1.41 2000/07/04 12:54:11 jinmei Exp $ */ 338494Sobrien 438494Sobrien/* 538494Sobrien * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 638494Sobrien * All rights reserved. 738494Sobrien * 838494Sobrien * Redistribution and use in source and binary forms, with or without 938494Sobrien * modification, are permitted provided that the following conditions 1038494Sobrien * are met: 1138494Sobrien * 1. Redistributions of source code must retain the above copyright 1238494Sobrien * notice, this list of conditions and the following disclaimer. 1338494Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1438494Sobrien * notice, this list of conditions and the following disclaimer in the 1538494Sobrien * documentation and/or other materials provided with the distribution. 1638494Sobrien * 3. Neither the name of the project nor the names of its contributors 1738494Sobrien * may be used to endorse or promote products derived from this software 1838494Sobrien * without specific prior written permission. 1938494Sobrien * 2042629Sobrien * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2138494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2238494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2338494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2438494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2538494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2638494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2738494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2838494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2938494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3038494Sobrien * SUCH DAMAGE. 3138494Sobrien */ 3238494Sobrien/* 3338494Sobrien * Copyright (c) 1984, 1993 3438494Sobrien * The Regents of the University of California. All rights reserved. 3538494Sobrien * 3638494Sobrien * This code is derived from software contributed to Berkeley by 3738494Sobrien * Sun Microsystems, Inc. 3838494Sobrien * 3938494Sobrien * Redistribution and use in source and binary forms, with or without 40174294Sobrien * modification, are permitted provided that the following conditions 4138494Sobrien * are met: 4238494Sobrien * 1. Redistributions of source code must retain the above copyright 4338494Sobrien * notice, this list of conditions and the following disclaimer. 4438494Sobrien * 2. Redistributions in binary form must reproduce the above copyright 4538494Sobrien * notice, this list of conditions and the following disclaimer in the 4638494Sobrien * documentation and/or other materials provided with the distribution. 4738494Sobrien * 3. All advertising materials mentioning features or use of this software 4838494Sobrien * must display the following acknowledgement: 4938494Sobrien * This product includes software developed by the University of 5038494Sobrien * California, Berkeley and its contributors. 5138494Sobrien * 4. Neither the name of the University nor the names of its contributors 5238494Sobrien * may be used to endorse or promote products derived from this software 5338494Sobrien * without specific prior written permission. 5438494Sobrien * 5538494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5638494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5738494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5838494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5938494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 6038494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 6138494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 6238494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 6338494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6438494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6538494Sobrien * SUCH DAMAGE. 6638494Sobrien */ 6738494Sobrien 6838494Sobrien/* 69174294Sobrien * Based on: 7038494Sobrien * "@(#) Copyright (c) 1984, 1993\n\ 7138494Sobrien * The Regents of the University of California. All rights reserved.\n"; 7238494Sobrien * 7338494Sobrien * "@(#)arp.c 8.2 (Berkeley) 1/2/94"; 74174294Sobrien */ 75174294Sobrien 7638494Sobrien/* 7738494Sobrien * ndp - display, set, delete and flush neighbor cache 7838494Sobrien */ 7938494Sobrien 8038494Sobrien 8138494Sobrien#include <sys/param.h> 8238494Sobrien#include <sys/file.h> 8338494Sobrien#include <sys/ioctl.h> 8438494Sobrien#include <sys/socket.h> 8538494Sobrien#include <sys/sysctl.h> 86174294Sobrien#include <sys/time.h> 87174294Sobrien 88174294Sobrien#include <net/if.h> 89174294Sobrien#include <net/if_var.h> 9038494Sobrien#include <net/if_dl.h> 9138494Sobrien#include <net/if_types.h> 9238494Sobrien#include <net/route.h> 9338494Sobrien 9438494Sobrien#include <netinet/in.h> 95174294Sobrien#include <netinet/if_ether.h> 96174294Sobrien 97174294Sobrien#include <netinet/icmp6.h> 98174294Sobrien#include <netinet6/in6_var.h> 99174294Sobrien#include <netinet6/nd6.h> 10038494Sobrien 10138494Sobrien#include <arpa/inet.h> 10238494Sobrien 10338494Sobrien#include <netdb.h> 10438494Sobrien#include <errno.h> 10538494Sobrien#include <nlist.h> 10638494Sobrien#include <stdio.h> 10738494Sobrien#include <string.h> 10838494Sobrien#include <paths.h> 10938494Sobrien#include <err.h> 11038494Sobrien#include <stdlib.h> 11138494Sobrien#include <fcntl.h> 11238494Sobrien#include <unistd.h> 11338494Sobrien#include "gmt2local.h" 11438494Sobrien 11538494Sobrien#ifndef NI_WITHSCOPEID 11638494Sobrien#define NI_WITHSCOPEID 0 11738494Sobrien#endif 11838494Sobrien 11938494Sobrien/* packing rule for routing socket */ 12038494Sobrien#define ROUNDUP(a) \ 12138494Sobrien ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 12238494Sobrien#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 123174294Sobrien 12438494Sobrienstatic int pid; 12538494Sobrienstatic int fflag; 12638494Sobrienstatic int nflag; 12738494Sobrienstatic int tflag; 12838494Sobrienstatic int32_t thiszone; /* time difference with gmt */ 12938494Sobrienstatic int s = -1; 13038494Sobrienstatic int repeat = 0; 13138494Sobrienstatic int lflag = 0; 13238494Sobrien 13338494Sobrienchar ntop_buf[INET6_ADDRSTRLEN]; /* inet_ntop() */ 13438494Sobrienchar host_buf[NI_MAXHOST]; /* getnameinfo() */ 13538494Sobrienchar ifix_buf[IFNAMSIZ]; /* if_indextoname() */ 13638494Sobrien 13738494Sobrienint main __P((int, char **)); 13838494Sobrienint file __P((char *)); 13938494Sobrienvoid getsocket __P((void)); 14038494Sobrienint set __P((int, char **)); 14138494Sobrienvoid get __P((char *)); 14238494Sobrienint delete __P((char *)); 14338494Sobrienvoid dump __P((struct in6_addr *)); 14438494Sobrienstatic struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *addr, 14538494Sobrien int ifindex, int)); 14638494Sobrienstatic char *ether_str __P((struct sockaddr_dl *)); 14738494Sobrienint ndp_ether_aton __P((char *, u_char *)); 14838494Sobrienvoid usage __P((void)); 14938494Sobrienint rtmsg __P((int)); 15038494Sobrienvoid ifinfo __P((int, char **)); 15138494Sobrienvoid rtrlist __P((void)); 15238494Sobrienvoid plist __P((void)); 15382794Sobrienvoid pfx_flush __P((void)); 15438494Sobrienvoid rtrlist __P((void)); 15538494Sobrienvoid rtr_flush __P((void)); 15638494Sobrienvoid harmonize_rtr __P((void)); 15738494Sobrien#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 15838494Sobrienstatic void getdefif __P((void)); 15938494Sobrienstatic void setdefif __P((char *)); 16038494Sobrien#endif 161174294Sobrienstatic char *sec2str __P((time_t t)); 16238494Sobrienstatic char *ether_str __P((struct sockaddr_dl *sdl)); 16338494Sobrienstatic void ts_print __P((const struct timeval *)); 16438494Sobrien 16538494Sobrienint 16638494Sobrienmain(argc, argv) 16738494Sobrien int argc; 16838494Sobrien char **argv; 16938494Sobrien{ 17038494Sobrien int ch; 17138494Sobrien int aflag = 0, cflag = 0, dflag = 0, sflag = 0, Hflag = 0, 17238494Sobrien pflag = 0, rflag = 0, Pflag = 0, Rflag = 0; 17338494Sobrien 17438494Sobrien pid = getpid(); 17538494Sobrien thiszone = gmt2local(0); 17638494Sobrien while ((ch = getopt(argc, argv, "acndfIilprstA:HPR")) != EOF) 17738494Sobrien switch ((char)ch) { 17838494Sobrien case 'a': 17938494Sobrien aflag = 1; 18038494Sobrien break; 18138494Sobrien case 'c': 18238494Sobrien fflag = 1; 18338494Sobrien cflag = 1; 18438494Sobrien break; 18538494Sobrien case 'd': 18638494Sobrien dflag = 1; 18738494Sobrien break; 18838494Sobrien case 'I': 18938494Sobrien#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 19038494Sobrien if (argc > 2) 19138494Sobrien setdefif(argv[2]); 19238494Sobrien getdefif(); /* always call it to print the result */ 19338494Sobrien exit(0); 19438494Sobrien#else 19538494Sobrien errx(1, "not supported yet"); 19638494Sobrien /*NOTREACHED*/ 19738494Sobrien#endif 19838494Sobrien case 'i' : 19938494Sobrien argc -= optind; 20038494Sobrien argv += optind; 20138494Sobrien if (argc < 1) 20238494Sobrien usage(); 20338494Sobrien ifinfo(argc, argv); 204174294Sobrien exit(0); 20538494Sobrien case 'n': 20638494Sobrien nflag = 1; 20738494Sobrien continue; 20838494Sobrien case 'p': 20938494Sobrien pflag = 1; 21038494Sobrien break; 21138494Sobrien case 'f' : 21238494Sobrien if (argc != 3) 21338494Sobrien usage(); 21438494Sobrien file(argv[2]); 215174294Sobrien exit(0); 216174294Sobrien case 'l' : 21738494Sobrien lflag = 1; 21838494Sobrien break; 219174294Sobrien case 'r' : 22038494Sobrien rflag = 1; 22138494Sobrien break; 22238494Sobrien case 's': 22338494Sobrien sflag = 1; 224174294Sobrien break; 22538494Sobrien case 't': 22638494Sobrien tflag = 1; 22738494Sobrien break; 22838494Sobrien case 'A': 22938494Sobrien aflag = 1; 23038494Sobrien repeat = atoi(optarg); 23138494Sobrien if (repeat < 0) 23238494Sobrien usage(); 23338494Sobrien break; 23438494Sobrien case 'H' : 23538494Sobrien Hflag = 1; 23638494Sobrien break; 23738494Sobrien case 'P': 23838494Sobrien Pflag = 1; 23938494Sobrien break; 24038494Sobrien case 'R': 24138494Sobrien Rflag = 1; 24238494Sobrien break; 24338494Sobrien default: 24438494Sobrien usage(); 24538494Sobrien } 24638494Sobrien 24738494Sobrien argc -= optind; 24838494Sobrien argv += optind; 24938494Sobrien 25038494Sobrien if (aflag || cflag) { 251174294Sobrien dump(0); 252174294Sobrien exit(0); 25338494Sobrien } 25438494Sobrien if (dflag) { 25538494Sobrien if (argc != 1) 25638494Sobrien usage(); 25738494Sobrien delete(argv[0]); 25838494Sobrien exit(0); 25938494Sobrien } 26038494Sobrien if (pflag) { 26138494Sobrien plist(); 26238494Sobrien exit(0); 26338494Sobrien } 26438494Sobrien if (rflag) { 26538494Sobrien rtrlist(); 26638494Sobrien exit(0); 26738494Sobrien } 26838494Sobrien if (sflag) { 26938494Sobrien if (argc < 2 || argc > 4) 27038494Sobrien usage(); 27138494Sobrien exit(set(argc, argv) ? 1 : 0); 27238494Sobrien } 27338494Sobrien if (Hflag) { 27438494Sobrien harmonize_rtr(); 27538494Sobrien exit(0); 27638494Sobrien } 27738494Sobrien if (Pflag) { 27838494Sobrien pfx_flush(); 279174294Sobrien exit(0); 280174294Sobrien } 281174294Sobrien if (Rflag) { 28238494Sobrien rtr_flush(); 28338494Sobrien exit(0); 28438494Sobrien } 28538494Sobrien 28638494Sobrien if (argc != 1) 28738494Sobrien usage(); 28838494Sobrien get(argv[0]); 28938494Sobrien exit(0); 29038494Sobrien} 29138494Sobrien 29238494Sobrien/* 29338494Sobrien * Process a file to set standard ndp entries 294174294Sobrien */ 29538494Sobrienint 29638494Sobrienfile(name) 29738494Sobrien char *name; 29838494Sobrien{ 29938494Sobrien FILE *fp; 30038494Sobrien int i, retval; 30138494Sobrien char line[100], arg[5][50], *args[5]; 30238494Sobrien 30338494Sobrien if ((fp = fopen(name, "r")) == NULL) { 304174294Sobrien fprintf(stderr, "ndp: cannot open %s\n", name); 30538494Sobrien exit(1); 306174294Sobrien } 30738494Sobrien args[0] = &arg[0][0]; 308174294Sobrien args[1] = &arg[1][0]; 30938494Sobrien args[2] = &arg[2][0]; 31038494Sobrien args[3] = &arg[3][0]; 31138494Sobrien args[4] = &arg[4][0]; 31238494Sobrien retval = 0; 31338494Sobrien while(fgets(line, 100, fp) != NULL) { 31438494Sobrien i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2], 31538494Sobrien arg[3], arg[4]); 31638494Sobrien if (i < 2) { 317174294Sobrien fprintf(stderr, "ndp: bad line: %s\n", line); 31838494Sobrien retval = 1; 31938494Sobrien continue; 32038494Sobrien } 32138494Sobrien if (set(i, args)) 32238494Sobrien retval = 1; 32338494Sobrien } 32438494Sobrien fclose(fp); 32538494Sobrien return (retval); 32638494Sobrien} 32738494Sobrien 32838494Sobrienvoid 32938494Sobriengetsocket() 33038494Sobrien{ 33138494Sobrien if (s < 0) { 33238494Sobrien s = socket(PF_ROUTE, SOCK_RAW, 0); 33338494Sobrien if (s < 0) { 33438494Sobrien perror("ndp: socket"); 33538494Sobrien exit(1); 33638494Sobrien } 33738494Sobrien } 33838494Sobrien} 33938494Sobrien 34038494Sobrienstruct sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 }; 34138494Sobrienstruct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m; 342174294Sobrienstruct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; 34338494Sobrienint expire_time, flags, found_entry; 34438494Sobrienstruct { 34538494Sobrien struct rt_msghdr m_rtm; 34638494Sobrien char m_space[512]; 34738494Sobrien} m_rtmsg; 34838494Sobrien 349174294Sobrien/* 350174294Sobrien * Set an individual neighbor cache entry 35138494Sobrien */ 35238494Sobrienint 35338494Sobrienset(argc, argv) 35438494Sobrien int argc; 355174294Sobrien char **argv; 35638494Sobrien{ 35738494Sobrien register struct sockaddr_in6 *sin = &sin_m; 358174294Sobrien register struct sockaddr_dl *sdl; 359174294Sobrien register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); 36038494Sobrien struct addrinfo hints, *res; 36138494Sobrien int gai_error; 362174294Sobrien u_char *ea; 36338494Sobrien char *host = argv[0], *eaddr = argv[1]; 36438494Sobrien 36538494Sobrien getsocket(); 36638494Sobrien argc -= 2; 36738494Sobrien argv += 2; 36838494Sobrien sdl_m = blank_sdl; 369174294Sobrien sin_m = blank_sin; 37038494Sobrien 37138494Sobrien bzero(&hints, sizeof(hints)); 37238494Sobrien hints.ai_family = AF_INET6; 37338494Sobrien gai_error = getaddrinfo(host, NULL, &hints, &res); 37438494Sobrien if (gai_error) { 375174294Sobrien fprintf(stderr, "ndp: %s: %s\n", host, 376174294Sobrien gai_strerror(gai_error)); 37738494Sobrien return 1; 37838494Sobrien } 37938494Sobrien sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 38038494Sobrien#ifdef __KAME__ 38138494Sobrien if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { 38238494Sobrien *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 38338494Sobrien htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); 384174294Sobrien } 385174294Sobrien#endif 386174294Sobrien ea = (u_char *)LLADDR(&sdl_m); 387174294Sobrien if (ndp_ether_aton(eaddr, ea) == 0) 388174294Sobrien sdl_m.sdl_alen = 6; 389174294Sobrien flags = expire_time = 0; 390174294Sobrien while (argc-- > 0) { 391174294Sobrien if (strncmp(argv[0], "temp", 4) == 0) { 392174294Sobrien struct timeval time; 393174294Sobrien gettimeofday(&time, 0); 39438494Sobrien expire_time = time.tv_sec + 20 * 60; 395174294Sobrien } else if (strncmp(argv[0], "proxy", 5) == 0) 396174294Sobrien flags |= RTF_ANNOUNCE; 397174294Sobrien argv++; 398174294Sobrien } 39938494Sobrien if (rtmsg(RTM_GET) < 0) { 40038494Sobrien perror(host); 401174294Sobrien return (1); 402174294Sobrien } 403174294Sobrien sin = (struct sockaddr_in6 *)(rtm + 1); 404174294Sobrien sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); 405174294Sobrien if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { 406174294Sobrien if (sdl->sdl_family == AF_LINK && 407174294Sobrien (rtm->rtm_flags & RTF_LLINFO) && 408174294Sobrien !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { 409174294Sobrien case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 410174294Sobrien case IFT_ISO88024: case IFT_ISO88025: 411174294Sobrien goto overwrite; 41238494Sobrien } 41338494Sobrien /* 414174294Sobrien * IPv4 arp command retries with sin_other = SIN_PROXY here. 415174294Sobrien */ 416174294Sobrien fprintf(stderr, "set: cannot configure a new entry\n"); 41738494Sobrien return 1; 41838494Sobrien } 41938494Sobrien 42038494Sobrienoverwrite: 42138494Sobrien if (sdl->sdl_family != AF_LINK) { 42238494Sobrien printf("cannot intuit interface index and type for %s\n", host); 42338494Sobrien return (1); 42438494Sobrien } 42538494Sobrien sdl_m.sdl_type = sdl->sdl_type; 42638494Sobrien sdl_m.sdl_index = sdl->sdl_index; 42738494Sobrien return (rtmsg(RTM_ADD)); 42838494Sobrien} 42938494Sobrien 430174294Sobrien/* 43138494Sobrien * Display an individual neighbor cache entry 432174294Sobrien */ 43338494Sobrienvoid 43438494Sobrienget(host) 43538494Sobrien char *host; 43638494Sobrien{ 43738494Sobrien struct sockaddr_in6 *sin = &sin_m; 43838494Sobrien struct addrinfo hints, *res; 43938494Sobrien int gai_error; 44038494Sobrien 44138494Sobrien sin_m = blank_sin; 442174294Sobrien bzero(&hints, sizeof(hints)); 44338494Sobrien hints.ai_family = AF_INET6; 44438494Sobrien gai_error = getaddrinfo(host, NULL, &hints, &res); 44538494Sobrien if (gai_error) { 44638494Sobrien fprintf(stderr, "ndp: %s: %s\n", host, 44738494Sobrien gai_strerror(gai_error)); 44838494Sobrien return; 44938494Sobrien } 45038494Sobrien sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 45138494Sobrien#ifdef __KAME__ 45238494Sobrien if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { 45338494Sobrien *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 45438494Sobrien htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); 45538494Sobrien } 45638494Sobrien#endif 45738494Sobrien dump(&sin->sin6_addr); 45842629Sobrien if (found_entry == 0) { 45938494Sobrien getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 46038494Sobrien sizeof(host_buf), NULL ,0, 46138494Sobrien NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 46238494Sobrien printf("%s (%s) -- no entry\n", host, host_buf); 46338494Sobrien exit(1); 46438494Sobrien } 465174294Sobrien} 46638494Sobrien 46738494Sobrien/* 46838494Sobrien * Delete a neighbor cache entry 46938494Sobrien */ 47038494Sobrienint 47138494Sobriendelete(host) 47238494Sobrien char *host; 47338494Sobrien{ 47438494Sobrien struct sockaddr_in6 *sin = &sin_m; 47538494Sobrien register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 47638494Sobrien struct sockaddr_dl *sdl; 47738494Sobrien struct addrinfo hints, *res; 47838494Sobrien int gai_error; 47938494Sobrien 48038494Sobrien getsocket(); 48138494Sobrien sin_m = blank_sin; 48238494Sobrien 483174294Sobrien bzero(&hints, sizeof(hints)); 48438494Sobrien hints.ai_family = AF_INET6; 48538494Sobrien gai_error = getaddrinfo(host, NULL, &hints, &res); 48638494Sobrien if (gai_error) { 48738494Sobrien fprintf(stderr, "ndp: %s: %s\n", host, 48838494Sobrien gai_strerror(gai_error)); 48938494Sobrien return 1; 49038494Sobrien } 49138494Sobrien sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 49238494Sobrien#ifdef __KAME__ 49338494Sobrien if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { 49438494Sobrien *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 49538494Sobrien htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); 496174294Sobrien } 497174294Sobrien#endif 49838494Sobrien if (rtmsg(RTM_GET) < 0) { 49938494Sobrien perror(host); 500174294Sobrien return (1); 50138494Sobrien } 50238494Sobrien sin = (struct sockaddr_in6 *)(rtm + 1); 50338494Sobrien sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); 50438494Sobrien if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { 50538494Sobrien if (sdl->sdl_family == AF_LINK && 50638494Sobrien (rtm->rtm_flags & RTF_LLINFO) && 50738494Sobrien !(rtm->rtm_flags & RTF_GATEWAY)) { 50838494Sobrien switch (sdl->sdl_type) { 50938494Sobrien case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 51038494Sobrien case IFT_ISO88024: case IFT_ISO88025: 51138494Sobrien goto delete; 51238494Sobrien } 513 } 514 /* 515 * IPv4 arp command retries with sin_other = SIN_PROXY here. 516 */ 517 fprintf(stderr, "delete: cannot delete non-NDP entry\n"); 518 return 1; 519 } 520 521delete: 522 if (sdl->sdl_family != AF_LINK) { 523 printf("cannot locate %s\n", host); 524 return (1); 525 } 526 if (rtmsg(RTM_DELETE) == 0) { 527 struct sockaddr_in6 s6 = *sin; /* XXX: for safety */ 528 529#ifdef __KAME__ 530 if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) { 531 s6.sin6_scope_id = ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]); 532 *(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0; 533 } 534#endif 535 getnameinfo((struct sockaddr *)&s6, 536 s6.sin6_len, host_buf, 537 sizeof(host_buf), NULL, 0, 538 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 539 printf("%s (%s) deleted\n", host, host_buf); 540 } 541 542 return 0; 543} 544 545/* 546 * Dump the entire neighbor cache 547 */ 548void 549dump(addr) 550 struct in6_addr *addr; 551{ 552 int mib[6]; 553 size_t needed; 554 char *lim, *buf, *next; 555 struct rt_msghdr *rtm; 556 struct sockaddr_in6 *sin; 557 struct sockaddr_dl *sdl; 558 extern int h_errno; 559 struct in6_nbrinfo *nbi; 560 struct timeval time; 561 int addrwidth; 562 char flgbuf[8]; 563 564 /* Print header */ 565 if (!tflag) 566 printf("%-31.31s %-17.17s %6.6s %-9.9s %2s %4s %4s\n", 567 "Neighbor", "Linklayer Address", "Netif", "Expire", 568 "St", "Flgs", "Prbs"); 569 570again:; 571 mib[0] = CTL_NET; 572 mib[1] = PF_ROUTE; 573 mib[2] = 0; 574 mib[3] = AF_INET6; 575 mib[4] = NET_RT_FLAGS; 576 mib[5] = RTF_LLINFO; 577 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 578 err(1, "sysctl(PF_ROUTE estimate)"); 579 if (needed > 0) { 580 if ((buf = malloc(needed)) == NULL) 581 errx(1, "malloc"); 582 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 583 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)"); 584 lim = buf + needed; 585 } else 586 buf = lim = NULL; 587 588 for (next = buf; next && next < lim; next += rtm->rtm_msglen) { 589 int isrouter = 0, prbs = 0; 590 591 rtm = (struct rt_msghdr *)next; 592 sin = (struct sockaddr_in6 *)(rtm + 1); 593 sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len)); 594 if (addr) { 595 if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr)) 596 continue; 597 found_entry = 1; 598 } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) 599 continue; 600 if (fflag == 1) { 601 delete((char *)inet_ntop(AF_INET6, &sin->sin6_addr, 602 ntop_buf, sizeof(ntop_buf))); 603 continue; 604 } 605 606 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) || 607 IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) { 608 /* XXX: should scope id be filled in the kernel? */ 609 if (sin->sin6_scope_id == 0) 610 sin->sin6_scope_id = sdl->sdl_index; 611 612 /* XXX: KAME specific hack; removed the embedded id */ 613 *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0; 614 } 615 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 616 sizeof(host_buf), NULL, 0, 617 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 618 gettimeofday(&time, 0); 619 if (tflag) 620 ts_print(&time); 621 622 if (lflag) { 623 addrwidth = strlen(host_buf); 624 if (addrwidth < 31) 625 addrwidth = 31; 626 } else 627 addrwidth = 31; 628 629 printf("%-*.*s %-17.17s %6.6s", addrwidth, addrwidth, host_buf, 630 ether_str(sdl), 631 if_indextoname(sdl->sdl_index, ifix_buf)); 632 633 /* Print neighbor discovery specific informations */ 634 nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1); 635 if (nbi) { 636 if (nbi->expire > time.tv_sec) { 637 printf(" %-9.9s", 638 sec2str(nbi->expire - time.tv_sec)); 639 } 640 else if (nbi->expire == 0) 641 printf(" %-9.9s", "permanent"); 642 else 643 printf(" %-9.9s", "expired"); 644 645 switch(nbi->state) { 646 case ND6_LLINFO_NOSTATE: 647 printf(" N"); 648 break; 649 case ND6_LLINFO_WAITDELETE: 650 printf(" W"); 651 break; 652 case ND6_LLINFO_INCOMPLETE: 653 printf(" I"); 654 break; 655 case ND6_LLINFO_REACHABLE: 656 printf(" R"); 657 break; 658 case ND6_LLINFO_STALE: 659 printf(" S"); 660 break; 661 case ND6_LLINFO_DELAY: 662 printf(" D"); 663 break; 664 case ND6_LLINFO_PROBE: 665 printf(" P"); 666 break; 667 default: 668 printf(" ?"); 669 break; 670 } 671 672 isrouter = nbi->isrouter; 673 prbs = nbi->asked; 674 } 675 else { 676 warnx("failed to get neighbor information"); 677 printf(" "); 678 } 679 putchar(' '); 680 681 /* 682 * other flags. R: router, P: proxy, W: ?? 683 */ 684 if ((rtm->rtm_addrs & RTA_NETMASK) == 0) { 685 snprintf(flgbuf, sizeof(flgbuf), "%s%s", 686 isrouter ? "R" : "", 687 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 688 } else { 689 sin = (struct sockaddr_in6 *) 690 (sdl->sdl_len + (char *)sdl); 691 snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s", 692 isrouter ? "R" : "", 693 !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) 694 ? "P" : "", 695 (sin->sin6_len != sizeof(struct sockaddr_in6)) 696 ? "W" : "", 697 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 698 } 699 printf(" %-4.4s", flgbuf); 700 701 if (prbs) 702 printf(" %4d", prbs); 703 704 printf("\n"); 705 } 706 707 if (repeat) { 708 printf("\n"); 709 sleep(repeat); 710 goto again; 711 } 712} 713 714static struct in6_nbrinfo * 715getnbrinfo(addr, ifindex, warning) 716 struct in6_addr *addr; 717 int ifindex; 718 int warning; 719{ 720 static struct in6_nbrinfo nbi; 721 int s; 722 723 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 724 err(1, "socket"); 725 726 bzero(&nbi, sizeof(nbi)); 727 if_indextoname(ifindex, nbi.ifname); 728 nbi.addr = *addr; 729 if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) { 730 if (warning) 731 warn("ioctl(SIOCGNBRINFO_IN6)"); 732 close(s); 733 return(NULL); 734 } 735 736 close(s); 737 return(&nbi); 738} 739 740static char * 741ether_str(sdl) 742 struct sockaddr_dl *sdl; 743{ 744 static char ebuf[32]; 745 u_char *cp; 746 747 if (sdl->sdl_alen) { 748 cp = (u_char *)LLADDR(sdl); 749 sprintf(ebuf, "%x:%x:%x:%x:%x:%x", 750 cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); 751 } 752 else { 753 sprintf(ebuf, "(incomplete)"); 754 } 755 756 return(ebuf); 757} 758 759int 760ndp_ether_aton(a, n) 761 char *a; 762 u_char *n; 763{ 764 int i, o[6]; 765 766 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 767 &o[3], &o[4], &o[5]); 768 if (i != 6) { 769 fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a); 770 return (1); 771 } 772 for (i=0; i<6; i++) 773 n[i] = o[i]; 774 return (0); 775} 776 777void 778usage() 779{ 780 printf("usage: ndp hostname\n"); 781 printf(" ndp -a[ntl]\n"); 782 printf(" ndp [-ntl] -A wait\n"); 783 printf(" ndp -c[nt]\n"); 784 printf(" ndp -d[nt] hostname\n"); 785 printf(" ndp -f[nt] filename\n"); 786 printf(" ndp -i interface [flags...]\n"); 787#ifdef SIOCSDEFIFACE_IN6 788 printf(" ndp -I [interface|delete]\n"); 789#endif 790 printf(" ndp -p\n"); 791 printf(" ndp -r\n"); 792 printf(" ndp -s hostname ether_addr [temp] [proxy]\n"); 793 printf(" ndp -H\n"); 794 printf(" ndp -P\n"); 795 printf(" ndp -R\n"); 796 exit(1); 797} 798 799int 800rtmsg(cmd) 801 int cmd; 802{ 803 static int seq; 804 int rlen; 805 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 806 register char *cp = m_rtmsg.m_space; 807 register int l; 808 809 errno = 0; 810 if (cmd == RTM_DELETE) 811 goto doit; 812 bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 813 rtm->rtm_flags = flags; 814 rtm->rtm_version = RTM_VERSION; 815 816 switch (cmd) { 817 default: 818 fprintf(stderr, "ndp: internal wrong cmd\n"); 819 exit(1); 820 case RTM_ADD: 821 rtm->rtm_addrs |= RTA_GATEWAY; 822 rtm->rtm_rmx.rmx_expire = expire_time; 823 rtm->rtm_inits = RTV_EXPIRE; 824 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); 825 if (rtm->rtm_flags & RTF_ANNOUNCE) { 826 rtm->rtm_flags &= ~RTF_HOST; 827 rtm->rtm_flags |= RTA_NETMASK; 828 } 829 /* FALLTHROUGH */ 830 case RTM_GET: 831 rtm->rtm_addrs |= RTA_DST; 832 } 833#define NEXTADDR(w, s) \ 834 if (rtm->rtm_addrs & (w)) { \ 835 bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);} 836 837 NEXTADDR(RTA_DST, sin_m); 838 NEXTADDR(RTA_GATEWAY, sdl_m); 839 memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr)); 840 NEXTADDR(RTA_NETMASK, so_mask); 841 842 rtm->rtm_msglen = cp - (char *)&m_rtmsg; 843doit: 844 l = rtm->rtm_msglen; 845 rtm->rtm_seq = ++seq; 846 rtm->rtm_type = cmd; 847 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 848 if (errno != ESRCH || cmd != RTM_DELETE) { 849 perror("writing to routing socket"); 850 return (-1); 851 } 852 } 853 do { 854 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 855 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 856 if (l < 0) 857 (void) fprintf(stderr, "ndp: read from routing socket: %s\n", 858 strerror(errno)); 859 return (0); 860} 861 862void 863ifinfo(argc, argv) 864 int argc; 865 char **argv; 866{ 867 struct in6_ndireq nd; 868 int i, s; 869 char *ifname = argv[0]; 870 u_int32_t newflags; 871 872 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 873 perror("ndp: socket"); 874 exit(1); 875 } 876 bzero(&nd, sizeof(nd)); 877 strcpy(nd.ifname, ifname); 878 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 879 perror("ioctl (SIOCGIFINFO_IN6)"); 880 exit(1); 881 } 882#define ND nd.ndi 883 newflags = ND.flags; 884 for (i = 1; i < argc; i++) { 885 int clear = 0; 886 char *cp = argv[i]; 887 888 if (*cp == '-') { 889 clear = 1; 890 cp++; 891 } 892 893#define SETFLAG(s, f) \ 894 do {\ 895 if (strcmp(cp, (s)) == 0) {\ 896 if (clear)\ 897 newflags &= ~(f);\ 898 else\ 899 newflags |= (f);\ 900 }\ 901 } while (0) 902 SETFLAG("nud", ND6_IFF_PERFORMNUD); 903 904 ND.flags = newflags; 905 if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) { 906 perror("ioctl(SIOCSIFINFO_FLAGS)"); 907 exit(1); 908 } 909#undef SETFLAG 910 } 911 912 printf("linkmtu=%d", ND.linkmtu); 913 printf(", curhlim=%d", ND.chlim); 914 printf(", basereachable=%ds%dms", 915 ND.basereachable / 1000, ND.basereachable % 1000); 916 printf(", reachable=%ds", ND.reachable); 917 printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000); 918 if (ND.flags) { 919 printf("\nFlags: "); 920 if ((ND.flags & ND6_IFF_PERFORMNUD) != 0) 921 printf("PERFORMNUD "); 922 } 923 putc('\n', stdout); 924#undef ND 925 926 close(s); 927} 928 929void 930rtrlist() 931{ 932 struct in6_drlist dr; 933 int s, i; 934 struct timeval time; 935 936 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 937 perror("ndp: socket"); 938 exit(1); 939 } 940 bzero(&dr, sizeof(dr)); 941 strcpy(dr.ifname, "lo0"); /* dummy */ 942 if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 943 perror("ioctl (SIOCGDRLST_IN6)"); 944 exit(1); 945 } 946#define DR dr.defrouter[i] 947 for (i = 0 ; DR.if_index && i < PRLSTSIZ ; i++) { 948 struct sockaddr_in6 sin6; 949 950 bzero(&sin6, sizeof(sin6)); 951 sin6.sin6_family = AF_INET6; 952 sin6.sin6_len = sizeof(sin6); 953 sin6.sin6_addr = DR.rtaddr; 954 getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf, 955 sizeof(host_buf), NULL, 0, 956 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 957 958 printf("%s if=%s", host_buf, 959 if_indextoname(DR.if_index, ifix_buf)); 960 printf(", flags=%s%s", 961 DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", 962 DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); 963 gettimeofday(&time, 0); 964 if (DR.expire == 0) 965 printf(", expire=Never\n"); 966 else 967 printf(", expire=%s\n", 968 sec2str(DR.expire - time.tv_sec)); 969 } 970#undef DR 971 close(s); 972} 973 974void 975plist() 976{ 977 struct in6_prlist pr; 978 int s, i; 979 struct timeval time; 980 981 gettimeofday(&time, 0); 982 983 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 984 perror("ndp: socket"); 985 exit(1); 986 } 987 bzero(&pr, sizeof(pr)); 988 strcpy(pr.ifname, "lo0"); /* dummy */ 989 if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { 990 perror("ioctl (SIOCGPRLST_IN6)"); 991 exit(1); 992 } 993#define PR pr.prefix[i] 994 for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { 995 printf("%s/%d if=%s\n", 996 inet_ntop(AF_INET6, &PR.prefix, ntop_buf, 997 sizeof(ntop_buf)), PR.prefixlen, 998 if_indextoname(PR.if_index, ifix_buf)); 999 gettimeofday(&time, 0); 1000 /* 1001 * meaning of fields, especially flags, is very different 1002 * by origin. notify the difference to the users. 1003 */ 1004 printf(" %s", PR.origin == PR_ORIG_RA ? "" : "advertise: "); 1005 printf("flags=%s%s", 1006 PR.raflags.onlink ? "L" : "", 1007 PR.raflags.autonomous ? "A" : ""); 1008 if (PR.vltime == ND6_INFINITE_LIFETIME) 1009 printf(" vltime=infinity"); 1010 else 1011 printf(" vltime=%ld", (long)PR.vltime); 1012 if (PR.pltime == ND6_INFINITE_LIFETIME) 1013 printf(", pltime=infinity"); 1014 else 1015 printf(", pltime=%ld", (long)PR.pltime); 1016 if (PR.expire == 0) 1017 printf(", expire=Never"); 1018 else if (PR.expire >= time.tv_sec) 1019 printf(", expire=%s", 1020 sec2str(PR.expire - time.tv_sec)); 1021 else 1022 printf(", expired"); 1023 switch (PR.origin) { 1024 case PR_ORIG_RA: 1025 printf(", origin=RA"); 1026 break; 1027 case PR_ORIG_RR: 1028 printf(", origin=RR"); 1029 break; 1030 case PR_ORIG_STATIC: 1031 printf(", origin=static"); 1032 break; 1033 case PR_ORIG_KERNEL: 1034 printf(", origin=kernel"); 1035 break; 1036 default: 1037 printf(", origin=?"); 1038 break; 1039 } 1040 printf("\n"); 1041 /* 1042 * "advertising router" list is meaningful only if the prefix 1043 * information is from RA. 1044 */ 1045 if (PR.origin != PR_ORIG_RA) 1046 ; 1047 else if (PR.advrtrs) { 1048 int j; 1049 printf(" advertised by\n"); 1050 for (j = 0; j < PR.advrtrs; j++) { 1051 struct sockaddr_in6 sin6; 1052 struct in6_nbrinfo *nbi; 1053 1054 bzero(&sin6, sizeof(sin6)); 1055 sin6.sin6_family = AF_INET6; 1056 sin6.sin6_len = sizeof(sin6); 1057 sin6.sin6_addr = PR.advrtr[j]; 1058 sin6.sin6_scope_id = PR.if_index; /* XXX */ 1059 getnameinfo((struct sockaddr *)&sin6, 1060 sin6.sin6_len, host_buf, 1061 sizeof(host_buf), NULL, 0, 1062 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)); 1063 printf(" %s", host_buf); 1064 1065 nbi = getnbrinfo(&sin6.sin6_addr, PR.if_index, 1066 0); 1067 if (nbi) { 1068 switch(nbi->state) { 1069 case ND6_LLINFO_REACHABLE: 1070 case ND6_LLINFO_STALE: 1071 case ND6_LLINFO_DELAY: 1072 case ND6_LLINFO_PROBE: 1073 printf(" (reachable)\n"); 1074 break; 1075 default: 1076 printf(" (unreachable)\n"); 1077 } 1078 } 1079 else 1080 printf(" (no neighbor state)\n"); 1081 } 1082 if (PR.advrtrs > DRLSTSIZ) 1083 printf(" and %d routers\n", 1084 PR.advrtrs - DRLSTSIZ); 1085 } else 1086 printf(" No advertising router\n"); 1087 } 1088#undef PR 1089 close(s); 1090} 1091 1092void 1093pfx_flush() 1094{ 1095 char dummyif[IFNAMSIZ+8]; 1096 int s; 1097 1098 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1099 err(1, "socket"); 1100 strcpy(dummyif, "lo0"); /* dummy */ 1101 if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0) 1102 err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); 1103} 1104 1105void 1106rtr_flush() 1107{ 1108 char dummyif[IFNAMSIZ+8]; 1109 int s; 1110 1111 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1112 err(1, "socket"); 1113 strcpy(dummyif, "lo0"); /* dummy */ 1114 if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0) 1115 err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); 1116 1117 close(s); 1118} 1119 1120void 1121harmonize_rtr() 1122{ 1123 char dummyif[IFNAMSIZ+8]; 1124 int s; 1125 1126 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1127 err(1, "socket"); 1128 strcpy(dummyif, "lo0"); /* dummy */ 1129 if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) 1130 err(1, "ioctl (SIOCSNDFLUSH_IN6)"); 1131 1132 close(s); 1133} 1134 1135#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 1136static void 1137setdefif(ifname) 1138 char *ifname; 1139{ 1140 struct in6_ndifreq ndifreq; 1141 unsigned int ifindex; 1142 1143 if (strcasecmp(ifname, "delete") == 0) 1144 ifindex = 0; 1145 else { 1146 if ((ifindex = if_nametoindex(ifname)) == 0) 1147 err(1, "failed to resolve i/f index for %s", ifname); 1148 } 1149 1150 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1151 err(1, "socket"); 1152 1153 strcpy(ndifreq.ifname, "lo0"); /* dummy */ 1154 ndifreq.ifindex = ifindex; 1155 1156 if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1157 err(1, "ioctl (SIOCSDEFIFACE_IN6)"); 1158 1159 close(s); 1160} 1161 1162static void 1163getdefif() 1164{ 1165 struct in6_ndifreq ndifreq; 1166 char ifname[IFNAMSIZ+8]; 1167 1168 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1169 err(1, "socket"); 1170 1171 memset(&ndifreq, 0, sizeof(ndifreq)); 1172 strcpy(ndifreq.ifname, "lo0"); /* dummy */ 1173 1174 if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1175 err(1, "ioctl (SIOCGDEFIFACE_IN6)"); 1176 1177 if (ndifreq.ifindex == 0) 1178 printf("No default interface.\n"); 1179 else { 1180 if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL) 1181 err(1, "failed to resolve ifname for index %lu", 1182 ndifreq.ifindex); 1183 printf("ND default interface = %s\n", ifname); 1184 } 1185 1186 close(s); 1187} 1188#endif 1189 1190static char * 1191sec2str(total) 1192 time_t total; 1193{ 1194 static char result[256]; 1195 int days, hours, mins, secs; 1196 int first = 1; 1197 char *p = result; 1198 1199 days = total / 3600 / 24; 1200 hours = (total / 3600) % 24; 1201 mins = (total / 60) % 60; 1202 secs = total % 60; 1203 1204 if (days) { 1205 first = 0; 1206 p += sprintf(p, "%dd", days); 1207 } 1208 if (!first || hours) { 1209 first = 0; 1210 p += sprintf(p, "%dh", hours); 1211 } 1212 if (!first || mins) { 1213 first = 0; 1214 p += sprintf(p, "%dm", mins); 1215 } 1216 sprintf(p, "%ds", secs); 1217 1218 return(result); 1219} 1220 1221/* 1222 * Print the timestamp 1223 * from tcpdump/util.c 1224 */ 1225static void 1226ts_print(tvp) 1227 const struct timeval *tvp; 1228{ 1229 int s; 1230 1231 /* Default */ 1232 s = (tvp->tv_sec + thiszone) % 86400; 1233 (void)printf("%02d:%02d:%02d.%06u ", 1234 s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec); 1235} 1236