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