1/*
2 * Copyright (c) 2009-2013 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*
29 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
30 * All rights reserved.
31 *
32 * Redistribution and use in source and binary forms, with or without
33 * modification, are permitted provided that the following conditions
34 * are met:
35 * 1. Redistributions of source code must retain the above copyright
36 *    notice, this list of conditions and the following disclaimer.
37 * 2. Redistributions in binary form must reproduce the above copyright
38 *    notice, this list of conditions and the following disclaimer in the
39 *    documentation and/or other materials provided with the distribution.
40 * 3. Neither the name of the project nor the names of its contributors
41 *    may be used to endorse or promote products derived from this software
42 *    without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56/*
57 * Copyright (c) 1984, 1993
58 *	The Regents of the University of California.  All rights reserved.
59 *
60 * This code is derived from software contributed to Berkeley by
61 * Sun Microsystems, Inc.
62 *
63 * Redistribution and use in source and binary forms, with or without
64 * modification, are permitted provided that the following conditions
65 * are met:
66 * 1. Redistributions of source code must retain the above copyright
67 *    notice, this list of conditions and the following disclaimer.
68 * 2. Redistributions in binary form must reproduce the above copyright
69 *    notice, this list of conditions and the following disclaimer in the
70 *    documentation and/or other materials provided with the distribution.
71 * 3. All advertising materials mentioning features or use of this software
72 *    must display the following acknowledgement:
73 *	This product includes software developed by the University of
74 *	California, Berkeley and its contributors.
75 * 4. Neither the name of the University nor the names of its contributors
76 *    may be used to endorse or promote products derived from this software
77 *    without specific prior written permission.
78 *
79 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
80 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
81 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
82 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
83 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
84 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
85 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
86 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
87 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
88 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
89 * SUCH DAMAGE.
90 */
91
92/*
93 * Based on:
94 * "@(#) Copyright (c) 1984, 1993\n\
95 *	The Regents of the University of California.  All rights reserved.\n";
96 *
97 * "@(#)arp.c	8.2 (Berkeley) 1/2/94";
98 */
99
100/*
101 * ndp - display, set, delete and flush neighbor cache
102 */
103
104#include <stdint.h>
105#include <sys/param.h>
106#include <sys/file.h>
107#include <sys/ioctl.h>
108#include <sys/socket.h>
109#include <sys/sysctl.h>
110#include <sys/time.h>
111#include <sys/queue.h>
112
113#include <net/if.h>
114#include <net/if_var.h>
115#include <net/if_dl.h>
116#include <net/if_types.h>
117#include <net/route.h>
118
119#include <netinet/in.h>
120#include <netinet/if_ether.h>
121
122#include <netinet/icmp6.h>
123#include <netinet6/in6_var.h>
124#include <netinet6/nd6.h>
125
126#include <arpa/inet.h>
127
128#include <netdb.h>
129#include <errno.h>
130#include <nlist.h>
131#include <stdio.h>
132#include <string.h>
133#include <paths.h>
134#include <err.h>
135#include <stdlib.h>
136#include <fcntl.h>
137#include <unistd.h>
138
139/* packing rule for routing socket */
140#define	ROUNDUP(a) \
141	((a) > 0 ? (1 + (((a) - 1) | (sizeof (uint32_t) - 1))) : \
142	sizeof (uint32_t))
143#define	ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
144
145static int pid;
146static int cflag;
147static int nflag;
148static int tflag;
149static int32_t thiszone = 0;	/* time difference with gmt */
150static int s = -1;
151static int repeat = 0;
152
153static char host_buf[NI_MAXHOST];		/* getnameinfo() */
154static char ifix_buf[IFNAMSIZ];		/* if_indextoname() */
155
156static int file(char *);
157static void getsocket(void);
158static int set(int, char **);
159static void get(char *);
160static int delete(char *);
161static void dump(struct in6_addr *);
162static void dump_ext(struct in6_addr *, int);
163static struct in6_nbrinfo *getnbrinfo(struct in6_addr *, int, int);
164static char *ether_str(struct sockaddr_dl *);
165static int ndp_ether_aton(char *, u_char *);
166static void usage(void);
167static int rtmsg(int);
168static void ifinfo(int, char **);
169static void rtrlist(void);
170static void plist(void);
171static void pfx_flush(void);
172static void rtrlist(void);
173static void rtr_flush(void);
174static void harmonize_rtr(void);
175static void getdefif(void);
176static void setdefif(char *);
177static char *sec2str(time_t);
178static char *ether_str(struct sockaddr_dl *);
179static void ts_print(const struct timeval *);
180static void read_cga_parameters(void);
181static void write_cga_parameters(const char[]);
182
183static char *rtpref_str[] = {
184	"medium",		/* 00 */
185	"high",			/* 01 */
186	"rsv",			/* 10 */
187	"low"			/* 11 */
188};
189
190int
191main(int argc, char **argv)
192{
193	int ch;
194	int aflag = 0, dflag = 0, sflag = 0, Hflag = 0, pflag = 0, rflag = 0,
195	    Pflag = 0, Rflag = 0, lflag = 0, xflag = 0, wflag = 0;
196
197	pid = getpid();
198	while ((ch = getopt(argc, argv, "acndfIilprstA:HPRxwW")) != -1)
199		switch ((char) ch) {
200		case 'a':
201			aflag = 1;
202			break;
203		case 'c':
204			cflag = 1;
205			break;
206		case 'd':
207			dflag = 1;
208			break;
209		case 'I':
210			if (argc > 2)
211				setdefif(argv[2]);
212			getdefif(); /* always call it to print the result */
213			exit(0);
214		case 'i' :
215			argc -= optind;
216			argv += optind;
217			if (argc < 1)
218				usage();
219			ifinfo(argc, argv);
220			exit(0);
221		case 'n':
222			nflag = 1;
223			continue;
224		case 'p':
225			pflag = 1;
226			break;
227		case 'f' :
228			if (argc != 3)
229				usage();
230			file(argv[2]);
231			exit(0);
232		case 'l' :
233			lflag = 1;
234			break;
235		case 'r' :
236			rflag = 1;
237			break;
238		case 's':
239			sflag = 1;
240			break;
241		case 't':
242			tflag = 1;
243			break;
244		case 'A':
245			aflag = 1;
246			repeat = atoi(optarg);
247			if (repeat < 0)
248				usage();
249			break;
250		case 'H' :
251			Hflag = 1;
252			break;
253		case 'P':
254			Pflag = 1;
255			break;
256		case 'R':
257			Rflag = 1;
258			break;
259		case 'x':
260			xflag = 1;
261			lflag = 1;
262			break;
263		case 'w':
264			wflag = 1;
265			break;
266		case 'W':
267			if (argc != 3)
268				usage();
269			write_cga_parameters(argv[2]);
270			exit(0);
271		default:
272			usage();
273		}
274
275	argc -= optind;
276	argv += optind;
277
278	if (aflag || cflag) {
279		if (lflag)
280			dump_ext(0, xflag);
281		else
282			dump(0);
283		exit(0);
284	}
285	if (dflag) {
286		if (argc != 1)
287			usage();
288		delete(argv[0]);
289		exit(0);
290	}
291	if (pflag) {
292		plist();
293		exit(0);
294	}
295	if (rflag) {
296		rtrlist();
297		exit(0);
298	}
299	if (sflag) {
300		if (argc < 2 || argc > 4)
301			usage();
302		exit(set(argc, argv) ? 1 : 0);
303	}
304	if (Hflag) {
305		harmonize_rtr();
306		exit(0);
307	}
308	if (Pflag) {
309		pfx_flush();
310		exit(0);
311	}
312	if (Rflag) {
313		rtr_flush();
314		exit(0);
315	}
316	if (wflag) {
317		read_cga_parameters();
318		exit(0);
319	}
320
321	if (argc != 1)
322		usage();
323	get(argv[0]);
324	exit(0);
325}
326
327/*
328 * Process a file to set standard ndp entries
329 */
330static int
331file(char *name)
332{
333	FILE *fp;
334	int i, retval;
335	char line[100], arg[5][50], *args[5];
336
337	if ((fp = fopen(name, "r")) == NULL) {
338		fprintf(stderr, "ndp: cannot open %s\n", name);
339		exit(1);
340	}
341	args[0] = &arg[0][0];
342	args[1] = &arg[1][0];
343	args[2] = &arg[2][0];
344	args[3] = &arg[3][0];
345	args[4] = &arg[4][0];
346	retval = 0;
347	while (fgets(line, 100, fp) != NULL) {
348		i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
349		    arg[3], arg[4]);
350		if (i < 2) {
351			fprintf(stderr, "ndp: bad line: %s\n", line);
352			retval = 1;
353			continue;
354		}
355		if (set(i, args))
356			retval = 1;
357	}
358	fclose(fp);
359	return (retval);
360}
361
362static void
363getsocket(void)
364{
365	if (s < 0) {
366		s = socket(PF_ROUTE, SOCK_RAW, 0);
367		if (s < 0) {
368			perror("ndp: socket");
369			exit(1);
370		}
371	}
372}
373
374struct sockaddr_in6 so_mask = {sizeof (so_mask), AF_INET6 };
375struct sockaddr_in6 blank_sin = {sizeof (blank_sin), AF_INET6 }, sin_m;
376struct sockaddr_dl blank_sdl = {sizeof (blank_sdl), AF_LINK }, sdl_m;
377int expire_time, flags, found_entry;
378struct {
379	struct	rt_msghdr m_rtm;
380	char	m_space[512];
381} m_rtmsg;
382
383/*
384 * Set an individual neighbor cache entry
385 */
386static int
387set(int argc, char **argv)
388{
389	register struct sockaddr_in6 *sin = &sin_m;
390	register struct sockaddr_dl *sdl;
391	register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
392	struct addrinfo hints, *res;
393	int gai_error;
394	u_char *ea;
395	char *host = argv[0], *eaddr = argv[1];
396
397	getsocket();
398	argc -= 2;
399	argv += 2;
400	sdl_m = blank_sdl;
401	sin_m = blank_sin;
402
403	bzero(&hints, sizeof (hints));
404	hints.ai_family = AF_INET6;
405	gai_error = getaddrinfo(host, NULL, &hints, &res);
406	if (gai_error) {
407		fprintf(stderr, "ndp: %s: %s\n", host,
408			gai_strerror(gai_error));
409		return (1);
410	}
411	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
412#ifdef __KAME__
413	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
414		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
415		    htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
416	}
417#endif
418	ea = (u_char *)LLADDR(&sdl_m);
419	if (ndp_ether_aton(eaddr, ea) == 0)
420		sdl_m.sdl_alen = 6;
421	flags = expire_time = 0;
422	while (argc-- > 0) {
423		if (strncmp(argv[0], "temp", 4) == 0) {
424			struct timeval time;
425			gettimeofday(&time, 0);
426			expire_time = time.tv_sec + 20 * 60;
427		} else if (strncmp(argv[0], "proxy", 5) == 0)
428			flags |= RTF_ANNOUNCE;
429		argv++;
430	}
431	if (rtmsg(RTM_GET) < 0) {
432		perror(host);
433		return (1);
434	}
435	sin = (struct sockaddr_in6 *)(rtm + 1);
436	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
437	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
438		if (sdl->sdl_family == AF_LINK &&
439		    (rtm->rtm_flags & RTF_LLINFO) &&
440		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
441		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
442		case IFT_ISO88024: case IFT_ISO88025:
443			goto overwrite;
444		}
445		/*
446		 * IPv4 arp command retries with sin_other = SIN_PROXY here.
447		 */
448		fprintf(stderr, "set: cannot configure a new entry\n");
449		return (1);
450	}
451
452overwrite:
453	if (sdl->sdl_family != AF_LINK) {
454		printf("cannot intuit interface index and type for %s\n", host);
455		return (1);
456	}
457	sdl_m.sdl_type = sdl->sdl_type;
458	sdl_m.sdl_index = sdl->sdl_index;
459	return (rtmsg(RTM_ADD));
460}
461
462/*
463 * Display an individual neighbor cache entry
464 */
465static void
466get(char *host)
467{
468	struct sockaddr_in6 *sin = &sin_m;
469	struct addrinfo hints, *res;
470	int gai_error;
471
472	sin_m = blank_sin;
473	bzero(&hints, sizeof (hints));
474	hints.ai_family = AF_INET6;
475	gai_error = getaddrinfo(host, NULL, &hints, &res);
476	if (gai_error) {
477		fprintf(stderr, "ndp: %s: %s\n", host,
478			gai_strerror(gai_error));
479		return;
480	}
481	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
482#ifdef __KAME__
483	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
484		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
485		    htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
486	}
487#endif
488	dump(&sin->sin6_addr);
489	if (found_entry == 0) {
490		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
491		    sizeof (host_buf), NULL, 0, NI_WITHSCOPEID | (nflag ?
492		    NI_NUMERICHOST : 0));
493		printf("%s (%s) -- no entry\n", host, host_buf);
494		exit(1);
495	}
496}
497
498/*
499 * Delete a neighbor cache entry
500 */
501static int
502delete(char *host)
503{
504	struct sockaddr_in6 *sin = &sin_m;
505	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
506	struct sockaddr_dl *sdl;
507	struct addrinfo hints, *res;
508	int gai_error;
509
510	getsocket();
511	sin_m = blank_sin;
512
513	bzero(&hints, sizeof (hints));
514	hints.ai_family = AF_INET6;
515	gai_error = getaddrinfo(host, NULL, &hints, &res);
516	if (gai_error) {
517		fprintf(stderr, "ndp: %s: %s\n", host,
518			gai_strerror(gai_error));
519		return (1);
520	}
521	sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
522#ifdef __KAME__
523	if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
524		*(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
525		    htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
526	}
527#endif
528	if (rtmsg(RTM_GET) < 0) {
529		perror(host);
530		return (1);
531	}
532	sin = (struct sockaddr_in6 *)(rtm + 1);
533	sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
534	if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
535		if (sdl->sdl_family == AF_LINK &&
536		    (rtm->rtm_flags & RTF_LLINFO) &&
537		    !(rtm->rtm_flags & RTF_GATEWAY)) {
538			goto delete;
539		}
540		/*
541		 * IPv4 arp command retries with sin_other = SIN_PROXY here.
542		 */
543		fprintf(stderr, "delete: cannot delete non-NDP entry\n");
544		return (1);
545	}
546
547delete:
548	if (sdl->sdl_family != AF_LINK) {
549		printf("cannot locate %s\n", host);
550		return (1);
551	}
552	if (rtmsg(RTM_DELETE) == 0) {
553		struct sockaddr_in6 s6 = *sin;
554
555#ifdef __KAME__
556		if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) {
557			s6.sin6_scope_id =
558			    ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]);
559			*(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0;
560		}
561#endif
562		getnameinfo((struct sockaddr *)&s6,
563			    s6.sin6_len, host_buf,
564			    sizeof (host_buf), NULL, 0,
565			    NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
566		printf("%s (%s) deleted\n", host, host_buf);
567	}
568
569	return (0);
570}
571
572#define	W_ADDR	31
573#define	W_LL	17
574#define	W_IF	6
575
576/*
577 * Dump the entire neighbor cache
578 */
579static void
580dump(struct in6_addr *addr)
581{
582	int mib[6];
583	size_t needed;
584	char *lim, *buf, *next;
585	struct rt_msghdr *rtm;
586	struct sockaddr_in6 *sin;
587	struct sockaddr_dl *sdl;
588	struct in6_nbrinfo *nbi;
589	struct timeval time;
590	int addrwidth;
591	int llwidth;
592	int ifwidth;
593	char flgbuf[8];
594	char *ifname;
595
596	/* Print header */
597	if (!tflag && !cflag)
598		printf("%-*.*s %-*.*s %*.*s %-9.9s %2s %4s %4s\n",
599		    W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
600		    W_IF, W_IF, "Netif", "Expire", "St", "Flgs", "Prbs");
601
602again:;
603	mib[0] = CTL_NET;
604	mib[1] = PF_ROUTE;
605	mib[2] = 0;
606	mib[3] = AF_INET6;
607	mib[4] = NET_RT_FLAGS;
608	mib[5] = RTF_LLINFO;
609	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
610		err(1, "sysctl(PF_ROUTE estimate)");
611	if (needed > 0) {
612		if ((buf = malloc(needed)) == NULL)
613			errx(1, "malloc");
614		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
615			err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
616		lim = buf + needed;
617	} else
618		buf = lim = NULL;
619
620	for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
621		int isrouter = 0, prbs = 0;
622
623		rtm = (struct rt_msghdr *)next;
624		sin = (struct sockaddr_in6 *)(rtm + 1);
625		sdl = (struct sockaddr_dl *)((char *)sin +
626		    ROUNDUP(sin->sin6_len));
627
628		/*
629		 * Some OSes can produce a route that has the LINK flag but
630		 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
631		 * and BSD/OS, where xx is not the interface identifier on
632		 * lo0).  Such routes entry would annoy getnbrinfo() below,
633		 * so we skip them.
634		 * XXX: such routes should have the GATEWAY flag, not the
635		 * LINK flag.  However, there are rotten routing software
636		 * that advertises all routes that have the GATEWAY flag.
637		 * Thus, KAME kernel intentionally does not set the LINK flag.
638		 * What is to be fixed is not ndp, but such routing software
639		 * (and the kernel workaround)...
640		 */
641		if (sdl->sdl_family != AF_LINK)
642			continue;
643
644		if (addr) {
645			if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
646				continue;
647			found_entry = 1;
648		} else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
649			continue;
650		if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
651		    IN6_IS_ADDR_MC_NODELOCAL(&sin->sin6_addr) ||
652		    IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
653			/* should scope id be filled in the kernel? */
654			if (sin->sin6_scope_id == 0)
655				sin->sin6_scope_id = sdl->sdl_index;
656#ifdef __KAME__
657			/* KAME specific hack; removed the embedded id */
658			*(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
659#endif
660		}
661		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
662			    sizeof (host_buf), NULL, 0,
663			    NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
664		if (cflag == 1) {
665			if (rtm->rtm_flags & RTF_WASCLONED)
666				delete(host_buf);
667			continue;
668		}
669		gettimeofday(&time, 0);
670		if (tflag)
671			ts_print(&time);
672
673		addrwidth = strlen(host_buf);
674		if (addrwidth < W_ADDR)
675			addrwidth = W_ADDR;
676		llwidth = strlen(ether_str(sdl));
677		if (W_ADDR + W_LL - addrwidth > llwidth)
678			llwidth = W_ADDR + W_LL - addrwidth;
679		ifname = if_indextoname(sdl->sdl_index, ifix_buf);
680		if (!ifname)
681			ifname = "?";
682		ifwidth = strlen(ifname);
683		if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
684			ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
685
686		printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
687		    llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
688
689		/* Print neighbor discovery specific informations */
690		nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
691		if (nbi) {
692			if (nbi->expire > time.tv_sec) {
693				printf(" %-9.9s", sec2str(nbi->expire -
694				    time.tv_sec));
695			} else if (nbi->expire == 0)
696				printf(" %-9.9s", "permanent");
697			else
698				printf(" %-9.9s", "expired");
699
700			switch (nbi->state) {
701			case ND6_LLINFO_NOSTATE:
702				printf(" N");
703				break;
704			case ND6_LLINFO_INCOMPLETE:
705				printf(" I");
706				break;
707			case ND6_LLINFO_REACHABLE:
708				printf(" R");
709				break;
710			case ND6_LLINFO_STALE:
711				printf(" S");
712				break;
713			case ND6_LLINFO_DELAY:
714				printf(" D");
715				break;
716			case ND6_LLINFO_PROBE:
717				printf(" P");
718				break;
719			default:
720				printf(" ?");
721				break;
722			}
723
724			isrouter = nbi->isrouter;
725			prbs = nbi->asked;
726		} else {
727			warnx("failed to get neighbor information");
728			printf("  ");
729		}
730		putchar(' ');
731
732		/*
733		 * other flags. R: router, P: proxy, W: ??
734		 */
735		if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
736			snprintf(flgbuf, sizeof (flgbuf), "%s%s",
737				isrouter ? "R" : "",
738				(rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
739		} else {
740			sin = (struct sockaddr_in6 *)
741				(sdl->sdl_len + (char *)sdl);
742			snprintf(flgbuf, sizeof (flgbuf), "%s%s%s%s",
743				isrouter ? "R" : "",
744				!IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)
745					? "P" : "",
746				(sin->sin6_len != sizeof (struct sockaddr_in6))
747					? "W" : "",
748				(rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
749		}
750		printf(" %-4.4s", flgbuf);
751
752		if (prbs)
753			printf(" %4d", prbs);
754
755		printf("\n");
756	}
757	if (buf != NULL)
758		free(buf);
759
760	if (repeat) {
761		printf("\n");
762		sleep(repeat);
763		goto again;
764	}
765}
766
767/*
768 * Dump the entire neighbor cache (extended)
769 */
770void
771dump_ext(addr, xflag)
772	struct in6_addr *addr;
773	int xflag;
774{
775	int mib[6];
776	size_t needed;
777	char *lim, *buf, *next;
778	struct rt_msghdr_ext *ertm;
779	struct sockaddr_in6 *sin;
780	struct sockaddr_dl *sdl;
781	struct in6_nbrinfo *nbi;
782	struct timeval time;
783	int addrwidth;
784	int llwidth;
785	int ifwidth;
786	char flgbuf[8];
787	char *ifname;
788
789	/* Print header */
790	if (!tflag && !cflag) {
791		printf("%-*.*s %-*.*s %*.*s %-9.9s %-9.9s %2s %4s %4s",
792		    W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
793		    W_IF, W_IF, "Netif", "Expire(O)", "Expire(I)", "St",
794		    "Flgs", "Prbs");
795		if (xflag)
796			printf(" %-7.7s %-7.7s %-7.7s", "RSSI", "LQM", "NPM");
797		printf("\n");
798	}
799
800again:;
801	mib[0] = CTL_NET;
802	mib[1] = PF_ROUTE;
803	mib[2] = 0;
804	mib[3] = AF_INET6;
805	mib[4] = NET_RT_DUMPX_FLAGS;
806	mib[5] = RTF_LLINFO;
807	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
808		err(1, "sysctl(PF_ROUTE estimate)");
809	if (needed > 0) {
810		if ((buf = malloc(needed)) == NULL)
811			errx(1, "malloc");
812		if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
813			err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
814		lim = buf + needed;
815	} else
816		buf = lim = NULL;
817
818	for (next = buf; next && next < lim; next += ertm->rtm_msglen) {
819		int isrouter = 0, prbs = 0;
820
821		ertm = (struct rt_msghdr_ext *)next;
822		sin = (struct sockaddr_in6 *)(ertm + 1);
823		sdl = (struct sockaddr_dl *)((char *)sin +
824		    ROUNDUP(sin->sin6_len));
825
826		/*
827		 * Some OSes can produce a route that has the LINK flag but
828		 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
829		 * and BSD/OS, where xx is not the interface identifier on
830		 * lo0).  Such routes entry would annoy getnbrinfo() below,
831		 * so we skip them.
832		 * XXX: such routes should have the GATEWAY flag, not the
833		 * LINK flag.  However, there are rotten routing software
834		 * that advertises all routes that have the GATEWAY flag.
835		 * Thus, KAME kernel intentionally does not set the LINK flag.
836		 * What is to be fixed is not ndp, but such routing software
837		 * (and the kernel workaround)...
838		 */
839		if (sdl->sdl_family != AF_LINK)
840			continue;
841
842		if (addr) {
843			if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
844				continue;
845			found_entry = 1;
846		} else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
847			continue;
848		if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
849		    IN6_IS_ADDR_MC_NODELOCAL(&sin->sin6_addr) ||
850		    IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
851			/* should scope id be filled in the kernel? */
852			if (sin->sin6_scope_id == 0)
853				sin->sin6_scope_id = sdl->sdl_index;
854#ifdef __KAME__
855			/* KAME specific hack; removed the embedded id */
856			*(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
857#endif
858		}
859		getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
860			    sizeof (host_buf), NULL, 0,
861			    NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
862		if (cflag == 1) {
863			if (ertm->rtm_flags & RTF_WASCLONED)
864				delete(host_buf);
865			continue;
866		}
867		gettimeofday(&time, 0);
868		if (tflag)
869			ts_print(&time);
870
871		addrwidth = strlen(host_buf);
872		if (addrwidth < W_ADDR)
873			addrwidth = W_ADDR;
874		llwidth = strlen(ether_str(sdl));
875		if (W_ADDR + W_LL - addrwidth > llwidth)
876			llwidth = W_ADDR + W_LL - addrwidth;
877		ifname = if_indextoname(sdl->sdl_index, ifix_buf);
878		if (!ifname)
879			ifname = "?";
880		ifwidth = strlen(ifname);
881		if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
882			ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
883
884		printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
885		    llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
886
887		if (ertm->rtm_ri.ri_refcnt == 0 ||
888		    ertm->rtm_ri.ri_snd_expire == 0)
889			printf(" %-9.9s", "(none)");
890		else if (ertm->rtm_ri.ri_snd_expire > time.tv_sec)
891			printf(" %-9.9s",
892			    sec2str(ertm->rtm_ri.ri_snd_expire - time.tv_sec));
893		else
894			printf(" %-9.9s", "expired");
895
896		if (ertm->rtm_ri.ri_refcnt == 0 ||
897		    ertm->rtm_ri.ri_rcv_expire == 0)
898			printf(" %-9.9s", "(none)");
899		else if (ertm->rtm_ri.ri_rcv_expire > time.tv_sec)
900			printf(" %-9.9s",
901			    sec2str(ertm->rtm_ri.ri_rcv_expire - time.tv_sec));
902		else
903			printf(" %-9.9s", "expired");
904
905		/* Print neighbor discovery specific informations */
906		nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
907		if (nbi) {
908			switch (nbi->state) {
909			case ND6_LLINFO_NOSTATE:
910				printf(" N");
911				break;
912			case ND6_LLINFO_INCOMPLETE:
913				printf(" I");
914				break;
915			case ND6_LLINFO_REACHABLE:
916				printf(" R");
917				break;
918			case ND6_LLINFO_STALE:
919				printf(" S");
920				break;
921			case ND6_LLINFO_DELAY:
922				printf(" D");
923				break;
924			case ND6_LLINFO_PROBE:
925				printf(" P");
926				break;
927			default:
928				printf(" ?");
929				break;
930			}
931
932			isrouter = nbi->isrouter;
933			prbs = nbi->asked;
934		} else {
935			warnx("failed to get neighbor information");
936			printf("  ");
937		}
938		putchar(' ');
939
940		/*
941		 * other flags. R: router, P: proxy, W: ??
942		 */
943		if ((ertm->rtm_addrs & RTA_NETMASK) == 0) {
944			snprintf(flgbuf, sizeof (flgbuf), "%s%s",
945				isrouter ? "R" : "",
946				(ertm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
947		} else {
948			sin = (struct sockaddr_in6 *)
949				(sdl->sdl_len + (char *)sdl);
950			snprintf(flgbuf, sizeof (flgbuf), "%s%s%s%s",
951				isrouter ? "R" : "",
952				!IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)
953					? "P" : "",
954				(sin->sin6_len != sizeof (struct sockaddr_in6))
955					? "W" : "",
956				(ertm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
957		}
958		printf(" %-4.4s", flgbuf);
959
960		if (prbs)
961			printf(" %4d", prbs);
962
963		if (xflag) {
964			if (!prbs)
965				printf(" %-4.4s", "none");
966
967			if (ertm->rtm_ri.ri_rssi != IFNET_RSSI_UNKNOWN)
968				printf(" %7d", ertm->rtm_ri.ri_rssi);
969			else
970				printf(" %-7.7s", "unknown");
971
972			switch (ertm->rtm_ri.ri_lqm)
973			{
974			case IFNET_LQM_THRESH_OFF:
975				printf(" %-7.7s", "off");
976				break;
977			case IFNET_LQM_THRESH_UNKNOWN:
978				printf(" %-7.7s", "unknown");
979				break;
980			case IFNET_LQM_THRESH_POOR:
981				printf(" %-7.7s", "poor");
982				break;
983			case IFNET_LQM_THRESH_GOOD:
984				printf(" %-7.7s", "good");
985				break;
986			default:
987				printf(" %7d", ertm->rtm_ri.ri_lqm);
988				break;
989			}
990
991			switch (ertm->rtm_ri.ri_npm)
992			{
993			case IFNET_NPM_THRESH_UNKNOWN:
994				printf(" %-7.7s", "unknown");
995				break;
996			case IFNET_NPM_THRESH_NEAR:
997				printf(" %-7.7s", "near");
998				break;
999			case IFNET_NPM_THRESH_GENERAL:
1000				printf(" %-7.7s", "general");
1001				break;
1002			case IFNET_NPM_THRESH_FAR:
1003				printf(" %-7.7s", "far");
1004				break;
1005			default:
1006				printf(" %7d", ertm->rtm_ri.ri_npm);
1007				break;
1008			}
1009		}
1010
1011		printf("\n");
1012	}
1013	if (buf != NULL)
1014		free(buf);
1015
1016	if (repeat) {
1017		printf("\n");
1018		sleep(repeat);
1019		goto again;
1020	}
1021}
1022
1023static struct in6_nbrinfo *
1024getnbrinfo(addr, ifindex, warning)
1025	struct in6_addr *addr;
1026	int ifindex;
1027	int warning;
1028{
1029	static struct in6_nbrinfo nbi;
1030	int s;
1031
1032	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1033		err(1, "socket");
1034
1035	bzero(&nbi, sizeof (nbi));
1036	if_indextoname(ifindex, nbi.ifname);
1037	nbi.addr = *addr;
1038	if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
1039		if (warning)
1040			warn("ioctl(SIOCGNBRINFO_IN6)");
1041		close(s);
1042		return (NULL);
1043	}
1044
1045	close(s);
1046	return (&nbi);
1047}
1048
1049static char *
1050ether_str(struct sockaddr_dl *sdl)
1051{
1052	static char ebuf[32];
1053	u_char *cp;
1054
1055	if (sdl->sdl_alen) {
1056		cp = (u_char *)LLADDR(sdl);
1057		snprintf(ebuf, sizeof (ebuf), "%x:%x:%x:%x:%x:%x",
1058			cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
1059	} else {
1060		snprintf(ebuf, sizeof (ebuf), "(incomplete)");
1061	}
1062
1063	return (ebuf);
1064}
1065
1066static int
1067ndp_ether_aton(char *a, u_char *n)
1068{
1069	int i, o[6];
1070
1071	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], &o[3], &o[4],
1072	    &o[5]);
1073	if (i != 6) {
1074		fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
1075		return (1);
1076	}
1077	for (i = 0; i < 6; i++)
1078		n[i] = o[i];
1079	return (0);
1080}
1081
1082static void
1083usage(void)
1084{
1085	printf("usage: ndp hostname\n");
1086	printf("       ndp -a[lnt]\n");
1087	printf("       ndp [-nt] -A wait\n");
1088	printf("       ndp -c[nt]\n");
1089	printf("       ndp -d[nt] hostname\n");
1090	printf("       ndp -f[nt] filename\n");
1091	printf("       ndp -i interface [flags...]\n");
1092	printf("       ndp -I [interface|delete]\n");
1093	printf("       ndp -p\n");
1094	printf("       ndp -r\n");
1095	printf("       ndp -s hostname ether_addr [temp] [proxy]\n");
1096	printf("       ndp -H\n");
1097	printf("       ndp -P\n");
1098	printf("       ndp -R\n");
1099	printf("       ndp -w\n");
1100	printf("       ndp -W cfgfile\n");
1101	exit(1);
1102}
1103
1104static int
1105rtmsg(int cmd)
1106{
1107	static int seq;
1108	int rlen;
1109	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
1110	register char *cp = m_rtmsg.m_space;
1111	register int l;
1112
1113	errno = 0;
1114	if (cmd == RTM_DELETE)
1115		goto doit;
1116	bzero((char *)&m_rtmsg, sizeof (m_rtmsg));
1117	rtm->rtm_flags = flags;
1118	rtm->rtm_version = RTM_VERSION;
1119
1120	switch (cmd) {
1121	default:
1122		fprintf(stderr, "ndp: internal wrong cmd\n");
1123		exit(1);
1124	case RTM_ADD:
1125		rtm->rtm_addrs |= RTA_GATEWAY;
1126		rtm->rtm_rmx.rmx_expire = expire_time;
1127		rtm->rtm_inits = RTV_EXPIRE;
1128		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
1129		if (rtm->rtm_flags & RTF_ANNOUNCE) {
1130			rtm->rtm_flags &= ~RTF_HOST;
1131			rtm->rtm_flags |= RTA_NETMASK;
1132		}
1133		/* FALLTHROUGH */
1134	case RTM_GET:
1135		rtm->rtm_addrs |= RTA_DST;
1136	}
1137#define	NEXTADDR(w, s) \
1138	if (rtm->rtm_addrs & (w)) { \
1139		bcopy((char *)&s, cp, sizeof (s)); cp += sizeof (s); \
1140	}
1141
1142	NEXTADDR(RTA_DST, sin_m);
1143	NEXTADDR(RTA_GATEWAY, sdl_m);
1144	memset(&so_mask.sin6_addr, 0xff, sizeof (so_mask.sin6_addr));
1145	NEXTADDR(RTA_NETMASK, so_mask);
1146
1147	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
1148doit:
1149	l = rtm->rtm_msglen;
1150	rtm->rtm_seq = ++seq;
1151	rtm->rtm_type = cmd;
1152	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
1153		if (errno != ESRCH || cmd != RTM_DELETE) {
1154			perror("writing to routing socket");
1155			return (-1);
1156		}
1157	}
1158	do {
1159		l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg));
1160	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
1161	if (l < 0)
1162		(void) fprintf(stderr, "ndp: read from routing socket: %s\n",
1163		    strerror(errno));
1164	return (0);
1165}
1166
1167static void
1168ifinfo(int argc, char **argv)
1169{
1170	struct in6_ndireq nd;
1171	int i, s;
1172	char *ifname = argv[0];
1173	u_int32_t newflags;
1174	u_int8_t nullbuf[8];
1175
1176	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1177		perror("ndp: socket");
1178		exit(1);
1179	}
1180	bzero(&nd, sizeof (nd));
1181	strlcpy(nd.ifname, ifname, sizeof (nd.ifname));
1182	if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
1183		perror("ioctl (SIOCGIFINFO_IN6)");
1184		exit(1);
1185	}
1186#define	ND nd.ndi
1187	newflags = ND.flags;
1188	for (i = 1; i < argc; i++) {
1189		int clear = 0;
1190		char *cp = argv[i];
1191
1192		if (*cp == '-') {
1193			clear = 1;
1194			cp++;
1195		}
1196
1197#define	SETFLAG(s, f) \
1198	do {\
1199		if (strcmp(cp, (s)) == 0) {\
1200			if (clear)\
1201				newflags &= ~(f);\
1202			else\
1203				newflags |= (f);\
1204		}\
1205	} while (0)
1206		SETFLAG("nud", ND6_IFF_PERFORMNUD);
1207		SETFLAG("proxy_prefixes", ND6_IFF_PROXY_PREFIXES);
1208		SETFLAG("ignore_na", ND6_IFF_IGNORE_NA);
1209		SETFLAG("disabled", ND6_IFF_IFDISABLED);
1210		SETFLAG("insecure", ND6_IFF_INSECURE);
1211
1212		ND.flags = newflags;
1213		if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) {
1214			perror("ioctl(SIOCSIFINFO_FLAGS)");
1215			exit(1);
1216		}
1217#undef SETFLAG
1218	}
1219
1220	printf("linkmtu=%d", ND.linkmtu);
1221	printf(", curhlim=%d", ND.chlim);
1222	printf(", basereachable=%ds%dms", ND.basereachable / 1000,
1223	    ND.basereachable % 1000);
1224	printf(", reachable=%ds", ND.reachable);
1225	printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000);
1226	memset(nullbuf, 0, sizeof (nullbuf));
1227	if (memcmp(nullbuf, ND.randomid, sizeof (nullbuf)) != 0) {
1228		int j;
1229		u_int8_t *rbuf = NULL;
1230
1231		for (i = 0; i < 3; i++) {
1232			switch (i) {
1233			case 0:
1234				printf("\nRandom seed(0): ");
1235				rbuf = ND.randomseed0;
1236				break;
1237			case 1:
1238				printf("\nRandom seed(1): ");
1239				rbuf = ND.randomseed1;
1240				break;
1241			case 2:
1242				printf("\nRandom ID:      ");
1243				rbuf = ND.randomid;
1244				break;
1245			}
1246			for (j = 0; j < 8; j++)
1247				printf("%02x", rbuf[j]);
1248		}
1249	}
1250	if (ND.flags) {
1251		printf("\nFlags: ");
1252		if ((ND.flags & ND6_IFF_IFDISABLED) != 0)
1253			printf("IFDISABLED ");
1254		if ((ND.flags & ND6_IFF_IGNORE_NA) != 0)
1255			printf("IGNORE_NA ");
1256		if ((ND.flags & ND6_IFF_INSECURE) != 0)
1257			printf("INSECURE ");
1258		if ((ND.flags & ND6_IFF_PERFORMNUD) != 0)
1259			printf("PERFORMNUD ");
1260		if ((ND.flags & ND6_IFF_PROXY_PREFIXES) != 0)
1261			printf("PROXY_PREFIXES ");
1262	}
1263	putc('\n', stdout);
1264#undef ND
1265
1266	close(s);
1267}
1268
1269#ifndef ND_RA_FLAG_RTPREF_MASK	/* XXX: just for compilation on *BSD release */
1270#define	ND_RA_FLAG_RTPREF_MASK	0x18 /* 00011000 */
1271#endif
1272
1273static void
1274rtrlist(void)
1275{
1276	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };
1277	char *buf;
1278	struct in6_defrouter *p, *ep;
1279	size_t l;
1280	struct timeval time;
1281
1282	if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), NULL, &l, NULL, 0)
1283	    < 0) {
1284		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
1285		/*NOTREACHED*/
1286	}
1287	buf = malloc(l);
1288	if (!buf) {
1289		errx(1, "not enough core");
1290		/*NOTREACHED*/
1291	}
1292	if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), buf, &l, NULL, 0) < 0) {
1293		err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
1294		/*NOTREACHED*/
1295	}
1296
1297	ep = (struct in6_defrouter *)(buf + l);
1298	for (p = (struct in6_defrouter *)buf; p < ep; p++) {
1299		int rtpref;
1300
1301		if (getnameinfo((struct sockaddr *)&p->rtaddr,
1302		    p->rtaddr.sin6_len, host_buf, sizeof (host_buf), NULL, 0,
1303		    NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)) != 0)
1304			strlcpy(host_buf, "?", sizeof (host_buf));
1305
1306		printf("%s if=%s", host_buf, if_indextoname(p->if_index,
1307		    ifix_buf));
1308		printf(", flags=%s%s%s%s%s",
1309		    p->stateflags & NDDRF_IFSCOPE ? "I" : "",
1310		    p->flags & ND_RA_FLAG_MANAGED ? "M" : "",
1311		    p->flags & ND_RA_FLAG_OTHER   ? "O" : "",
1312		    p->stateflags & NDDRF_STATIC ? "S" : "",
1313		    p->stateflags & NDDRF_INSTALLED ? "T" : "");
1314		rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
1315		printf(", pref=%s", rtpref_str[rtpref]);
1316
1317		gettimeofday(&time, 0);
1318		if (p->expire == 0)
1319			printf(", expire=Never\n");
1320		else
1321			printf(", expire=%s\n",
1322				sec2str(p->expire - time.tv_sec));
1323	}
1324	free(buf);
1325}
1326
1327static void
1328plist(void)
1329{
1330	int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST };
1331	char *buf;
1332	struct in6_prefix *p, *ep, *n;
1333	struct sockaddr_in6 *advrtr;
1334	size_t l;
1335	struct timeval time;
1336	const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
1337	int ninflags = (nflag ? NI_NUMERICHOST : 0) | NI_WITHSCOPEID;
1338	char namebuf[NI_MAXHOST];
1339
1340	if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), NULL, &l, NULL, 0)
1341	    < 0) {
1342		err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
1343		/*NOTREACHED*/
1344	}
1345	buf = malloc(l);
1346	if (!buf) {
1347		errx(1, "not enough core");
1348		/*NOTREACHED*/
1349	}
1350	if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), buf, &l, NULL, 0)
1351	    < 0) {
1352		err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
1353		/*NOTREACHED*/
1354	}
1355
1356	ep = (struct in6_prefix *)(buf + l);
1357	for (p = (struct in6_prefix *)buf; p < ep; p = n) {
1358		advrtr = (struct sockaddr_in6 *)(p + 1);
1359		n = (struct in6_prefix *)&advrtr[p->advrtrs];
1360
1361		if (getnameinfo((struct sockaddr *)&p->prefix,
1362		    p->prefix.sin6_len, namebuf, sizeof (namebuf),
1363		    NULL, 0, niflags) != 0)
1364			strlcpy(namebuf, "?", sizeof (namebuf));
1365		printf("%s/%d if=%s\n", namebuf, p->prefixlen,
1366		    if_indextoname(p->if_index, ifix_buf));
1367
1368		gettimeofday(&time, 0);
1369		/*
1370		 * meaning of fields, especially flags, is very different
1371		 * by origin.  notify the difference to the users.
1372		 */
1373		printf("flags=%s%s%s%s%s%s%s",
1374		    p->raflags.autonomous ? "A" : "",
1375		    (p->flags & NDPRF_DETACHED) != 0 ? "D" : "",
1376		    (p->flags & NDPRF_IFSCOPE) != 0 ? "I" : "",
1377		    p->raflags.onlink ? "L" : "",
1378		    (p->flags & NDPRF_STATIC) != 0 ? "S" : "",
1379		    (p->flags & NDPRF_ONLINK) != 0 ? "O" : "",
1380		    (p->flags & NDPRF_PRPROXY) != 0 ? "Y" : "");
1381		if (p->vltime == ND6_INFINITE_LIFETIME)
1382			printf(" vltime=infinity");
1383		else
1384			printf(" vltime=%ld", (long)p->vltime);
1385		if (p->pltime == ND6_INFINITE_LIFETIME)
1386			printf(", pltime=infinity");
1387		else
1388			printf(", pltime=%ld", (long)p->pltime);
1389		if (p->expire == 0)
1390			printf(", expire=Never");
1391		else if (p->expire >= time.tv_sec)
1392			printf(", expire=%s",
1393				sec2str(p->expire - time.tv_sec));
1394		else
1395			printf(", expired");
1396		printf(", ref=%d", p->refcnt);
1397		printf("\n");
1398		/*
1399		 * "advertising router" list is meaningful only if the prefix
1400		 * information is from RA.
1401		 */
1402		if (p->advrtrs) {
1403			int j;
1404			struct sockaddr_in6 *sin6;
1405
1406			sin6 = (struct sockaddr_in6 *)(p + 1);
1407			printf("  advertised by\n");
1408			for (j = 0; j < p->advrtrs; j++) {
1409				struct in6_nbrinfo *nbi;
1410
1411				if (getnameinfo((struct sockaddr *)sin6,
1412				    sin6->sin6_len, namebuf, sizeof (namebuf),
1413				    NULL, 0, ninflags) != 0)
1414					strlcpy(namebuf, "?", sizeof (namebuf));
1415				printf("    %s", namebuf);
1416
1417				nbi = getnbrinfo(&sin6->sin6_addr, p->if_index,
1418				    0);
1419				if (nbi) {
1420					switch (nbi->state) {
1421					case ND6_LLINFO_REACHABLE:
1422					case ND6_LLINFO_STALE:
1423					case ND6_LLINFO_DELAY:
1424					case ND6_LLINFO_PROBE:
1425						printf(" (reachable)\n");
1426						break;
1427					default:
1428						printf(" (unreachable)\n");
1429					}
1430				} else
1431					printf(" (no neighbor state)\n");
1432				sin6++;
1433			}
1434		} else
1435			printf("  No advertising router\n");
1436	}
1437	free(buf);
1438}
1439
1440static void
1441pfx_flush(void)
1442{
1443	char dummyif[IFNAMSIZ+8];
1444	int s;
1445
1446	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1447		err(1, "socket");
1448	strlcpy(dummyif, "lo0", sizeof (dummyif)); /* dummy */
1449	if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
1450		err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
1451}
1452
1453static void
1454rtr_flush(void)
1455{
1456	char dummyif[IFNAMSIZ+8];
1457	int s;
1458
1459	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1460		err(1, "socket");
1461	strlcpy(dummyif, "lo0", sizeof (dummyif)); /* dummy */
1462	if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
1463		err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
1464
1465	close(s);
1466}
1467
1468static void
1469harmonize_rtr(void)
1470{
1471	char dummyif[IFNAMSIZ+8];
1472	int s;
1473
1474	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1475		err(1, "socket");
1476	strlcpy(dummyif, "lo0", sizeof (dummyif)); /* dummy */
1477	if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
1478		err(1, "ioctl (SIOCSNDFLUSH_IN6)");
1479
1480	close(s);
1481}
1482
1483static void
1484setdefif(char *ifname)
1485{
1486	struct in6_ndifreq ndifreq;
1487	unsigned int ifindex;
1488
1489	if (strcasecmp(ifname, "delete") == 0)
1490		ifindex = 0;
1491	else {
1492		if ((ifindex = if_nametoindex(ifname)) == 0)
1493			err(1, "failed to resolve i/f index for %s", ifname);
1494	}
1495
1496	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1497		err(1, "socket");
1498
1499	strlcpy(ndifreq.ifname, "lo0", sizeof (ndifreq.ifname)); /* dummy */
1500	ndifreq.ifindex = ifindex;
1501
1502	if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1503		err(1, "ioctl (SIOCSDEFIFACE_IN6)");
1504
1505	close(s);
1506}
1507
1508static void
1509getdefif(void)
1510{
1511	struct in6_ndifreq ndifreq;
1512	char ifname[IFNAMSIZ+8];
1513
1514	if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1515		err(1, "socket");
1516
1517	memset(&ndifreq, 0, sizeof (ndifreq));
1518	strlcpy(ndifreq.ifname, "lo0", sizeof (ndifreq.ifname)); /* dummy */
1519
1520	if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1521		err(1, "ioctl (SIOCGDEFIFACE_IN6)");
1522
1523	if (ndifreq.ifindex == 0)
1524		printf("No default interface.\n");
1525	else {
1526		if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
1527			err(1, "failed to resolve ifname for index %lu",
1528			    ndifreq.ifindex);
1529		printf("ND default interface = %s\n", ifname);
1530	}
1531
1532	close(s);
1533}
1534
1535static char *
1536sec2str(time_t total)
1537{
1538	static char result[256];
1539	int days, hours, mins, secs;
1540	int first = 1;
1541	char *p = result;
1542
1543	days = total / 3600 / 24;
1544	hours = (total / 3600) % 24;
1545	mins = (total / 60) % 60;
1546	secs = total % 60;
1547
1548	if (days) {
1549		first = 0;
1550		p += snprintf(p, sizeof (result) - (p - result), "%dd", days);
1551	}
1552	if (!first || hours) {
1553		first = 0;
1554		p += snprintf(p, sizeof (result) - (p - result), "%dh", hours);
1555	}
1556	if (!first || mins)
1557		p += snprintf(p, sizeof (result) - (p - result), "%dm", mins);
1558	snprintf(p, sizeof (result) - (p - result), "%ds", secs);
1559
1560	return (result);
1561}
1562
1563/*
1564 * Print the timestamp
1565 * from tcpdump/util.c
1566 */
1567static void
1568ts_print(const struct timeval *tvp)
1569{
1570	int s;
1571
1572	/* Default */
1573	s = (tvp->tv_sec + thiszone) % 86400;
1574	printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60,
1575	    (u_int32_t)tvp->tv_usec);
1576}
1577
1578#define	SYSCTL_CGA_PARAMETERS_BUFFER_SIZE \
1579	2 * (sizeof (size_t) + IN6_CGA_KEY_MAXSIZE) + \
1580	sizeof (struct in6_cga_prepare)
1581
1582static void
1583read_cga_parameters(void)
1584{
1585	static char oldb[SYSCTL_CGA_PARAMETERS_BUFFER_SIZE];
1586
1587	int error;
1588	struct in6_cga_nodecfg cfg;
1589	struct iovec *iov;
1590	const char *oldp;
1591	const char *finp;
1592	size_t oldn;
1593	unsigned int column;
1594	uint16_t u16;
1595
1596	oldn = sizeof oldb;
1597	error = sysctlbyname("net.inet6.send.cga_parameters", oldb, &oldn,
1598	    NULL, NULL);
1599	if (error != 0)
1600		err(1, "sysctlbyname");
1601
1602	if (oldn == 0) {
1603		printf("No CGA parameters.\n");
1604		exit(0);
1605	}
1606
1607	oldp = oldb;
1608	finp = &oldb[oldn];
1609	memset(&cfg, 0, sizeof (cfg));
1610
1611	if (oldp + sizeof (cfg.cga_prepare) > finp)
1612		err(1, "format error[1]");
1613
1614	memcpy(&cfg.cga_prepare, oldp, sizeof (cfg.cga_prepare));
1615	oldp += sizeof (cfg.cga_prepare);
1616
1617	iov = &cfg.cga_pubkey;
1618
1619	if (oldp + sizeof (u16) > finp)
1620		err(1, "format error[2]");
1621
1622	memcpy(&u16, oldp, sizeof (u16));
1623	oldp += sizeof (u16);
1624	iov->iov_len = u16;
1625
1626	if (oldp + iov->iov_len > finp)
1627		err(1, "format error[3]");
1628
1629	iov->iov_base = (void *)oldp;
1630	oldp += iov->iov_len;
1631
1632	if (oldp != finp)
1633		err(1, "format error[4]");
1634
1635	puts("Public Key:");
1636	finp = &iov->iov_base[iov->iov_len];
1637	column = 0;
1638	oldp = iov->iov_base;
1639	while (oldp < finp) {
1640		if (column++ != 0)
1641			putchar(':');
1642		printf("%02x", (unsigned char) *oldp++);
1643		if (column >= 32) {
1644			column = 0;
1645			puts("");
1646		}
1647	}
1648	if (column < 32)
1649		puts("");
1650	puts("");
1651	puts("Modifier:");
1652	oldp = (const char*) cfg.cga_prepare.cga_modifier.octets;
1653	finp = &oldp[sizeof (cfg.cga_prepare.cga_modifier.octets)];
1654	column = 0;
1655	while (oldp < finp) {
1656		if (column++ != 0)
1657			putchar(':');
1658		printf("%02x", (unsigned char) *oldp++);
1659	}
1660	puts("\n");
1661	printf("Security Level: %u\n", cfg.cga_prepare.cga_security_level);
1662}
1663
1664static void
1665write_cga_parameters(const char filename[])
1666{
1667	static char newb[SYSCTL_CGA_PARAMETERS_BUFFER_SIZE];
1668
1669	int error;
1670	FILE* fp;
1671	size_t oldn, newn;
1672
1673	fp = fopen(filename, "r");
1674	if (fp == NULL)
1675		err(1, "opening '%s' for reading.", filename);
1676
1677	newn = fread(newb, 1, sizeof (newb), fp);
1678	if (feof(fp) == 0)
1679		err(1, "parameters too large");
1680
1681	if (fclose(fp) != 0)
1682		err(1, "closing file.");
1683
1684	oldn = 0;
1685	error = sysctlbyname("net.inet6.send.cga_parameters", NULL, NULL, newb,
1686	    newn);
1687	if (error != 0)
1688		err(1, "sysctlbyname");
1689}
1690