ndp.c revision 210936
162590Sitojun/* $FreeBSD: head/usr.sbin/ndp/ndp.c 210936 2010-08-06 15:09:21Z jhb $ */ 2122615Sume/* $KAME: ndp.c,v 1.104 2003/06/27 07:48:39 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 * 4. Neither the name of the University nor the names of its contributors 4855505Sshin * may be used to endorse or promote products derived from this software 4955505Sshin * without specific prior written permission. 5055505Sshin * 5155505Sshin * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5255505Sshin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5355505Sshin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5455505Sshin * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5555505Sshin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5655505Sshin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5755505Sshin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5855505Sshin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5955505Sshin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6055505Sshin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6155505Sshin * SUCH DAMAGE. 6255505Sshin */ 6355505Sshin 6455505Sshin/* 6555505Sshin * Based on: 6655505Sshin * "@(#) Copyright (c) 1984, 1993\n\ 6755505Sshin * The Regents of the University of California. All rights reserved.\n"; 6855505Sshin * 6955505Sshin * "@(#)arp.c 8.2 (Berkeley) 1/2/94"; 7055505Sshin */ 7155505Sshin 7255505Sshin/* 7355505Sshin * ndp - display, set, delete and flush neighbor cache 7455505Sshin */ 7555505Sshin 7655505Sshin 7755505Sshin#include <sys/param.h> 7855505Sshin#include <sys/file.h> 7955505Sshin#include <sys/ioctl.h> 8055505Sshin#include <sys/socket.h> 8155505Sshin#include <sys/sysctl.h> 8255505Sshin#include <sys/time.h> 8378064Sume#include <sys/queue.h> 8455505Sshin 8555505Sshin#include <net/if.h> 8655505Sshin#include <net/if_var.h> 8755505Sshin#include <net/if_dl.h> 8855505Sshin#include <net/if_types.h> 8955505Sshin#include <net/route.h> 9055505Sshin 9155505Sshin#include <netinet/in.h> 9255505Sshin#include <netinet/if_ether.h> 9355505Sshin 9455505Sshin#include <netinet/icmp6.h> 9555505Sshin#include <netinet6/in6_var.h> 9655505Sshin#include <netinet6/nd6.h> 9755505Sshin 9855505Sshin#include <arpa/inet.h> 9955505Sshin 10055505Sshin#include <netdb.h> 10155505Sshin#include <errno.h> 10255505Sshin#include <nlist.h> 10355505Sshin#include <stdio.h> 10455505Sshin#include <string.h> 10555505Sshin#include <paths.h> 10655505Sshin#include <err.h> 10755505Sshin#include <stdlib.h> 10855505Sshin#include <fcntl.h> 10955505Sshin#include <unistd.h> 11055505Sshin#include "gmt2local.h" 11155505Sshin 11255505Sshin/* packing rule for routing socket */ 11362590Sitojun#define ROUNDUP(a) \ 11455505Sshin ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 11562590Sitojun#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len)) 11655505Sshin 117186119Sqingli#define NEXTADDR(w, s) \ 118186119Sqingli if (rtm->rtm_addrs & (w)) { \ 119196866Sbz bcopy((char *)&s, cp, sizeof(s)); cp += SA_SIZE(&s);} 120186119Sqingli 121186119Sqingli 122100650Sjmallettstatic pid_t pid; 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 133173412Skevloint main(int, char **); 134173412Skevloint file(char *); 135173412Skevlovoid getsocket(void); 136173412Skevloint set(int, char **); 137173412Skevlovoid get(char *); 138173412Skevloint delete(char *); 139173412Skevlovoid dump(struct in6_addr *, int); 140173412Skevlostatic struct in6_nbrinfo *getnbrinfo(struct in6_addr *, int, int); 141173412Skevlostatic char *ether_str(struct sockaddr_dl *); 142173412Skevloint ndp_ether_aton(char *, u_char *); 143173412Skevlovoid usage(void); 144173412Skevloint rtmsg(int); 145173412Skevlovoid ifinfo(char *, int, char **); 146173412Skevlovoid rtrlist(void); 147173412Skevlovoid plist(void); 148173412Skevlovoid pfx_flush(void); 149173412Skevlovoid rtr_flush(void); 150173412Skevlovoid harmonize_rtr(void); 15162590Sitojun#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 152173412Skevlostatic void getdefif(void); 153173412Skevlostatic void setdefif(char *); 15462590Sitojun#endif 155173412Skevlostatic char *sec2str(time_t); 156173412Skevlostatic char *ether_str(struct sockaddr_dl *); 157173412Skevlostatic void ts_print(const struct timeval *); 15855505Sshin 159122615Sume#ifdef ICMPV6CTL_ND6_DRLIST 16078064Sumestatic char *rtpref_str[] = { 16178064Sume "medium", /* 00 */ 16278064Sume "high", /* 01 */ 16378064Sume "rsv", /* 10 */ 16478064Sume "low" /* 11 */ 16578064Sume}; 166122615Sume#endif 16778064Sume 168122615Sumeint mode = 0; 169122615Sumechar *arg = NULL; 170122615Sume 17155505Sshinint 17255505Sshinmain(argc, argv) 17355505Sshin int argc; 17455505Sshin char **argv; 17555505Sshin{ 17655505Sshin int ch; 17755505Sshin 17855505Sshin pid = getpid(); 17955505Sshin thiszone = gmt2local(0); 180122615Sume while ((ch = getopt(argc, argv, "acd:f:Ii:nprstA:HPR")) != -1) 181121156Sume switch (ch) { 18255505Sshin case 'a': 18355505Sshin case 'c': 184122615Sume case 'p': 185122615Sume case 'r': 186122615Sume case 'H': 187122615Sume case 'P': 188122615Sume case 'R': 189122615Sume case 's': 190122615Sume case 'I': 191122615Sume if (mode) { 192122615Sume usage(); 193122615Sume /*NOTREACHED*/ 194122615Sume } 195122615Sume mode = ch; 196122615Sume arg = NULL; 19755505Sshin break; 19855505Sshin case 'd': 199122615Sume case 'f': 20055505Sshin case 'i' : 201122615Sume if (mode) { 20255505Sshin usage(); 203122615Sume /*NOTREACHED*/ 204122615Sume } 205122615Sume mode = ch; 206122615Sume arg = optarg; 207122615Sume break; 20855505Sshin case 'n': 20955505Sshin nflag = 1; 21055505Sshin break; 21155505Sshin case 't': 21255505Sshin tflag = 1; 21355505Sshin break; 21455505Sshin case 'A': 215122615Sume if (mode) { 216122615Sume usage(); 217122615Sume /*NOTREACHED*/ 218122615Sume } 219122615Sume mode = 'a'; 22055505Sshin repeat = atoi(optarg); 221122615Sume if (repeat < 0) { 22255505Sshin usage(); 223122615Sume /*NOTREACHED*/ 224122615Sume } 22555505Sshin break; 22655505Sshin default: 22755505Sshin usage(); 22855505Sshin } 22955505Sshin 23055505Sshin argc -= optind; 23155505Sshin argv += optind; 23255505Sshin 233122615Sume switch (mode) { 234122615Sume case 'a': 235122615Sume case 'c': 236122615Sume if (argc != 0) { 23755505Sshin usage(); 238122615Sume /*NOTREACHED*/ 239122615Sume } 240122615Sume dump(0, mode == 'c'); 241122615Sume break; 242122615Sume case 'd': 243122615Sume if (argc != 0) { 244122615Sume usage(); 245122615Sume /*NOTREACHED*/ 246122615Sume } 247122615Sume delete(arg); 248122615Sume break; 249122615Sume case 'I': 250122615Sume#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 251122615Sume if (argc > 1) { 252122615Sume usage(); 253122615Sume /*NOTREACHED*/ 254122615Sume } else if (argc == 1) { 255122615Sume if (strcmp(*argv, "delete") == 0 || 256122615Sume if_nametoindex(*argv)) 257122615Sume setdefif(*argv); 258122615Sume else 259122615Sume errx(1, "invalid interface %s", *argv); 260122615Sume } 261122615Sume getdefif(); /* always call it to print the result */ 262122615Sume break; 263122615Sume#else 264122615Sume errx(1, "not supported yet"); 265122615Sume /*NOTREACHED*/ 266122615Sume#endif 267122615Sume case 'p': 268122615Sume if (argc != 0) { 269122615Sume usage(); 270122615Sume /*NOTREACHED*/ 271122615Sume } 27255505Sshin plist(); 273122615Sume break; 274122615Sume case 'i': 275122615Sume ifinfo(arg, argc, argv); 276122615Sume break; 277122615Sume case 'r': 278122615Sume if (argc != 0) { 279122615Sume usage(); 280122615Sume /*NOTREACHED*/ 281122615Sume } 28255505Sshin rtrlist(); 283122615Sume break; 284122615Sume case 's': 28555505Sshin if (argc < 2 || argc > 4) 28655505Sshin usage(); 28755505Sshin exit(set(argc, argv) ? 1 : 0); 288122615Sume case 'H': 289122615Sume if (argc != 0) { 290122615Sume usage(); 291122615Sume /*NOTREACHED*/ 292122615Sume } 29355505Sshin harmonize_rtr(); 294122615Sume break; 295122615Sume case 'P': 296122615Sume if (argc != 0) { 297122615Sume usage(); 298122615Sume /*NOTREACHED*/ 299122615Sume } 30055505Sshin pfx_flush(); 301122615Sume break; 302122615Sume case 'R': 303122615Sume if (argc != 0) { 304122615Sume usage(); 305122615Sume /*NOTREACHED*/ 306122615Sume } 30755505Sshin rtr_flush(); 308122615Sume break; 309122615Sume case 0: 310122615Sume if (argc != 1) { 311122615Sume usage(); 312122615Sume /*NOTREACHED*/ 313122615Sume } 314122615Sume get(argv[0]); 315122615Sume break; 31655505Sshin } 31755505Sshin exit(0); 31855505Sshin} 31955505Sshin 32055505Sshin/* 32155505Sshin * Process a file to set standard ndp entries 32255505Sshin */ 32355505Sshinint 32455505Sshinfile(name) 32555505Sshin char *name; 32655505Sshin{ 32755505Sshin FILE *fp; 32855505Sshin int i, retval; 32955505Sshin char line[100], arg[5][50], *args[5]; 33055505Sshin 33155505Sshin if ((fp = fopen(name, "r")) == NULL) { 33255505Sshin fprintf(stderr, "ndp: cannot open %s\n", name); 33355505Sshin exit(1); 33455505Sshin } 33555505Sshin args[0] = &arg[0][0]; 33655505Sshin args[1] = &arg[1][0]; 33755505Sshin args[2] = &arg[2][0]; 33855505Sshin args[3] = &arg[3][0]; 33955505Sshin args[4] = &arg[4][0]; 34055505Sshin retval = 0; 341167260Skevlo while (fgets(line, sizeof(line), fp) != NULL) { 342122615Sume i = sscanf(line, "%49s %49s %49s %49s %49s", 343122615Sume arg[0], arg[1], arg[2], arg[3], arg[4]); 34455505Sshin if (i < 2) { 34555505Sshin fprintf(stderr, "ndp: bad line: %s\n", line); 34655505Sshin retval = 1; 34755505Sshin continue; 34855505Sshin } 34955505Sshin if (set(i, args)) 35055505Sshin retval = 1; 35155505Sshin } 35255505Sshin fclose(fp); 35355505Sshin return (retval); 35455505Sshin} 35555505Sshin 35655505Sshinvoid 35755505Sshingetsocket() 35855505Sshin{ 35955505Sshin if (s < 0) { 36055505Sshin s = socket(PF_ROUTE, SOCK_RAW, 0); 36155505Sshin if (s < 0) { 362121156Sume err(1, "socket"); 363121156Sume /* NOTREACHED */ 36455505Sshin } 36555505Sshin } 36655505Sshin} 36755505Sshin 36862590Sitojunstruct sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 }; 36955505Sshinstruct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m; 37055505Sshinstruct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; 37155505Sshinint expire_time, flags, found_entry; 37255505Sshinstruct { 37355505Sshin struct rt_msghdr m_rtm; 37455505Sshin char m_space[512]; 37555505Sshin} m_rtmsg; 37655505Sshin 37755505Sshin/* 37855505Sshin * Set an individual neighbor cache entry 37955505Sshin */ 38055505Sshinint 38155505Sshinset(argc, argv) 38255505Sshin int argc; 38355505Sshin char **argv; 38455505Sshin{ 38555505Sshin register struct sockaddr_in6 *sin = &sin_m; 38655505Sshin register struct sockaddr_dl *sdl; 38755505Sshin register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); 38855505Sshin struct addrinfo hints, *res; 38955505Sshin int gai_error; 39055505Sshin u_char *ea; 39155505Sshin char *host = argv[0], *eaddr = argv[1]; 39255505Sshin 39355505Sshin getsocket(); 39455505Sshin argc -= 2; 39555505Sshin argv += 2; 39655505Sshin sdl_m = blank_sdl; 39755505Sshin sin_m = blank_sin; 39855505Sshin 39955505Sshin bzero(&hints, sizeof(hints)); 40055505Sshin hints.ai_family = AF_INET6; 40155505Sshin gai_error = getaddrinfo(host, NULL, &hints, &res); 40255505Sshin if (gai_error) { 40355505Sshin fprintf(stderr, "ndp: %s: %s\n", host, 40455505Sshin gai_strerror(gai_error)); 40555505Sshin return 1; 40655505Sshin } 40755505Sshin sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 40862590Sitojun#ifdef __KAME__ 40962590Sitojun if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { 41062590Sitojun *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 411121156Sume htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); 41262590Sitojun } 41362590Sitojun#endif 41455505Sshin ea = (u_char *)LLADDR(&sdl_m); 41555505Sshin if (ndp_ether_aton(eaddr, ea) == 0) 41655505Sshin sdl_m.sdl_alen = 6; 41755505Sshin flags = expire_time = 0; 41855505Sshin while (argc-- > 0) { 41955505Sshin if (strncmp(argv[0], "temp", 4) == 0) { 42055505Sshin struct timeval time; 421121156Sume 42255505Sshin gettimeofday(&time, 0); 42355505Sshin expire_time = time.tv_sec + 20 * 60; 42462590Sitojun } else if (strncmp(argv[0], "proxy", 5) == 0) 42562590Sitojun flags |= RTF_ANNOUNCE; 42655505Sshin argv++; 42755505Sshin } 42855505Sshin if (rtmsg(RTM_GET) < 0) { 429121156Sume errx(1, "RTM_GET(%s) failed", host); 430121156Sume /* NOTREACHED */ 43155505Sshin } 43255505Sshin sin = (struct sockaddr_in6 *)(rtm + 1); 43355505Sshin sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); 43455505Sshin if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { 43555505Sshin if (sdl->sdl_family == AF_LINK && 436122615Sume !(rtm->rtm_flags & RTF_GATEWAY)) { 437122615Sume switch (sdl->sdl_type) { 438122615Sume case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 439122615Sume case IFT_ISO88024: case IFT_ISO88025: 440210936Sjhb case IFT_L2VLAN: case IFT_BRIDGE: 441122615Sume goto overwrite; 442122615Sume } 44355505Sshin } 44462590Sitojun /* 44562590Sitojun * IPv4 arp command retries with sin_other = SIN_PROXY here. 44662590Sitojun */ 44762590Sitojun fprintf(stderr, "set: cannot configure a new entry\n"); 44862590Sitojun return 1; 44955505Sshin } 45062590Sitojun 45155505Sshinoverwrite: 45255505Sshin if (sdl->sdl_family != AF_LINK) { 45355505Sshin printf("cannot intuit interface index and type for %s\n", host); 45455505Sshin return (1); 45555505Sshin } 45655505Sshin sdl_m.sdl_type = sdl->sdl_type; 45755505Sshin sdl_m.sdl_index = sdl->sdl_index; 45855505Sshin return (rtmsg(RTM_ADD)); 45955505Sshin} 46055505Sshin 46155505Sshin/* 46255505Sshin * Display an individual neighbor cache entry 46355505Sshin */ 46455505Sshinvoid 46555505Sshinget(host) 46655505Sshin char *host; 46755505Sshin{ 46855505Sshin struct sockaddr_in6 *sin = &sin_m; 46955505Sshin struct addrinfo hints, *res; 47055505Sshin int gai_error; 47155505Sshin 47255505Sshin sin_m = blank_sin; 47355505Sshin bzero(&hints, sizeof(hints)); 47455505Sshin hints.ai_family = AF_INET6; 47555505Sshin gai_error = getaddrinfo(host, NULL, &hints, &res); 47655505Sshin if (gai_error) { 47755505Sshin fprintf(stderr, "ndp: %s: %s\n", host, 478121156Sume gai_strerror(gai_error)); 47955505Sshin return; 48055505Sshin } 48155505Sshin sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 48262590Sitojun#ifdef __KAME__ 48362590Sitojun if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { 48462590Sitojun *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 485121156Sume htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); 48662590Sitojun } 48762590Sitojun#endif 488122615Sume dump(&sin->sin6_addr, 0); 48955505Sshin if (found_entry == 0) { 49055505Sshin getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 491121156Sume sizeof(host_buf), NULL ,0, 492121156Sume (nflag ? NI_NUMERICHOST : 0)); 49355505Sshin printf("%s (%s) -- no entry\n", host, host_buf); 49455505Sshin exit(1); 49555505Sshin } 49655505Sshin} 49755505Sshin 49855505Sshin/* 49955505Sshin * Delete a neighbor cache entry 50055505Sshin */ 50155505Sshinint 50255505Sshindelete(host) 50355505Sshin char *host; 50455505Sshin{ 50555505Sshin struct sockaddr_in6 *sin = &sin_m; 50655505Sshin register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 507186119Sqingli register char *cp = m_rtmsg.m_space; 50855505Sshin struct sockaddr_dl *sdl; 50955505Sshin struct addrinfo hints, *res; 51055505Sshin int gai_error; 51155505Sshin 51255505Sshin getsocket(); 51355505Sshin sin_m = blank_sin; 51455505Sshin 51555505Sshin bzero(&hints, sizeof(hints)); 51655505Sshin hints.ai_family = AF_INET6; 51755505Sshin gai_error = getaddrinfo(host, NULL, &hints, &res); 51855505Sshin if (gai_error) { 51955505Sshin fprintf(stderr, "ndp: %s: %s\n", host, 520121156Sume gai_strerror(gai_error)); 52155505Sshin return 1; 52255505Sshin } 52355505Sshin sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 52462590Sitojun#ifdef __KAME__ 52562590Sitojun if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) { 52662590Sitojun *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 527121156Sume htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id); 52862590Sitojun } 52962590Sitojun#endif 53055505Sshin if (rtmsg(RTM_GET) < 0) { 531121156Sume errx(1, "RTM_GET(%s) failed", host); 532121156Sume /* NOTREACHED */ 53355505Sshin } 53455505Sshin sin = (struct sockaddr_in6 *)(rtm + 1); 53555505Sshin sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin); 53655505Sshin if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { 53755505Sshin if (sdl->sdl_family == AF_LINK && 53862590Sitojun !(rtm->rtm_flags & RTF_GATEWAY)) { 53978064Sume goto delete; 54055505Sshin } 54162590Sitojun /* 54262590Sitojun * IPv4 arp command retries with sin_other = SIN_PROXY here. 54362590Sitojun */ 54462590Sitojun fprintf(stderr, "delete: cannot delete non-NDP entry\n"); 54562590Sitojun return 1; 54655505Sshin } 54762590Sitojun 54855505Sshindelete: 54955505Sshin if (sdl->sdl_family != AF_LINK) { 55055505Sshin printf("cannot locate %s\n", host); 55155505Sshin return (1); 55255505Sshin } 553186119Sqingli /* 554186119Sqingli * need to reinit the field because it has rt_key 555186119Sqingli * but we want the actual address 556186119Sqingli */ 557186119Sqingli NEXTADDR(RTA_DST, sin_m); 558186500Sqingli rtm->rtm_flags |= RTF_LLDATA; 55955505Sshin if (rtmsg(RTM_DELETE) == 0) { 56062590Sitojun struct sockaddr_in6 s6 = *sin; /* XXX: for safety */ 56162590Sitojun 56262590Sitojun#ifdef __KAME__ 56362590Sitojun if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) { 56462590Sitojun s6.sin6_scope_id = ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]); 56562590Sitojun *(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0; 56662590Sitojun } 56762590Sitojun#endif 56862590Sitojun getnameinfo((struct sockaddr *)&s6, 569121156Sume s6.sin6_len, host_buf, 570121156Sume sizeof(host_buf), NULL, 0, 571121156Sume (nflag ? NI_NUMERICHOST : 0)); 57255505Sshin printf("%s (%s) deleted\n", host, host_buf); 57355505Sshin } 57455505Sshin 57555505Sshin return 0; 57655505Sshin} 57755505Sshin 578122615Sume#define W_ADDR 36 57978064Sume#define W_LL 17 58078064Sume#define W_IF 6 58178064Sume 58255505Sshin/* 58355505Sshin * Dump the entire neighbor cache 58455505Sshin */ 58555505Sshinvoid 586122615Sumedump(addr, cflag) 58755505Sshin struct in6_addr *addr; 588122615Sume int cflag; 58955505Sshin{ 59055505Sshin int mib[6]; 59155505Sshin size_t needed; 59262590Sitojun char *lim, *buf, *next; 59355505Sshin struct rt_msghdr *rtm; 59455505Sshin struct sockaddr_in6 *sin; 59555505Sshin struct sockaddr_dl *sdl; 59655505Sshin extern int h_errno; 59755505Sshin struct in6_nbrinfo *nbi; 59855505Sshin struct timeval time; 59955505Sshin int addrwidth; 60078064Sume int llwidth; 60178064Sume int ifwidth; 60262590Sitojun char flgbuf[8]; 60378064Sume char *ifname; 60455505Sshin 60555505Sshin /* Print header */ 60666865Ssumikawa if (!tflag && !cflag) 607122615Sume printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %5s\n", 60878064Sume W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address", 609122615Sume W_IF, W_IF, "Netif", "Expire", "S", "Flags"); 61055505Sshin 61155505Sshinagain:; 61255505Sshin mib[0] = CTL_NET; 61355505Sshin mib[1] = PF_ROUTE; 61455505Sshin mib[2] = 0; 61555505Sshin mib[3] = AF_INET6; 61655505Sshin mib[4] = NET_RT_FLAGS; 617186119Sqingli#ifdef RTF_LLINFO 61855505Sshin mib[5] = RTF_LLINFO; 619186119Sqingli#else 620186119Sqingli mib[5] = 0; 621186119Sqingli#endif 62255505Sshin if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 62355505Sshin err(1, "sysctl(PF_ROUTE estimate)"); 62455505Sshin if (needed > 0) { 62555505Sshin if ((buf = malloc(needed)) == NULL) 626121156Sume err(1, "malloc"); 62755505Sshin if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 62855505Sshin err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)"); 62955505Sshin lim = buf + needed; 63055505Sshin } else 63155505Sshin buf = lim = NULL; 63255505Sshin 63355505Sshin for (next = buf; next && next < lim; next += rtm->rtm_msglen) { 63455505Sshin int isrouter = 0, prbs = 0; 63555505Sshin 63655505Sshin rtm = (struct rt_msghdr *)next; 63755505Sshin sin = (struct sockaddr_in6 *)(rtm + 1); 63855505Sshin sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len)); 63978064Sume 64078064Sume /* 64178064Sume * Some OSes can produce a route that has the LINK flag but 64278064Sume * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD 64378064Sume * and BSD/OS, where xx is not the interface identifier on 64478064Sume * lo0). Such routes entry would annoy getnbrinfo() below, 64578064Sume * so we skip them. 64678064Sume * XXX: such routes should have the GATEWAY flag, not the 647121156Sume * LINK flag. However, there is rotten routing software 64878064Sume * that advertises all routes that have the GATEWAY flag. 64978064Sume * Thus, KAME kernel intentionally does not set the LINK flag. 65078064Sume * What is to be fixed is not ndp, but such routing software 65178064Sume * (and the kernel workaround)... 65278064Sume */ 65378064Sume if (sdl->sdl_family != AF_LINK) 65478064Sume continue; 65578064Sume 656122615Sume if (!(rtm->rtm_flags & RTF_HOST)) 657122615Sume continue; 658122615Sume 65955505Sshin if (addr) { 66055505Sshin if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr)) 66155505Sshin continue; 66255505Sshin found_entry = 1; 66355505Sshin } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) 66455505Sshin continue; 66555505Sshin if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) || 66655505Sshin IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) { 66755505Sshin /* XXX: should scope id be filled in the kernel? */ 66855505Sshin if (sin->sin6_scope_id == 0) 66955505Sshin sin->sin6_scope_id = sdl->sdl_index; 67066865Ssumikawa#ifdef __KAME__ 67166865Ssumikawa /* KAME specific hack; removed the embedded id */ 67255505Sshin *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0; 67366865Ssumikawa#endif 67455505Sshin } 67555505Sshin getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 676121156Sume sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0)); 677122615Sume if (cflag) { 67881366Ssumikawa#ifdef RTF_WASCLONED 67981366Ssumikawa if (rtm->rtm_flags & RTF_WASCLONED) 68081366Ssumikawa delete(host_buf); 681122615Sume#elif defined(RTF_CLONED) 682122615Sume if (rtm->rtm_flags & RTF_CLONED) 683122615Sume delete(host_buf); 68481366Ssumikawa#else 68566865Ssumikawa delete(host_buf); 68681366Ssumikawa#endif 68766865Ssumikawa continue; 68866865Ssumikawa } 68955505Sshin gettimeofday(&time, 0); 69055505Sshin if (tflag) 69155505Sshin ts_print(&time); 69255505Sshin 69378064Sume addrwidth = strlen(host_buf); 69478064Sume if (addrwidth < W_ADDR) 69578064Sume addrwidth = W_ADDR; 69678064Sume llwidth = strlen(ether_str(sdl)); 69778064Sume if (W_ADDR + W_LL - addrwidth > llwidth) 69878064Sume llwidth = W_ADDR + W_LL - addrwidth; 69978064Sume ifname = if_indextoname(sdl->sdl_index, ifix_buf); 70078064Sume if (!ifname) 70178064Sume ifname = "?"; 70278064Sume ifwidth = strlen(ifname); 70378064Sume if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth) 70478064Sume ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth; 70555505Sshin 70678064Sume printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf, 70778064Sume llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname); 70855505Sshin 70955505Sshin /* Print neighbor discovery specific informations */ 71062590Sitojun nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1); 71155505Sshin if (nbi) { 71255505Sshin if (nbi->expire > time.tv_sec) { 71355505Sshin printf(" %-9.9s", 714121156Sume sec2str(nbi->expire - time.tv_sec)); 71578064Sume } else if (nbi->expire == 0) 71655505Sshin printf(" %-9.9s", "permanent"); 71755505Sshin else 71855505Sshin printf(" %-9.9s", "expired"); 71955505Sshin 720121156Sume switch (nbi->state) { 721121156Sume case ND6_LLINFO_NOSTATE: 72255505Sshin printf(" N"); 72355505Sshin break; 72478064Sume#ifdef ND6_LLINFO_WAITDELETE 725121156Sume case ND6_LLINFO_WAITDELETE: 72655505Sshin printf(" W"); 72755505Sshin break; 72878064Sume#endif 729121156Sume case ND6_LLINFO_INCOMPLETE: 73055505Sshin printf(" I"); 73155505Sshin break; 732121156Sume case ND6_LLINFO_REACHABLE: 73355505Sshin printf(" R"); 73455505Sshin break; 735121156Sume case ND6_LLINFO_STALE: 73655505Sshin printf(" S"); 73755505Sshin break; 738121156Sume case ND6_LLINFO_DELAY: 73955505Sshin printf(" D"); 74055505Sshin break; 741121156Sume case ND6_LLINFO_PROBE: 74255505Sshin printf(" P"); 74355505Sshin break; 744121156Sume default: 74555505Sshin printf(" ?"); 74655505Sshin break; 74755505Sshin } 74855505Sshin 74955505Sshin isrouter = nbi->isrouter; 75055505Sshin prbs = nbi->asked; 75178064Sume } else { 75255505Sshin warnx("failed to get neighbor information"); 75355505Sshin printf(" "); 75455505Sshin } 75555505Sshin 75662590Sitojun /* 75762590Sitojun * other flags. R: router, P: proxy, W: ?? 75862590Sitojun */ 75962590Sitojun if ((rtm->rtm_addrs & RTA_NETMASK) == 0) { 76062590Sitojun snprintf(flgbuf, sizeof(flgbuf), "%s%s", 761121156Sume isrouter ? "R" : "", 762121156Sume (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 76362590Sitojun } else { 76462590Sitojun sin = (struct sockaddr_in6 *) 765121156Sume (sdl->sdl_len + (char *)sdl); 766122615Sume#if 0 /* W and P are mystery even for us */ 76762590Sitojun snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s", 768121156Sume isrouter ? "R" : "", 769121156Sume !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "P" : "", 770121156Sume (sin->sin6_len != sizeof(struct sockaddr_in6)) ? "W" : "", 771121156Sume (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 772122615Sume#else 773122615Sume snprintf(flgbuf, sizeof(flgbuf), "%s%s", 774122615Sume isrouter ? "R" : "", 775122615Sume (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 776122615Sume#endif 77755505Sshin } 778122615Sume printf(" %s", flgbuf); 77955505Sshin 78055505Sshin if (prbs) 781122615Sume printf(" %d", prbs); 78255505Sshin 78355505Sshin printf("\n"); 78455505Sshin } 78578064Sume if (buf != NULL) 78678064Sume free(buf); 78755505Sshin 78855505Sshin if (repeat) { 78955505Sshin printf("\n"); 790125675Ssumikawa fflush(stdout); 79155505Sshin sleep(repeat); 79255505Sshin goto again; 79355505Sshin } 79455505Sshin} 79555505Sshin 79655505Sshinstatic struct in6_nbrinfo * 79762590Sitojungetnbrinfo(addr, ifindex, warning) 79855505Sshin struct in6_addr *addr; 79955505Sshin int ifindex; 80062590Sitojun int warning; 80155505Sshin{ 80255505Sshin static struct in6_nbrinfo nbi; 80355505Sshin int s; 80455505Sshin 80555505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 80655505Sshin err(1, "socket"); 80755505Sshin 80855505Sshin bzero(&nbi, sizeof(nbi)); 80955505Sshin if_indextoname(ifindex, nbi.ifname); 81055505Sshin nbi.addr = *addr; 81155505Sshin if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) { 81262590Sitojun if (warning) 81362590Sitojun warn("ioctl(SIOCGNBRINFO_IN6)"); 81455505Sshin close(s); 81555505Sshin return(NULL); 81655505Sshin } 81755505Sshin 81855505Sshin close(s); 81955505Sshin return(&nbi); 82055505Sshin} 82155505Sshin 82255505Sshinstatic char * 82355505Sshinether_str(sdl) 82455505Sshin struct sockaddr_dl *sdl; 82555505Sshin{ 826121156Sume static char hbuf[NI_MAXHOST]; 82755505Sshin u_char *cp; 82855505Sshin 82955505Sshin if (sdl->sdl_alen) { 83055505Sshin cp = (u_char *)LLADDR(sdl); 831121156Sume snprintf(hbuf, sizeof(hbuf), "%x:%x:%x:%x:%x:%x", 832121156Sume cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); 833121156Sume } else 834121156Sume snprintf(hbuf, sizeof(hbuf), "(incomplete)"); 83555505Sshin 836121156Sume return(hbuf); 83755505Sshin} 83855505Sshin 83955505Sshinint 84055505Sshinndp_ether_aton(a, n) 84155505Sshin char *a; 84255505Sshin u_char *n; 84355505Sshin{ 84455505Sshin int i, o[6]; 84555505Sshin 84655505Sshin i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 847121156Sume &o[3], &o[4], &o[5]); 84855505Sshin if (i != 6) { 84955505Sshin fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a); 85055505Sshin return (1); 85155505Sshin } 852121156Sume for (i = 0; i < 6; i++) 85355505Sshin n[i] = o[i]; 85455505Sshin return (0); 85555505Sshin} 85655505Sshin 85755505Sshinvoid 85855505Sshinusage() 85955505Sshin{ 860122615Sume printf("usage: ndp [-nt] hostname\n"); 861122615Sume printf(" ndp [-nt] -a | -c | -p | -r | -H | -P | -R\n"); 86278064Sume printf(" ndp [-nt] -A wait\n"); 863122615Sume printf(" ndp [-nt] -d hostname\n"); 864122615Sume printf(" ndp [-nt] -f filename\n"); 865122615Sume printf(" ndp [-nt] -i interface [flags...]\n"); 86662590Sitojun#ifdef SIOCSDEFIFACE_IN6 867122615Sume printf(" ndp [-nt] -I [interface|delete]\n"); 86862590Sitojun#endif 869122615Sume printf(" ndp [-nt] -s nodename etheraddr [temp] [proxy]\n"); 87055505Sshin exit(1); 87155505Sshin} 87255505Sshin 87355505Sshinint 87455505Sshinrtmsg(cmd) 87555505Sshin int cmd; 87655505Sshin{ 87755505Sshin static int seq; 87855505Sshin int rlen; 87955505Sshin register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 88055505Sshin register char *cp = m_rtmsg.m_space; 88155505Sshin register int l; 88255505Sshin 88355505Sshin errno = 0; 88455505Sshin if (cmd == RTM_DELETE) 88555505Sshin goto doit; 88655505Sshin bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 88755505Sshin rtm->rtm_flags = flags; 88855505Sshin rtm->rtm_version = RTM_VERSION; 88955505Sshin 89055505Sshin switch (cmd) { 89155505Sshin default: 89255505Sshin fprintf(stderr, "ndp: internal wrong cmd\n"); 89355505Sshin exit(1); 89455505Sshin case RTM_ADD: 89555505Sshin rtm->rtm_addrs |= RTA_GATEWAY; 896122615Sume if (expire_time) { 897122615Sume rtm->rtm_rmx.rmx_expire = expire_time; 898122615Sume rtm->rtm_inits = RTV_EXPIRE; 899122615Sume } 900186500Sqingli rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA); 901151473Ssuz#if 0 /* we don't support ipv6addr/128 type proxying */ 90262590Sitojun if (rtm->rtm_flags & RTF_ANNOUNCE) { 90362590Sitojun rtm->rtm_flags &= ~RTF_HOST; 904124241Ssuz rtm->rtm_addrs |= RTA_NETMASK; 90562590Sitojun } 906151473Ssuz#endif 90755505Sshin /* FALLTHROUGH */ 90855505Sshin case RTM_GET: 90955505Sshin rtm->rtm_addrs |= RTA_DST; 91055505Sshin } 91155505Sshin 91255505Sshin NEXTADDR(RTA_DST, sin_m); 91355505Sshin NEXTADDR(RTA_GATEWAY, sdl_m); 914151473Ssuz#if 0 /* we don't support ipv6addr/128 type proxying */ 91562590Sitojun memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr)); 91655505Sshin NEXTADDR(RTA_NETMASK, so_mask); 917151473Ssuz#endif 91855505Sshin 91955505Sshin rtm->rtm_msglen = cp - (char *)&m_rtmsg; 92055505Sshindoit: 92155505Sshin l = rtm->rtm_msglen; 92255505Sshin rtm->rtm_seq = ++seq; 92355505Sshin rtm->rtm_type = cmd; 92455505Sshin if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 92555505Sshin if (errno != ESRCH || cmd != RTM_DELETE) { 926121156Sume err(1, "writing to routing socket"); 927121156Sume /* NOTREACHED */ 92855505Sshin } 92955505Sshin } 93055505Sshin do { 93155505Sshin l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 93255505Sshin } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 93355505Sshin if (l < 0) 93455505Sshin (void) fprintf(stderr, "ndp: read from routing socket: %s\n", 93555505Sshin strerror(errno)); 93655505Sshin return (0); 93755505Sshin} 93855505Sshin 93955505Sshinvoid 940122615Sumeifinfo(ifname, argc, argv) 941122615Sume char *ifname; 94262590Sitojun int argc; 94362590Sitojun char **argv; 94455505Sshin{ 94555505Sshin struct in6_ndireq nd; 94662590Sitojun int i, s; 94762590Sitojun u_int32_t newflags; 94878064Sume#ifdef IPV6CTL_USETEMPADDR 94978064Sume u_int8_t nullbuf[8]; 95078064Sume#endif 95155505Sshin 95255505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 953121156Sume err(1, "socket"); 954121156Sume /* NOTREACHED */ 95555505Sshin } 95655505Sshin bzero(&nd, sizeof(nd)); 957121156Sume strlcpy(nd.ifname, ifname, sizeof(nd.ifname)); 95855505Sshin if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 959121156Sume err(1, "ioctl(SIOCGIFINFO_IN6)"); 960121156Sume /* NOTREACHED */ 961122615Sume } 96262590Sitojun#define ND nd.ndi 96362590Sitojun newflags = ND.flags; 964122615Sume for (i = 0; i < argc; i++) { 96562590Sitojun int clear = 0; 96662590Sitojun char *cp = argv[i]; 96762590Sitojun 96862590Sitojun if (*cp == '-') { 96962590Sitojun clear = 1; 97062590Sitojun cp++; 97162590Sitojun } 97262590Sitojun 97362590Sitojun#define SETFLAG(s, f) \ 97462590Sitojun do {\ 97562590Sitojun if (strcmp(cp, (s)) == 0) {\ 97662590Sitojun if (clear)\ 97762590Sitojun newflags &= ~(f);\ 97862590Sitojun else\ 97962590Sitojun newflags |= (f);\ 98062590Sitojun }\ 98162590Sitojun } while (0) 982151468Ssuz/* 983151468Ssuz * XXX: this macro is not 100% correct, in that it matches "nud" against 984151468Ssuz * "nudbogus". But we just let it go since this is minor. 985151468Ssuz */ 986151468Ssuz#define SETVALUE(f, v) \ 987151468Ssuz do { \ 988151468Ssuz char *valptr; \ 989151468Ssuz unsigned long newval; \ 990151468Ssuz v = 0; /* unspecified */ \ 991151468Ssuz if (strncmp(cp, f, strlen(f)) == 0) { \ 992151468Ssuz valptr = strchr(cp, '='); \ 993151468Ssuz if (valptr == NULL) \ 994151468Ssuz err(1, "syntax error in %s field", (f)); \ 995151468Ssuz errno = 0; \ 996151468Ssuz newval = strtoul(++valptr, NULL, 0); \ 997151468Ssuz if (errno) \ 998151468Ssuz err(1, "syntax error in %s's value", (f)); \ 999151468Ssuz v = newval; \ 1000151468Ssuz } \ 1001151468Ssuz } while (0) 1002151468Ssuz 1003151474Ssuz SETFLAG("disabled", ND6_IFF_IFDISABLED); 100462590Sitojun SETFLAG("nud", ND6_IFF_PERFORMNUD); 1005118498Sume#ifdef ND6_IFF_ACCEPT_RTADV 1006118498Sume SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV); 1007118498Sume#endif 1008197138Shrs#ifdef ND6_IFF_AUTO_LINKLOCAL 1009197138Shrs SETFLAG("auto_linklocal", ND6_IFF_AUTO_LINKLOCAL); 1010197138Shrs#endif 1011122615Sume#ifdef ND6_IFF_PREFER_SOURCE 1012122615Sume SETFLAG("prefer_source", ND6_IFF_PREFER_SOURCE); 1013122615Sume#endif 1014151468Ssuz SETVALUE("basereachable", ND.basereachable); 1015151468Ssuz SETVALUE("retrans", ND.retrans); 1016151468Ssuz SETVALUE("curhlim", ND.chlim); 101762590Sitojun 101862590Sitojun ND.flags = newflags; 1019151468Ssuz if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) { 1020151468Ssuz err(1, "ioctl(SIOCSIFINFO_IN6)"); 1021121156Sume /* NOTREACHED */ 102262590Sitojun } 102362590Sitojun#undef SETFLAG 1024151468Ssuz#undef SETVALUE 102562590Sitojun } 102662590Sitojun 1027121162Sume if (!ND.initialized) { 1028121162Sume errx(1, "%s: not initialized yet", ifname); 1029121162Sume /* NOTREACHED */ 1030121162Sume } 1031121162Sume 1032151468Ssuz if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 1033151468Ssuz err(1, "ioctl(SIOCGIFINFO_IN6)"); 1034151468Ssuz /* NOTREACHED */ 1035151468Ssuz } 103655505Sshin printf("linkmtu=%d", ND.linkmtu); 1037121471Sume printf(", maxmtu=%d", ND.maxmtu); 103855505Sshin printf(", curhlim=%d", ND.chlim); 103955505Sshin printf(", basereachable=%ds%dms", 1040121156Sume ND.basereachable / 1000, ND.basereachable % 1000); 104155505Sshin printf(", reachable=%ds", ND.reachable); 104262590Sitojun printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000); 104378064Sume#ifdef IPV6CTL_USETEMPADDR 104478064Sume memset(nullbuf, 0, sizeof(nullbuf)); 104578064Sume if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) { 104678064Sume int j; 104778064Sume u_int8_t *rbuf; 104878064Sume 104978064Sume for (i = 0; i < 3; i++) { 1050121156Sume switch (i) { 105178064Sume case 0: 105278064Sume printf("\nRandom seed(0): "); 105378064Sume rbuf = ND.randomseed0; 105478064Sume break; 105578064Sume case 1: 105678064Sume printf("\nRandom seed(1): "); 105778064Sume rbuf = ND.randomseed1; 105878064Sume break; 105978064Sume case 2: 106078064Sume printf("\nRandom ID: "); 106178064Sume rbuf = ND.randomid; 106278064Sume break; 1063151472Ssuz default: 1064151472Ssuz errx(1, "impossible case for tempaddr display"); 106578064Sume } 106678064Sume for (j = 0; j < 8; j++) 106778064Sume printf("%02x", rbuf[j]); 106878064Sume } 106978064Sume } 107078064Sume#endif 107162590Sitojun if (ND.flags) { 107262590Sitojun printf("\nFlags: "); 1073151474Ssuz#ifdef ND6_IFF_IFDISABLED 1074151474Ssuz if ((ND.flags & ND6_IFF_IFDISABLED)) 1075151474Ssuz printf("disabled "); 1076151474Ssuz#endif 1077118498Sume if ((ND.flags & ND6_IFF_PERFORMNUD)) 1078118498Sume printf("nud "); 1079118498Sume#ifdef ND6_IFF_ACCEPT_RTADV 1080118498Sume if ((ND.flags & ND6_IFF_ACCEPT_RTADV)) 1081118498Sume printf("accept_rtadv "); 1082118498Sume#endif 1083197138Shrs#ifdef ND6_IFF_AUTO_LINKLOCAL 1084197138Shrs if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL)) 1085197138Shrs printf("auto_linklocal "); 1086197138Shrs#endif 1087122615Sume#ifdef ND6_IFF_PREFER_SOURCE 1088122615Sume if ((ND.flags & ND6_IFF_PREFER_SOURCE)) 1089122615Sume printf("prefer_source "); 1090122615Sume#endif 1091122615Sume } 109262590Sitojun putc('\n', stdout); 109355505Sshin#undef ND 1094121156Sume 109555505Sshin close(s); 109655505Sshin} 109755505Sshin 109878064Sume#ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */ 109978064Sume#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 110078064Sume#endif 110178064Sume 110255505Sshinvoid 110355505Sshinrtrlist() 110455505Sshin{ 110578064Sume#ifdef ICMPV6CTL_ND6_DRLIST 110678064Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST }; 110778064Sume char *buf; 110878064Sume struct in6_defrouter *p, *ep; 110978064Sume size_t l; 111078064Sume struct timeval time; 111178064Sume 111278064Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { 111378064Sume err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); 111478064Sume /*NOTREACHED*/ 111578064Sume } 1116151472Ssuz if (l == 0) 1117151472Ssuz return; 111878064Sume buf = malloc(l); 111978064Sume if (!buf) { 1120121156Sume err(1, "malloc"); 112178064Sume /*NOTREACHED*/ 112278064Sume } 112378064Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 112478064Sume err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); 112578064Sume /*NOTREACHED*/ 112678064Sume } 112778064Sume 112878064Sume ep = (struct in6_defrouter *)(buf + l); 112978064Sume for (p = (struct in6_defrouter *)buf; p < ep; p++) { 113078064Sume int rtpref; 113178064Sume 113278064Sume if (getnameinfo((struct sockaddr *)&p->rtaddr, 113378064Sume p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0, 1134121156Sume (nflag ? NI_NUMERICHOST : 0)) != 0) 113578064Sume strlcpy(host_buf, "?", sizeof(host_buf)); 1136121156Sume 113778064Sume printf("%s if=%s", host_buf, 1138121156Sume if_indextoname(p->if_index, ifix_buf)); 113978064Sume printf(", flags=%s%s", 1140121156Sume p->flags & ND_RA_FLAG_MANAGED ? "M" : "", 1141121156Sume p->flags & ND_RA_FLAG_OTHER ? "O" : ""); 114278064Sume rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff; 114378064Sume printf(", pref=%s", rtpref_str[rtpref]); 1144121156Sume 114578064Sume gettimeofday(&time, 0); 114678064Sume if (p->expire == 0) 114778064Sume printf(", expire=Never\n"); 114878064Sume else 114978064Sume printf(", expire=%s\n", 1150121156Sume sec2str(p->expire - time.tv_sec)); 115178064Sume } 115278064Sume free(buf); 115378064Sume#else 115455505Sshin struct in6_drlist dr; 115555505Sshin int s, i; 115655505Sshin struct timeval time; 115755505Sshin 115855505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1159121156Sume err(1, "socket"); 1160121156Sume /* NOTREACHED */ 116155505Sshin } 116255505Sshin bzero(&dr, sizeof(dr)); 1163121156Sume strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */ 116455505Sshin if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 1165121156Sume err(1, "ioctl(SIOCGDRLST_IN6)"); 1166121156Sume /* NOTREACHED */ 1167121156Sume } 116862590Sitojun#define DR dr.defrouter[i] 116978064Sume for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) { 117055505Sshin struct sockaddr_in6 sin6; 117155505Sshin 117255505Sshin bzero(&sin6, sizeof(sin6)); 117355505Sshin sin6.sin6_family = AF_INET6; 117455505Sshin sin6.sin6_len = sizeof(sin6); 117555505Sshin sin6.sin6_addr = DR.rtaddr; 117655505Sshin getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf, 1177121156Sume sizeof(host_buf), NULL, 0, 1178121156Sume (nflag ? NI_NUMERICHOST : 0)); 1179121156Sume 118055505Sshin printf("%s if=%s", host_buf, 1181121156Sume if_indextoname(DR.if_index, ifix_buf)); 118255505Sshin printf(", flags=%s%s", 1183121156Sume DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", 1184121156Sume DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); 118555505Sshin gettimeofday(&time, 0); 118655505Sshin if (DR.expire == 0) 118755505Sshin printf(", expire=Never\n"); 118855505Sshin else 118955505Sshin printf(", expire=%s\n", 1190121156Sume sec2str(DR.expire - time.tv_sec)); 119155505Sshin } 119255505Sshin#undef DR 119355505Sshin close(s); 119478064Sume#endif 119555505Sshin} 119655505Sshin 119755505Sshinvoid 119855505Sshinplist() 119955505Sshin{ 120078064Sume#ifdef ICMPV6CTL_ND6_PRLIST 120178064Sume int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST }; 120278064Sume char *buf; 120378064Sume struct in6_prefix *p, *ep, *n; 120478064Sume struct sockaddr_in6 *advrtr; 120578064Sume size_t l; 120678064Sume struct timeval time; 120778064Sume const int niflags = NI_NUMERICHOST; 120878064Sume int ninflags = nflag ? NI_NUMERICHOST : 0; 120978064Sume char namebuf[NI_MAXHOST]; 121078064Sume 121178064Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { 121278064Sume err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); 121378064Sume /*NOTREACHED*/ 121478064Sume } 121578064Sume buf = malloc(l); 121678064Sume if (!buf) { 1217121156Sume err(1, "malloc"); 121878064Sume /*NOTREACHED*/ 121978064Sume } 122078064Sume if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 122178064Sume err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); 122278064Sume /*NOTREACHED*/ 122378064Sume } 122478064Sume 122578064Sume ep = (struct in6_prefix *)(buf + l); 122678064Sume for (p = (struct in6_prefix *)buf; p < ep; p = n) { 122778064Sume advrtr = (struct sockaddr_in6 *)(p + 1); 122878064Sume n = (struct in6_prefix *)&advrtr[p->advrtrs]; 122978064Sume 123078064Sume if (getnameinfo((struct sockaddr *)&p->prefix, 123178064Sume p->prefix.sin6_len, namebuf, sizeof(namebuf), 123278064Sume NULL, 0, niflags) != 0) 123378064Sume strlcpy(namebuf, "?", sizeof(namebuf)); 123478064Sume printf("%s/%d if=%s\n", namebuf, p->prefixlen, 1235121156Sume if_indextoname(p->if_index, ifix_buf)); 123678064Sume 123778064Sume gettimeofday(&time, 0); 123878064Sume /* 123978064Sume * meaning of fields, especially flags, is very different 124078064Sume * by origin. notify the difference to the users. 124178064Sume */ 124278064Sume printf("flags=%s%s%s%s%s", 1243121156Sume p->raflags.onlink ? "L" : "", 1244121156Sume p->raflags.autonomous ? "A" : "", 1245121156Sume (p->flags & NDPRF_ONLINK) != 0 ? "O" : "", 1246121156Sume (p->flags & NDPRF_DETACHED) != 0 ? "D" : "", 124778064Sume#ifdef NDPRF_HOME 1248121156Sume (p->flags & NDPRF_HOME) != 0 ? "H" : "" 124978064Sume#else 1250121156Sume "" 125178064Sume#endif 1252121156Sume ); 125378064Sume if (p->vltime == ND6_INFINITE_LIFETIME) 125478064Sume printf(" vltime=infinity"); 125578064Sume else 1256122615Sume printf(" vltime=%lu", (unsigned long)p->vltime); 125778064Sume if (p->pltime == ND6_INFINITE_LIFETIME) 125878064Sume printf(", pltime=infinity"); 125978064Sume else 1260122615Sume printf(", pltime=%lu", (unsigned long)p->pltime); 126178064Sume if (p->expire == 0) 126278064Sume printf(", expire=Never"); 126378064Sume else if (p->expire >= time.tv_sec) 126478064Sume printf(", expire=%s", 1265121156Sume sec2str(p->expire - time.tv_sec)); 126678064Sume else 126778064Sume printf(", expired"); 126878064Sume printf(", ref=%d", p->refcnt); 126978064Sume printf("\n"); 127078064Sume /* 127178064Sume * "advertising router" list is meaningful only if the prefix 127278064Sume * information is from RA. 127378064Sume */ 127478064Sume if (p->advrtrs) { 127578064Sume int j; 127678064Sume struct sockaddr_in6 *sin6; 127778064Sume 1278122615Sume sin6 = advrtr; 127978064Sume printf(" advertised by\n"); 128078064Sume for (j = 0; j < p->advrtrs; j++) { 128178064Sume struct in6_nbrinfo *nbi; 128278064Sume 128378064Sume if (getnameinfo((struct sockaddr *)sin6, 128478064Sume sin6->sin6_len, namebuf, sizeof(namebuf), 128578064Sume NULL, 0, ninflags) != 0) 128678064Sume strlcpy(namebuf, "?", sizeof(namebuf)); 128778064Sume printf(" %s", namebuf); 128878064Sume 1289121156Sume nbi = getnbrinfo(&sin6->sin6_addr, 1290121156Sume p->if_index, 0); 129178064Sume if (nbi) { 1292121156Sume switch (nbi->state) { 129378064Sume case ND6_LLINFO_REACHABLE: 129478064Sume case ND6_LLINFO_STALE: 129578064Sume case ND6_LLINFO_DELAY: 129678064Sume case ND6_LLINFO_PROBE: 129778064Sume printf(" (reachable)\n"); 129878064Sume break; 129978064Sume default: 130078064Sume printf(" (unreachable)\n"); 130178064Sume } 130278064Sume } else 130378064Sume printf(" (no neighbor state)\n"); 130478064Sume sin6++; 130578064Sume } 130678064Sume } else 130778064Sume printf(" No advertising router\n"); 130878064Sume } 130978064Sume free(buf); 131078064Sume#else 131155505Sshin struct in6_prlist pr; 131255505Sshin int s, i; 131355505Sshin struct timeval time; 131455505Sshin 131555505Sshin gettimeofday(&time, 0); 131655505Sshin 131755505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1318121156Sume err(1, "socket"); 1319121156Sume /* NOTREACHED */ 132055505Sshin } 132155505Sshin bzero(&pr, sizeof(pr)); 1322121156Sume strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */ 132355505Sshin if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { 1324121156Sume err(1, "ioctl(SIOCGPRLST_IN6)"); 1325121156Sume /* NOTREACHED */ 1326121156Sume } 132762590Sitojun#define PR pr.prefix[i] 132855505Sshin for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { 132978064Sume struct sockaddr_in6 p6; 133078064Sume char namebuf[NI_MAXHOST]; 133178064Sume int niflags; 133278064Sume 133378064Sume#ifdef NDPRF_ONLINK 133478064Sume p6 = PR.prefix; 133578064Sume#else 133678064Sume memset(&p6, 0, sizeof(p6)); 133778064Sume p6.sin6_family = AF_INET6; 133878064Sume p6.sin6_len = sizeof(p6); 133978064Sume p6.sin6_addr = PR.prefix; 134078064Sume#endif 134178064Sume 134278064Sume /* 134378064Sume * copy link index to sin6_scope_id field. 134478064Sume * XXX: KAME specific. 134578064Sume */ 134678064Sume if (IN6_IS_ADDR_LINKLOCAL(&p6.sin6_addr)) { 134778064Sume u_int16_t linkid; 134878064Sume 134978064Sume memcpy(&linkid, &p6.sin6_addr.s6_addr[2], 1350121156Sume sizeof(linkid)); 135178064Sume linkid = ntohs(linkid); 135278064Sume p6.sin6_scope_id = linkid; 135378064Sume p6.sin6_addr.s6_addr[2] = 0; 135478064Sume p6.sin6_addr.s6_addr[3] = 0; 135578064Sume } 135678064Sume 135778064Sume niflags = NI_NUMERICHOST; 135878064Sume if (getnameinfo((struct sockaddr *)&p6, 1359121156Sume sizeof(p6), namebuf, sizeof(namebuf), 1360121156Sume NULL, 0, niflags)) { 136178064Sume warnx("getnameinfo failed"); 136278064Sume continue; 136378064Sume } 136478064Sume printf("%s/%d if=%s\n", namebuf, PR.prefixlen, 1365121156Sume if_indextoname(PR.if_index, ifix_buf)); 136678064Sume 136755505Sshin gettimeofday(&time, 0); 136862590Sitojun /* 136962590Sitojun * meaning of fields, especially flags, is very different 137062590Sitojun * by origin. notify the difference to the users. 137162590Sitojun */ 137278064Sume#if 0 137378064Sume printf(" %s", 1374121156Sume PR.origin == PR_ORIG_RA ? "" : "advertise: "); 137578064Sume#endif 137678064Sume#ifdef NDPRF_ONLINK 137778064Sume printf("flags=%s%s%s%s%s", 1378121156Sume PR.raflags.onlink ? "L" : "", 1379121156Sume PR.raflags.autonomous ? "A" : "", 1380121156Sume (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "", 1381121156Sume (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "", 138278064Sume#ifdef NDPRF_HOME 1383121156Sume (PR.flags & NDPRF_HOME) != 0 ? "H" : "" 138478064Sume#else 1385121156Sume "" 138678064Sume#endif 1387121156Sume ); 138878064Sume#else 138962590Sitojun printf("flags=%s%s", 1390121156Sume PR.raflags.onlink ? "L" : "", 1391121156Sume PR.raflags.autonomous ? "A" : ""); 139278064Sume#endif 139355505Sshin if (PR.vltime == ND6_INFINITE_LIFETIME) 139455505Sshin printf(" vltime=infinity"); 139555505Sshin else 1396122615Sume printf(" vltime=%lu", PR.vltime); 139755505Sshin if (PR.pltime == ND6_INFINITE_LIFETIME) 139855505Sshin printf(", pltime=infinity"); 139955505Sshin else 1400122615Sume printf(", pltime=%lu", PR.pltime); 140155505Sshin if (PR.expire == 0) 140262590Sitojun printf(", expire=Never"); 140355505Sshin else if (PR.expire >= time.tv_sec) 140462590Sitojun printf(", expire=%s", 1405121156Sume sec2str(PR.expire - time.tv_sec)); 140655505Sshin else 140762590Sitojun printf(", expired"); 140878064Sume#ifdef NDPRF_ONLINK 140978064Sume printf(", ref=%d", PR.refcnt); 141078064Sume#endif 141178064Sume#if 0 141262590Sitojun switch (PR.origin) { 141362590Sitojun case PR_ORIG_RA: 141462590Sitojun printf(", origin=RA"); 141562590Sitojun break; 141662590Sitojun case PR_ORIG_RR: 141762590Sitojun printf(", origin=RR"); 141862590Sitojun break; 141962590Sitojun case PR_ORIG_STATIC: 142062590Sitojun printf(", origin=static"); 142162590Sitojun break; 142262590Sitojun case PR_ORIG_KERNEL: 142362590Sitojun printf(", origin=kernel"); 142462590Sitojun break; 142562590Sitojun default: 142662590Sitojun printf(", origin=?"); 142762590Sitojun break; 142862590Sitojun } 142978064Sume#endif 143062590Sitojun printf("\n"); 143162590Sitojun /* 143262590Sitojun * "advertising router" list is meaningful only if the prefix 143362590Sitojun * information is from RA. 143462590Sitojun */ 143578064Sume if (0 && /* prefix origin is almost obsolted */ 143678064Sume PR.origin != PR_ORIG_RA) 143762590Sitojun ; 143862590Sitojun else if (PR.advrtrs) { 143955505Sshin int j; 144055505Sshin printf(" advertised by\n"); 144155505Sshin for (j = 0; j < PR.advrtrs; j++) { 144255505Sshin struct sockaddr_in6 sin6; 144362590Sitojun struct in6_nbrinfo *nbi; 144455505Sshin 144555505Sshin bzero(&sin6, sizeof(sin6)); 144655505Sshin sin6.sin6_family = AF_INET6; 144755505Sshin sin6.sin6_len = sizeof(sin6); 144855505Sshin sin6.sin6_addr = PR.advrtr[j]; 144962590Sitojun sin6.sin6_scope_id = PR.if_index; /* XXX */ 145055505Sshin getnameinfo((struct sockaddr *)&sin6, 1451121156Sume sin6.sin6_len, host_buf, 1452121156Sume sizeof(host_buf), NULL, 0, 1453121156Sume (nflag ? NI_NUMERICHOST : 0)); 145462590Sitojun printf(" %s", host_buf); 145555505Sshin 1456121156Sume nbi = getnbrinfo(&sin6.sin6_addr, 1457121156Sume PR.if_index, 0); 145862590Sitojun if (nbi) { 1459121156Sume switch (nbi->state) { 1460121156Sume case ND6_LLINFO_REACHABLE: 1461121156Sume case ND6_LLINFO_STALE: 1462121156Sume case ND6_LLINFO_DELAY: 1463121156Sume case ND6_LLINFO_PROBE: 146462590Sitojun printf(" (reachable)\n"); 146562590Sitojun break; 1466121156Sume default: 146762590Sitojun printf(" (unreachable)\n"); 146862590Sitojun } 146978064Sume } else 147062590Sitojun printf(" (no neighbor state)\n"); 147155505Sshin } 147255505Sshin if (PR.advrtrs > DRLSTSIZ) 147355505Sshin printf(" and %d routers\n", 1474121156Sume PR.advrtrs - DRLSTSIZ); 147562590Sitojun } else 147655505Sshin printf(" No advertising router\n"); 147755505Sshin } 147855505Sshin#undef PR 147955505Sshin close(s); 148078064Sume#endif 148155505Sshin} 148255505Sshin 148355505Sshinvoid 148455505Sshinpfx_flush() 148555505Sshin{ 148655505Sshin char dummyif[IFNAMSIZ+8]; 148755505Sshin int s; 148855505Sshin 148955505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 149055505Sshin err(1, "socket"); 1491121156Sume strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 149255505Sshin if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0) 1493121156Sume err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); 149455505Sshin} 149555505Sshin 149655505Sshinvoid 149755505Sshinrtr_flush() 149855505Sshin{ 149955505Sshin char dummyif[IFNAMSIZ+8]; 150055505Sshin int s; 150155505Sshin 150255505Sshin if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 150355505Sshin err(1, "socket"); 1504121156Sume strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 150555505Sshin if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0) 1506121156Sume err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); 150762590Sitojun 150862590Sitojun close(s); 150955505Sshin} 151055505Sshin 151155505Sshinvoid 151255505Sshinharmonize_rtr() 151355505Sshin{ 151455505Sshin char dummyif[IFNAMSIZ+8]; 151555505Sshin int s; 151655505Sshin 151762590Sitojun if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 151862590Sitojun err(1, "socket"); 1519121156Sume strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 152062590Sitojun if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) 1521121156Sume err(1, "ioctl(SIOCSNDFLUSH_IN6)"); 152262590Sitojun 152362590Sitojun close(s); 152455505Sshin} 152555505Sshin 152662590Sitojun#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 152762590Sitojunstatic void 152862590Sitojunsetdefif(ifname) 152962590Sitojun char *ifname; 153062590Sitojun{ 153162590Sitojun struct in6_ndifreq ndifreq; 153262590Sitojun unsigned int ifindex; 153362590Sitojun 153462590Sitojun if (strcasecmp(ifname, "delete") == 0) 153562590Sitojun ifindex = 0; 153662590Sitojun else { 153762590Sitojun if ((ifindex = if_nametoindex(ifname)) == 0) 153862590Sitojun err(1, "failed to resolve i/f index for %s", ifname); 153962590Sitojun } 154062590Sitojun 154162590Sitojun if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 154262590Sitojun err(1, "socket"); 154362590Sitojun 1544121156Sume strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */ 154562590Sitojun ndifreq.ifindex = ifindex; 154662590Sitojun 154762590Sitojun if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1548121156Sume err(1, "ioctl(SIOCSDEFIFACE_IN6)"); 154962590Sitojun 155062590Sitojun close(s); 155162590Sitojun} 155262590Sitojun 155362590Sitojunstatic void 155462590Sitojungetdefif() 155562590Sitojun{ 155662590Sitojun struct in6_ndifreq ndifreq; 155762590Sitojun char ifname[IFNAMSIZ+8]; 155862590Sitojun 155962590Sitojun if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 156062590Sitojun err(1, "socket"); 156162590Sitojun 156262590Sitojun memset(&ndifreq, 0, sizeof(ndifreq)); 1563121156Sume strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */ 156462590Sitojun 156562590Sitojun if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1566121156Sume err(1, "ioctl(SIOCGDEFIFACE_IN6)"); 156762590Sitojun 156862590Sitojun if (ndifreq.ifindex == 0) 156962590Sitojun printf("No default interface.\n"); 157062590Sitojun else { 157162590Sitojun if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL) 157262590Sitojun err(1, "failed to resolve ifname for index %lu", 157362590Sitojun ndifreq.ifindex); 157462590Sitojun printf("ND default interface = %s\n", ifname); 157562590Sitojun } 157662590Sitojun 157762590Sitojun close(s); 157862590Sitojun} 157962590Sitojun#endif 158062590Sitojun 158155505Sshinstatic char * 158255505Sshinsec2str(total) 158355505Sshin time_t total; 158455505Sshin{ 158555505Sshin static char result[256]; 158655505Sshin int days, hours, mins, secs; 158755505Sshin int first = 1; 158855505Sshin char *p = result; 1589121156Sume char *ep = &result[sizeof(result)]; 1590121156Sume int n; 159155505Sshin 159255505Sshin days = total / 3600 / 24; 159355505Sshin hours = (total / 3600) % 24; 159455505Sshin mins = (total / 60) % 60; 159555505Sshin secs = total % 60; 159655505Sshin 159755505Sshin if (days) { 159855505Sshin first = 0; 1599121156Sume n = snprintf(p, ep - p, "%dd", days); 1600121156Sume if (n < 0 || n >= ep - p) 1601121156Sume return "?"; 1602121156Sume p += n; 160355505Sshin } 160455505Sshin if (!first || hours) { 160555505Sshin first = 0; 1606121156Sume n = snprintf(p, ep - p, "%dh", hours); 1607121156Sume if (n < 0 || n >= ep - p) 1608121156Sume return "?"; 1609121156Sume p += n; 161055505Sshin } 161155505Sshin if (!first || mins) { 161255505Sshin first = 0; 1613121156Sume n = snprintf(p, ep - p, "%dm", mins); 1614121156Sume if (n < 0 || n >= ep - p) 1615121156Sume return "?"; 1616121156Sume p += n; 161755505Sshin } 1618121156Sume snprintf(p, ep - p, "%ds", secs); 161955505Sshin 162055505Sshin return(result); 162155505Sshin} 162255505Sshin 162355505Sshin/* 162455505Sshin * Print the timestamp 162555505Sshin * from tcpdump/util.c 162655505Sshin */ 162755505Sshinstatic void 162855505Sshints_print(tvp) 162955505Sshin const struct timeval *tvp; 163055505Sshin{ 163155505Sshin int s; 163255505Sshin 163355505Sshin /* Default */ 163455505Sshin s = (tvp->tv_sec + thiszone) % 86400; 163555505Sshin (void)printf("%02d:%02d:%02d.%06u ", 163655505Sshin s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec); 163755505Sshin} 1638186119Sqingli 1639186119Sqingli#undef NEXTADDR 1640