ndp.c revision 268827
142421Syokota/* $FreeBSD: head/usr.sbin/ndp/ndp.c 268827 2014-07-18 06:48:02Z peter $ */ 242421Syokota/* $KAME: ndp.c,v 1.104 2003/06/27 07:48:39 itojun Exp $ */ 342421Syokota 442421Syokota/* 542421Syokota * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. 642421Syokota * All rights reserved. 742421Syokota * 842421Syokota * Redistribution and use in source and binary forms, with or without 942421Syokota * modification, are permitted provided that the following conditions 1042421Syokota * are met: 1142421Syokota * 1. Redistributions of source code must retain the above copyright 1242421Syokota * notice, this list of conditions and the following disclaimer. 1342421Syokota * 2. Redistributions in binary form must reproduce the above copyright 1442421Syokota * notice, this list of conditions and the following disclaimer in the 1542421Syokota * documentation and/or other materials provided with the distribution. 1642421Syokota * 3. Neither the name of the project nor the names of its contributors 1742421Syokota * may be used to endorse or promote products derived from this software 1842421Syokota * without specific prior written permission. 1942421Syokota * 2042421Syokota * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 2142421Syokota * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2242421Syokota * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2342421Syokota * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 2442421Syokota * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2542421Syokota * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2642421Syokota * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2742421Syokota * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2842421Syokota * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29119418Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30119418Sobrien * SUCH DAMAGE. 31119418Sobrien */ 3242421Syokota/* 3342421Syokota * Copyright (c) 1984, 1993 3442421Syokota * The Regents of the University of California. All rights reserved. 3542421Syokota * 3642421Syokota * This code is derived from software contributed to Berkeley by 3748104Syokota * Sun Microsystems, Inc. 3842421Syokota * 3942421Syokota * Redistribution and use in source and binary forms, with or without 4071862Speter * modification, are permitted provided that the following conditions 4148104Syokota * are met: 4248104Syokota * 1. Redistributions of source code must retain the above copyright 4378161Speter * notice, this list of conditions and the following disclaimer. 4442421Syokota * 2. Redistributions in binary form must reproduce the above copyright 4548104Syokota * notice, this list of conditions and the following disclaimer in the 4648104Syokota * documentation and/or other materials provided with the distribution. 4742421Syokota * 4. Neither the name of the University nor the names of its contributors 4842421Syokota * may be used to endorse or promote products derived from this software 4942421Syokota * without specific prior written permission. 5078161Speter * 5178161Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 5242421Syokota * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 5342421Syokota * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 5442421Syokota * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 5542421Syokota * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 5642421Syokota * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 5742421Syokota * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 5842421Syokota * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 5942564Syokota * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 6048104Syokota * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 6142564Syokota * SUCH DAMAGE. 6242421Syokota */ 6342564Syokota 6442421Syokota/* 6542421Syokota * Based on: 6642421Syokota * "@(#) Copyright (c) 1984, 1993\n\ 6742564Syokota * The Regents of the University of California. All rights reserved.\n"; 6848104Syokota * 6948104Syokota * "@(#)arp.c 8.2 (Berkeley) 1/2/94"; 7048104Syokota */ 7142564Syokota 7242421Syokota/* 7342421Syokota * ndp - display, set, delete and flush neighbor cache 7448104Syokota */ 7542421Syokota 7642421Syokota 7742421Syokota#include <sys/param.h> 7842421Syokota#include <sys/file.h> 7948104Syokota#include <sys/ioctl.h> 8042421Syokota#include <sys/socket.h> 8148104Syokota#include <sys/sysctl.h> 8242421Syokota#include <sys/time.h> 8342421Syokota#include <sys/queue.h> 8442421Syokota 8548104Syokota#include <net/if.h> 8648104Syokota#include <net/if_var.h> 8748104Syokota#include <net/if_dl.h> 8842421Syokota#include <net/if_types.h> 8942421Syokota#include <net/route.h> 90111119Simp 9169781Sdwmalone#include <netinet/in.h> 92111119Simp#include <netinet/if_ether.h> 9348104Syokota 9469781Sdwmalone#include <netinet/icmp6.h> 95111119Simp#include <netinet6/in6_var.h> 9648104Syokota#include <netinet6/nd6.h> 9742421Syokota 9842421Syokota#include <arpa/inet.h> 9948104Syokota 10042421Syokota#include <ctype.h> 10148104Syokota#include <netdb.h> 10242421Syokota#include <errno.h> 10342421Syokota#include <nlist.h> 10442421Syokota#include <stdio.h> 10548104Syokota#include <string.h> 10642421Syokota#include <paths.h> 10748104Syokota#include <err.h> 10842421Syokota#include <stdlib.h> 10942421Syokota#include <fcntl.h> 11042421Syokota#include <unistd.h> 11148104Syokota#include "gmt2local.h" 11242421Syokota 11348104Syokota#define NEXTADDR(w, s) \ 11442421Syokota if (rtm->rtm_addrs & (w)) { \ 11542421Syokota bcopy((char *)&s, cp, sizeof(s)); cp += SA_SIZE(&s);} 11642421Syokota 11742421Syokota 11842421Syokotastatic pid_t pid; 11948104Syokotastatic int nflag; 12048104Syokotastatic int tflag; 12142421Syokotastatic int32_t thiszone; /* time difference with gmt */ 12242421Syokotastatic int s = -1; 12348104Syokotastatic int repeat = 0; 12448104Syokota 12548104Syokotachar ntop_buf[INET6_ADDRSTRLEN]; /* inet_ntop() */ 12648104Syokotachar host_buf[NI_MAXHOST]; /* getnameinfo() */ 12748104Syokotachar ifix_buf[IFNAMSIZ]; /* if_indextoname() */ 12842564Syokota 12948104Syokotaint main(int, char **); 13048104Syokotastatic int file(char *); 13142421Syokotavoid getsocket(void); 13242421Syokotaint set(int, char **); 13342421Syokotavoid get(char *); 13442421Syokotaint delete(char *); 13542421Syokotavoid dump(struct sockaddr_in6 *, int); 13642421Syokotastatic struct in6_nbrinfo *getnbrinfo(struct in6_addr *, int, int); 13742421Syokotastatic char *ether_str(struct sockaddr_dl *); 13842421Syokotaint ndp_ether_aton(char *, u_char *); 13942421Syokotavoid usage(void); 14042421Syokotaint rtmsg(int); 14142421Syokotavoid ifinfo(char *, int, char **); 14242421Syokotavoid rtrlist(void); 14342421Syokotavoid plist(void); 14442421Syokotavoid pfx_flush(void); 14542421Syokotavoid rtr_flush(void); 14642421Syokotavoid harmonize_rtr(void); 14742421Syokota#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 14842421Syokotastatic void getdefif(void); 14942421Syokotastatic void setdefif(char *); 15042421Syokota#endif 15142421Syokotastatic char *sec2str(time_t); 15248104Syokotastatic void ts_print(const struct timeval *); 15348104Syokota 15442421Syokota#ifdef ICMPV6CTL_ND6_DRLIST 15542421Syokotastatic char *rtpref_str[] = { 15642421Syokota "medium", /* 00 */ 15742421Syokota "high", /* 01 */ 15842421Syokota "rsv", /* 10 */ 15942421Syokota "low" /* 11 */ 16048104Syokota}; 16148104Syokota#endif 16248104Syokota 16348104Syokotaint mode = 0; 16442421Syokotachar *arg = NULL; 16542421Syokota 16642421Syokotaint 16778161Spetermain(int argc, char **argv) 16878161Speter{ 16942421Syokota int ch; 17042421Syokota 17142421Syokota pid = getpid(); 17242421Syokota thiszone = gmt2local(0); 17342421Syokota while ((ch = getopt(argc, argv, "acd:f:Ii:nprstA:HPR")) != -1) 17442421Syokota switch (ch) { 17542421Syokota case 'a': 17642421Syokota case 'c': 17742421Syokota case 'p': 17842421Syokota case 'r': 17942421Syokota case 'H': 18042421Syokota case 'P': 18142421Syokota case 'R': 18242421Syokota case 's': 18342421Syokota case 'I': 18442421Syokota if (mode) { 18542421Syokota usage(); 18642421Syokota /*NOTREACHED*/ 18742421Syokota } 18842421Syokota mode = ch; 18942421Syokota arg = NULL; 19042421Syokota break; 19142421Syokota case 'f': 19242421Syokota exit(file(optarg) ? 1 : 0); 19342421Syokota case 'd': 19442421Syokota case 'i': 19542421Syokota if (mode) { 19648104Syokota usage(); 19748104Syokota /*NOTREACHED*/ 19842421Syokota } 19978161Speter mode = ch; 20078161Speter arg = optarg; 20142421Syokota break; 20242421Syokota case 'n': 20342421Syokota nflag = 1; 20442421Syokota break; 20542421Syokota case 't': 20642421Syokota tflag = 1; 20742421Syokota break; 20842421Syokota case 'A': 20942421Syokota if (mode) { 21042421Syokota usage(); 21142421Syokota /*NOTREACHED*/ 21242421Syokota } 21342421Syokota mode = 'a'; 21442421Syokota repeat = atoi(optarg); 21542421Syokota if (repeat < 0) { 21642421Syokota usage(); 21742421Syokota /*NOTREACHED*/ 21842421Syokota } 21942421Syokota break; 22042421Syokota default: 22142421Syokota usage(); 22242421Syokota } 22342421Syokota 22442421Syokota argc -= optind; 22542421Syokota argv += optind; 22642421Syokota 22742421Syokota switch (mode) { 22842421Syokota case 'a': 22942421Syokota case 'c': 23042421Syokota if (argc != 0) { 23142421Syokota usage(); 23242421Syokota /*NOTREACHED*/ 23342421Syokota } 23442421Syokota dump(0, mode == 'c'); 23542421Syokota break; 23642421Syokota case 'd': 23742421Syokota if (argc != 0) { 23842421Syokota usage(); 23942421Syokota /*NOTREACHED*/ 24042421Syokota } 24142421Syokota delete(arg); 24242421Syokota break; 24342421Syokota case 'I': 24442421Syokota#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 24542421Syokota if (argc > 1) { 24642421Syokota usage(); 24742421Syokota /*NOTREACHED*/ 24842421Syokota } else if (argc == 1) { 24942421Syokota if (strcmp(*argv, "delete") == 0 || 25042421Syokota if_nametoindex(*argv)) 25142421Syokota setdefif(*argv); 25242421Syokota else 25342421Syokota errx(1, "invalid interface %s", *argv); 25442421Syokota } 25542421Syokota getdefif(); /* always call it to print the result */ 25642421Syokota break; 25742421Syokota#else 25842421Syokota errx(1, "not supported yet"); 25942421Syokota /*NOTREACHED*/ 26042421Syokota#endif 26142421Syokota case 'p': 26242421Syokota if (argc != 0) { 26342421Syokota usage(); 26442421Syokota /*NOTREACHED*/ 26542421Syokota } 26642421Syokota plist(); 26742421Syokota break; 26842421Syokota case 'i': 26942421Syokota ifinfo(arg, argc, argv); 27042421Syokota break; 27142421Syokota case 'r': 27242421Syokota if (argc != 0) { 27342421Syokota usage(); 27442421Syokota /*NOTREACHED*/ 27542421Syokota } 27642421Syokota rtrlist(); 27742421Syokota break; 27842421Syokota case 's': 27942421Syokota if (argc < 2 || argc > 4) 28042421Syokota usage(); 28142421Syokota exit(set(argc, argv) ? 1 : 0); 28242421Syokota case 'H': 28342421Syokota if (argc != 0) { 28442421Syokota usage(); 28548104Syokota /*NOTREACHED*/ 28648104Syokota } 28742421Syokota harmonize_rtr(); 28878161Speter break; 28978161Speter case 'P': 29042421Syokota if (argc != 0) { 29142421Syokota usage(); 29242421Syokota /*NOTREACHED*/ 29342421Syokota } 29442421Syokota pfx_flush(); 29542421Syokota break; 29642421Syokota case 'R': 29742421Syokota if (argc != 0) { 29842421Syokota usage(); 29942421Syokota /*NOTREACHED*/ 30042421Syokota } 30142421Syokota rtr_flush(); 30242421Syokota break; 30348104Syokota case 0: 30442421Syokota if (argc != 1) { 30542421Syokota usage(); 30642421Syokota /*NOTREACHED*/ 307153084Sru } 30848104Syokota get(argv[0]); 30948104Syokota break; 31048104Syokota } 31148104Syokota exit(0); 31248104Syokota} 31348104Syokota 31448104Syokota/* 31548104Syokota * Process a file to set standard ndp entries 31648104Syokota */ 31748104Syokotastatic int 31848104Syokotafile(char *name) 31948104Syokota{ 32048104Syokota FILE *fp; 32148104Syokota int i, retval; 32248104Syokota char line[100], arg[5][50], *args[5], *p; 32348104Syokota 32448104Syokota if ((fp = fopen(name, "r")) == NULL) 32548104Syokota err(1, "cannot open %s", name); 32648104Syokota args[0] = &arg[0][0]; 32748104Syokota args[1] = &arg[1][0]; 32848104Syokota args[2] = &arg[2][0]; 32948104Syokota args[3] = &arg[3][0]; 33048104Syokota args[4] = &arg[4][0]; 33148104Syokota retval = 0; 33248104Syokota while (fgets(line, sizeof(line), fp) != NULL) { 33348104Syokota if ((p = strchr(line, '#')) != NULL) 33448104Syokota *p = '\0'; 33548104Syokota for (p = line; isblank(*p); p++); 33648104Syokota if (*p == '\n' || *p == '\0') 33748104Syokota continue; 33848104Syokota i = sscanf(line, "%49s %49s %49s %49s %49s", 33948104Syokota arg[0], arg[1], arg[2], arg[3], arg[4]); 34048104Syokota if (i < 2) { 34148104Syokota warnx("bad line: %s", line); 34248104Syokota retval = 1; 34348104Syokota continue; 34448104Syokota } 34548104Syokota if (set(i, args)) 34648104Syokota retval = 1; 34748104Syokota } 34848104Syokota fclose(fp); 34948104Syokota return (retval); 35048104Syokota} 351153084Sru 35248104Syokotavoid 35342421Syokotagetsocket() 35442421Syokota{ 35542421Syokota if (s < 0) { 356153084Sru s = socket(PF_ROUTE, SOCK_RAW, 0); 35742421Syokota if (s < 0) { 35842421Syokota err(1, "socket"); 35948104Syokota /* NOTREACHED */ 36048104Syokota } 36142421Syokota } 36242421Syokota} 36342421Syokota 36442421Syokotastruct sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 }; 36542421Syokotastruct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m; 366126080Sphkstruct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; 367126080Sphktime_t expire_time; 368111815Sphkint flags, found_entry; 369111815Sphkstruct { 370111815Sphk struct rt_msghdr m_rtm; 371111815Sphk char m_space[512]; 372111815Sphk} m_rtmsg; 373111815Sphk 374111815Sphk/* 37542421Syokota * Set an individual neighbor cache entry 376111576Sphk */ 37742421Syokotaint 37842421Syokotaset(int argc, char **argv) 37971862Speter{ 38071862Speter register struct sockaddr_in6 *sin = &sin_m; 38171862Speter register struct sockaddr_dl *sdl; 38271862Speter register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); 38371862Speter struct addrinfo hints, *res; 38471862Speter int gai_error; 38571862Speter u_char *ea; 38671862Speter char *host = argv[0], *eaddr = argv[1]; 38771862Speter 38871862Speter getsocket(); 389132199Sphk argc -= 2; 390132199Sphk argv += 2; 39171862Speter sdl_m = blank_sdl; 39271862Speter sin_m = blank_sin; 39371862Speter 39442421Syokota bzero(&hints, sizeof(hints)); 39571862Speter hints.ai_family = AF_INET6; 39671862Speter gai_error = getaddrinfo(host, NULL, &hints, &res); 39771862Speter if (gai_error) { 39871862Speter fprintf(stderr, "ndp: %s: %s\n", host, 39971862Speter gai_strerror(gai_error)); 40042421Syokota return 1; 40171862Speter } 40271862Speter sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 40342421Syokota sin->sin6_scope_id = 404120465Sphk ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 40542421Syokota ea = (u_char *)LLADDR(&sdl_m); 40642421Syokota if (ndp_ether_aton(eaddr, ea) == 0) 40742421Syokota sdl_m.sdl_alen = 6; 40842421Syokota flags = expire_time = 0; 40942421Syokota while (argc-- > 0) { 41042421Syokota if (strncmp(argv[0], "temp", 4) == 0) { 41142421Syokota struct timeval now; 41242421Syokota 41342421Syokota gettimeofday(&now, 0); 414120465Sphk expire_time = now.tv_sec + 20 * 60; 41542421Syokota } else if (strncmp(argv[0], "proxy", 5) == 0) 41642421Syokota flags |= RTF_ANNOUNCE; 41742421Syokota argv++; 41842421Syokota } 41942421Syokota if (rtmsg(RTM_GET) < 0) { 42042421Syokota errx(1, "RTM_GET(%s) failed", host); 42142421Syokota /* NOTREACHED */ 42242421Syokota } 423120465Sphk sin = (struct sockaddr_in6 *)(rtm + 1); 42442421Syokota sdl = (struct sockaddr_dl *)(ALIGN(sin->sin6_len) + (char *)sin); 42542421Syokota if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { 42642421Syokota if (sdl->sdl_family == AF_LINK && 42742421Syokota !(rtm->rtm_flags & RTF_GATEWAY)) { 42842421Syokota switch (sdl->sdl_type) { 42942421Syokota case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 43042421Syokota case IFT_ISO88024: case IFT_ISO88025: 43142421Syokota case IFT_L2VLAN: case IFT_BRIDGE: 43242421Syokota goto overwrite; 43342421Syokota } 43442421Syokota } 43542421Syokota fprintf(stderr, "set: cannot configure a new entry\n"); 43642421Syokota return 1; 43742421Syokota } 43842421Syokota 43942421Syokotaoverwrite: 44048104Syokota if (sdl->sdl_family != AF_LINK) { 44148104Syokota printf("cannot intuit interface index and type for %s\n", host); 44248104Syokota return (1); 44348104Syokota } 44448104Syokota sdl_m.sdl_type = sdl->sdl_type; 44548104Syokota sdl_m.sdl_index = sdl->sdl_index; 44648104Syokota return (rtmsg(RTM_ADD)); 44783366Sjulian} 44848104Syokota 44948104Syokota/* 45048104Syokota * Display an individual neighbor cache entry 45148104Syokota */ 45248104Syokotavoid 45348104Syokotaget(char *host) 45448104Syokota{ 45548104Syokota struct sockaddr_in6 *sin = &sin_m; 45648104Syokota struct addrinfo hints, *res; 45748104Syokota int gai_error; 45848104Syokota 45983366Sjulian sin_m = blank_sin; 46048104Syokota bzero(&hints, sizeof(hints)); 46148104Syokota hints.ai_family = AF_INET6; 46248104Syokota gai_error = getaddrinfo(host, NULL, &hints, &res); 46348104Syokota if (gai_error) { 46448104Syokota fprintf(stderr, "ndp: %s: %s\n", host, 46548104Syokota gai_strerror(gai_error)); 46648104Syokota return; 46748104Syokota } 46848104Syokota sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 46948104Syokota sin->sin6_scope_id = 47048104Syokota ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 47148104Syokota dump(sin, 0); 47248104Syokota if (found_entry == 0) { 47348104Syokota getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 47448104Syokota sizeof(host_buf), NULL ,0, 47548104Syokota (nflag ? NI_NUMERICHOST : 0)); 47648104Syokota printf("%s (%s) -- no entry\n", host, host_buf); 47748104Syokota exit(1); 47848104Syokota } 47948104Syokota} 48048104Syokota 48148104Syokota/* 48248104Syokota * Delete a neighbor cache entry 48348104Syokota */ 48448104Syokotaint 48548104Syokotadelete(char *host) 48648104Syokota{ 487174985Swkoszek struct sockaddr_in6 *sin = &sin_m; 48848104Syokota register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 48948104Syokota register char *cp = m_rtmsg.m_space; 49048104Syokota struct sockaddr_dl *sdl; 49148104Syokota struct addrinfo hints, *res; 49248104Syokota int gai_error; 49348104Syokota 49448104Syokota getsocket(); 49548104Syokota sin_m = blank_sin; 49648104Syokota 49748104Syokota bzero(&hints, sizeof(hints)); 49848104Syokota hints.ai_family = AF_INET6; 49948104Syokota gai_error = getaddrinfo(host, NULL, &hints, &res); 50048104Syokota if (gai_error) { 50148104Syokota fprintf(stderr, "ndp: %s: %s\n", host, 50283366Sjulian gai_strerror(gai_error)); 50348104Syokota return 1; 50448104Syokota } 50548104Syokota sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; 50648104Syokota sin->sin6_scope_id = 50748104Syokota ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; 508174985Swkoszek if (rtmsg(RTM_GET) < 0) { 50948104Syokota errx(1, "RTM_GET(%s) failed", host); 51048104Syokota /* NOTREACHED */ 51148104Syokota } 51248104Syokota sin = (struct sockaddr_in6 *)(rtm + 1); 51348104Syokota sdl = (struct sockaddr_dl *)(ALIGN(sin->sin6_len) + (char *)sin); 51448104Syokota if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) { 515111462Smux if (sdl->sdl_family == AF_LINK && 51648104Syokota !(rtm->rtm_flags & RTF_GATEWAY)) { 517174985Swkoszek goto delete; 51848104Syokota } 51948104Syokota fprintf(stderr, "delete: cannot delete non-NDP entry\n"); 52042421Syokota return 1; 52142421Syokota } 52242421Syokota 52342421Syokotadelete: 52442421Syokota if (sdl->sdl_family != AF_LINK) { 52542421Syokota printf("cannot locate %s\n", host); 52642421Syokota return (1); 52742421Syokota } 52842421Syokota /* 52942421Syokota * need to reinit the field because it has rt_key 53042421Syokota * but we want the actual address 53142421Syokota */ 53242421Syokota NEXTADDR(RTA_DST, sin_m); 53342421Syokota rtm->rtm_flags |= RTF_LLDATA; 53442421Syokota if (rtmsg(RTM_DELETE) == 0) { 53548104Syokota getnameinfo((struct sockaddr *)sin, 53642421Syokota sin->sin6_len, host_buf, 53742421Syokota sizeof(host_buf), NULL, 0, 53842421Syokota (nflag ? NI_NUMERICHOST : 0)); 53942421Syokota printf("%s (%s) deleted\n", host, host_buf); 54042421Syokota } 54142421Syokota 54242421Syokota return 0; 54342421Syokota} 54442421Syokota 54542421Syokota#define W_ADDR 36 54648104Syokota#define W_LL 17 54748104Syokota#define W_IF 6 54848104Syokota 54948104Syokota/* 55048104Syokota * Dump the entire neighbor cache 55148104Syokota */ 55242421Syokotavoid 55342421Syokotadump(struct sockaddr_in6 *addr, int cflag) 55442421Syokota{ 55542421Syokota int mib[6]; 55642421Syokota size_t needed; 55742421Syokota char *lim, *buf, *next; 55842421Syokota struct rt_msghdr *rtm; 55948104Syokota struct sockaddr_in6 *sin; 56042421Syokota struct sockaddr_dl *sdl; 56194617Sobrien extern int h_errno; 56294617Sobrien struct in6_nbrinfo *nbi; 56394617Sobrien struct timeval now; 56494617Sobrien int addrwidth; 56594617Sobrien int llwidth; 56642421Syokota int ifwidth; 56748104Syokota char flgbuf[8]; 56842421Syokota char *ifname; 56948104Syokota 57048104Syokota /* Print header */ 57148104Syokota if (!tflag && !cflag) 57248104Syokota printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %5s\n", 57342831Syokota W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address", 57442421Syokota W_IF, W_IF, "Netif", "Expire", "S", "Flags"); 57542421Syokota 57642421Syokotaagain:; 57742421Syokota mib[0] = CTL_NET; 57842421Syokota mib[1] = PF_ROUTE; 57942421Syokota mib[2] = 0; 58042421Syokota mib[3] = AF_INET6; 58142421Syokota mib[4] = NET_RT_FLAGS; 58242421Syokota#ifdef RTF_LLINFO 58342421Syokota mib[5] = RTF_LLINFO; 58442421Syokota#else 58542421Syokota mib[5] = 0; 58642421Syokota#endif 58742421Syokota if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 58842421Syokota err(1, "sysctl(PF_ROUTE estimate)"); 58942421Syokota if (needed > 0) { 59042421Syokota if ((buf = malloc(needed)) == NULL) 59142421Syokota err(1, "malloc"); 59242421Syokota if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 59342421Syokota err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)"); 59494617Sobrien lim = buf + needed; 59542421Syokota } else 59648104Syokota buf = lim = NULL; 59748104Syokota 59848104Syokota for (next = buf; next && next < lim; next += rtm->rtm_msglen) { 59948104Syokota int isrouter = 0, prbs = 0; 60048104Syokota 60148104Syokota rtm = (struct rt_msghdr *)next; 60248104Syokota sin = (struct sockaddr_in6 *)(rtm + 1); 60348104Syokota sdl = (struct sockaddr_dl *)((char *)sin + ALIGN(sin->sin6_len)); 60448104Syokota 60548104Syokota /* 60648104Syokota * Some OSes can produce a route that has the LINK flag but 60748104Syokota * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD 60848104Syokota * and BSD/OS, where xx is not the interface identifier on 60948104Syokota * lo0). Such routes entry would annoy getnbrinfo() below, 61048104Syokota * so we skip them. 61148104Syokota * XXX: such routes should have the GATEWAY flag, not the 61248104Syokota * LINK flag. However, there is rotten routing software 61348104Syokota * that advertises all routes that have the GATEWAY flag. 61448104Syokota * Thus, KAME kernel intentionally does not set the LINK flag. 61548104Syokota * What is to be fixed is not ndp, but such routing software 61648104Syokota * (and the kernel workaround)... 61748104Syokota */ 61848104Syokota if (sdl->sdl_family != AF_LINK) 61948104Syokota continue; 62048104Syokota 62148104Syokota if (!(rtm->rtm_flags & RTF_HOST)) 62248104Syokota continue; 62348104Syokota 62448104Syokota if (addr) { 62548104Syokota if (IN6_ARE_ADDR_EQUAL(&addr->sin6_addr, 62648104Syokota &sin->sin6_addr) == 0 || 62748104Syokota addr->sin6_scope_id != sin->sin6_scope_id) 62848104Syokota continue; 62948104Syokota found_entry = 1; 63048104Syokota } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)) 63148104Syokota continue; 63248104Syokota if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) || 63348104Syokota IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) { 63448104Syokota /* XXX: should scope id be filled in the kernel? */ 63548104Syokota if (sin->sin6_scope_id == 0) 63648104Syokota sin->sin6_scope_id = sdl->sdl_index; 63748104Syokota } 63848104Syokota getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf, 63948104Syokota sizeof(host_buf), NULL, 0, (nflag ? NI_NUMERICHOST : 0)); 64048104Syokota if (cflag) { 64148104Syokota#ifdef RTF_WASCLONED 64248104Syokota if (rtm->rtm_flags & RTF_WASCLONED) 64348104Syokota delete(host_buf); 64448104Syokota#elif defined(RTF_CLONED) 64548104Syokota if (rtm->rtm_flags & RTF_CLONED) 64648104Syokota delete(host_buf); 64748104Syokota#else 64848104Syokota delete(host_buf); 64948104Syokota#endif 65048104Syokota continue; 65148104Syokota } 65248104Syokota gettimeofday(&now, 0); 65348104Syokota if (tflag) 65448104Syokota ts_print(&now); 65548104Syokota 65660742Sgallatin addrwidth = strlen(host_buf); 65748104Syokota if (addrwidth < W_ADDR) 65860742Sgallatin addrwidth = W_ADDR; 65960742Sgallatin llwidth = strlen(ether_str(sdl)); 66060742Sgallatin if (W_ADDR + W_LL - addrwidth > llwidth) 66148104Syokota llwidth = W_ADDR + W_LL - addrwidth; 66248104Syokota ifname = if_indextoname(sdl->sdl_index, ifix_buf); 66348104Syokota if (!ifname) 66448104Syokota ifname = "?"; 66548104Syokota ifwidth = strlen(ifname); 66648104Syokota if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth) 66748104Syokota ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth; 66860742Sgallatin 66948104Syokota printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf, 67060742Sgallatin llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname); 67160742Sgallatin 67260742Sgallatin /* Print neighbor discovery specific informations */ 67348104Syokota nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1); 67448104Syokota if (nbi) { 67548104Syokota if (nbi->expire > now.tv_sec) { 67648104Syokota printf(" %-9.9s", 67748104Syokota sec2str(nbi->expire - now.tv_sec)); 67848104Syokota } else if (nbi->expire == 0) 67948104Syokota printf(" %-9.9s", "permanent"); 68048104Syokota else 68148104Syokota printf(" %-9.9s", "expired"); 68248104Syokota 68348104Syokota switch (nbi->state) { 68448104Syokota case ND6_LLINFO_NOSTATE: 68548104Syokota printf(" N"); 68648104Syokota break; 68748104Syokota#ifdef ND6_LLINFO_WAITDELETE 68848104Syokota case ND6_LLINFO_WAITDELETE: 689174985Swkoszek printf(" W"); 690174985Swkoszek break; 691174985Swkoszek#endif 69248104Syokota case ND6_LLINFO_INCOMPLETE: 69348104Syokota printf(" I"); 69448104Syokota break; 69548104Syokota case ND6_LLINFO_REACHABLE: 69648104Syokota printf(" R"); 697174985Swkoszek break; 69848104Syokota case ND6_LLINFO_STALE: 69948104Syokota printf(" S"); 70048104Syokota break; 70148104Syokota case ND6_LLINFO_DELAY: 70248104Syokota printf(" D"); 70348104Syokota break; 70448104Syokota case ND6_LLINFO_PROBE: 705174985Swkoszek printf(" P"); 70648104Syokota break; 70748104Syokota default: 70848104Syokota printf(" ?"); 70948104Syokota break; 71048104Syokota } 71148104Syokota 71248104Syokota isrouter = nbi->isrouter; 71348104Syokota prbs = nbi->asked; 71448104Syokota } else { 71548104Syokota warnx("failed to get neighbor information"); 71648104Syokota printf(" "); 71748104Syokota } 71848104Syokota 71948104Syokota /* 72048104Syokota * other flags. R: router, P: proxy, W: ?? 72148104Syokota */ 72248104Syokota if ((rtm->rtm_addrs & RTA_NETMASK) == 0) { 72381039Syokota snprintf(flgbuf, sizeof(flgbuf), "%s%s", 724174985Swkoszek isrouter ? "R" : "", 72581039Syokota (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 72681039Syokota } else { 72748104Syokota sin = (struct sockaddr_in6 *) 72848104Syokota (sdl->sdl_len + (char *)sdl); 72948104Syokota#if 0 /* W and P are mystery even for us */ 73048104Syokota snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s", 73148104Syokota isrouter ? "R" : "", 73248104Syokota !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr) ? "P" : "", 73381039Syokota (sin->sin6_len != sizeof(struct sockaddr_in6)) ? "W" : "", 73481039Syokota (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 73548104Syokota#else 73648104Syokota snprintf(flgbuf, sizeof(flgbuf), "%s%s", 73748104Syokota isrouter ? "R" : "", 73848104Syokota (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : ""); 73948104Syokota#endif 74048104Syokota } 74148104Syokota printf(" %s", flgbuf); 74248104Syokota 74348104Syokota if (prbs) 74448104Syokota printf(" %d", prbs); 74581039Syokota 74648104Syokota printf("\n"); 74748104Syokota } 74848104Syokota if (buf != NULL) 74948104Syokota free(buf); 75048104Syokota 75181039Syokota if (repeat) { 75281039Syokota printf("\n"); 75348104Syokota fflush(stdout); 75448104Syokota sleep(repeat); 75548104Syokota goto again; 75648104Syokota } 75748104Syokota} 75848104Syokota 75948104Syokotastatic struct in6_nbrinfo * 76048104Syokotagetnbrinfo(struct in6_addr *addr, int ifindex, int warning) 76148104Syokota{ 762 static struct in6_nbrinfo nbi; 763 int s; 764 765 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 766 err(1, "socket"); 767 768 bzero(&nbi, sizeof(nbi)); 769 if_indextoname(ifindex, nbi.ifname); 770 nbi.addr = *addr; 771 if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) { 772 if (warning) 773 warn("ioctl(SIOCGNBRINFO_IN6)"); 774 close(s); 775 return(NULL); 776 } 777 778 close(s); 779 return(&nbi); 780} 781 782static char * 783ether_str(struct sockaddr_dl *sdl) 784{ 785 static char hbuf[NI_MAXHOST]; 786 char *cp; 787 788 if (sdl->sdl_alen == ETHER_ADDR_LEN) { 789 strlcpy(hbuf, ether_ntoa((struct ether_addr *)LLADDR(sdl)), 790 sizeof(hbuf)); 791 } else if (sdl->sdl_alen) { 792 int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0; 793 snprintf(hbuf, sizeof(hbuf), "%s", link_ntoa(sdl) + n); 794 } else 795 snprintf(hbuf, sizeof(hbuf), "(incomplete)"); 796 797 return(hbuf); 798} 799 800int 801ndp_ether_aton(char *a, u_char *n) 802{ 803 int i, o[6]; 804 805 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 806 &o[3], &o[4], &o[5]); 807 if (i != 6) { 808 fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a); 809 return (1); 810 } 811 for (i = 0; i < 6; i++) 812 n[i] = o[i]; 813 return (0); 814} 815 816void 817usage() 818{ 819 printf("usage: ndp [-nt] hostname\n"); 820 printf(" ndp [-nt] -a | -c | -p | -r | -H | -P | -R\n"); 821 printf(" ndp [-nt] -A wait\n"); 822 printf(" ndp [-nt] -d hostname\n"); 823 printf(" ndp [-nt] -f filename\n"); 824 printf(" ndp [-nt] -i interface [flags...]\n"); 825#ifdef SIOCSDEFIFACE_IN6 826 printf(" ndp [-nt] -I [interface|delete]\n"); 827#endif 828 printf(" ndp [-nt] -s nodename etheraddr [temp] [proxy]\n"); 829 exit(1); 830} 831 832int 833rtmsg(int cmd) 834{ 835 static int seq; 836 int rlen; 837 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 838 register char *cp = m_rtmsg.m_space; 839 register int l; 840 841 errno = 0; 842 if (cmd == RTM_DELETE) 843 goto doit; 844 bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 845 rtm->rtm_flags = flags; 846 rtm->rtm_version = RTM_VERSION; 847 848 switch (cmd) { 849 default: 850 fprintf(stderr, "ndp: internal wrong cmd\n"); 851 exit(1); 852 case RTM_ADD: 853 rtm->rtm_addrs |= RTA_GATEWAY; 854 if (expire_time) { 855 rtm->rtm_rmx.rmx_expire = expire_time; 856 rtm->rtm_inits = RTV_EXPIRE; 857 } 858 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA); 859#if 0 /* we don't support ipv6addr/128 type proxying */ 860 if (rtm->rtm_flags & RTF_ANNOUNCE) { 861 rtm->rtm_flags &= ~RTF_HOST; 862 rtm->rtm_addrs |= RTA_NETMASK; 863 } 864#endif 865 /* FALLTHROUGH */ 866 case RTM_GET: 867 rtm->rtm_addrs |= RTA_DST; 868 } 869 870 NEXTADDR(RTA_DST, sin_m); 871 NEXTADDR(RTA_GATEWAY, sdl_m); 872#if 0 /* we don't support ipv6addr/128 type proxying */ 873 memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr)); 874 NEXTADDR(RTA_NETMASK, so_mask); 875#endif 876 877 rtm->rtm_msglen = cp - (char *)&m_rtmsg; 878doit: 879 l = rtm->rtm_msglen; 880 rtm->rtm_seq = ++seq; 881 rtm->rtm_type = cmd; 882 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 883 if (errno != ESRCH || cmd != RTM_DELETE) { 884 err(1, "writing to routing socket"); 885 /* NOTREACHED */ 886 } 887 } 888 do { 889 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 890 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 891 if (l < 0) 892 (void) fprintf(stderr, "ndp: read from routing socket: %s\n", 893 strerror(errno)); 894 return (0); 895} 896 897void 898ifinfo(char *ifname, int argc, char **argv) 899{ 900 struct in6_ndireq nd; 901 int i, s; 902 u_int32_t newflags; 903#ifdef IPV6CTL_USETEMPADDR 904 u_int8_t nullbuf[8]; 905#endif 906 907 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 908 err(1, "socket"); 909 /* NOTREACHED */ 910 } 911 bzero(&nd, sizeof(nd)); 912 strlcpy(nd.ifname, ifname, sizeof(nd.ifname)); 913 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 914 err(1, "ioctl(SIOCGIFINFO_IN6)"); 915 /* NOTREACHED */ 916 } 917#define ND nd.ndi 918 newflags = ND.flags; 919 for (i = 0; i < argc; i++) { 920 int clear = 0; 921 char *cp = argv[i]; 922 923 if (*cp == '-') { 924 clear = 1; 925 cp++; 926 } 927 928#define SETFLAG(s, f) \ 929 do {\ 930 if (strcmp(cp, (s)) == 0) {\ 931 if (clear)\ 932 newflags &= ~(f);\ 933 else\ 934 newflags |= (f);\ 935 }\ 936 } while (0) 937/* 938 * XXX: this macro is not 100% correct, in that it matches "nud" against 939 * "nudbogus". But we just let it go since this is minor. 940 */ 941#define SETVALUE(f, v) \ 942 do { \ 943 char *valptr; \ 944 unsigned long newval; \ 945 v = 0; /* unspecified */ \ 946 if (strncmp(cp, f, strlen(f)) == 0) { \ 947 valptr = strchr(cp, '='); \ 948 if (valptr == NULL) \ 949 err(1, "syntax error in %s field", (f)); \ 950 errno = 0; \ 951 newval = strtoul(++valptr, NULL, 0); \ 952 if (errno) \ 953 err(1, "syntax error in %s's value", (f)); \ 954 v = newval; \ 955 } \ 956 } while (0) 957 958 SETFLAG("disabled", ND6_IFF_IFDISABLED); 959 SETFLAG("nud", ND6_IFF_PERFORMNUD); 960#ifdef ND6_IFF_ACCEPT_RTADV 961 SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV); 962#endif 963#ifdef ND6_IFF_AUTO_LINKLOCAL 964 SETFLAG("auto_linklocal", ND6_IFF_AUTO_LINKLOCAL); 965#endif 966#ifdef ND6_IFF_NO_PREFER_IFACE 967 SETFLAG("no_prefer_iface", ND6_IFF_NO_PREFER_IFACE); 968#endif 969 SETVALUE("basereachable", ND.basereachable); 970 SETVALUE("retrans", ND.retrans); 971 SETVALUE("curhlim", ND.chlim); 972 973 ND.flags = newflags; 974 if (ioctl(s, SIOCSIFINFO_IN6, (caddr_t)&nd) < 0) { 975 err(1, "ioctl(SIOCSIFINFO_IN6)"); 976 /* NOTREACHED */ 977 } 978#undef SETFLAG 979#undef SETVALUE 980 } 981 982 if (!ND.initialized) { 983 errx(1, "%s: not initialized yet", ifname); 984 /* NOTREACHED */ 985 } 986 987 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) { 988 err(1, "ioctl(SIOCGIFINFO_IN6)"); 989 /* NOTREACHED */ 990 } 991 printf("linkmtu=%d", ND.linkmtu); 992 printf(", maxmtu=%d", ND.maxmtu); 993 printf(", curhlim=%d", ND.chlim); 994 printf(", basereachable=%ds%dms", 995 ND.basereachable / 1000, ND.basereachable % 1000); 996 printf(", reachable=%ds", ND.reachable); 997 printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000); 998#ifdef IPV6CTL_USETEMPADDR 999 memset(nullbuf, 0, sizeof(nullbuf)); 1000 if (memcmp(nullbuf, ND.randomid, sizeof(nullbuf)) != 0) { 1001 int j; 1002 u_int8_t *rbuf; 1003 1004 for (i = 0; i < 3; i++) { 1005 switch (i) { 1006 case 0: 1007 printf("\nRandom seed(0): "); 1008 rbuf = ND.randomseed0; 1009 break; 1010 case 1: 1011 printf("\nRandom seed(1): "); 1012 rbuf = ND.randomseed1; 1013 break; 1014 case 2: 1015 printf("\nRandom ID: "); 1016 rbuf = ND.randomid; 1017 break; 1018 default: 1019 errx(1, "impossible case for tempaddr display"); 1020 } 1021 for (j = 0; j < 8; j++) 1022 printf("%02x", rbuf[j]); 1023 } 1024 } 1025#endif 1026 if (ND.flags) { 1027 printf("\nFlags: "); 1028#ifdef ND6_IFF_IFDISABLED 1029 if ((ND.flags & ND6_IFF_IFDISABLED)) 1030 printf("disabled "); 1031#endif 1032 if ((ND.flags & ND6_IFF_PERFORMNUD)) 1033 printf("nud "); 1034#ifdef ND6_IFF_ACCEPT_RTADV 1035 if ((ND.flags & ND6_IFF_ACCEPT_RTADV)) 1036 printf("accept_rtadv "); 1037#endif 1038#ifdef ND6_IFF_AUTO_LINKLOCAL 1039 if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL)) 1040 printf("auto_linklocal "); 1041#endif 1042#ifdef ND6_IFF_NO_PREFER_IFACE 1043 if ((ND.flags & ND6_IFF_NO_PREFER_IFACE)) 1044 printf("no_prefer_iface "); 1045#endif 1046 } 1047 putc('\n', stdout); 1048#undef ND 1049 1050 close(s); 1051} 1052 1053#ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */ 1054#define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */ 1055#endif 1056 1057void 1058rtrlist() 1059{ 1060#ifdef ICMPV6CTL_ND6_DRLIST 1061 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST }; 1062 char *buf; 1063 struct in6_defrouter *p, *ep; 1064 size_t l; 1065 struct timeval now; 1066 1067 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { 1068 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); 1069 /*NOTREACHED*/ 1070 } 1071 if (l == 0) 1072 return; 1073 buf = malloc(l); 1074 if (!buf) { 1075 err(1, "malloc"); 1076 /*NOTREACHED*/ 1077 } 1078 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 1079 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)"); 1080 /*NOTREACHED*/ 1081 } 1082 1083 ep = (struct in6_defrouter *)(buf + l); 1084 for (p = (struct in6_defrouter *)buf; p < ep; p++) { 1085 int rtpref; 1086 1087 if (getnameinfo((struct sockaddr *)&p->rtaddr, 1088 p->rtaddr.sin6_len, host_buf, sizeof(host_buf), NULL, 0, 1089 (nflag ? NI_NUMERICHOST : 0)) != 0) 1090 strlcpy(host_buf, "?", sizeof(host_buf)); 1091 1092 printf("%s if=%s", host_buf, 1093 if_indextoname(p->if_index, ifix_buf)); 1094 printf(", flags=%s%s", 1095 p->flags & ND_RA_FLAG_MANAGED ? "M" : "", 1096 p->flags & ND_RA_FLAG_OTHER ? "O" : ""); 1097 rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff; 1098 printf(", pref=%s", rtpref_str[rtpref]); 1099 1100 gettimeofday(&now, 0); 1101 if (p->expire == 0) 1102 printf(", expire=Never\n"); 1103 else 1104 printf(", expire=%s\n", 1105 sec2str(p->expire - now.tv_sec)); 1106 } 1107 free(buf); 1108#else 1109 struct in6_drlist dr; 1110 int s, i; 1111 struct timeval now; 1112 1113 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1114 err(1, "socket"); 1115 /* NOTREACHED */ 1116 } 1117 bzero(&dr, sizeof(dr)); 1118 strlcpy(dr.ifname, "lo0", sizeof(dr.ifname)); /* dummy */ 1119 if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) { 1120 err(1, "ioctl(SIOCGDRLST_IN6)"); 1121 /* NOTREACHED */ 1122 } 1123#define DR dr.defrouter[i] 1124 for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) { 1125 struct sockaddr_in6 sin6; 1126 1127 bzero(&sin6, sizeof(sin6)); 1128 sin6.sin6_family = AF_INET6; 1129 sin6.sin6_len = sizeof(sin6); 1130 sin6.sin6_addr = DR.rtaddr; 1131 getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf, 1132 sizeof(host_buf), NULL, 0, 1133 (nflag ? NI_NUMERICHOST : 0)); 1134 1135 printf("%s if=%s", host_buf, 1136 if_indextoname(DR.if_index, ifix_buf)); 1137 printf(", flags=%s%s", 1138 DR.flags & ND_RA_FLAG_MANAGED ? "M" : "", 1139 DR.flags & ND_RA_FLAG_OTHER ? "O" : ""); 1140 gettimeofday(&now, 0); 1141 if (DR.expire == 0) 1142 printf(", expire=Never\n"); 1143 else 1144 printf(", expire=%s\n", 1145 sec2str(DR.expire - now.tv_sec)); 1146 } 1147#undef DR 1148 close(s); 1149#endif 1150} 1151 1152void 1153plist() 1154{ 1155#ifdef ICMPV6CTL_ND6_PRLIST 1156 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST }; 1157 char *buf; 1158 struct in6_prefix *p, *ep, *n; 1159 struct sockaddr_in6 *advrtr; 1160 size_t l; 1161 struct timeval now; 1162 const int niflags = NI_NUMERICHOST; 1163 int ninflags = nflag ? NI_NUMERICHOST : 0; 1164 char namebuf[NI_MAXHOST]; 1165 1166 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) { 1167 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); 1168 /*NOTREACHED*/ 1169 } 1170 buf = malloc(l); 1171 if (!buf) { 1172 err(1, "malloc"); 1173 /*NOTREACHED*/ 1174 } 1175 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) { 1176 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)"); 1177 /*NOTREACHED*/ 1178 } 1179 1180 ep = (struct in6_prefix *)(buf + l); 1181 for (p = (struct in6_prefix *)buf; p < ep; p = n) { 1182 advrtr = (struct sockaddr_in6 *)(p + 1); 1183 n = (struct in6_prefix *)&advrtr[p->advrtrs]; 1184 1185 if (getnameinfo((struct sockaddr *)&p->prefix, 1186 p->prefix.sin6_len, namebuf, sizeof(namebuf), 1187 NULL, 0, niflags) != 0) 1188 strlcpy(namebuf, "?", sizeof(namebuf)); 1189 printf("%s/%d if=%s\n", namebuf, p->prefixlen, 1190 if_indextoname(p->if_index, ifix_buf)); 1191 1192 gettimeofday(&now, 0); 1193 /* 1194 * meaning of fields, especially flags, is very different 1195 * by origin. notify the difference to the users. 1196 */ 1197 printf("flags=%s%s%s%s%s", 1198 p->raflags.onlink ? "L" : "", 1199 p->raflags.autonomous ? "A" : "", 1200 (p->flags & NDPRF_ONLINK) != 0 ? "O" : "", 1201 (p->flags & NDPRF_DETACHED) != 0 ? "D" : "", 1202#ifdef NDPRF_HOME 1203 (p->flags & NDPRF_HOME) != 0 ? "H" : "" 1204#else 1205 "" 1206#endif 1207 ); 1208 if (p->vltime == ND6_INFINITE_LIFETIME) 1209 printf(" vltime=infinity"); 1210 else 1211 printf(" vltime=%lu", (unsigned long)p->vltime); 1212 if (p->pltime == ND6_INFINITE_LIFETIME) 1213 printf(", pltime=infinity"); 1214 else 1215 printf(", pltime=%lu", (unsigned long)p->pltime); 1216 if (p->expire == 0) 1217 printf(", expire=Never"); 1218 else if (p->expire >= now.tv_sec) 1219 printf(", expire=%s", 1220 sec2str(p->expire - now.tv_sec)); 1221 else 1222 printf(", expired"); 1223 printf(", ref=%d", p->refcnt); 1224 printf("\n"); 1225 /* 1226 * "advertising router" list is meaningful only if the prefix 1227 * information is from RA. 1228 */ 1229 if (p->advrtrs) { 1230 int j; 1231 struct sockaddr_in6 *sin6; 1232 1233 sin6 = advrtr; 1234 printf(" advertised by\n"); 1235 for (j = 0; j < p->advrtrs; j++) { 1236 struct in6_nbrinfo *nbi; 1237 1238 if (getnameinfo((struct sockaddr *)sin6, 1239 sin6->sin6_len, namebuf, sizeof(namebuf), 1240 NULL, 0, ninflags) != 0) 1241 strlcpy(namebuf, "?", sizeof(namebuf)); 1242 printf(" %s", namebuf); 1243 1244 nbi = getnbrinfo(&sin6->sin6_addr, 1245 p->if_index, 0); 1246 if (nbi) { 1247 switch (nbi->state) { 1248 case ND6_LLINFO_REACHABLE: 1249 case ND6_LLINFO_STALE: 1250 case ND6_LLINFO_DELAY: 1251 case ND6_LLINFO_PROBE: 1252 printf(" (reachable)\n"); 1253 break; 1254 default: 1255 printf(" (unreachable)\n"); 1256 } 1257 } else 1258 printf(" (no neighbor state)\n"); 1259 sin6++; 1260 } 1261 } else 1262 printf(" No advertising router\n"); 1263 } 1264 free(buf); 1265#else 1266 struct in6_prlist pr; 1267 int s, i; 1268 struct timeval now; 1269 1270 gettimeofday(&now, 0); 1271 1272 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { 1273 err(1, "socket"); 1274 /* NOTREACHED */ 1275 } 1276 bzero(&pr, sizeof(pr)); 1277 strlcpy(pr.ifname, "lo0", sizeof(pr.ifname)); /* dummy */ 1278 if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) { 1279 err(1, "ioctl(SIOCGPRLST_IN6)"); 1280 /* NOTREACHED */ 1281 } 1282#define PR pr.prefix[i] 1283 for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) { 1284 struct sockaddr_in6 p6; 1285 char namebuf[NI_MAXHOST]; 1286 int niflags; 1287 1288#ifdef NDPRF_ONLINK 1289 p6 = PR.prefix; 1290#else 1291 memset(&p6, 0, sizeof(p6)); 1292 p6.sin6_family = AF_INET6; 1293 p6.sin6_len = sizeof(p6); 1294 p6.sin6_addr = PR.prefix; 1295#endif 1296 niflags = NI_NUMERICHOST; 1297 if (getnameinfo((struct sockaddr *)&p6, 1298 sizeof(p6), namebuf, sizeof(namebuf), 1299 NULL, 0, niflags)) { 1300 warnx("getnameinfo failed"); 1301 continue; 1302 } 1303 printf("%s/%d if=%s\n", namebuf, PR.prefixlen, 1304 if_indextoname(PR.if_index, ifix_buf)); 1305 1306 gettimeofday(&now, 0); 1307 /* 1308 * meaning of fields, especially flags, is very different 1309 * by origin. notify the difference to the users. 1310 */ 1311#if 0 1312 printf(" %s", 1313 PR.origin == PR_ORIG_RA ? "" : "advertise: "); 1314#endif 1315#ifdef NDPRF_ONLINK 1316 printf("flags=%s%s%s%s%s", 1317 PR.raflags.onlink ? "L" : "", 1318 PR.raflags.autonomous ? "A" : "", 1319 (PR.flags & NDPRF_ONLINK) != 0 ? "O" : "", 1320 (PR.flags & NDPRF_DETACHED) != 0 ? "D" : "", 1321#ifdef NDPRF_HOME 1322 (PR.flags & NDPRF_HOME) != 0 ? "H" : "" 1323#else 1324 "" 1325#endif 1326 ); 1327#else 1328 printf("flags=%s%s", 1329 PR.raflags.onlink ? "L" : "", 1330 PR.raflags.autonomous ? "A" : ""); 1331#endif 1332 if (PR.vltime == ND6_INFINITE_LIFETIME) 1333 printf(" vltime=infinity"); 1334 else 1335 printf(" vltime=%lu", PR.vltime); 1336 if (PR.pltime == ND6_INFINITE_LIFETIME) 1337 printf(", pltime=infinity"); 1338 else 1339 printf(", pltime=%lu", PR.pltime); 1340 if (PR.expire == 0) 1341 printf(", expire=Never"); 1342 else if (PR.expire >= now.tv_sec) 1343 printf(", expire=%s", 1344 sec2str(PR.expire - now.tv_sec)); 1345 else 1346 printf(", expired"); 1347#ifdef NDPRF_ONLINK 1348 printf(", ref=%d", PR.refcnt); 1349#endif 1350#if 0 1351 switch (PR.origin) { 1352 case PR_ORIG_RA: 1353 printf(", origin=RA"); 1354 break; 1355 case PR_ORIG_RR: 1356 printf(", origin=RR"); 1357 break; 1358 case PR_ORIG_STATIC: 1359 printf(", origin=static"); 1360 break; 1361 case PR_ORIG_KERNEL: 1362 printf(", origin=kernel"); 1363 break; 1364 default: 1365 printf(", origin=?"); 1366 break; 1367 } 1368#endif 1369 printf("\n"); 1370 /* 1371 * "advertising router" list is meaningful only if the prefix 1372 * information is from RA. 1373 */ 1374 if (0 && /* prefix origin is almost obsolted */ 1375 PR.origin != PR_ORIG_RA) 1376 ; 1377 else if (PR.advrtrs) { 1378 int j; 1379 printf(" advertised by\n"); 1380 for (j = 0; j < PR.advrtrs; j++) { 1381 struct sockaddr_in6 sin6; 1382 struct in6_nbrinfo *nbi; 1383 1384 bzero(&sin6, sizeof(sin6)); 1385 sin6.sin6_family = AF_INET6; 1386 sin6.sin6_len = sizeof(sin6); 1387 sin6.sin6_addr = PR.advrtr[j]; 1388 sin6.sin6_scope_id = PR.if_index; /* XXX */ 1389 getnameinfo((struct sockaddr *)&sin6, 1390 sin6.sin6_len, host_buf, 1391 sizeof(host_buf), NULL, 0, 1392 (nflag ? NI_NUMERICHOST : 0)); 1393 printf(" %s", host_buf); 1394 1395 nbi = getnbrinfo(&sin6.sin6_addr, 1396 PR.if_index, 0); 1397 if (nbi) { 1398 switch (nbi->state) { 1399 case ND6_LLINFO_REACHABLE: 1400 case ND6_LLINFO_STALE: 1401 case ND6_LLINFO_DELAY: 1402 case ND6_LLINFO_PROBE: 1403 printf(" (reachable)\n"); 1404 break; 1405 default: 1406 printf(" (unreachable)\n"); 1407 } 1408 } else 1409 printf(" (no neighbor state)\n"); 1410 } 1411 if (PR.advrtrs > DRLSTSIZ) 1412 printf(" and %d routers\n", 1413 PR.advrtrs - DRLSTSIZ); 1414 } else 1415 printf(" No advertising router\n"); 1416 } 1417#undef PR 1418 close(s); 1419#endif 1420} 1421 1422void 1423pfx_flush() 1424{ 1425 char dummyif[IFNAMSIZ+8]; 1426 int s; 1427 1428 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1429 err(1, "socket"); 1430 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 1431 if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0) 1432 err(1, "ioctl(SIOCSPFXFLUSH_IN6)"); 1433} 1434 1435void 1436rtr_flush() 1437{ 1438 char dummyif[IFNAMSIZ+8]; 1439 int s; 1440 1441 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1442 err(1, "socket"); 1443 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 1444 if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0) 1445 err(1, "ioctl(SIOCSRTRFLUSH_IN6)"); 1446 1447 close(s); 1448} 1449 1450void 1451harmonize_rtr() 1452{ 1453 char dummyif[IFNAMSIZ+8]; 1454 int s; 1455 1456 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1457 err(1, "socket"); 1458 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */ 1459 if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) 1460 err(1, "ioctl(SIOCSNDFLUSH_IN6)"); 1461 1462 close(s); 1463} 1464 1465#ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */ 1466static void 1467setdefif(char *ifname) 1468{ 1469 struct in6_ndifreq ndifreq; 1470 unsigned int ifindex; 1471 1472 if (strcasecmp(ifname, "delete") == 0) 1473 ifindex = 0; 1474 else { 1475 if ((ifindex = if_nametoindex(ifname)) == 0) 1476 err(1, "failed to resolve i/f index for %s", ifname); 1477 } 1478 1479 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1480 err(1, "socket"); 1481 1482 strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */ 1483 ndifreq.ifindex = ifindex; 1484 1485 if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1486 err(1, "ioctl(SIOCSDEFIFACE_IN6)"); 1487 1488 close(s); 1489} 1490 1491static void 1492getdefif() 1493{ 1494 struct in6_ndifreq ndifreq; 1495 char ifname[IFNAMSIZ+8]; 1496 1497 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) 1498 err(1, "socket"); 1499 1500 memset(&ndifreq, 0, sizeof(ndifreq)); 1501 strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */ 1502 1503 if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0) 1504 err(1, "ioctl(SIOCGDEFIFACE_IN6)"); 1505 1506 if (ndifreq.ifindex == 0) 1507 printf("No default interface.\n"); 1508 else { 1509 if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL) 1510 err(1, "failed to resolve ifname for index %lu", 1511 ndifreq.ifindex); 1512 printf("ND default interface = %s\n", ifname); 1513 } 1514 1515 close(s); 1516} 1517#endif 1518 1519static char * 1520sec2str(time_t total) 1521{ 1522 static char result[256]; 1523 int days, hours, mins, secs; 1524 int first = 1; 1525 char *p = result; 1526 char *ep = &result[sizeof(result)]; 1527 int n; 1528 1529 days = total / 3600 / 24; 1530 hours = (total / 3600) % 24; 1531 mins = (total / 60) % 60; 1532 secs = total % 60; 1533 1534 if (days) { 1535 first = 0; 1536 n = snprintf(p, ep - p, "%dd", days); 1537 if (n < 0 || n >= ep - p) 1538 return "?"; 1539 p += n; 1540 } 1541 if (!first || hours) { 1542 first = 0; 1543 n = snprintf(p, ep - p, "%dh", hours); 1544 if (n < 0 || n >= ep - p) 1545 return "?"; 1546 p += n; 1547 } 1548 if (!first || mins) { 1549 first = 0; 1550 n = snprintf(p, ep - p, "%dm", mins); 1551 if (n < 0 || n >= ep - p) 1552 return "?"; 1553 p += n; 1554 } 1555 snprintf(p, ep - p, "%ds", secs); 1556 1557 return(result); 1558} 1559 1560/* 1561 * Print the timestamp 1562 * from tcpdump/util.c 1563 */ 1564static void 1565ts_print(const struct timeval *tvp) 1566{ 1567 int s; 1568 1569 /* Default */ 1570 s = (tvp->tv_sec + thiszone) % 86400; 1571 (void)printf("%02d:%02d:%02d.%06u ", 1572 s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec); 1573} 1574 1575#undef NEXTADDR 1576