Home | History | Annotate | Line # | Download | only in ndp
ndp.c revision 1.2
      1 /*	$NetBSD: ndp.c,v 1.2 1999/07/06 13:20:04 itojun Exp $	*/
      2 
      3 /*
      4  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. Neither the name of the project nor the names of its contributors
     16  *    may be used to endorse or promote products derived from this software
     17  *    without specific prior written permission.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
     20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
     23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29  * SUCH DAMAGE.
     30  */
     31 /*
     32  * Copyright (c) 1984, 1993
     33  *	The Regents of the University of California.  All rights reserved.
     34  *
     35  * This code is derived from software contributed to Berkeley by
     36  * Sun Microsystems, Inc.
     37  *
     38  * Redistribution and use in source and binary forms, with or without
     39  * modification, are permitted provided that the following conditions
     40  * are met:
     41  * 1. Redistributions of source code must retain the above copyright
     42  *    notice, this list of conditions and the following disclaimer.
     43  * 2. Redistributions in binary form must reproduce the above copyright
     44  *    notice, this list of conditions and the following disclaimer in the
     45  *    documentation and/or other materials provided with the distribution.
     46  * 3. All advertising materials mentioning features or use of this software
     47  *    must display the following acknowledgement:
     48  *	This product includes software developed by the University of
     49  *	California, Berkeley and its contributors.
     50  * 4. Neither the name of the University nor the names of its contributors
     51  *    may be used to endorse or promote products derived from this software
     52  *    without specific prior written permission.
     53  *
     54  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     55  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     56  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     57  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     58  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     59  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     60  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     61  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     62  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     63  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     64  * SUCH DAMAGE.
     65  */
     66 
     67 /*
     68  * Based on:
     69  * "@(#) Copyright (c) 1984, 1993\n\
     70  *	The Regents of the University of California.  All rights reserved.\n";
     71  *
     72  * "@(#)arp.c	8.2 (Berkeley) 1/2/94";
     73  */
     74 
     75 /*
     76  * ndp - display, set, delete and flush neighbor cache
     77  */
     78 
     79 
     80 #include <sys/param.h>
     81 #include <sys/file.h>
     82 #include <sys/ioctl.h>
     83 #include <sys/socket.h>
     84 #include <sys/sysctl.h>
     85 #include <sys/time.h>
     86 
     87 #include <net/if.h>
     88 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
     89 #include <net/if_var.h>
     90 #endif /* __FreeBSD__ >= 3 */
     91 #include <net/if_dl.h>
     92 #include <net/if_types.h>
     93 #include <net/route.h>
     94 
     95 #include <netinet/in.h>
     96 #ifndef __NetBSD__
     97 #include <netinet/if_ether.h>
     98 #endif
     99 
    100 #include <netinet/icmp6.h>
    101 #include <netinet6/in6_var.h>
    102 #include <netinet6/nd6.h>
    103 
    104 #include <arpa/inet.h>
    105 
    106 #include <netdb.h>
    107 #include <errno.h>
    108 #include <nlist.h>
    109 #include <stdio.h>
    110 #include <string.h>
    111 #include <paths.h>
    112 #include <err.h>
    113 #include <stdlib.h>
    114 #include <fcntl.h>
    115 #include <unistd.h>
    116 #include "gmt2local.h"
    117 
    118 extern int errno;
    119 static int pid;
    120 static int fflag;
    121 static int nflag;
    122 static int tflag;
    123 static int32_t thiszone;	/* time difference with gmt */
    124 static int s = -1;
    125 static int repeat = 0;
    126 
    127 char ntop_buf[INET6_ADDRSTRLEN];	/* inet_ntop() */
    128 char ifix_buf[IFNAMSIZ];		/* if_indextoname() */
    129 
    130 int main __P((int, char **));
    131 int file __P((char *));
    132 void getsocket __P((void));
    133 int set __P((int, char **));
    134 void get __P((char *));
    135 int delete __P((char *));
    136 void dump __P((struct in6_addr *));
    137 static struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *addr, int ifindex));
    138 static char *ether_str __P((struct sockaddr_dl *));
    139 int ndp_ether_aton __P((char *, u_char *));
    140 void usage __P((void));
    141 int rtmsg __P((int));
    142 void ifinfo __P((char *));
    143 void rtrlist __P((void));
    144 void plist __P((void));
    145 void pfx_flush __P((void));
    146 void rtr_flush __P((void));
    147 void harmonize_rtr __P((void));
    148 void quit __P((char *));
    149 static char *sec2str __P((time_t t));
    150 static char *ether_str __P((struct sockaddr_dl *sdl));
    151 static void ts_print __P((const struct timeval *));
    152 
    153 int
    154 main(argc, argv)
    155 	int argc;
    156 	char **argv;
    157 {
    158 	int ch;
    159 	int aflag = 0, cflag = 0, dflag = 0, sflag = 0, Hflag = 0,
    160 		pflag = 0, rflag = 0, Pflag = 0, Rflag = 0;
    161 	extern char *optarg;
    162 	extern int optind;
    163 
    164 	pid = getpid();
    165 	thiszone = gmt2local(0);
    166 	while ((ch = getopt(argc, argv, "acndfiprstA:HPR")) != EOF)
    167 		switch ((char)ch) {
    168 		case 'a':
    169 			aflag = 1;
    170 			break;
    171 		case 'c':
    172 			fflag = 1;
    173 			cflag = 1;
    174 			break;
    175 		case 'd':
    176 			dflag = 1;
    177 			break;
    178 		case 'i' :
    179 			if (argc != 3)
    180 				usage();
    181 			ifinfo(argv[2]);
    182 			exit(0);
    183 		case 'n':
    184 			nflag = 1;
    185 			continue;
    186 		case 'p':
    187 			pflag = 1;
    188 			break;
    189 		case 'f' :
    190 			if (argc != 3)
    191 				usage();
    192 			file(argv[2]);
    193 			exit(0);
    194 		case 'r' :
    195 			rflag = 1;
    196 			break;
    197 		case 's':
    198 			sflag = 1;
    199 			break;
    200 		case 't':
    201 			tflag = 1;
    202 			break;
    203 		case 'A':
    204 			aflag = 1;
    205 			repeat = atoi(optarg);
    206 			if (repeat < 0)
    207 				usage();
    208 			break;
    209 		case 'H' :
    210 			Hflag = 1;
    211 			break;
    212 		case 'P':
    213 			Pflag = 1;
    214 			break;
    215 		case 'R':
    216 			Rflag = 1;
    217 			break;
    218 		default:
    219 			usage();
    220 		}
    221 
    222 	argc -= optind;
    223 	argv += optind;
    224 
    225 	if (aflag || cflag) {
    226 		dump(0);
    227 		exit(0);
    228 	}
    229 	if (dflag) {
    230 		if (argc != 1)
    231 			usage();
    232 		delete(argv[0]);
    233 	}
    234 	if (pflag) {
    235 		plist();
    236 		exit(0);
    237 	}
    238 	if (rflag) {
    239 		rtrlist();
    240 		exit(0);
    241 	}
    242 	if (sflag) {
    243 		if (argc < 2 || argc > 4)
    244 			usage();
    245 		exit(set(argc, argv) ? 1 : 0);
    246 	}
    247 	if (Hflag) {
    248 		harmonize_rtr();
    249 		exit(0);
    250 	}
    251 	if (Pflag) {
    252 		pfx_flush();
    253 		exit(0);
    254 	}
    255 	if (Rflag) {
    256 		rtr_flush();
    257 		exit(0);
    258 	}
    259 
    260 	if (argc != 1)
    261 		usage();
    262 	get(argv[0]);
    263 	exit(0);
    264 }
    265 
    266 /*
    267  * Process a file to set standard ndp entries
    268  */
    269 int
    270 file(name)
    271 	char *name;
    272 {
    273 	FILE *fp;
    274 	int i, retval;
    275 	char line[100], arg[5][50], *args[5];
    276 
    277 	if ((fp = fopen(name, "r")) == NULL) {
    278 		fprintf(stderr, "ndp: cannot open %s\n", name);
    279 		exit(1);
    280 	}
    281 	args[0] = &arg[0][0];
    282 	args[1] = &arg[1][0];
    283 	args[2] = &arg[2][0];
    284 	args[3] = &arg[3][0];
    285 	args[4] = &arg[4][0];
    286 	retval = 0;
    287 	while(fgets(line, 100, fp) != NULL) {
    288 		i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
    289 		    arg[3], arg[4]);
    290 		if (i < 2) {
    291 			fprintf(stderr, "ndp: bad line: %s\n", line);
    292 			retval = 1;
    293 			continue;
    294 		}
    295 		if (set(i, args))
    296 			retval = 1;
    297 	}
    298 	fclose(fp);
    299 	return (retval);
    300 }
    301 
    302 void
    303 getsocket()
    304 {
    305 	if (s < 0) {
    306 		s = socket(PF_ROUTE, SOCK_RAW, 0);
    307 		if (s < 0) {
    308 			perror("ndp: socket");
    309 			exit(1);
    310 		}
    311 	}
    312 }
    313 
    314 struct	sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}};
    315 struct	sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m;
    316 struct	sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
    317 int	expire_time, flags, found_entry;
    318 struct	{
    319 	struct	rt_msghdr m_rtm;
    320 	char	m_space[512];
    321 }	m_rtmsg;
    322 
    323 /*
    324  * Set an individual neighbor cache entry
    325  */
    326 int
    327 set(argc, argv)
    328 	int argc;
    329 	char **argv;
    330 {
    331 	register struct sockaddr_in6 *sin = &sin_m;
    332 	register struct sockaddr_dl *sdl;
    333 	register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
    334 	struct addrinfo hints, *res;
    335 	int gai_error;
    336 	u_char *ea;
    337 	char *host = argv[0], *eaddr = argv[1];
    338 
    339 	getsocket();
    340 	argc -= 2;
    341 	argv += 2;
    342 	sdl_m = blank_sdl;
    343 	sin_m = blank_sin;
    344 
    345 	bzero(&hints, sizeof(hints));
    346 	hints.ai_family = AF_INET6;
    347 	gai_error = getaddrinfo(host, NULL, &hints, &res);
    348 	if (gai_error) {
    349 		fprintf(stderr, "ndp: %s: %s\n", host,
    350 			gai_strerror(gai_error));
    351 		return 1;
    352 	}
    353 	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
    354 	ea = (u_char *)LLADDR(&sdl_m);
    355 	if (ndp_ether_aton(eaddr, ea) == 0)
    356 		sdl_m.sdl_alen = 6;
    357 	flags = expire_time = 0;
    358 	while (argc-- > 0) {
    359 		if (strncmp(argv[0], "temp", 4) == 0) {
    360 			struct timeval time;
    361 			gettimeofday(&time, 0);
    362 			expire_time = time.tv_sec + 20 * 60;
    363 		}
    364 		argv++;
    365 	}
    366 tryagain:
    367 	if (rtmsg(RTM_GET) < 0) {
    368 		perror(host);
    369 		return (1);
    370 	}
    371 	sin = (struct sockaddr_in6 *)(rtm + 1);
    372 	sdl = (struct sockaddr_dl *)(sin->sin6_len + (char *)sin);
    373 	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
    374 		if (sdl->sdl_family == AF_LINK &&
    375 		    (rtm->rtm_flags & RTF_LLINFO) &&
    376 		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
    377 		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
    378 		case IFT_ISO88024: case IFT_ISO88025:
    379 			goto overwrite;
    380 		}
    381 		goto tryagain;
    382 	}
    383 overwrite:
    384 	if (sdl->sdl_family != AF_LINK) {
    385 		printf("cannot intuit interface index and type for %s\n", host);
    386 		return (1);
    387 	}
    388 	sdl_m.sdl_type = sdl->sdl_type;
    389 	sdl_m.sdl_index = sdl->sdl_index;
    390 	return (rtmsg(RTM_ADD));
    391 }
    392 
    393 /*
    394  * Display an individual neighbor cache entry
    395  */
    396 void
    397 get(host)
    398 	char *host;
    399 {
    400 	struct sockaddr_in6 *sin = &sin_m;
    401 	struct addrinfo hints, *res;
    402 	int gai_error;
    403 
    404 	sin_m = blank_sin;
    405 	bzero(&hints, sizeof(hints));
    406 	hints.ai_family = AF_INET6;
    407 	gai_error = getaddrinfo(host, NULL, &hints, &res);
    408 	if (gai_error) {
    409 		fprintf(stderr, "ndp: %s: %s\n", host,
    410 			gai_strerror(gai_error));
    411 		return;
    412 	}
    413 	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
    414 	dump(&sin->sin6_addr);
    415 	if (found_entry == 0) {
    416 		printf("%s (%s) -- no entry\n",
    417 		    host, inet_ntop(AF_INET6, &sin->sin6_addr, ntop_buf,
    418 				sizeof(ntop_buf)));
    419 		exit(1);
    420 	}
    421 }
    422 
    423 /*
    424  * Delete a neighbor cache entry
    425  */
    426 int
    427 delete(host)
    428 	char *host;
    429 {
    430 	register struct sockaddr_in6 *sin = &sin_m;
    431 	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
    432 	struct sockaddr_dl *sdl;
    433 	struct addrinfo hints, *res;
    434 	int gai_error;
    435 
    436 	getsocket();
    437 	sin_m = blank_sin;
    438 
    439 	bzero(&hints, sizeof(hints));
    440 	hints.ai_family = AF_INET6;
    441 	gai_error = getaddrinfo(host, NULL, &hints, &res);
    442 	if (gai_error) {
    443 		fprintf(stderr, "ndp: %s: %s\n", host,
    444 			gai_strerror(gai_error));
    445 		return 1;
    446 	}
    447 	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
    448 /*tryagain:*/
    449 	if (rtmsg(RTM_GET) < 0) {
    450 		perror(host);
    451 		return (1);
    452 	}
    453 	sin = (struct sockaddr_in6 *)(rtm + 1);
    454 	sdl = (struct sockaddr_dl *)(sin->sin6_len + (char *)sin);
    455 	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
    456 		if (sdl->sdl_family == AF_LINK &&
    457 		    (rtm->rtm_flags & RTF_LLINFO) &&
    458 		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
    459 		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
    460 		case IFT_ISO88024: case IFT_ISO88025:
    461 			goto delete;
    462 		}
    463 	}
    464 delete:
    465 	if (sdl->sdl_family != AF_LINK) {
    466 		printf("cannot locate %s\n", host);
    467 		return (1);
    468 	}
    469 	if (rtmsg(RTM_DELETE) == 0)
    470 		printf("%s (%s) deleted\n", host,
    471 			inet_ntop(AF_INET6, &sin->sin6_addr, ntop_buf,
    472 					sizeof(ntop_buf)));
    473 	return 0;
    474 }
    475 
    476 /*
    477  * Dump the entire neighbor cache
    478  */
    479 void
    480 dump(addr)
    481 	struct in6_addr *addr;
    482 {
    483 	int mib[6];
    484 	size_t needed;
    485 	char *host, *lim, *buf, *next;
    486 	struct rt_msghdr *rtm;
    487 	struct sockaddr_in6 *sin;
    488 	struct sockaddr_dl *sdl;
    489 	extern int h_errno;
    490 	struct hostent *hp;
    491 	struct in6_nbrinfo *nbi;
    492 	struct timeval time;
    493 
    494 	/* Print header */
    495 	if (!tflag)
    496 		printf("%-29.29s %-18.18s %6.6s %-9.9s %2s %4s %4s\n",
    497 		       "Neighbor", "Linklayer Address", "Netif", "Expire",
    498 		       "St", "Flgs", "Prbs");
    499 
    500 again:;
    501 	mib[0] = CTL_NET;
    502 	mib[1] = PF_ROUTE;
    503 	mib[2] = 0;
    504 	mib[3] = AF_INET6;
    505 	mib[4] = NET_RT_FLAGS;
    506 	mib[5] = RTF_LLINFO;
    507 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
    508 		quit("route-sysctl-estimate");
    509 	if ((buf = malloc(needed)) == NULL)
    510 		quit("malloc");
    511 	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
    512 		quit("actual retrieval of routing table");
    513 	lim = buf + needed;
    514 
    515 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
    516 		int isrouter = 0, prbs = 0;
    517 
    518 		rtm = (struct rt_msghdr *)next;
    519 		sin = (struct sockaddr_in6 *)(rtm + 1);
    520 		sdl = (struct sockaddr_dl *)(sin + 1);
    521 		if (addr) {
    522 			if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
    523 				continue;
    524 			found_entry = 1;
    525 		} else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
    526 			continue;
    527 		if (fflag == 1) {
    528 			delete((char *)inet_ntop(AF_INET6, &sin->sin6_addr,
    529 						ntop_buf, sizeof(ntop_buf)));
    530 			continue;
    531 		}
    532 		host = NULL;
    533 		if (nflag == 0) {
    534 			hp = gethostbyaddr((char *)&sin->sin6_addr,
    535 					   sizeof(struct in6_addr), AF_INET6);
    536 			if (hp)
    537 				host = hp->h_name;
    538 		}
    539 		if (host == NULL) {
    540 			inet_ntop(AF_INET6, &sin->sin6_addr,
    541 				  ntop_buf, sizeof(ntop_buf));
    542 			host = ntop_buf;
    543 		}
    544 
    545 		gettimeofday(&time, 0);
    546 		if (tflag)
    547 			ts_print(&time);
    548 
    549 		printf("%-29.29s %-18.18s %6.6s", host,
    550 		       ether_str(sdl),
    551 		       if_indextoname(sdl->sdl_index, ifix_buf));
    552 
    553 		/* Print neighbor discovery specific informations */
    554 		putchar(' ');
    555 		nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index);
    556 		if (nbi) {
    557 			if (nbi->expire > time.tv_sec) {
    558 				printf(" %-9.9s",
    559 				       sec2str(nbi->expire - time.tv_sec));
    560 			}
    561 			else if (nbi->expire == 0)
    562 				printf(" %-9.9s", "permanent");
    563 			else
    564 				printf(" %-9.9s", "expired");
    565 
    566 			switch(nbi->state) {
    567 			 case ND6_LLINFO_NOSTATE:
    568 				 printf(" N");
    569 				 break;
    570 			 case ND6_LLINFO_WAITDELETE:
    571 				 printf(" W");
    572 				 break;
    573 			 case ND6_LLINFO_INCOMPLETE:
    574 				 printf(" I");
    575 				 break;
    576 			 case ND6_LLINFO_REACHABLE:
    577 				 printf(" R");
    578 				 break;
    579 			 case ND6_LLINFO_STALE:
    580 				 printf(" S");
    581 				 break;
    582 			 case ND6_LLINFO_DELAY:
    583 				 printf(" D");
    584 				 break;
    585 			 case ND6_LLINFO_PROBE:
    586 				 printf(" P");
    587 				 break;
    588 			 default:
    589 				 printf(" ?");
    590 				 break;
    591 			}
    592 
    593 			isrouter = nbi->isrouter;
    594 			prbs = nbi->asked;
    595 		}
    596 		else {
    597 			warnx("failed to get neighbor information");
    598 			printf("  ");
    599 		}
    600 
    601 		/* other flags */
    602 		putchar(' ');
    603 		{
    604 			u_char flgbuf[8], *p = flgbuf;
    605 
    606 			flgbuf[0] = '\0';
    607 			if (isrouter)
    608 				p += sprintf((char *)p, "R");
    609 #ifndef RADISH
    610 			if (rtm->rtm_addrs & RTA_NETMASK) {
    611 				sin = (struct sockaddr_in6 *)
    612 					(sdl->sdl_len + (char *)sdl);
    613 				if (!IN6_IS_ADDR_ANY(&sin->sin6_addr))
    614 					p += sprintf((char *)p, "P");
    615 				if (sin->sin6_len != sizeof(struct sockaddr_in6))
    616 					p += sprintf((char *)p, "W");
    617 			}
    618 #endif /*RADISH*/
    619 			printf("%4s", flgbuf);
    620 		}
    621 
    622 		putchar(' ');
    623 		if (prbs)
    624 			printf("% 4d", prbs);
    625 
    626 		printf("\n");
    627 	}
    628 
    629 	if (repeat) {
    630 		printf("\n");
    631 		sleep(repeat);
    632 		goto again;
    633 	}
    634 }
    635 
    636 static struct in6_nbrinfo *
    637 getnbrinfo(addr, ifindex)
    638 	struct in6_addr *addr;
    639 	int ifindex;
    640 {
    641 	static struct in6_nbrinfo nbi;
    642 	int s;
    643 
    644 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
    645 		err(1, "socket");
    646 
    647 	bzero(&nbi, sizeof(nbi));
    648 	if_indextoname(ifindex, nbi.ifname);
    649 	nbi.addr = *addr;
    650 	if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
    651 		warn("ioctl");
    652 		close(s);
    653 		return(NULL);
    654 	}
    655 
    656 	close(s);
    657 	return(&nbi);
    658 }
    659 
    660 static char *
    661 ether_str(sdl)
    662 	struct sockaddr_dl *sdl;
    663 {
    664 	static char ebuf[32];
    665 	u_char *cp;
    666 
    667 	if (sdl->sdl_alen) {
    668 		cp = (u_char *)LLADDR(sdl);
    669 		sprintf(ebuf, "%x:%x:%x:%x:%x:%x",
    670 			cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
    671 	}
    672 	else {
    673 		sprintf(ebuf, "(incomplete)");
    674 	}
    675 
    676 	return(ebuf);
    677 }
    678 
    679 int
    680 ndp_ether_aton(a, n)
    681 	char *a;
    682 	u_char *n;
    683 {
    684 	int i, o[6];
    685 
    686 	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
    687 					   &o[3], &o[4], &o[5]);
    688 	if (i != 6) {
    689 		fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
    690 		return (1);
    691 	}
    692 	for (i=0; i<6; i++)
    693 		n[i] = o[i];
    694 	return (0);
    695 }
    696 
    697 void
    698 usage()
    699 {
    700 	printf("usage: ndp hostname\n");
    701 	printf("       ndp -a[nt]\n");
    702 	printf("       ndp [-nt] -A wait\n");
    703 	printf("       ndp -c[nt]\n");
    704 	printf("       ndp -d[nt] hostname\n");
    705 	printf("       ndp -f[nt] filename\n");
    706 	printf("       ndp -i interface\n");
    707 	printf("       ndp -p\n");
    708 	printf("       ndp -r\n");
    709 	printf("       ndp -s hostname ether_addr [temp]\n");
    710 	printf("       ndp -H\n");
    711 	printf("       ndp -P\n");
    712 	printf("       ndp -R\n");
    713 	exit(1);
    714 }
    715 
    716 int
    717 rtmsg(cmd)
    718 	int cmd;
    719 {
    720 	static int seq;
    721 	int rlen;
    722 	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
    723 	register char *cp = m_rtmsg.m_space;
    724 	register int l;
    725 
    726 	errno = 0;
    727 	if (cmd == RTM_DELETE)
    728 		goto doit;
    729 	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
    730 	rtm->rtm_flags = flags;
    731 	rtm->rtm_version = RTM_VERSION;
    732 
    733 	switch (cmd) {
    734 	default:
    735 		fprintf(stderr, "ndp: internal wrong cmd\n");
    736 		exit(1);
    737 	case RTM_ADD:
    738 		rtm->rtm_addrs |= RTA_GATEWAY;
    739 		rtm->rtm_rmx.rmx_expire = expire_time;
    740 		rtm->rtm_inits = RTV_EXPIRE;
    741 		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
    742 		/* FALLTHROUGH */
    743 	case RTM_GET:
    744 		rtm->rtm_addrs |= RTA_DST;
    745 	}
    746 #define NEXTADDR(w, s) \
    747 	if (rtm->rtm_addrs & (w)) { \
    748 		bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);}
    749 
    750 	NEXTADDR(RTA_DST, sin_m);
    751 	NEXTADDR(RTA_GATEWAY, sdl_m);
    752 	NEXTADDR(RTA_NETMASK, so_mask);
    753 
    754 	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
    755 doit:
    756 	l = rtm->rtm_msglen;
    757 	rtm->rtm_seq = ++seq;
    758 	rtm->rtm_type = cmd;
    759 	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
    760 		if (errno != ESRCH || cmd != RTM_DELETE) {
    761 			perror("writing to routing socket");
    762 			return (-1);
    763 		}
    764 	}
    765 	do {
    766 		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
    767 	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
    768 	if (l < 0)
    769 		(void) fprintf(stderr, "ndp: read from routing socket: %s\n",
    770 		    strerror(errno));
    771 	return (0);
    772 }
    773 
    774 void
    775 ifinfo(ifname)
    776 	char *ifname;
    777 {
    778 	struct in6_ndireq nd;
    779 	int s;
    780 
    781 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
    782 		perror("ndp: socket");
    783 		exit(1);
    784 	}
    785 	bzero(&nd, sizeof(nd));
    786 	strcpy(nd.ifname, ifname);
    787 	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
    788  		perror("ioctl (SIOCGIFINFO_IN6)");
    789  		exit(1);
    790  	}
    791 #define ND nd.ndi
    792 	printf("linkmtu=%d", ND.linkmtu);
    793 	printf(", curhlim=%d", ND.chlim);
    794 	printf(", basereachable=%ds%dms",
    795 	       ND.basereachable / 1000, ND.basereachable % 1000);
    796 	printf(", reachable=%ds", ND.reachable);
    797 	printf(", retrans=%ds%dms\n", ND.retrans / 1000, ND.retrans % 1000);
    798 #undef ND
    799 	close(s);
    800 }
    801 
    802 void
    803 rtrlist()
    804 {
    805 	struct in6_drlist dr;
    806 	int s, i;
    807 	struct timeval time;
    808 
    809 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
    810 		perror("ndp: socket");
    811 		exit(1);
    812 	}
    813 	bzero(&dr, sizeof(dr));
    814 	strcpy(dr.ifname, "lo0"); /* dummy */
    815 	if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
    816  		perror("ioctl (SIOCGDRLST_IN6)");
    817  		exit(1);
    818  	}
    819 #define DR dr.defrouter[i]
    820 	for (i = 0 ; DR.if_index && i < PRLSTSIZ ; i++) {
    821 		printf("%s if=%s", inet_ntop(AF_INET6, &DR.rtaddr,
    822 					     ntop_buf, sizeof(ntop_buf)),
    823 		       if_indextoname(DR.if_index, ifix_buf));
    824 		printf(", flags=%s%s",
    825 		       DR.flags & ND_RA_FLAG_MANAGED ? "M" : "",
    826 		       DR.flags & ND_RA_FLAG_OTHER   ? "O" : "");
    827 		gettimeofday(&time, 0);
    828 		if (DR.expire == 0)
    829 			printf(", expire=Never\n");
    830 		else
    831 			printf(", expire=%s\n",
    832 				sec2str(DR.expire - time.tv_sec));
    833 	}
    834 #undef DR
    835 	close(s);
    836 }
    837 
    838 void
    839 plist()
    840 {
    841 	struct in6_prlist pr;
    842 	int s, i;
    843 	struct timeval time;
    844 
    845 	gettimeofday(&time, 0);
    846 
    847 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
    848 		perror("ndp: socket");
    849 		exit(1);
    850 	}
    851 	bzero(&pr, sizeof(pr));
    852 	strcpy(pr.ifname, "lo0"); /* dummy */
    853 	if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) {
    854  		perror("ioctl (SIOCGPRLST_IN6)");
    855  		exit(1);
    856  	}
    857 #define PR pr.prefix[i]
    858 	for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) {
    859 		printf("%s/%d if=%s\n",
    860 		       inet_ntop(AF_INET6, &PR.prefix, ntop_buf,
    861 				 sizeof(ntop_buf)), PR.prefixlen,
    862 		       if_indextoname(PR.if_index, ifix_buf));
    863 		gettimeofday(&time, 0);
    864 		printf("  flags=%s%s",
    865 		       PR.raflags.onlink ? "L" : "",
    866 		       PR.raflags.autonomous ? "A" : "");
    867 		if (PR.vltime == ND6_INFINITE_LIFETIME)
    868 			printf(" vltime=infinity");
    869 		else
    870 			printf(" vltime=%ld", (long)PR.vltime);
    871 		if (PR.pltime == ND6_INFINITE_LIFETIME)
    872 			printf(", pltime=infinity");
    873 		else
    874 			printf(", pltime=%ld", (long)PR.pltime);
    875 		if (PR.expire == 0)
    876 			printf(", expire=Never\n");
    877 		else if (PR.expire >= time.tv_sec)
    878 			printf(", expire=%s\n",
    879 				sec2str(PR.expire - time.tv_sec));
    880 		else
    881 			printf(", expired\n");
    882 		if (PR.advrtrs) {
    883 			int j;
    884 			printf("  advertised by\n");
    885 			for (j = 0; j < PR.advrtrs; j++) {
    886 				printf("    %s\n",
    887 				       inet_ntop(AF_INET6, &PR.advrtr[j],
    888 						 ntop_buf,
    889 						 sizeof(ntop_buf)));
    890 			}
    891 			if (PR.advrtrs > DRLSTSIZ)
    892 				printf("    and %d routers\n",
    893 				       PR.advrtrs - DRLSTSIZ);
    894 		}
    895 		else
    896 			printf("  No advertising router\n");
    897 	}
    898 #undef PR
    899 	close(s);
    900 }
    901 
    902 void
    903 pfx_flush()
    904 {
    905 	char dummyif[IFNAMSIZ+8];
    906 	int s;
    907 
    908 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
    909 		err(1, "socket");
    910 	strcpy(dummyif, "lo0"); /* dummy */
    911 	if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
    912  		err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
    913 }
    914 
    915 void
    916 rtr_flush()
    917 {
    918 	char dummyif[IFNAMSIZ+8];
    919 	int s;
    920 
    921 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
    922 		err(1, "socket");
    923 	strcpy(dummyif, "lo0"); /* dummy */
    924 	if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
    925  		err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
    926 }
    927 
    928 void
    929 harmonize_rtr()
    930 {
    931 	char dummyif[IFNAMSIZ+8];
    932 	int s;
    933 
    934 	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
    935 		perror("ndp: socket");
    936 		exit(1);
    937 	}
    938 	strcpy(dummyif, "lo0"); /* dummy */
    939 	if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0) {
    940  		perror("ioctl (SIOCSNDFLUSH_IN6)");
    941  		exit(1);
    942  	}
    943 }
    944 
    945 void
    946 quit(msg)
    947 	char *msg;
    948 {
    949 	fprintf(stderr, "%s\n", msg);
    950 	exit(1);
    951 }
    952 
    953 static char *
    954 sec2str(total)
    955 	time_t total;
    956 {
    957 	static char result[256];
    958 	int days, hours, mins, secs;
    959 	int first = 1;
    960 	char *p = result;
    961 
    962 	days = total / 3600 / 24;
    963 	hours = (total / 3600) % 24;
    964 	mins = (total / 60) % 60;
    965 	secs = total % 60;
    966 
    967 	if (days) {
    968 		first = 0;
    969 		p += sprintf(p, "%dd", days);
    970 	}
    971 	if (!first || hours) {
    972 		first = 0;
    973 		p += sprintf(p, "%dh", hours);
    974 	}
    975 	if (!first || mins) {
    976 		first = 0;
    977 		p += sprintf(p, "%dm", mins);
    978 	}
    979 	sprintf(p, "%ds", secs);
    980 
    981 	return(result);
    982 }
    983 
    984 /*
    985  * Print the timestamp
    986  * from tcpdump/util.c
    987  */
    988 static void
    989 ts_print(tvp)
    990 	const struct timeval *tvp;
    991 {
    992 	int s;
    993 
    994 	/* Default */
    995 	s = (tvp->tv_sec + thiszone) % 86400;
    996 	(void)printf("%02d:%02d:%02d.%06u ",
    997 	    s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec);
    998 }
    999