ndp.c revision 121162
162590Sitojun/* $FreeBSD: head/usr.sbin/ndp/ndp.c 121162 2003-10-17 16:17:47Z ume $ */ 278064Sume/* $KAME: ndp.c,v 1.65 2001/05/08 04:36:34 itojun Exp $ */ 362590Sitojun 455505Sshin/* 555505Sshin * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 655505Sshin * All rights reserved. 755505Sshin * 855505Sshin * Redistribution and use in source and binary forms, with or without 955505Sshin * modification, are permitted provided that the following conditions 1055505Sshin * are met: 1155505Sshin * 1. Redistributions of source code must retain the above copyright 1255505Sshin * notice, this list of conditions and the following disclaimer. 1355505Sshin * 2. Redistributions in binary form must reproduce the above copyright 1455505Sshin * notice, this list of conditions and the following disclaimer in the 1555505Sshin * documentation and/or other materials provided with the distribution. 1655505Sshin * 3. Neither the name of the project nor the names of its contributors 1755505Sshin * may be used to endorse or promote products derived from this software 1855505Sshin * without specific prior written permission. 1955505Sshin * 2055505Sshin * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2155505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2255505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2355505Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2455505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2555505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2655505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2755505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2855505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2955505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3055505Sshin * SUCH DAMAGE. 3155505Sshin */ 3255505Sshin/* 3355505Sshin * Copyright (c) 1984, 1993 3455505Sshin * The Regents of the University of California. All rights reserved. 3555505Sshin * 3655505Sshin * This code is derived from software contributed to Berkeley by 3755505Sshin * Sun Microsystems, Inc. 3855505Sshin * 3955505Sshin * Redistribution and use in source and binary forms, with or without 4055505Sshin * modification, are permitted provided that the following conditions 4155505Sshin * are met: 4255505Sshin * 1. Redistributions of source code must retain the above copyright 4355505Sshin * notice, this list of conditions and the following disclaimer. 4455505Sshin * 2. Redistributions in binary form must reproduce the above copyright 4555505Sshin * notice, this list of conditions and the following disclaimer in the 4655505Sshin * documentation and/or other materials provided with the distribution. 4755505Sshin * 3. All advertising materials mentioning features or use of this software 4855505Sshin * must display the following acknowledgement: 4955505Sshin * This product includes software developed by the University of 5055505Sshin * California, Berkeley and its contributors. 5155505Sshin * 4. Neither the name of the University nor the names of its contributors 5255505Sshin * may be used to endorse or promote products derived from this software 5355505Sshin * without specific prior written permission. 5455505Sshin * 5555505Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5655505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5755505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5855505Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5955505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 6055505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 6155505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 6255505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 6355505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6455505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6555505Sshin * SUCH DAMAGE. 6655505Sshin */ 6755505Sshin 6855505Sshin/* 6955505Sshin * Based on: 7055505Sshin * "@(#) Copyright (c) 1984, 1993\n\ 7155505Sshin * The Regents of the University of California. All rights reserved.\n"; 7255505Sshin * 7355505Sshin * "@(#)arp.c 8.2 (Berkeley) 1/2/94"; 7455505Sshin */ 7555505Sshin 7655505Sshin/* 7755505Sshin * ndp - display, set, delete and flush neighbor cache 7855505Sshin */ 7955505Sshin 8055505Sshin 8155505Sshin#include <sys/param.h> 8255505Sshin#include <sys/file.h> 8355505Sshin#include <sys/ioctl.h> 8455505Sshin#include <sys/socket.h> 8555505Sshin#include <sys/sysctl.h> 8655505Sshin#include <sys/time.h> 8778064Sume#include <sys/queue.h> 8855505Sshin 8955505Sshin#include <net/if.h> 9055505Sshin#include <net/if_var.h> 9155505Sshin#include <net/if_dl.h> 9255505Sshin#include <net/if_types.h> 9355505Sshin#include <net/route.h> 9455505Sshin 9555505Sshin#include <netinet/in.h> 9655505Sshin#include <netinet/if_ether.h> 9755505Sshin 9855505Sshin#include <netinet/icmp6.h> 9955505Sshin#include <netinet6/in6_var.h> 10055505Sshin#include <netinet6/nd6.h> 10155505Sshin 10255505Sshin#include <arpa/inet.h> 10355505Sshin 10455505Sshin#include <netdb.h> 10555505Sshin#include <errno.h> 10655505Sshin#include <nlist.h> 10755505Sshin#include <stdio.h> 10855505Sshin#include <string.h> 10955505Sshin#include <paths.h> 11055505Sshin#include <err.h> 11155505Sshin#include <stdlib.h> 11255505Sshin#include <fcntl.h> 11355505Sshin#include <unistd.h> 11455505Sshin#include "gmt2local.h" 11555505Sshin 11655505Sshin/* packing rule for routing socket */ 11762590Sitojun#define ROUNDUP(a) \ 11855505Sshin ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 11962590Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 12055505Sshin 121100650Sjmallettstatic pid_t pid; 12266865Ssumikawastatic int cflag; 12362590Sitojunstatic int nflag; 12462590Sitojunstatic int tflag; 12562590Sitojunstatic int32_t thiszone; /* time difference with gmt */ 12662590Sitojunstatic int s = -1; 12762590Sitojunstatic int repeat = 0; 12855505Sshin 12962590Sitojunchar ntop_buf[INET6_ADDRSTRLEN]; /* inet_ntop() */ 13062590Sitojunchar host_buf[NI_MAXHOST]; /* getnameinfo() */ 13162590Sitojunchar ifix_buf[IFNAMSIZ]; /* if_indextoname() */ 13255505Sshin 13362590Sitojunint main __P((int, char **)); 13462590Sitojunint file __P((char *)); 13562590Sitojunvoid getsocket __P((void)); 13662590Sitojunint set __P((int, char **)); 13762590Sitojunvoid get __P((char *)); 13862590Sitojunint delete __P((char *)); 13962590Sitojunvoid dump __P((struct in6_addr *)); 14062590Sitojunstatic struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *addr, 14162590Sitojun int ifindex, int)); 14262590Sitojunstatic char *ether_str __P((struct sockaddr_dl *)); 14362590Sitojunint ndp_ether_aton __P((char *, u_char *)); 14462590Sitojunvoid usage __P((void)); 14562590Sitojunint rtmsg __P((int)); 14662590Sitojunvoid ifinfo __P((int, char **)); 14762590Sitojunvoid rtrlist __P((void)); 14862590Sitojunvoid plist __P((void)); 14962590Sitojunvoid pfx_flush __P((void)); 15062590Sitojunvoid rtrlist __P((void)); 15162590Sitojunvoid rtr_flush __P((void)); 15262590Sitojunvoid harmonize_rtr __P((void)); 15362590Sitojun#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 15462590Sitojunstatic void getdefif __P((void)); 15562590Sitojunstatic void setdefif __P((char *)); 15662590Sitojun#endif 15762590Sitojunstatic char *sec2str __P((time_t t)); 15862590Sitojunstatic char *ether_str __P((struct sockaddr_dl *sdl)); 15962590Sitojunstatic void ts_print __P((const struct timeval *)); 16055505Sshin 16178064Sumestatic char *rtpref_str[] = { 16278064Sume "medium", /* 00 */ 16378064Sume "high", /* 01 */ 16478064Sume "rsv", /* 10 */ 16578064Sume "low" /* 11 */ 16678064Sume}; 16778064Sume 16855505Sshinint 16955505Sshinmain(argc, argv) 17055505Sshin int argc; 17155505Sshin char **argv; 17255505Sshin{ 17355505Sshin int ch; 17466865Ssumikawa int aflag = 0, dflag = 0, sflag = 0, Hflag = 0, 17555505Sshin pflag = 0, rflag = 0, Pflag = 0, Rflag = 0; 17655505Sshin 17755505Sshin pid = getpid(); 17855505Sshin thiszone = gmt2local(0); 17978064Sume while ((ch = getopt(argc, argv, "acndfIilprstA:HPR")) != -1) 180121156Sume switch (ch) { 18155505Sshin case 'a': 18255505Sshin aflag = 1; 18355505Sshin break; 18455505Sshin case 'c': 18555505Sshin cflag = 1; 18655505Sshin break; 18755505Sshin case 'd': 18855505Sshin dflag = 1; 18955505Sshin break; 19062590Sitojun case 'I': 19162590Sitojun#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 19262590Sitojun if (argc > 2) 19362590Sitojun setdefif(argv[2]); 19462590Sitojun getdefif(); /* always call it to print the result */ 19562590Sitojun exit(0); 19662590Sitojun#else 19762590Sitojun errx(1, "not supported yet"); 19862590Sitojun /*NOTREACHED*/ 19962590Sitojun#endif 20055505Sshin case 'i' : 20162590Sitojun argc -= optind; 20262590Sitojun argv += optind; 20362590Sitojun if (argc < 1) 20455505Sshin usage(); 20562590Sitojun ifinfo(argc, argv); 20655505Sshin exit(0); 20755505Sshin case 'n': 20855505Sshin nflag = 1; 20955505Sshin continue; 21055505Sshin case 'p': 21155505Sshin pflag = 1; 21255505Sshin break; 21355505Sshin case 'f' : 21455505Sshin if (argc != 3) 21555505Sshin usage(); 21655505Sshin file(argv[2]); 21755505Sshin exit(0); 21855505Sshin case 'l' : 21978064Sume /* obsolete, ignored */ 22055505Sshin break; 22155505Sshin case 'r' : 22255505Sshin rflag = 1; 22355505Sshin break; 22455505Sshin case 's': 22555505Sshin sflag = 1; 22655505Sshin break; 22755505Sshin case 't': 22855505Sshin tflag = 1; 22955505Sshin break; 23055505Sshin case 'A': 23155505Sshin aflag = 1; 23255505Sshin repeat = atoi(optarg); 23355505Sshin if (repeat < 0) 23455505Sshin usage(); 23555505Sshin break; 23655505Sshin case 'H' : 23755505Sshin Hflag = 1; 23855505Sshin break; 23955505Sshin case 'P': 24055505Sshin Pflag = 1; 24155505Sshin break; 24255505Sshin case 'R': 24355505Sshin Rflag = 1; 24455505Sshin break; 24555505Sshin default: 24655505Sshin usage(); 24755505Sshin } 24855505Sshin 24955505Sshin argc -= optind; 25055505Sshin argv += optind; 25155505Sshin 25255505Sshin if (aflag || cflag) { 25355505Sshin dump(0); 25455505Sshin exit(0); 25555505Sshin } 25655505Sshin if (dflag) { 25755505Sshin if (argc != 1) 25855505Sshin usage(); 25955505Sshin delete(argv[0]); 26062590Sitojun exit(0); 26155505Sshin } 26255505Sshin if (pflag) { 26355505Sshin plist(); 26455505Sshin exit(0); 26555505Sshin } 26655505Sshin if (rflag) { 26755505Sshin rtrlist(); 26855505Sshin exit(0); 26955505Sshin } 27055505Sshin if (sflag) { 27155505Sshin if (argc < 2 || argc > 4) 27255505Sshin usage(); 27355505Sshin exit(set(argc, argv) ? 1 : 0); 27455505Sshin } 27555505Sshin if (Hflag) { 27655505Sshin harmonize_rtr(); 27755505Sshin exit(0); 27855505Sshin } 27955505Sshin if (Pflag) { 28055505Sshin pfx_flush(); 28155505Sshin exit(0); 28255505Sshin } 28355505Sshin if (Rflag) { 28455505Sshin rtr_flush(); 28555505Sshin exit(0); 28655505Sshin } 28755505Sshin 28855505Sshin if (argc != 1) 28955505Sshin usage(); 29055505Sshin get(argv[0]); 29155505Sshin exit(0); 29255505Sshin} 29355505Sshin 29455505Sshin/* 29555505Sshin * Process a file to set standard ndp entries 29655505Sshin */ 29755505Sshinint 29855505Sshinfile(name) 29955505Sshin char *name; 30055505Sshin{ 30155505Sshin FILE *fp; 30255505Sshin int i, retval; 30355505Sshin char line[100], arg[5][50], *args[5]; 30455505Sshin 30555505Sshin if ((fp = fopen(name, "r")) == NULL) { 30655505Sshin fprintf(stderr, "ndp: cannot open %s\n", name); 30755505Sshin exit(1); 30855505Sshin } 30955505Sshin args[0] = &arg[0][0]; 31055505Sshin args[1] = &arg[1][0]; 31155505Sshin args[2] = &arg[2][0]; 31255505Sshin args[3] = &arg[3][0]; 31355505Sshin args[4] = &arg[4][0]; 31455505Sshin retval = 0; 315121156Sume while (fgets(line, 100, fp) != NULL) { 31655505Sshin i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2], 31755505Sshin arg[3], arg[4]); 31855505Sshin if (i < 2) { 31955505Sshin fprintf(stderr, "ndp: bad line: %s\n", line); 32055505Sshin retval = 1; 32155505Sshin continue; 32255505Sshin } 32355505Sshin if (set(i, args)) 32455505Sshin retval = 1; 32555505Sshin } 32655505Sshin fclose(fp); 32755505Sshin return (retval); 32855505Sshin} 32955505Sshin 33055505Sshinvoid 33155505Sshingetsocket() 33255505Sshin{ 33355505Sshin if (s < 0) { 33455505Sshin s = socket(PF_ROUTE, SOCK_RAW, 0); 33555505Sshin if (s < 0) { 336121156Sume err(1, "socket"); 337121156Sume /* NOTREACHED */ 33855505Sshin } 33955505Sshin } 34055505Sshin} 34155505Sshin 34262590Sitojunstruct sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 }; 34355505Sshinstruct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m; 34455505Sshinstruct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; 34555505Sshinint expire_time, flags, found_entry; 34655505Sshinstruct { 34755505Sshin struct rt_msghdr m_rtm; 34855505Sshin char m_space[512]; 34955505Sshin} m_rtmsg; 35055505Sshin 35155505Sshin/* 35255505Sshin * Set an individual neighbor cache entry 35355505Sshin */ 35455505Sshinint 35555505Sshinset(argc, argv) 35655505Sshin int argc; 35755505Sshin char **argv; 35855505Sshin{ 35955505Sshin register struct sockaddr_in6 *sin = &sin_m; 36055505Sshin register struct sockaddr_dl *sdl; 36155505Sshin register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); 36255505Sshin struct addrinfo hints, *res; 36355505Sshin int gai_error; 36455505Sshin u_char *ea; 36555505Sshin char *host = argv[0], *eaddr = argv[1]; 36655505Sshin 36755505Sshin getsocket(); 36855505Sshin argc -= 2; 36955505Sshin argv += 2; 37055505Sshin sdl_m = blank_sdl; 37155505Sshin sin_m = blank_sin; 37255505Sshin 37355505Sshin bzero(&hints, sizeof(hints)); 37455505Sshin hints.ai_family = AF_INET6; 37555505Sshin gai_error = getaddrinfo(host, NULL, &hints, &res); 37655505Sshin if (gai_error) { 37755505Sshin fprintf(stderr, "ndp: %s: %s\n", host, 37855505Sshin gai_strerror(gai_error)); 37955505Sshin return 1; 38055505Sshin } 38155505Sshin sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 38262590Sitojun#ifdef __KAME__ 38362590Sitojun if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { 38462590Sitojun *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 385121156Sume htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); 38662590Sitojun } 38762590Sitojun#endif 38855505Sshin ea = (u_char *)LLADDR(&sdl_m); 38955505Sshin if (ndp_ether_aton(eaddr, ea) == 0) 39055505Sshin sdl_m.sdl_alen = 6; 39155505Sshin flags = expire_time = 0; 39255505Sshin while (argc-- > 0) { 39355505Sshin if (strncmp(argv[0], "temp", 4) == 0) { 39455505Sshin struct timeval time; 395121156Sume 39655505Sshin gettimeofday(&time, 0); 39755505Sshin expire_time = time.tv_sec + 20 * 60; 39862590Sitojun } else if (strncmp(argv[0], "proxy", 5) == 0) 39962590Sitojun flags |= RTF_ANNOUNCE; 40055505Sshin argv++; 40155505Sshin } 40255505Sshin if (rtmsg(RTM_GET) < 0) { 403121156Sume errx(1, "RTM_GET(%s) failed", host); 404121156Sume /* NOTREACHED */ 40555505Sshin } 40655505Sshin sin = (struct sockaddr_in6 *)(rtm + 1); 40755505Sshin sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); 40855505Sshin if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { 40955505Sshin if (sdl->sdl_family == AF_LINK && 41055505Sshin (rtm->rtm_flags & RTF_LLINFO) && 41155505Sshin !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { 41255505Sshin case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 41355505Sshin case IFT_ISO88024: case IFT_ISO88025: 41455505Sshin goto overwrite; 41555505Sshin } 41662590Sitojun /* 41762590Sitojun * IPv4 arp command retries with sin_other = SIN_PROXY here. 41862590Sitojun */ 41962590Sitojun fprintf(stderr, "set: cannot configure a new entry\n"); 42062590Sitojun return 1; 42155505Sshin } 42262590Sitojun 42355505Sshinoverwrite: 42455505Sshin if (sdl->sdl_family != AF_LINK) { 42555505Sshin printf("cannot intuit interface index and type for %s\n", host); 42655505Sshin return (1); 42755505Sshin } 42855505Sshin sdl_m.sdl_type = sdl->sdl_type; 42955505Sshin sdl_m.sdl_index = sdl->sdl_index; 43055505Sshin return (rtmsg(RTM_ADD)); 43155505Sshin} 43255505Sshin 43355505Sshin/* 43455505Sshin * Display an individual neighbor cache entry 43555505Sshin */ 43655505Sshinvoid 43755505Sshinget(host) 43855505Sshin char *host; 43955505Sshin{ 44055505Sshin struct sockaddr_in6 *sin = &sin_m; 44155505Sshin struct addrinfo hints, *res; 44255505Sshin int gai_error; 44355505Sshin 44455505Sshin sin_m = blank_sin; 44555505Sshin bzero(&hints, sizeof(hints)); 44655505Sshin hints.ai_family = AF_INET6; 44755505Sshin gai_error = getaddrinfo(host, NULL, &hints, &res); 44855505Sshin if (gai_error) { 44955505Sshin fprintf(stderr, "ndp: %s: %s\n", host, 450121156Sume gai_strerror(gai_error)); 45155505Sshin return; 45255505Sshin } 45355505Sshin sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 45462590Sitojun#ifdef __KAME__ 45562590Sitojun if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { 45662590Sitojun *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 457121156Sume htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); 45862590Sitojun } 45962590Sitojun#endif 46055505Sshin dump(&sin->sin6_addr); 46155505Sshin if (found_entry == 0) { 46255505Sshin getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 463121156Sume sizeof(host_buf), NULL ,0, 464121156Sume (nflag ? NI_NUMERICHOST : 0)); 46555505Sshin printf("%s (%s) -- no entry\n", host, host_buf); 46655505Sshin exit(1); 46755505Sshin } 46855505Sshin} 46955505Sshin 47055505Sshin/* 47155505Sshin * Delete a neighbor cache entry 47255505Sshin */ 47355505Sshinint 47455505Sshindelete(host) 47555505Sshin char *host; 47655505Sshin{ 47755505Sshin struct sockaddr_in6 *sin = &sin_m; 47855505Sshin register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 47955505Sshin struct sockaddr_dl *sdl; 48055505Sshin struct addrinfo hints, *res; 48155505Sshin int gai_error; 48255505Sshin 48355505Sshin getsocket(); 48455505Sshin sin_m = blank_sin; 48555505Sshin 48655505Sshin bzero(&hints, sizeof(hints)); 48755505Sshin hints.ai_family = AF_INET6; 48855505Sshin gai_error = getaddrinfo(host, NULL, &hints, &res); 48955505Sshin if (gai_error) { 49055505Sshin fprintf(stderr, "ndp: %s: %s\n", host, 491121156Sume gai_strerror(gai_error)); 49255505Sshin return 1; 49355505Sshin } 49455505Sshin sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 49562590Sitojun#ifdef __KAME__ 49662590Sitojun if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { 49762590Sitojun *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 498121156Sume htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); 49962590Sitojun } 50062590Sitojun#endif 50155505Sshin if (rtmsg(RTM_GET) < 0) { 502121156Sume errx(1, "RTM_GET(%s) failed", host); 503121156Sume /* NOTREACHED */ 50455505Sshin } 50555505Sshin sin = (struct sockaddr_in6 *)(rtm + 1); 50655505Sshin sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); 50755505Sshin if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { 50855505Sshin if (sdl->sdl_family == AF_LINK && 50955505Sshin (rtm->rtm_flags & RTF_LLINFO) && 51062590Sitojun !(rtm->rtm_flags & RTF_GATEWAY)) { 51178064Sume goto delete; 51255505Sshin } 51362590Sitojun /* 51462590Sitojun * IPv4 arp command retries with sin_other = SIN_PROXY here. 51562590Sitojun */ 51662590Sitojun fprintf(stderr, "delete: cannot delete non-NDP entry\n"); 51762590Sitojun return 1; 51855505Sshin } 51962590Sitojun 52055505Sshindelete: 52155505Sshin if (sdl->sdl_family != AF_LINK) { 52255505Sshin printf("cannot locate %s\n", host); 52355505Sshin return (1); 52455505Sshin } 52555505Sshin if (rtmsg(RTM_DELETE) == 0) { 52662590Sitojun struct sockaddr_in6 s6 = *sin; /* XXX: for safety */ 52762590Sitojun 52862590Sitojun#ifdef __KAME__ 52962590Sitojun if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) { 53062590Sitojun s6.sin6_scope_id = ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]); 53162590Sitojun *(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0; 53262590Sitojun } 53362590Sitojun#endif 53462590Sitojun getnameinfo((struct sockaddr *)&s6, 535121156Sume s6.sin6_len, host_buf, 536121156Sume sizeof(host_buf), NULL, 0, 537121156Sume (nflag ? NI_NUMERICHOST : 0)); 53855505Sshin printf("%s (%s) deleted\n", host, host_buf); 53955505Sshin } 54055505Sshin 54155505Sshin return 0; 54255505Sshin} 54355505Sshin 54478064Sume#define W_ADDR 31 54578064Sume#define W_LL 17 54678064Sume#define W_IF 6 54778064Sume 54855505Sshin/* 54955505Sshin * Dump the entire neighbor cache 55055505Sshin */ 55155505Sshinvoid 55255505Sshindump(addr) 55355505Sshin struct in6_addr *addr; 55455505Sshin{ 55555505Sshin int mib[6]; 55655505Sshin size_t needed; 55762590Sitojun char *lim, *buf, *next; 55855505Sshin struct rt_msghdr *rtm; 55955505Sshin struct sockaddr_in6 *sin; 56055505Sshin struct sockaddr_dl *sdl; 56155505Sshin extern int h_errno; 56255505Sshin struct in6_nbrinfo *nbi; 56355505Sshin struct timeval time; 56455505Sshin int addrwidth; 56578064Sume int llwidth; 56678064Sume int ifwidth; 56762590Sitojun char flgbuf[8]; 56878064Sume char *ifname; 56955505Sshin 57055505Sshin /* Print header */ 57166865Ssumikawa if (!tflag && !cflag) 57278064Sume printf("%-*.*s %-*.*s %*.*s %-9.9s %2s %4s %4s\n", 57378064Sume W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address", 57478064Sume W_IF, W_IF, "Netif", "Expire", "St", "Flgs", "Prbs"); 57555505Sshin 57655505Sshinagain:; 57755505Sshin mib[0] = CTL_NET; 57855505Sshin mib[1] = PF_ROUTE; 57955505Sshin mib[2] = 0; 58055505Sshin mib[3] = AF_INET6; 58155505Sshin mib[4] = NET_RT_FLAGS; 58255505Sshin mib[5] = RTF_LLINFO; 58355505Sshin if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 58455505Sshin err(1, "sysctl(PF_ROUTE estimate)"); 58555505Sshin if (needed > 0) { 58655505Sshin if ((buf = malloc(needed)) == NULL) 587121156Sume err(1, "malloc"); 58855505Sshin if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 58955505Sshin err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)"); 59055505Sshin lim = buf + needed; 59155505Sshin } else 59255505Sshin buf = lim = NULL; 59355505Sshin 59455505Sshin for (next = buf; next && next < lim; next += rtm->rtm_msglen) { 59555505Sshin int isrouter = 0, prbs = 0; 59655505Sshin 59755505Sshin rtm = (struct rt_msghdr *)next; 59855505Sshin sin = (struct sockaddr_in6 *)(rtm + 1); 59955505Sshin sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len)); 60078064Sume 60178064Sume /* 60278064Sume * Some OSes can produce a route that has the LINK flag but 60378064Sume * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD 60478064Sume * and BSD/OS, where xx is not the interface identifier on 60578064Sume * lo0). Such routes entry would annoy getnbrinfo() below, 60678064Sume * so we skip them. 60778064Sume * XXX: such routes should have the GATEWAY flag, not the 608121156Sume * LINK flag. However, there is rotten routing software 60978064Sume * that advertises all routes that have the GATEWAY flag. 61078064Sume * Thus, KAME kernel intentionally does not set the LINK flag. 61178064Sume * What is to be fixed is not ndp, but such routing software 61278064Sume * (and the kernel workaround)... 61378064Sume */ 61478064Sume if (sdl->sdl_family != AF_LINK) 61578064Sume continue; 61678064Sume 61755505Sshin if (addr) { 61855505Sshin if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr)) 61955505Sshin continue; 62055505Sshin found_entry = 1; 62155505Sshin } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) 62255505Sshin continue; 62355505Sshin if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) || 62455505Sshin IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) { 62555505Sshin /* XXX: should scope id be filled in the kernel? */ 62655505Sshin if (sin->sin6_scope_id == 0) 62755505Sshin sin->sin6_scope_id = sdl->sdl_index; 62866865Ssumikawa#ifdef __KAME__ 62966865Ssumikawa /* KAME specific hack; removed the embedded id */ 63055505Sshin *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0; 63166865Ssumikawa#endif 63255505Sshin } 63355505Sshin getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 634121156Sume sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0)); 63566865Ssumikawa if (cflag == 1) { 63681366Ssumikawa#ifdef RTF_WASCLONED 63781366Ssumikawa if (rtm->rtm_flags & RTF_WASCLONED) 63881366Ssumikawa delete(host_buf); 63981366Ssumikawa#else 64066865Ssumikawa delete(host_buf); 64181366Ssumikawa#endif 64266865Ssumikawa continue; 64366865Ssumikawa } 64455505Sshin gettimeofday(&time, 0); 64555505Sshin if (tflag) 64655505Sshin ts_print(&time); 64755505Sshin 64878064Sume addrwidth = strlen(host_buf); 64978064Sume if (addrwidth < W_ADDR) 65078064Sume addrwidth = W_ADDR; 65178064Sume llwidth = strlen(ether_str(sdl)); 65278064Sume if (W_ADDR + W_LL - addrwidth > llwidth) 65378064Sume llwidth = W_ADDR + W_LL - addrwidth; 65478064Sume ifname = if_indextoname(sdl->sdl_index, ifix_buf); 65578064Sume if (!ifname) 65678064Sume ifname = "?"; 65778064Sume ifwidth = strlen(ifname); 65878064Sume if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth) 65978064Sume ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth; 66055505Sshin 66178064Sume printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf, 66278064Sume llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname); 66355505Sshin 66455505Sshin /* Print neighbor discovery specific informations */ 66562590Sitojun nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1); 66655505Sshin if (nbi) { 66755505Sshin if (nbi->expire > time.tv_sec) { 66855505Sshin printf(" %-9.9s", 669121156Sume sec2str(nbi->expire - time.tv_sec)); 67078064Sume } else if (nbi->expire == 0) 67155505Sshin printf(" %-9.9s", "permanent"); 67255505Sshin else 67355505Sshin printf(" %-9.9s", "expired"); 67455505Sshin 675121156Sume switch (nbi->state) { 676121156Sume case ND6_LLINFO_NOSTATE: 67755505Sshin printf(" N"); 67855505Sshin break; 67978064Sume#ifdef ND6_LLINFO_WAITDELETE 680121156Sume case ND6_LLINFO_WAITDELETE: 68155505Sshin printf(" W"); 68255505Sshin break; 68378064Sume#endif 684121156Sume case ND6_LLINFO_INCOMPLETE: 68555505Sshin printf(" I"); 68655505Sshin break; 687121156Sume case ND6_LLINFO_REACHABLE: 68855505Sshin printf(" R"); 68955505Sshin break; 690121156Sume case ND6_LLINFO_STALE: 69155505Sshin printf(" S"); 69255505Sshin break; 693121156Sume case ND6_LLINFO_DELAY: 69455505Sshin printf(" D"); 69555505Sshin break; 696121156Sume case ND6_LLINFO_PROBE: 69755505Sshin printf(" P"); 69855505Sshin break; 699121156Sume default: 70055505Sshin printf(" ?"); 70155505Sshin break; 70255505Sshin } 70355505Sshin 70455505Sshin isrouter = nbi->isrouter; 70555505Sshin prbs = nbi->asked; 70678064Sume } else { 70755505Sshin warnx("failed to get neighbor information"); 70855505Sshin printf(" "); 70955505Sshin } 71055505Sshin putchar(' '); 71155505Sshin 71262590Sitojun /* 71362590Sitojun * other flags. R: router, P: proxy, W: ?? 71462590Sitojun */ 71562590Sitojun if ((rtm->rtm_addrs & RTA_NETMASK) == 0) { 71662590Sitojun snprintf(flgbuf, sizeof(flgbuf), "%s%s", 717121156Sume isrouter ? "R" : "", 718121156Sume (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 71962590Sitojun } else { 72062590Sitojun sin = (struct sockaddr_in6 *) 721121156Sume (sdl->sdl_len + (char *)sdl); 72262590Sitojun snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s", 723121156Sume isrouter ? "R" : "", 724121156Sume !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "P" : "", 725121156Sume (sin->sin6_len != sizeof(struct sockaddr_in6)) ? "W" : "", 726121156Sume (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 72755505Sshin } 72862590Sitojun printf(" %-4.4s", flgbuf); 72955505Sshin 73055505Sshin if (prbs) 73162590Sitojun printf(" %4d", prbs); 73255505Sshin 73355505Sshin printf("\n"); 73455505Sshin } 73578064Sume if (buf != NULL) 73678064Sume free(buf); 73755505Sshin 73855505Sshin if (repeat) { 73955505Sshin printf("\n"); 74055505Sshin sleep(repeat); 74155505Sshin goto again; 74255505Sshin } 74355505Sshin} 74455505Sshin 74555505Sshinstatic struct in6_nbrinfo * 74662590Sitojungetnbrinfo(addr, ifindex, warning) 74755505Sshin struct in6_addr *addr; 74855505Sshin int ifindex; 74962590Sitojun int warning; 75055505Sshin{ 75155505Sshin static struct in6_nbrinfo nbi; 75255505Sshin int s; 75355505Sshin 75455505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 75555505Sshin err(1, "socket"); 75655505Sshin 75755505Sshin bzero(&nbi, sizeof(nbi)); 75855505Sshin if_indextoname(ifindex, nbi.ifname); 75955505Sshin nbi.addr = *addr; 76055505Sshin if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) { 76162590Sitojun if (warning) 76262590Sitojun warn("ioctl(SIOCGNBRINFO_IN6)"); 76355505Sshin close(s); 76455505Sshin return(NULL); 76555505Sshin } 76655505Sshin 76755505Sshin close(s); 76855505Sshin return(&nbi); 76955505Sshin} 77055505Sshin 77155505Sshinstatic char * 77255505Sshinether_str(sdl) 77355505Sshin struct sockaddr_dl *sdl; 77455505Sshin{ 775121156Sume static char hbuf[NI_MAXHOST]; 77655505Sshin u_char *cp; 77755505Sshin 77855505Sshin if (sdl->sdl_alen) { 77955505Sshin cp = (u_char *)LLADDR(sdl); 780121156Sume snprintf(hbuf, sizeof(hbuf), "%x:%x:%x:%x:%x:%x", 781121156Sume cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); 782121156Sume } else 783121156Sume snprintf(hbuf, sizeof(hbuf), "(incomplete)"); 78455505Sshin 785121156Sume return(hbuf); 78655505Sshin} 78755505Sshin 78855505Sshinint 78955505Sshinndp_ether_aton(a, n) 79055505Sshin char *a; 79155505Sshin u_char *n; 79255505Sshin{ 79355505Sshin int i, o[6]; 79455505Sshin 79555505Sshin i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 796121156Sume &o[3], &o[4], &o[5]); 79755505Sshin if (i != 6) { 79855505Sshin fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a); 79955505Sshin return (1); 80055505Sshin } 801121156Sume for (i = 0; i < 6; i++) 80255505Sshin n[i] = o[i]; 80355505Sshin return (0); 80455505Sshin} 80555505Sshin 80655505Sshinvoid 80755505Sshinusage() 80855505Sshin{ 80955505Sshin printf("usage: ndp hostname\n"); 81078064Sume printf(" ndp -a[nt]\n"); 81178064Sume printf(" ndp [-nt] -A wait\n"); 81255505Sshin printf(" ndp -c[nt]\n"); 81355505Sshin printf(" ndp -d[nt] hostname\n"); 81455505Sshin printf(" ndp -f[nt] filename\n"); 81562590Sitojun printf(" ndp -i interface [flags...]\n"); 81662590Sitojun#ifdef SIOCSDEFIFACE_IN6 81762590Sitojun printf(" ndp -I [interface|delete]\n"); 81862590Sitojun#endif 81955505Sshin printf(" ndp -p\n"); 82055505Sshin printf(" ndp -r\n"); 82162590Sitojun printf(" ndp -s hostname ether_addr [temp] [proxy]\n"); 82255505Sshin printf(" ndp -H\n"); 82355505Sshin printf(" ndp -P\n"); 82455505Sshin printf(" ndp -R\n"); 82555505Sshin exit(1); 82655505Sshin} 82755505Sshin 82855505Sshinint 82955505Sshinrtmsg(cmd) 83055505Sshin int cmd; 83155505Sshin{ 83255505Sshin static int seq; 83355505Sshin int rlen; 83455505Sshin register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 83555505Sshin register char *cp = m_rtmsg.m_space; 83655505Sshin register int l; 83755505Sshin 83855505Sshin errno = 0; 83955505Sshin if (cmd == RTM_DELETE) 84055505Sshin goto doit; 84155505Sshin bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 84255505Sshin rtm->rtm_flags = flags; 84355505Sshin rtm->rtm_version = RTM_VERSION; 84455505Sshin 84555505Sshin switch (cmd) { 84655505Sshin default: 84755505Sshin fprintf(stderr, "ndp: internal wrong cmd\n"); 84855505Sshin exit(1); 84955505Sshin case RTM_ADD: 85055505Sshin rtm->rtm_addrs |= RTA_GATEWAY; 85155505Sshin rtm->rtm_rmx.rmx_expire = expire_time; 85255505Sshin rtm->rtm_inits = RTV_EXPIRE; 85355505Sshin rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); 85462590Sitojun if (rtm->rtm_flags & RTF_ANNOUNCE) { 85562590Sitojun rtm->rtm_flags &= ~RTF_HOST; 85662590Sitojun rtm->rtm_flags |= RTA_NETMASK; 85762590Sitojun } 85855505Sshin /* FALLTHROUGH */ 85955505Sshin case RTM_GET: 86055505Sshin rtm->rtm_addrs |= RTA_DST; 86155505Sshin } 86262590Sitojun#define NEXTADDR(w, s) \ 86355505Sshin if (rtm->rtm_addrs & (w)) { \ 86455505Sshin bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);} 86555505Sshin 86655505Sshin NEXTADDR(RTA_DST, sin_m); 86755505Sshin NEXTADDR(RTA_GATEWAY, sdl_m); 86862590Sitojun memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr)); 86955505Sshin NEXTADDR(RTA_NETMASK, so_mask); 87055505Sshin 87155505Sshin rtm->rtm_msglen = cp - (char *)&m_rtmsg; 87255505Sshindoit: 87355505Sshin l = rtm->rtm_msglen; 87455505Sshin rtm->rtm_seq = ++seq; 87555505Sshin rtm->rtm_type = cmd; 87655505Sshin if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 87755505Sshin if (errno != ESRCH || cmd != RTM_DELETE) { 878121156Sume err(1, "writing to routing socket"); 879121156Sume /* NOTREACHED */ 88055505Sshin } 88155505Sshin } 88255505Sshin do { 88355505Sshin l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 88455505Sshin } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 88555505Sshin if (l < 0) 88655505Sshin (void) fprintf(stderr, "ndp: read from routing socket: %s\n", 88755505Sshin strerror(errno)); 88855505Sshin return (0); 88955505Sshin} 89055505Sshin 89155505Sshinvoid 89262590Sitojunifinfo(argc, argv) 89362590Sitojun int argc; 89462590Sitojun char **argv; 89555505Sshin{ 89655505Sshin struct in6_ndireq nd; 89762590Sitojun int i, s; 89862590Sitojun char *ifname = argv[0]; 89962590Sitojun u_int32_t newflags; 90078064Sume#ifdef IPV6CTL_USETEMPADDR 90178064Sume u_int8_t nullbuf[8]; 90278064Sume#endif 90355505Sshin 90455505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 905121156Sume err(1, "socket"); 906121156Sume /* NOTREACHED */ 90755505Sshin } 90855505Sshin bzero(&nd, sizeof(nd)); 909121156Sume strlcpy(nd.ifname, ifname, sizeof(nd.ifname)); 91055505Sshin if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 911121156Sume err(1, "ioctl(SIOCGIFINFO_IN6)"); 912121156Sume /* NOTREACHED */ 91355505Sshin } 91462590Sitojun#define ND nd.ndi 91562590Sitojun newflags = ND.flags; 91662590Sitojun for (i = 1; i < argc; i++) { 91762590Sitojun int clear = 0; 91862590Sitojun char *cp = argv[i]; 91962590Sitojun 92062590Sitojun if (*cp == '-') { 92162590Sitojun clear = 1; 92262590Sitojun cp++; 92362590Sitojun } 92462590Sitojun 92562590Sitojun#define SETFLAG(s, f) \ 92662590Sitojun do {\ 92762590Sitojun if (strcmp(cp, (s)) == 0) {\ 92862590Sitojun if (clear)\ 92962590Sitojun newflags &= ~(f);\ 93062590Sitojun else\ 93162590Sitojun newflags |= (f);\ 93262590Sitojun }\ 93362590Sitojun } while (0) 93462590Sitojun SETFLAG("nud", ND6_IFF_PERFORMNUD); 935118498Sume#ifdef ND6_IFF_ACCEPT_RTADV 936118498Sume SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV); 937118498Sume#endif 93862590Sitojun 93962590Sitojun ND.flags = newflags; 94062590Sitojun if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) { 941121156Sume err(1, "ioctl(SIOCSIFINFO_FLAGS)"); 942121156Sume /* NOTREACHED */ 94362590Sitojun } 94462590Sitojun#undef SETFLAG 94562590Sitojun } 94662590Sitojun 947121162Sume if (!ND.initialized) { 948121162Sume errx(1, "%s: not initialized yet", ifname); 949121162Sume /* NOTREACHED */ 950121162Sume } 951121162Sume 95255505Sshin printf("linkmtu=%d", ND.linkmtu); 95355505Sshin printf(", curhlim=%d", ND.chlim); 95455505Sshin printf(", basereachable=%ds%dms", 955121156Sume ND.basereachable / 1000, ND.basereachable % 1000); 95655505Sshin printf(", reachable=%ds", ND.reachable); 95762590Sitojun printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000); 95878064Sume#ifdef IPV6CTL_USETEMPADDR 95978064Sume memset(nullbuf, 0, sizeof(nullbuf)); 96078064Sume if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) { 96178064Sume int j; 96278064Sume u_int8_t *rbuf; 96378064Sume 96478064Sume for (i = 0; i < 3; i++) { 965121156Sume switch (i) { 96678064Sume case 0: 96778064Sume printf("\nRandom seed(0): "); 96878064Sume rbuf = ND.randomseed0; 96978064Sume break; 97078064Sume case 1: 97178064Sume printf("\nRandom seed(1): "); 97278064Sume rbuf = ND.randomseed1; 97378064Sume break; 97478064Sume case 2: 97578064Sume printf("\nRandom ID: "); 97678064Sume rbuf = ND.randomid; 97778064Sume break; 97878064Sume } 97978064Sume for (j = 0; j < 8; j++) 98078064Sume printf("%02x", rbuf[j]); 98178064Sume } 98278064Sume } 98378064Sume#endif 98462590Sitojun if (ND.flags) { 98562590Sitojun printf("\nFlags: "); 986118498Sume if ((ND.flags & ND6_IFF_PERFORMNUD)) 987118498Sume printf("nud "); 988118498Sume#ifdef ND6_IFF_ACCEPT_RTADV 989118498Sume if ((ND.flags & ND6_IFF_ACCEPT_RTADV)) 990118498Sume printf("accept_rtadv "); 991118498Sume#endif 992118498Sume} 99362590Sitojun putc('\n', stdout); 99455505Sshin#undef ND 995121156Sume 99655505Sshin close(s); 99755505Sshin} 99855505Sshin 99978064Sume#ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */ 100078064Sume#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 100178064Sume#endif 100278064Sume 100355505Sshinvoid 100455505Sshinrtrlist() 100555505Sshin{ 100678064Sume#ifdef ICMPV6CTL_ND6_DRLIST 100778064Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST }; 100878064Sume char *buf; 100978064Sume struct in6_defrouter *p, *ep; 101078064Sume size_t l; 101178064Sume struct timeval time; 101278064Sume 101378064Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { 101478064Sume err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); 101578064Sume /*NOTREACHED*/ 101678064Sume } 101778064Sume buf = malloc(l); 101878064Sume if (!buf) { 1019121156Sume err(1, "malloc"); 102078064Sume /*NOTREACHED*/ 102178064Sume } 102278064Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 102378064Sume err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); 102478064Sume /*NOTREACHED*/ 102578064Sume } 102678064Sume 102778064Sume ep = (struct in6_defrouter *)(buf + l); 102878064Sume for (p = (struct in6_defrouter *)buf; p < ep; p++) { 102978064Sume int rtpref; 103078064Sume 103178064Sume if (getnameinfo((struct sockaddr *)&p->rtaddr, 103278064Sume p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0, 1033121156Sume (nflag ? NI_NUMERICHOST : 0)) != 0) 103478064Sume strlcpy(host_buf, "?", sizeof(host_buf)); 1035121156Sume 103678064Sume printf("%s if=%s", host_buf, 1037121156Sume if_indextoname(p->if_index, ifix_buf)); 103878064Sume printf(", flags=%s%s", 1039121156Sume p->flags & ND_RA_FLAG_MANAGED ? "M" : "", 1040121156Sume p->flags & ND_RA_FLAG_OTHER ? "O" : ""); 104178064Sume rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff; 104278064Sume printf(", pref=%s", rtpref_str[rtpref]); 1043121156Sume 104478064Sume gettimeofday(&time, 0); 104578064Sume if (p->expire == 0) 104678064Sume printf(", expire=Never\n"); 104778064Sume else 104878064Sume printf(", expire=%s\n", 1049121156Sume sec2str(p->expire - time.tv_sec)); 105078064Sume } 105178064Sume free(buf); 105278064Sume#else 105355505Sshin struct in6_drlist dr; 105455505Sshin int s, i; 105555505Sshin struct timeval time; 105655505Sshin 105755505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1058121156Sume err(1, "socket"); 1059121156Sume /* NOTREACHED */ 106055505Sshin } 106155505Sshin bzero(&dr, sizeof(dr)); 1062121156Sume strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */ 106355505Sshin if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 1064121156Sume err(1, "ioctl(SIOCGDRLST_IN6)"); 1065121156Sume /* NOTREACHED */ 1066121156Sume } 106762590Sitojun#define DR dr.defrouter[i] 106878064Sume for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) { 106955505Sshin struct sockaddr_in6 sin6; 107055505Sshin 107155505Sshin bzero(&sin6, sizeof(sin6)); 107255505Sshin sin6.sin6_family = AF_INET6; 107355505Sshin sin6.sin6_len = sizeof(sin6); 107455505Sshin sin6.sin6_addr = DR.rtaddr; 107555505Sshin getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf, 1076121156Sume sizeof(host_buf), NULL, 0, 1077121156Sume (nflag ? NI_NUMERICHOST : 0)); 1078121156Sume 107955505Sshin printf("%s if=%s", host_buf, 1080121156Sume if_indextoname(DR.if_index, ifix_buf)); 108155505Sshin printf(", flags=%s%s", 1082121156Sume DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", 1083121156Sume DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); 108455505Sshin gettimeofday(&time, 0); 108555505Sshin if (DR.expire == 0) 108655505Sshin printf(", expire=Never\n"); 108755505Sshin else 108855505Sshin printf(", expire=%s\n", 1089121156Sume sec2str(DR.expire - time.tv_sec)); 109055505Sshin } 109155505Sshin#undef DR 109255505Sshin close(s); 109378064Sume#endif 109455505Sshin} 109555505Sshin 109655505Sshinvoid 109755505Sshinplist() 109855505Sshin{ 109978064Sume#ifdef ICMPV6CTL_ND6_PRLIST 110078064Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST }; 110178064Sume char *buf; 110278064Sume struct in6_prefix *p, *ep, *n; 110378064Sume struct sockaddr_in6 *advrtr; 110478064Sume size_t l; 110578064Sume struct timeval time; 110678064Sume const int niflags = NI_NUMERICHOST; 110778064Sume int ninflags = nflag ? NI_NUMERICHOST : 0; 110878064Sume char namebuf[NI_MAXHOST]; 110978064Sume 111078064Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { 111178064Sume err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); 111278064Sume /*NOTREACHED*/ 111378064Sume } 111478064Sume buf = malloc(l); 111578064Sume if (!buf) { 1116121156Sume err(1, "malloc"); 111778064Sume /*NOTREACHED*/ 111878064Sume } 111978064Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 112078064Sume err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); 112178064Sume /*NOTREACHED*/ 112278064Sume } 112378064Sume 112478064Sume ep = (struct in6_prefix *)(buf + l); 112578064Sume for (p = (struct in6_prefix *)buf; p < ep; p = n) { 112678064Sume advrtr = (struct sockaddr_in6 *)(p + 1); 112778064Sume n = (struct in6_prefix *)&advrtr[p->advrtrs]; 112878064Sume 112978064Sume if (getnameinfo((struct sockaddr *)&p->prefix, 113078064Sume p->prefix.sin6_len, namebuf, sizeof(namebuf), 113178064Sume NULL, 0, niflags) != 0) 113278064Sume strlcpy(namebuf, "?", sizeof(namebuf)); 113378064Sume printf("%s/%d if=%s\n", namebuf, p->prefixlen, 1134121156Sume if_indextoname(p->if_index, ifix_buf)); 113578064Sume 113678064Sume gettimeofday(&time, 0); 113778064Sume /* 113878064Sume * meaning of fields, especially flags, is very different 113978064Sume * by origin. notify the difference to the users. 114078064Sume */ 114178064Sume printf("flags=%s%s%s%s%s", 1142121156Sume p->raflags.onlink ? "L" : "", 1143121156Sume p->raflags.autonomous ? "A" : "", 1144121156Sume (p->flags & NDPRF_ONLINK) != 0 ? "O" : "", 1145121156Sume (p->flags & NDPRF_DETACHED) != 0 ? "D" : "", 114678064Sume#ifdef NDPRF_HOME 1147121156Sume (p->flags & NDPRF_HOME) != 0 ? "H" : "" 114878064Sume#else 1149121156Sume "" 115078064Sume#endif 1151121156Sume ); 115278064Sume if (p->vltime == ND6_INFINITE_LIFETIME) 115378064Sume printf(" vltime=infinity"); 115478064Sume else 115578064Sume printf(" vltime=%ld", (long)p->vltime); 115678064Sume if (p->pltime == ND6_INFINITE_LIFETIME) 115778064Sume printf(", pltime=infinity"); 115878064Sume else 115978064Sume printf(", pltime=%ld", (long)p->pltime); 116078064Sume if (p->expire == 0) 116178064Sume printf(", expire=Never"); 116278064Sume else if (p->expire >= time.tv_sec) 116378064Sume printf(", expire=%s", 1164121156Sume sec2str(p->expire - time.tv_sec)); 116578064Sume else 116678064Sume printf(", expired"); 116778064Sume printf(", ref=%d", p->refcnt); 116878064Sume printf("\n"); 116978064Sume /* 117078064Sume * "advertising router" list is meaningful only if the prefix 117178064Sume * information is from RA. 117278064Sume */ 117378064Sume if (p->advrtrs) { 117478064Sume int j; 117578064Sume struct sockaddr_in6 *sin6; 117678064Sume 117778064Sume sin6 = (struct sockaddr_in6 *)(p + 1); 117878064Sume printf(" advertised by\n"); 117978064Sume for (j = 0; j < p->advrtrs; j++) { 118078064Sume struct in6_nbrinfo *nbi; 118178064Sume 118278064Sume if (getnameinfo((struct sockaddr *)sin6, 118378064Sume sin6->sin6_len, namebuf, sizeof(namebuf), 118478064Sume NULL, 0, ninflags) != 0) 118578064Sume strlcpy(namebuf, "?", sizeof(namebuf)); 118678064Sume printf(" %s", namebuf); 118778064Sume 1188121156Sume nbi = getnbrinfo(&sin6->sin6_addr, 1189121156Sume p->if_index, 0); 119078064Sume if (nbi) { 1191121156Sume switch (nbi->state) { 119278064Sume case ND6_LLINFO_REACHABLE: 119378064Sume case ND6_LLINFO_STALE: 119478064Sume case ND6_LLINFO_DELAY: 119578064Sume case ND6_LLINFO_PROBE: 119678064Sume printf(" (reachable)\n"); 119778064Sume break; 119878064Sume default: 119978064Sume printf(" (unreachable)\n"); 120078064Sume } 120178064Sume } else 120278064Sume printf(" (no neighbor state)\n"); 120378064Sume sin6++; 120478064Sume } 120578064Sume } else 120678064Sume printf(" No advertising router\n"); 120778064Sume } 120878064Sume free(buf); 120978064Sume#else 121055505Sshin struct in6_prlist pr; 121155505Sshin int s, i; 121255505Sshin struct timeval time; 121355505Sshin 121455505Sshin gettimeofday(&time, 0); 121555505Sshin 121655505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1217121156Sume err(1, "socket"); 1218121156Sume /* NOTREACHED */ 121955505Sshin } 122055505Sshin bzero(&pr, sizeof(pr)); 1221121156Sume strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */ 122255505Sshin if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { 1223121156Sume err(1, "ioctl(SIOCGPRLST_IN6)"); 1224121156Sume /* NOTREACHED */ 1225121156Sume } 122662590Sitojun#define PR pr.prefix[i] 122755505Sshin for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { 122878064Sume struct sockaddr_in6 p6; 122978064Sume char namebuf[NI_MAXHOST]; 123078064Sume int niflags; 123178064Sume 123278064Sume#ifdef NDPRF_ONLINK 123378064Sume p6 = PR.prefix; 123478064Sume#else 123578064Sume memset(&p6, 0, sizeof(p6)); 123678064Sume p6.sin6_family = AF_INET6; 123778064Sume p6.sin6_len = sizeof(p6); 123878064Sume p6.sin6_addr = PR.prefix; 123978064Sume#endif 124078064Sume 124178064Sume /* 124278064Sume * copy link index to sin6_scope_id field. 124378064Sume * XXX: KAME specific. 124478064Sume */ 124578064Sume if (IN6_IS_ADDR_LINKLOCAL(&p6.sin6_addr)) { 124678064Sume u_int16_t linkid; 124778064Sume 124878064Sume memcpy(&linkid, &p6.sin6_addr.s6_addr[2], 1249121156Sume sizeof(linkid)); 125078064Sume linkid = ntohs(linkid); 125178064Sume p6.sin6_scope_id = linkid; 125278064Sume p6.sin6_addr.s6_addr[2] = 0; 125378064Sume p6.sin6_addr.s6_addr[3] = 0; 125478064Sume } 125578064Sume 125678064Sume niflags = NI_NUMERICHOST; 125778064Sume if (getnameinfo((struct sockaddr *)&p6, 1258121156Sume sizeof(p6), namebuf, sizeof(namebuf), 1259121156Sume NULL, 0, niflags)) { 126078064Sume warnx("getnameinfo failed"); 126178064Sume continue; 126278064Sume } 126378064Sume printf("%s/%d if=%s\n", namebuf, PR.prefixlen, 1264121156Sume if_indextoname(PR.if_index, ifix_buf)); 126578064Sume 126655505Sshin gettimeofday(&time, 0); 126762590Sitojun /* 126862590Sitojun * meaning of fields, especially flags, is very different 126962590Sitojun * by origin. notify the difference to the users. 127062590Sitojun */ 127178064Sume#if 0 127278064Sume printf(" %s", 1273121156Sume PR.origin == PR_ORIG_RA ? "" : "advertise: "); 127478064Sume#endif 127578064Sume#ifdef NDPRF_ONLINK 127678064Sume printf("flags=%s%s%s%s%s", 1277121156Sume PR.raflags.onlink ? "L" : "", 1278121156Sume PR.raflags.autonomous ? "A" : "", 1279121156Sume (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "", 1280121156Sume (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "", 128178064Sume#ifdef NDPRF_HOME 1282121156Sume (PR.flags & NDPRF_HOME) != 0 ? "H" : "" 128378064Sume#else 1284121156Sume "" 128578064Sume#endif 1286121156Sume ); 128778064Sume#else 128862590Sitojun printf("flags=%s%s", 1289121156Sume PR.raflags.onlink ? "L" : "", 1290121156Sume PR.raflags.autonomous ? "A" : ""); 129178064Sume#endif 129255505Sshin if (PR.vltime == ND6_INFINITE_LIFETIME) 129355505Sshin printf(" vltime=infinity"); 129455505Sshin else 129555505Sshin printf(" vltime=%ld", (long)PR.vltime); 129655505Sshin if (PR.pltime == ND6_INFINITE_LIFETIME) 129755505Sshin printf(", pltime=infinity"); 129855505Sshin else 129955505Sshin printf(", pltime=%ld", (long)PR.pltime); 130055505Sshin if (PR.expire == 0) 130162590Sitojun printf(", expire=Never"); 130255505Sshin else if (PR.expire >= time.tv_sec) 130362590Sitojun printf(", expire=%s", 1304121156Sume sec2str(PR.expire - time.tv_sec)); 130555505Sshin else 130662590Sitojun printf(", expired"); 130778064Sume#ifdef NDPRF_ONLINK 130878064Sume printf(", ref=%d", PR.refcnt); 130978064Sume#endif 131078064Sume#if 0 131162590Sitojun switch (PR.origin) { 131262590Sitojun case PR_ORIG_RA: 131362590Sitojun printf(", origin=RA"); 131462590Sitojun break; 131562590Sitojun case PR_ORIG_RR: 131662590Sitojun printf(", origin=RR"); 131762590Sitojun break; 131862590Sitojun case PR_ORIG_STATIC: 131962590Sitojun printf(", origin=static"); 132062590Sitojun break; 132162590Sitojun case PR_ORIG_KERNEL: 132262590Sitojun printf(", origin=kernel"); 132362590Sitojun break; 132462590Sitojun default: 132562590Sitojun printf(", origin=?"); 132662590Sitojun break; 132762590Sitojun } 132878064Sume#endif 132962590Sitojun printf("\n"); 133062590Sitojun /* 133162590Sitojun * "advertising router" list is meaningful only if the prefix 133262590Sitojun * information is from RA. 133362590Sitojun */ 133478064Sume if (0 && /* prefix origin is almost obsolted */ 133578064Sume PR.origin != PR_ORIG_RA) 133662590Sitojun ; 133762590Sitojun else if (PR.advrtrs) { 133855505Sshin int j; 133955505Sshin printf(" advertised by\n"); 134055505Sshin for (j = 0; j < PR.advrtrs; j++) { 134155505Sshin struct sockaddr_in6 sin6; 134262590Sitojun struct in6_nbrinfo *nbi; 134355505Sshin 134455505Sshin bzero(&sin6, sizeof(sin6)); 134555505Sshin sin6.sin6_family = AF_INET6; 134655505Sshin sin6.sin6_len = sizeof(sin6); 134755505Sshin sin6.sin6_addr = PR.advrtr[j]; 134862590Sitojun sin6.sin6_scope_id = PR.if_index; /* XXX */ 134955505Sshin getnameinfo((struct sockaddr *)&sin6, 1350121156Sume sin6.sin6_len, host_buf, 1351121156Sume sizeof(host_buf), NULL, 0, 1352121156Sume (nflag ? NI_NUMERICHOST : 0)); 135362590Sitojun printf(" %s", host_buf); 135455505Sshin 1355121156Sume nbi = getnbrinfo(&sin6.sin6_addr, 1356121156Sume PR.if_index, 0); 135762590Sitojun if (nbi) { 1358121156Sume switch (nbi->state) { 1359121156Sume case ND6_LLINFO_REACHABLE: 1360121156Sume case ND6_LLINFO_STALE: 1361121156Sume case ND6_LLINFO_DELAY: 1362121156Sume case ND6_LLINFO_PROBE: 136362590Sitojun printf(" (reachable)\n"); 136462590Sitojun break; 1365121156Sume default: 136662590Sitojun printf(" (unreachable)\n"); 136762590Sitojun } 136878064Sume } else 136962590Sitojun printf(" (no neighbor state)\n"); 137055505Sshin } 137155505Sshin if (PR.advrtrs > DRLSTSIZ) 137255505Sshin printf(" and %d routers\n", 1373121156Sume PR.advrtrs - DRLSTSIZ); 137462590Sitojun } else 137555505Sshin printf(" No advertising router\n"); 137655505Sshin } 137755505Sshin#undef PR 137855505Sshin close(s); 137978064Sume#endif 138055505Sshin} 138155505Sshin 138255505Sshinvoid 138355505Sshinpfx_flush() 138455505Sshin{ 138555505Sshin char dummyif[IFNAMSIZ+8]; 138655505Sshin int s; 138755505Sshin 138855505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 138955505Sshin err(1, "socket"); 1390121156Sume strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 139155505Sshin if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0) 1392121156Sume err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); 139355505Sshin} 139455505Sshin 139555505Sshinvoid 139655505Sshinrtr_flush() 139755505Sshin{ 139855505Sshin char dummyif[IFNAMSIZ+8]; 139955505Sshin int s; 140055505Sshin 140155505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 140255505Sshin err(1, "socket"); 1403121156Sume strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 140455505Sshin if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0) 1405121156Sume err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); 140662590Sitojun 140762590Sitojun close(s); 140855505Sshin} 140955505Sshin 141055505Sshinvoid 141155505Sshinharmonize_rtr() 141255505Sshin{ 141355505Sshin char dummyif[IFNAMSIZ+8]; 141455505Sshin int s; 141555505Sshin 141662590Sitojun if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 141762590Sitojun err(1, "socket"); 1418121156Sume strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 141962590Sitojun if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) 1420121156Sume err(1, "ioctl(SIOCSNDFLUSH_IN6)"); 142162590Sitojun 142262590Sitojun close(s); 142355505Sshin} 142455505Sshin 142562590Sitojun#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 142662590Sitojunstatic void 142762590Sitojunsetdefif(ifname) 142862590Sitojun char *ifname; 142962590Sitojun{ 143062590Sitojun struct in6_ndifreq ndifreq; 143162590Sitojun unsigned int ifindex; 143262590Sitojun 143362590Sitojun if (strcasecmp(ifname, "delete") == 0) 143462590Sitojun ifindex = 0; 143562590Sitojun else { 143662590Sitojun if ((ifindex = if_nametoindex(ifname)) == 0) 143762590Sitojun err(1, "failed to resolve i/f index for %s", ifname); 143862590Sitojun } 143962590Sitojun 144062590Sitojun if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 144162590Sitojun err(1, "socket"); 144262590Sitojun 1443121156Sume strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */ 144462590Sitojun ndifreq.ifindex = ifindex; 144562590Sitojun 144662590Sitojun if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1447121156Sume err(1, "ioctl(SIOCSDEFIFACE_IN6)"); 144862590Sitojun 144962590Sitojun close(s); 145062590Sitojun} 145162590Sitojun 145262590Sitojunstatic void 145362590Sitojungetdefif() 145462590Sitojun{ 145562590Sitojun struct in6_ndifreq ndifreq; 145662590Sitojun char ifname[IFNAMSIZ+8]; 145762590Sitojun 145862590Sitojun if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 145962590Sitojun err(1, "socket"); 146062590Sitojun 146162590Sitojun memset(&ndifreq, 0, sizeof(ndifreq)); 1462121156Sume strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */ 146362590Sitojun 146462590Sitojun if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1465121156Sume err(1, "ioctl(SIOCGDEFIFACE_IN6)"); 146662590Sitojun 146762590Sitojun if (ndifreq.ifindex == 0) 146862590Sitojun printf("No default interface.\n"); 146962590Sitojun else { 147062590Sitojun if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL) 147162590Sitojun err(1, "failed to resolve ifname for index %lu", 147262590Sitojun ndifreq.ifindex); 147362590Sitojun printf("ND default interface = %s\n", ifname); 147462590Sitojun } 147562590Sitojun 147662590Sitojun close(s); 147762590Sitojun} 147862590Sitojun#endif 147962590Sitojun 148055505Sshinstatic char * 148155505Sshinsec2str(total) 148255505Sshin time_t total; 148355505Sshin{ 148455505Sshin static char result[256]; 148555505Sshin int days, hours, mins, secs; 148655505Sshin int first = 1; 148755505Sshin char *p = result; 1488121156Sume char *ep = &result[sizeof(result)]; 1489121156Sume int n; 149055505Sshin 149155505Sshin days = total / 3600 / 24; 149255505Sshin hours = (total / 3600) % 24; 149355505Sshin mins = (total / 60) % 60; 149455505Sshin secs = total % 60; 149555505Sshin 149655505Sshin if (days) { 149755505Sshin first = 0; 1498121156Sume n = snprintf(p, ep - p, "%dd", days); 1499121156Sume if (n < 0 || n >= ep - p) 1500121156Sume return "?"; 1501121156Sume p += n; 150255505Sshin } 150355505Sshin if (!first || hours) { 150455505Sshin first = 0; 1505121156Sume n = snprintf(p, ep - p, "%dh", hours); 1506121156Sume if (n < 0 || n >= ep - p) 1507121156Sume return "?"; 1508121156Sume p += n; 150955505Sshin } 151055505Sshin if (!first || mins) { 151155505Sshin first = 0; 1512121156Sume n = snprintf(p, ep - p, "%dm", mins); 1513121156Sume if (n < 0 || n >= ep - p) 1514121156Sume return "?"; 1515121156Sume p += n; 151655505Sshin } 1517121156Sume snprintf(p, ep - p, "%ds", secs); 151855505Sshin 151955505Sshin return(result); 152055505Sshin} 152155505Sshin 152255505Sshin/* 152355505Sshin * Print the timestamp 152455505Sshin * from tcpdump/util.c 152555505Sshin */ 152655505Sshinstatic void 152755505Sshints_print(tvp) 152855505Sshin const struct timeval *tvp; 152955505Sshin{ 153055505Sshin int s; 153155505Sshin 153255505Sshin /* Default */ 153355505Sshin s = (tvp->tv_sec + thiszone) % 86400; 153455505Sshin (void)printf("%02d:%02d:%02d.%06u ", 153555505Sshin s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec); 153655505Sshin} 1537