]>
git.saurik.com Git - apple/network_cmds.git/blob - ndp.tproj/ndp.c
76770171c26164fe2934f3b6122a005d970f44a9
2 * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 /* $FreeBSD: src/usr.sbin/ndp/ndp.c,v 1.2.2.5 2001/08/13 02:58:26 sumikawa Exp $ */
30 /* $KAME: ndp.c,v 1.65 2001/05/08 04:36:34 itojun Exp $ */
33 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the project nor the names of its contributors
45 * may be used to endorse or promote products derived from this software
46 * without specific prior written permission.
48 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * Copyright (c) 1984, 1993
62 * The Regents of the University of California. All rights reserved.
64 * This code is derived from software contributed to Berkeley by
65 * Sun Microsystems, Inc.
67 * Redistribution and use in source and binary forms, with or without
68 * modification, are permitted provided that the following conditions
70 * 1. Redistributions of source code must retain the above copyright
71 * notice, this list of conditions and the following disclaimer.
72 * 2. Redistributions in binary form must reproduce the above copyright
73 * notice, this list of conditions and the following disclaimer in the
74 * documentation and/or other materials provided with the distribution.
75 * 3. All advertising materials mentioning features or use of this software
76 * must display the following acknowledgement:
77 * This product includes software developed by the University of
78 * California, Berkeley and its contributors.
79 * 4. Neither the name of the University nor the names of its contributors
80 * may be used to endorse or promote products derived from this software
81 * without specific prior written permission.
83 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
84 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
85 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
86 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
87 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
88 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
89 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
90 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
91 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
92 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
98 * "@(#) Copyright (c) 1984, 1993\n\
99 * The Regents of the University of California. All rights reserved.\n";
101 * "@(#)arp.c 8.2 (Berkeley) 1/2/94";
105 * ndp - display, set, delete and flush neighbor cache
109 #include <sys/param.h>
110 #include <sys/file.h>
111 #include <sys/ioctl.h>
112 #include <sys/socket.h>
113 #include <sys/sysctl.h>
114 #include <sys/time.h>
115 #include <sys/queue.h>
118 #include <net/if_var.h>
119 #include <net/if_dl.h>
120 #include <net/if_types.h>
121 #include <net/route.h>
123 #include <netinet/in.h>
124 #include <netinet/if_ether.h>
126 #include <netinet/icmp6.h>
127 #include <netinet6/in6_var.h>
128 #include <netinet6/nd6.h>
130 #include <arpa/inet.h>
142 //#include "gmt2local.h"
144 #ifndef NI_WITHSCOPEID
145 #define NI_WITHSCOPEID 0
148 /* packing rule for routing socket */
150 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
151 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
157 static int32_t thiszone
=0 ; /* time difference with gmt */
159 static int repeat
= 0;
161 char ntop_buf
[INET6_ADDRSTRLEN
]; /* inet_ntop() */
162 char host_buf
[NI_MAXHOST
]; /* getnameinfo() */
163 char ifix_buf
[IFNAMSIZ
]; /* if_indextoname() */
165 int main
__P((int, char **));
166 int file
__P((char *));
167 void getsocket
__P((void));
168 int set
__P((int, char **));
169 void get
__P((char *));
170 int delete __P((char *));
171 void dump
__P((struct in6_addr
*));
172 void dump_ext
__P((struct in6_addr
*, int));
173 static struct in6_nbrinfo
*getnbrinfo
__P((struct in6_addr
*addr
,
175 static char *ether_str
__P((struct sockaddr_dl
*));
176 int ndp_ether_aton
__P((char *, u_char
*));
177 void usage
__P((void));
178 int rtmsg
__P((int));
179 void ifinfo
__P((int, char **));
180 void rtrlist
__P((void));
181 void plist
__P((void));
182 void pfx_flush
__P((void));
183 void rtrlist
__P((void));
184 void rtr_flush
__P((void));
185 void harmonize_rtr
__P((void));
186 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */
187 static void getdefif
__P((void));
188 static void setdefif
__P((char *));
190 static char *sec2str
__P((time_t t
));
191 static char *ether_str
__P((struct sockaddr_dl
*sdl
));
192 static void ts_print
__P((const struct timeval
*));
194 static char *rtpref_str
[] = {
207 int aflag
= 0, dflag
= 0, sflag
= 0, Hflag
= 0,
208 pflag
= 0, rflag
= 0, Pflag
= 0, Rflag
= 0, lflag
= 0,
212 // thiszone = gmt2local(0);
213 while ((ch
= getopt(argc
, argv
, "acndfIilprstA:HPRx")) != -1)
225 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */
228 getdefif(); /* always call it to print the result */
231 errx(1, "not supported yet");
266 repeat
= atoi(optarg
);
290 if (aflag
|| cflag
) {
312 if (argc
< 2 || argc
> 4)
314 exit(set(argc
, argv
) ? 1 : 0);
336 * Process a file to set standard ndp entries
344 char line
[100], arg
[5][50], *args
[5];
346 if ((fp
= fopen(name
, "r")) == NULL
) {
347 fprintf(stderr
, "ndp: cannot open %s\n", name
);
350 args
[0] = &arg
[0][0];
351 args
[1] = &arg
[1][0];
352 args
[2] = &arg
[2][0];
353 args
[3] = &arg
[3][0];
354 args
[4] = &arg
[4][0];
356 while(fgets(line
, 100, fp
) != NULL
) {
357 i
= sscanf(line
, "%s %s %s %s %s", arg
[0], arg
[1], arg
[2],
360 fprintf(stderr
, "ndp: bad line: %s\n", line
);
375 s
= socket(PF_ROUTE
, SOCK_RAW
, 0);
377 perror("ndp: socket");
383 struct sockaddr_in6 so_mask
= {sizeof(so_mask
), AF_INET6
};
384 struct sockaddr_in6 blank_sin
= {sizeof(blank_sin
), AF_INET6
}, sin_m
;
385 struct sockaddr_dl blank_sdl
= {sizeof(blank_sdl
), AF_LINK
}, sdl_m
;
386 int expire_time
, flags
, found_entry
;
388 struct rt_msghdr m_rtm
;
393 * Set an individual neighbor cache entry
400 register struct sockaddr_in6
*sin
= &sin_m
;
401 register struct sockaddr_dl
*sdl
;
402 register struct rt_msghdr
*rtm
= &(m_rtmsg
.m_rtm
);
403 struct addrinfo hints
, *res
;
406 char *host
= argv
[0], *eaddr
= argv
[1];
414 bzero(&hints
, sizeof(hints
));
415 hints
.ai_family
= AF_INET6
;
416 gai_error
= getaddrinfo(host
, NULL
, &hints
, &res
);
418 fprintf(stderr
, "ndp: %s: %s\n", host
,
419 gai_strerror(gai_error
));
422 sin
->sin6_addr
= ((struct sockaddr_in6
*)res
->ai_addr
)->sin6_addr
;
424 if (IN6_IS_ADDR_LINKLOCAL(&sin
->sin6_addr
)) {
425 *(u_int16_t
*)&sin
->sin6_addr
.s6_addr
[2] =
426 htons(((struct sockaddr_in6
*)res
->ai_addr
)->sin6_scope_id
);
429 ea
= (u_char
*)LLADDR(&sdl_m
);
430 if (ndp_ether_aton(eaddr
, ea
) == 0)
432 flags
= expire_time
= 0;
434 if (strncmp(argv
[0], "temp", 4) == 0) {
436 gettimeofday(&time
, 0);
437 expire_time
= time
.tv_sec
+ 20 * 60;
438 } else if (strncmp(argv
[0], "proxy", 5) == 0)
439 flags
|= RTF_ANNOUNCE
;
442 if (rtmsg(RTM_GET
) < 0) {
446 sin
= (struct sockaddr_in6
*)(rtm
+ 1);
447 sdl
= (struct sockaddr_dl
*)(ROUNDUP(sin
->sin6_len
) + (char *)sin
);
448 if (IN6_ARE_ADDR_EQUAL(&sin
->sin6_addr
, &sin_m
.sin6_addr
)) {
449 if (sdl
->sdl_family
== AF_LINK
&&
450 (rtm
->rtm_flags
& RTF_LLINFO
) &&
451 !(rtm
->rtm_flags
& RTF_GATEWAY
)) switch (sdl
->sdl_type
) {
452 case IFT_ETHER
: case IFT_FDDI
: case IFT_ISO88023
:
453 case IFT_ISO88024
: case IFT_ISO88025
:
457 * IPv4 arp command retries with sin_other = SIN_PROXY here.
459 fprintf(stderr
, "set: cannot configure a new entry\n");
464 if (sdl
->sdl_family
!= AF_LINK
) {
465 printf("cannot intuit interface index and type for %s\n", host
);
468 sdl_m
.sdl_type
= sdl
->sdl_type
;
469 sdl_m
.sdl_index
= sdl
->sdl_index
;
470 return (rtmsg(RTM_ADD
));
474 * Display an individual neighbor cache entry
480 struct sockaddr_in6
*sin
= &sin_m
;
481 struct addrinfo hints
, *res
;
485 bzero(&hints
, sizeof(hints
));
486 hints
.ai_family
= AF_INET6
;
487 gai_error
= getaddrinfo(host
, NULL
, &hints
, &res
);
489 fprintf(stderr
, "ndp: %s: %s\n", host
,
490 gai_strerror(gai_error
));
493 sin
->sin6_addr
= ((struct sockaddr_in6
*)res
->ai_addr
)->sin6_addr
;
495 if (IN6_IS_ADDR_LINKLOCAL(&sin
->sin6_addr
)) {
496 *(u_int16_t
*)&sin
->sin6_addr
.s6_addr
[2] =
497 htons(((struct sockaddr_in6
*)res
->ai_addr
)->sin6_scope_id
);
500 dump(&sin
->sin6_addr
);
501 if (found_entry
== 0) {
502 getnameinfo((struct sockaddr
*)sin
, sin
->sin6_len
, host_buf
,
503 sizeof(host_buf
), NULL
,0,
504 NI_WITHSCOPEID
| (nflag
? NI_NUMERICHOST
: 0));
505 printf("%s (%s) -- no entry\n", host
, host_buf
);
511 * Delete a neighbor cache entry
517 struct sockaddr_in6
*sin
= &sin_m
;
518 register struct rt_msghdr
*rtm
= &m_rtmsg
.m_rtm
;
519 struct sockaddr_dl
*sdl
;
520 struct addrinfo hints
, *res
;
526 bzero(&hints
, sizeof(hints
));
527 hints
.ai_family
= AF_INET6
;
528 gai_error
= getaddrinfo(host
, NULL
, &hints
, &res
);
530 fprintf(stderr
, "ndp: %s: %s\n", host
,
531 gai_strerror(gai_error
));
534 sin
->sin6_addr
= ((struct sockaddr_in6
*)res
->ai_addr
)->sin6_addr
;
536 if (IN6_IS_ADDR_LINKLOCAL(&sin
->sin6_addr
)) {
537 *(u_int16_t
*)&sin
->sin6_addr
.s6_addr
[2] =
538 htons(((struct sockaddr_in6
*)res
->ai_addr
)->sin6_scope_id
);
541 if (rtmsg(RTM_GET
) < 0) {
545 sin
= (struct sockaddr_in6
*)(rtm
+ 1);
546 sdl
= (struct sockaddr_dl
*)(ROUNDUP(sin
->sin6_len
) + (char *)sin
);
547 if (IN6_ARE_ADDR_EQUAL(&sin
->sin6_addr
, &sin_m
.sin6_addr
)) {
548 if (sdl
->sdl_family
== AF_LINK
&&
549 (rtm
->rtm_flags
& RTF_LLINFO
) &&
550 !(rtm
->rtm_flags
& RTF_GATEWAY
)) {
554 * IPv4 arp command retries with sin_other = SIN_PROXY here.
556 fprintf(stderr
, "delete: cannot delete non-NDP entry\n");
561 if (sdl
->sdl_family
!= AF_LINK
) {
562 printf("cannot locate %s\n", host
);
565 if (rtmsg(RTM_DELETE
) == 0) {
566 struct sockaddr_in6 s6
= *sin
; /* XXX: for safety */
569 if (IN6_IS_ADDR_LINKLOCAL(&s6
.sin6_addr
)) {
570 s6
.sin6_scope_id
= ntohs(*(u_int16_t
*)&s6
.sin6_addr
.s6_addr
[2]);
571 *(u_int16_t
*)&s6
.sin6_addr
.s6_addr
[2] = 0;
574 getnameinfo((struct sockaddr
*)&s6
,
575 s6
.sin6_len
, host_buf
,
576 sizeof(host_buf
), NULL
, 0,
577 NI_WITHSCOPEID
| (nflag
? NI_NUMERICHOST
: 0));
578 printf("%s (%s) deleted\n", host
, host_buf
);
589 * Dump the entire neighbor cache
593 struct in6_addr
*addr
;
597 char *lim
, *buf
, *next
;
598 struct rt_msghdr
*rtm
;
599 struct sockaddr_in6
*sin
;
600 struct sockaddr_dl
*sdl
;
601 struct in6_nbrinfo
*nbi
;
610 if (!tflag
&& !cflag
)
611 printf("%-*.*s %-*.*s %*.*s %-9.9s %2s %4s %4s\n",
612 W_ADDR
, W_ADDR
, "Neighbor", W_LL
, W_LL
, "Linklayer Address",
613 W_IF
, W_IF
, "Netif", "Expire", "St", "Flgs", "Prbs");
620 mib
[4] = NET_RT_FLAGS
;
622 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
623 err(1, "sysctl(PF_ROUTE estimate)");
625 if ((buf
= malloc(needed
)) == NULL
)
627 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0)
628 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
633 for (next
= buf
; next
&& next
< lim
; next
+= rtm
->rtm_msglen
) {
634 int isrouter
= 0, prbs
= 0;
636 rtm
= (struct rt_msghdr
*)next
;
637 sin
= (struct sockaddr_in6
*)(rtm
+ 1);
638 sdl
= (struct sockaddr_dl
*)((char *)sin
+ ROUNDUP(sin
->sin6_len
));
641 * Some OSes can produce a route that has the LINK flag but
642 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
643 * and BSD/OS, where xx is not the interface identifier on
644 * lo0). Such routes entry would annoy getnbrinfo() below,
646 * XXX: such routes should have the GATEWAY flag, not the
647 * LINK flag. However, there are rotten routing software
648 * that advertises all routes that have the GATEWAY flag.
649 * Thus, KAME kernel intentionally does not set the LINK flag.
650 * What is to be fixed is not ndp, but such routing software
651 * (and the kernel workaround)...
653 if (sdl
->sdl_family
!= AF_LINK
)
657 if (!IN6_ARE_ADDR_EQUAL(addr
, &sin
->sin6_addr
))
660 } else if (IN6_IS_ADDR_MULTICAST(&sin
->sin6_addr
))
662 if (IN6_IS_ADDR_LINKLOCAL(&sin
->sin6_addr
) ||
663 IN6_IS_ADDR_MC_NODELOCAL(&sin
->sin6_addr
) ||
664 IN6_IS_ADDR_MC_LINKLOCAL(&sin
->sin6_addr
)) {
665 /* XXX: should scope id be filled in the kernel? */
666 if (sin
->sin6_scope_id
== 0)
667 sin
->sin6_scope_id
= sdl
->sdl_index
;
669 /* KAME specific hack; removed the embedded id */
670 *(u_int16_t
*)&sin
->sin6_addr
.s6_addr
[2] = 0;
673 getnameinfo((struct sockaddr
*)sin
, sin
->sin6_len
, host_buf
,
674 sizeof(host_buf
), NULL
, 0,
675 NI_WITHSCOPEID
| (nflag
? NI_NUMERICHOST
: 0));
678 if (rtm
->rtm_flags
& RTF_WASCLONED
)
685 gettimeofday(&time
, 0);
689 addrwidth
= strlen(host_buf
);
690 if (addrwidth
< W_ADDR
)
692 llwidth
= strlen(ether_str(sdl
));
693 if (W_ADDR
+ W_LL
- addrwidth
> llwidth
)
694 llwidth
= W_ADDR
+ W_LL
- addrwidth
;
695 ifname
= if_indextoname(sdl
->sdl_index
, ifix_buf
);
698 ifwidth
= strlen(ifname
);
699 if (W_ADDR
+ W_LL
+ W_IF
- addrwidth
- llwidth
> ifwidth
)
700 ifwidth
= W_ADDR
+ W_LL
+ W_IF
- addrwidth
- llwidth
;
702 printf("%-*.*s %-*.*s %*.*s", addrwidth
, addrwidth
, host_buf
,
703 llwidth
, llwidth
, ether_str(sdl
), ifwidth
, ifwidth
, ifname
);
705 /* Print neighbor discovery specific informations */
706 nbi
= getnbrinfo(&sin
->sin6_addr
, sdl
->sdl_index
, 1);
708 if (nbi
->expire
> time
.tv_sec
) {
710 sec2str(nbi
->expire
- time
.tv_sec
));
711 } else if (nbi
->expire
== 0)
712 printf(" %-9.9s", "permanent");
714 printf(" %-9.9s", "expired");
717 case ND6_LLINFO_NOSTATE
:
720 #ifdef ND6_LLINFO_WAITDELETE
721 case ND6_LLINFO_WAITDELETE
:
725 case ND6_LLINFO_INCOMPLETE
:
728 case ND6_LLINFO_REACHABLE
:
731 case ND6_LLINFO_STALE
:
734 case ND6_LLINFO_DELAY
:
737 case ND6_LLINFO_PROBE
:
745 isrouter
= nbi
->isrouter
;
748 warnx("failed to get neighbor information");
754 * other flags. R: router, P: proxy, W: ??
756 if ((rtm
->rtm_addrs
& RTA_NETMASK
) == 0) {
757 snprintf(flgbuf
, sizeof(flgbuf
), "%s%s",
759 (rtm
->rtm_flags
& RTF_ANNOUNCE
) ? "p" : "");
761 sin
= (struct sockaddr_in6
*)
762 (sdl
->sdl_len
+ (char *)sdl
);
763 snprintf(flgbuf
, sizeof(flgbuf
), "%s%s%s%s",
765 !IN6_IS_ADDR_UNSPECIFIED(&sin
->sin6_addr
)
767 (sin
->sin6_len
!= sizeof(struct sockaddr_in6
))
769 (rtm
->rtm_flags
& RTF_ANNOUNCE
) ? "p" : "");
771 printf(" %-4.4s", flgbuf
);
774 printf(" %4d", prbs
);
789 * Dump the entire neighbor cache (extended)
792 dump_ext(addr
, xflag
)
793 struct in6_addr
*addr
;
798 char *lim
, *buf
, *next
;
799 struct rt_msghdr_ext
*ertm
;
800 struct sockaddr_in6
*sin
;
801 struct sockaddr_dl
*sdl
;
802 struct in6_nbrinfo
*nbi
;
811 if (!tflag
&& !cflag
) {
812 printf("%-*.*s %-*.*s %*.*s %-9.9s %-9.9s %2s %4s %4s",
813 W_ADDR
, W_ADDR
, "Neighbor", W_LL
, W_LL
, "Linklayer Address",
814 W_IF
, W_IF
, "Netif", "Expire(O)", "Expire(I)", "St",
817 printf(" %-7.7s %-7.7s %-7.7s", "RSSI", "LQM", "NPM");
826 mib
[4] = NET_RT_DUMPX_FLAGS
;
828 if (sysctl(mib
, 6, NULL
, &needed
, NULL
, 0) < 0)
829 err(1, "sysctl(PF_ROUTE estimate)");
831 if ((buf
= malloc(needed
)) == NULL
)
833 if (sysctl(mib
, 6, buf
, &needed
, NULL
, 0) < 0)
834 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
839 for (next
= buf
; next
&& next
< lim
; next
+= ertm
->rtm_msglen
) {
840 int isrouter
= 0, prbs
= 0;
842 ertm
= (struct rt_msghdr_ext
*)next
;
843 sin
= (struct sockaddr_in6
*)(ertm
+ 1);
844 sdl
= (struct sockaddr_dl
*)((char *)sin
+ ROUNDUP(sin
->sin6_len
));
847 * Some OSes can produce a route that has the LINK flag but
848 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
849 * and BSD/OS, where xx is not the interface identifier on
850 * lo0). Such routes entry would annoy getnbrinfo() below,
852 * XXX: such routes should have the GATEWAY flag, not the
853 * LINK flag. However, there are rotten routing software
854 * that advertises all routes that have the GATEWAY flag.
855 * Thus, KAME kernel intentionally does not set the LINK flag.
856 * What is to be fixed is not ndp, but such routing software
857 * (and the kernel workaround)...
859 if (sdl
->sdl_family
!= AF_LINK
)
863 if (!IN6_ARE_ADDR_EQUAL(addr
, &sin
->sin6_addr
))
866 } else if (IN6_IS_ADDR_MULTICAST(&sin
->sin6_addr
))
868 if (IN6_IS_ADDR_LINKLOCAL(&sin
->sin6_addr
) ||
869 IN6_IS_ADDR_MC_NODELOCAL(&sin
->sin6_addr
) ||
870 IN6_IS_ADDR_MC_LINKLOCAL(&sin
->sin6_addr
)) {
871 /* XXX: should scope id be filled in the kernel? */
872 if (sin
->sin6_scope_id
== 0)
873 sin
->sin6_scope_id
= sdl
->sdl_index
;
875 /* KAME specific hack; removed the embedded id */
876 *(u_int16_t
*)&sin
->sin6_addr
.s6_addr
[2] = 0;
879 getnameinfo((struct sockaddr
*)sin
, sin
->sin6_len
, host_buf
,
880 sizeof(host_buf
), NULL
, 0,
881 NI_WITHSCOPEID
| (nflag
? NI_NUMERICHOST
: 0));
884 if (ertm
->rtm_flags
& RTF_WASCLONED
)
891 gettimeofday(&time
, 0);
895 addrwidth
= strlen(host_buf
);
896 if (addrwidth
< W_ADDR
)
898 llwidth
= strlen(ether_str(sdl
));
899 if (W_ADDR
+ W_LL
- addrwidth
> llwidth
)
900 llwidth
= W_ADDR
+ W_LL
- addrwidth
;
901 ifname
= if_indextoname(sdl
->sdl_index
, ifix_buf
);
904 ifwidth
= strlen(ifname
);
905 if (W_ADDR
+ W_LL
+ W_IF
- addrwidth
- llwidth
> ifwidth
)
906 ifwidth
= W_ADDR
+ W_LL
+ W_IF
- addrwidth
- llwidth
;
908 printf("%-*.*s %-*.*s %*.*s", addrwidth
, addrwidth
, host_buf
,
909 llwidth
, llwidth
, ether_str(sdl
), ifwidth
, ifwidth
, ifname
);
911 if (ertm
->rtm_ri
.ri_refcnt
== 0 ||
912 ertm
->rtm_ri
.ri_snd_expire
== 0)
913 printf(" %-9.9s", "(none)");
914 else if (ertm
->rtm_ri
.ri_snd_expire
> time
.tv_sec
)
916 sec2str(ertm
->rtm_ri
.ri_snd_expire
- time
.tv_sec
));
918 printf(" %-9.9s", "expired");
920 if (ertm
->rtm_ri
.ri_refcnt
== 0 ||
921 ertm
->rtm_ri
.ri_rcv_expire
== 0)
922 printf(" %-9.9s", "(none)");
923 else if (ertm
->rtm_ri
.ri_rcv_expire
> time
.tv_sec
)
925 sec2str(ertm
->rtm_ri
.ri_rcv_expire
- time
.tv_sec
));
927 printf(" %-9.9s", "expired");
929 /* Print neighbor discovery specific informations */
930 nbi
= getnbrinfo(&sin
->sin6_addr
, sdl
->sdl_index
, 1);
933 case ND6_LLINFO_NOSTATE
:
936 #ifdef ND6_LLINFO_WAITDELETE
937 case ND6_LLINFO_WAITDELETE
:
941 case ND6_LLINFO_INCOMPLETE
:
944 case ND6_LLINFO_REACHABLE
:
947 case ND6_LLINFO_STALE
:
950 case ND6_LLINFO_DELAY
:
953 case ND6_LLINFO_PROBE
:
961 isrouter
= nbi
->isrouter
;
964 warnx("failed to get neighbor information");
970 * other flags. R: router, P: proxy, W: ??
972 if ((ertm
->rtm_addrs
& RTA_NETMASK
) == 0) {
973 snprintf(flgbuf
, sizeof(flgbuf
), "%s%s",
975 (ertm
->rtm_flags
& RTF_ANNOUNCE
) ? "p" : "");
977 sin
= (struct sockaddr_in6
*)
978 (sdl
->sdl_len
+ (char *)sdl
);
979 snprintf(flgbuf
, sizeof(flgbuf
), "%s%s%s%s",
981 !IN6_IS_ADDR_UNSPECIFIED(&sin
->sin6_addr
)
983 (sin
->sin6_len
!= sizeof(struct sockaddr_in6
))
985 (ertm
->rtm_flags
& RTF_ANNOUNCE
) ? "p" : "");
987 printf(" %-4.4s", flgbuf
);
990 printf(" %4d", prbs
);
994 printf(" %-4.4s", "none");
996 if (ertm
->rtm_ri
.ri_rssi
!= IFNET_RSSI_UNKNOWN
)
997 printf(" %7d", ertm
->rtm_ri
.ri_rssi
);
999 printf(" %-7.7s", "unknown");
1001 switch (ertm
->rtm_ri
.ri_lqm
)
1003 case IFNET_LQM_THRESH_OFF
:
1004 printf(" %-7.7s", "off");
1006 case IFNET_LQM_THRESH_UNKNOWN
:
1007 printf(" %-7.7s", "unknown");
1009 case IFNET_LQM_THRESH_POOR
:
1010 printf(" %-7.7s", "poor");
1012 case IFNET_LQM_THRESH_GOOD
:
1013 printf(" %-7.7s", "good");
1016 printf(" %7d", ertm
->rtm_ri
.ri_lqm
);
1020 switch (ertm
->rtm_ri
.ri_npm
)
1022 case IFNET_NPM_THRESH_UNKNOWN
:
1023 printf(" %-7.7s", "unknown");
1025 case IFNET_NPM_THRESH_NEAR
:
1026 printf(" %-7.7s", "near");
1028 case IFNET_NPM_THRESH_GENERAL
:
1029 printf(" %-7.7s", "general");
1031 case IFNET_NPM_THRESH_FAR
:
1032 printf(" %-7.7s", "far");
1035 printf(" %7d", ertm
->rtm_ri
.ri_npm
);
1052 static struct in6_nbrinfo
*
1053 getnbrinfo(addr
, ifindex
, warning
)
1054 struct in6_addr
*addr
;
1058 static struct in6_nbrinfo nbi
;
1061 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0)
1064 bzero(&nbi
, sizeof(nbi
));
1065 if_indextoname(ifindex
, nbi
.ifname
);
1067 if (ioctl(s
, SIOCGNBRINFO_IN6
, (caddr_t
)&nbi
) < 0) {
1069 warn("ioctl(SIOCGNBRINFO_IN6)");
1080 struct sockaddr_dl
*sdl
;
1082 static char ebuf
[32];
1085 if (sdl
->sdl_alen
) {
1086 cp
= (u_char
*)LLADDR(sdl
);
1087 snprintf(ebuf
, sizeof(ebuf
), "%x:%x:%x:%x:%x:%x",
1088 cp
[0], cp
[1], cp
[2], cp
[3], cp
[4], cp
[5]);
1090 snprintf(ebuf
, sizeof(ebuf
), "(incomplete)");
1097 ndp_ether_aton(a
, n
)
1103 i
= sscanf(a
, "%x:%x:%x:%x:%x:%x", &o
[0], &o
[1], &o
[2],
1104 &o
[3], &o
[4], &o
[5]);
1106 fprintf(stderr
, "ndp: invalid Ethernet address '%s'\n", a
);
1117 printf("usage: ndp hostname\n");
1118 printf(" ndp -a[lnt]\n");
1119 printf(" ndp [-nt] -A wait\n");
1120 printf(" ndp -c[nt]\n");
1121 printf(" ndp -d[nt] hostname\n");
1122 printf(" ndp -f[nt] filename\n");
1123 printf(" ndp -i interface [flags...]\n");
1124 #ifdef SIOCSDEFIFACE_IN6
1125 printf(" ndp -I [interface|delete]\n");
1127 printf(" ndp -p\n");
1128 printf(" ndp -r\n");
1129 printf(" ndp -s hostname ether_addr [temp] [proxy]\n");
1130 printf(" ndp -H\n");
1131 printf(" ndp -P\n");
1132 printf(" ndp -R\n");
1142 register struct rt_msghdr
*rtm
= &m_rtmsg
.m_rtm
;
1143 register char *cp
= m_rtmsg
.m_space
;
1147 if (cmd
== RTM_DELETE
)
1149 bzero((char *)&m_rtmsg
, sizeof(m_rtmsg
));
1150 rtm
->rtm_flags
= flags
;
1151 rtm
->rtm_version
= RTM_VERSION
;
1155 fprintf(stderr
, "ndp: internal wrong cmd\n");
1158 rtm
->rtm_addrs
|= RTA_GATEWAY
;
1159 rtm
->rtm_rmx
.rmx_expire
= expire_time
;
1160 rtm
->rtm_inits
= RTV_EXPIRE
;
1161 rtm
->rtm_flags
|= (RTF_HOST
| RTF_STATIC
);
1162 if (rtm
->rtm_flags
& RTF_ANNOUNCE
) {
1163 rtm
->rtm_flags
&= ~RTF_HOST
;
1164 rtm
->rtm_flags
|= RTA_NETMASK
;
1168 rtm
->rtm_addrs
|= RTA_DST
;
1170 #define NEXTADDR(w, s) \
1171 if (rtm->rtm_addrs & (w)) { \
1172 bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);}
1174 NEXTADDR(RTA_DST
, sin_m
);
1175 NEXTADDR(RTA_GATEWAY
, sdl_m
);
1176 memset(&so_mask
.sin6_addr
, 0xff, sizeof(so_mask
.sin6_addr
));
1177 NEXTADDR(RTA_NETMASK
, so_mask
);
1179 rtm
->rtm_msglen
= cp
- (char *)&m_rtmsg
;
1181 l
= rtm
->rtm_msglen
;
1182 rtm
->rtm_seq
= ++seq
;
1183 rtm
->rtm_type
= cmd
;
1184 if ((rlen
= write(s
, (char *)&m_rtmsg
, l
)) < 0) {
1185 if (errno
!= ESRCH
|| cmd
!= RTM_DELETE
) {
1186 perror("writing to routing socket");
1191 l
= read(s
, (char *)&m_rtmsg
, sizeof(m_rtmsg
));
1192 } while (l
> 0 && (rtm
->rtm_seq
!= seq
|| rtm
->rtm_pid
!= pid
));
1194 (void) fprintf(stderr
, "ndp: read from routing socket: %s\n",
1204 struct in6_ndireq nd
;
1206 char *ifname
= argv
[0];
1208 #ifdef IPV6CTL_USETEMPADDR
1209 u_int8_t nullbuf
[8];
1212 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
1213 perror("ndp: socket");
1216 bzero(&nd
, sizeof(nd
));
1217 strlcpy(nd
.ifname
, ifname
, sizeof(nd
.ifname
));
1218 if (ioctl(s
, SIOCGIFINFO_IN6
, (caddr_t
)&nd
) < 0) {
1219 perror("ioctl (SIOCGIFINFO_IN6)");
1223 newflags
= ND
.flags
;
1224 for (i
= 1; i
< argc
; i
++) {
1233 #define SETFLAG(s, f) \
1235 if (strcmp(cp, (s)) == 0) {\
1242 SETFLAG("nud", ND6_IFF_PERFORMNUD
);
1243 SETFLAG("proxy_prefixes", ND6_IFF_PROXY_PREFIXES
);
1244 SETFLAG("ignore_na", ND6_IFF_IGNORE_NA
);
1246 ND
.flags
= newflags
;
1247 if (ioctl(s
, SIOCSIFINFO_FLAGS
, (caddr_t
)&nd
) < 0) {
1248 perror("ioctl(SIOCSIFINFO_FLAGS)");
1254 printf("linkmtu=%d", ND
.linkmtu
);
1255 printf(", curhlim=%d", ND
.chlim
);
1256 printf(", basereachable=%ds%dms",
1257 ND
.basereachable
/ 1000, ND
.basereachable
% 1000);
1258 printf(", reachable=%ds", ND
.reachable
);
1259 printf(", retrans=%ds%dms", ND
.retrans
/ 1000, ND
.retrans
% 1000);
1260 #ifdef IPV6CTL_USETEMPADDR
1261 memset(nullbuf
, 0, sizeof(nullbuf
));
1262 if (memcmp(nullbuf
, ND
.randomid
, sizeof(nullbuf
)) != 0) {
1264 u_int8_t
*rbuf
= NULL
;
1266 for (i
= 0; i
< 3; i
++) {
1269 printf("\nRandom seed(0): ");
1270 rbuf
= ND
.randomseed0
;
1273 printf("\nRandom seed(1): ");
1274 rbuf
= ND
.randomseed1
;
1277 printf("\nRandom ID: ");
1281 for (j
= 0; j
< 8; j
++)
1282 printf("%02x", rbuf
[j
]);
1287 printf("\nFlags: ");
1288 if ((ND
.flags
& ND6_IFF_PERFORMNUD
) != 0)
1289 printf("PERFORMNUD ");
1290 if ((ND
.flags
& ND6_IFF_PROXY_PREFIXES
) != 0)
1291 printf("PROXY_PREFIXES ");
1292 if ((ND
.flags
& ND6_IFF_IFDISABLED
) != 0)
1293 printf("IFDISABLED ");
1294 if ((ND
.flags
& ND6_IFF_IGNORE_NA
) != 0)
1295 printf("IGNORE_NA ");
1303 #ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */
1304 #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
1310 #ifdef ICMPV6CTL_ND6_DRLIST
1311 int mib
[] = { CTL_NET
, PF_INET6
, IPPROTO_ICMPV6
, ICMPV6CTL_ND6_DRLIST
};
1313 struct in6_defrouter
*p
, *ep
;
1315 struct timeval time
;
1317 if (sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), NULL
, &l
, NULL
, 0) < 0) {
1318 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
1323 errx(1, "not enough core");
1326 if (sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), buf
, &l
, NULL
, 0) < 0) {
1327 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
1331 ep
= (struct in6_defrouter
*)(buf
+ l
);
1332 for (p
= (struct in6_defrouter
*)buf
; p
< ep
; p
++) {
1335 if (getnameinfo((struct sockaddr
*)&p
->rtaddr
,
1336 p
->rtaddr
.sin6_len
, host_buf
, sizeof(host_buf
), NULL
, 0,
1337 NI_WITHSCOPEID
| (nflag
? NI_NUMERICHOST
: 0)) != 0)
1338 strlcpy(host_buf
, "?", sizeof(host_buf
));
1340 printf("%s if=%s", host_buf
,
1341 if_indextoname(p
->if_index
, ifix_buf
));
1342 printf(", flags=%s%s%s%s%s",
1343 p
->flags
& ND_RA_FLAG_MANAGED
? "M" : "",
1344 p
->flags
& ND_RA_FLAG_OTHER
? "O" : "",
1345 p
->stateflags
& NDDRF_INSTALLED
? "T" : "",
1346 p
->stateflags
& NDDRF_IFSCOPE
? "I" : "",
1347 p
->stateflags
& NDDRF_STATIC
? "S" : "");
1348 rtpref
= ((p
->flags
& ND_RA_FLAG_RTPREF_MASK
) >> 3) & 0xff;
1349 printf(", pref=%s", rtpref_str
[rtpref
]);
1351 gettimeofday(&time
, 0);
1353 printf(", expire=Never\n");
1355 printf(", expire=%s\n",
1356 sec2str(p
->expire
- time
.tv_sec
));
1360 struct in6_drlist dr
;
1362 struct timeval time
;
1364 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
1365 perror("ndp: socket");
1368 bzero(&dr
, sizeof(dr
));
1369 strlcpy(dr
.ifname
, "lo0", sizeof(dr
.ifname
)); /* dummy */
1370 if (ioctl(s
, SIOCGDRLST_IN6
, (caddr_t
)&dr
) < 0) {
1371 perror("ioctl (SIOCGDRLST_IN6)");
1374 #define DR dr.defrouter[i]
1375 for (i
= 0 ; DR
.if_index
&& i
< DRLSTSIZ
; i
++) {
1376 struct sockaddr_in6 sin6
;
1378 bzero(&sin6
, sizeof(sin6
));
1379 sin6
.sin6_family
= AF_INET6
;
1380 sin6
.sin6_len
= sizeof(sin6
);
1381 sin6
.sin6_addr
= DR
.rtaddr
;
1382 getnameinfo((struct sockaddr
*)&sin6
, sin6
.sin6_len
, host_buf
,
1383 sizeof(host_buf
), NULL
, 0,
1384 NI_WITHSCOPEID
| (nflag
? NI_NUMERICHOST
: 0));
1386 printf("%s if=%s", host_buf
,
1387 if_indextoname(DR
.if_index
, ifix_buf
));
1388 printf(", flags=%s%s",
1389 DR
.flags
& ND_RA_FLAG_MANAGED
? "M" : "",
1390 DR
.flags
& ND_RA_FLAG_OTHER
? "O" : "");
1391 gettimeofday(&time
, 0);
1393 printf(", expire=Never\n");
1395 printf(", expire=%s\n",
1396 sec2str(DR
.expire
- time
.tv_sec
));
1406 #ifdef ICMPV6CTL_ND6_PRLIST
1407 int mib
[] = { CTL_NET
, PF_INET6
, IPPROTO_ICMPV6
, ICMPV6CTL_ND6_PRLIST
};
1409 struct in6_prefix
*p
, *ep
, *n
;
1410 struct sockaddr_in6
*advrtr
;
1412 struct timeval time
;
1413 #ifdef NI_WITHSCOPEID
1414 const int niflags
= NI_NUMERICHOST
| NI_WITHSCOPEID
;
1415 int ninflags
= (nflag
? NI_NUMERICHOST
: 0) | NI_WITHSCOPEID
;
1417 const int niflags
= NI_NUMERICHOST
;
1418 int ninflags
= nflag
? NI_NUMERICHOST
: 0;
1420 char namebuf
[NI_MAXHOST
];
1422 if (sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), NULL
, &l
, NULL
, 0) < 0) {
1423 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
1428 errx(1, "not enough core");
1431 if (sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), buf
, &l
, NULL
, 0) < 0) {
1432 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
1436 ep
= (struct in6_prefix
*)(buf
+ l
);
1437 for (p
= (struct in6_prefix
*)buf
; p
< ep
; p
= n
) {
1438 advrtr
= (struct sockaddr_in6
*)(p
+ 1);
1439 n
= (struct in6_prefix
*)&advrtr
[p
->advrtrs
];
1441 if (getnameinfo((struct sockaddr
*)&p
->prefix
,
1442 p
->prefix
.sin6_len
, namebuf
, sizeof(namebuf
),
1443 NULL
, 0, niflags
) != 0)
1444 strlcpy(namebuf
, "?", sizeof(namebuf
));
1445 printf("%s/%d if=%s\n", namebuf
, p
->prefixlen
,
1446 if_indextoname(p
->if_index
, ifix_buf
));
1448 gettimeofday(&time
, 0);
1450 * meaning of fields, especially flags, is very different
1451 * by origin. notify the difference to the users.
1453 printf("flags=%s%s%s%s%s%s%s%s",
1454 p
->raflags
.onlink
? "L" : "",
1455 p
->raflags
.autonomous
? "A" : "",
1456 (p
->flags
& NDPRF_ONLINK
) != 0 ? "O" : "",
1457 (p
->flags
& NDPRF_DETACHED
) != 0 ? "D" : "",
1458 (p
->flags
& NDPRF_IFSCOPE
) != 0 ? "I" : "",
1459 (p
->flags
& NDPRF_PRPROXY
) != 0 ? "Y" : "",
1461 (p
->flags
& NDPRF_HOME
) != 0 ? "H" : "",
1466 (p
->flags
& NDPRF_STATIC
) != 0 ? "S" : ""
1471 if (p
->vltime
== ND6_INFINITE_LIFETIME
)
1472 printf(" vltime=infinity");
1474 printf(" vltime=%ld", (long)p
->vltime
);
1475 if (p
->pltime
== ND6_INFINITE_LIFETIME
)
1476 printf(", pltime=infinity");
1478 printf(", pltime=%ld", (long)p
->pltime
);
1480 printf(", expire=Never");
1481 else if (p
->expire
>= time
.tv_sec
)
1482 printf(", expire=%s",
1483 sec2str(p
->expire
- time
.tv_sec
));
1485 printf(", expired");
1486 printf(", ref=%d", p
->refcnt
);
1489 * "advertising router" list is meaningful only if the prefix
1490 * information is from RA.
1494 struct sockaddr_in6
*sin6
;
1496 sin6
= (struct sockaddr_in6
*)(p
+ 1);
1497 printf(" advertised by\n");
1498 for (j
= 0; j
< p
->advrtrs
; j
++) {
1499 struct in6_nbrinfo
*nbi
;
1501 if (getnameinfo((struct sockaddr
*)sin6
,
1502 sin6
->sin6_len
, namebuf
, sizeof(namebuf
),
1503 NULL
, 0, ninflags
) != 0)
1504 strlcpy(namebuf
, "?", sizeof(namebuf
));
1505 printf(" %s", namebuf
);
1507 nbi
= getnbrinfo(&sin6
->sin6_addr
, p
->if_index
,
1510 switch(nbi
->state
) {
1511 case ND6_LLINFO_REACHABLE
:
1512 case ND6_LLINFO_STALE
:
1513 case ND6_LLINFO_DELAY
:
1514 case ND6_LLINFO_PROBE
:
1515 printf(" (reachable)\n");
1518 printf(" (unreachable)\n");
1521 printf(" (no neighbor state)\n");
1525 printf(" No advertising router\n");
1529 struct in6_prlist pr
;
1531 struct timeval time
;
1533 gettimeofday(&time
, 0);
1535 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0) {
1536 perror("ndp: socket");
1539 bzero(&pr
, sizeof(pr
));
1540 strlcpy(pr
.ifname
, "lo0", sizeof(pr
.ifname
)); /* dummy */
1541 if (ioctl(s
, SIOCGPRLST_IN6
, (caddr_t
)&pr
) < 0) {
1542 perror("ioctl (SIOCGPRLST_IN6)");
1545 #define PR pr.prefix[i]
1546 for (i
= 0; PR
.if_index
&& i
< PRLSTSIZ
; i
++) {
1547 struct sockaddr_in6 p6
;
1548 char namebuf
[NI_MAXHOST
];
1554 memset(&p6
, 0, sizeof(p6
));
1555 p6
.sin6_family
= AF_INET6
;
1556 p6
.sin6_len
= sizeof(p6
);
1557 p6
.sin6_addr
= PR
.prefix
;
1561 * copy link index to sin6_scope_id field.
1562 * XXX: KAME specific.
1564 if (IN6_IS_ADDR_LINKLOCAL(&p6
.sin6_addr
)) {
1567 memcpy(&linkid
, &p6
.sin6_addr
.s6_addr
[2],
1569 linkid
= ntohs(linkid
);
1570 p6
.sin6_scope_id
= linkid
;
1571 p6
.sin6_addr
.s6_addr
[2] = 0;
1572 p6
.sin6_addr
.s6_addr
[3] = 0;
1575 niflags
= NI_NUMERICHOST
;
1577 niflags
|= NI_WITHSCOPEID
;
1579 if (getnameinfo((struct sockaddr
*)&p6
,
1580 sizeof(p6
), namebuf
, sizeof(namebuf
),
1581 NULL
, 0, niflags
)) {
1582 warnx("getnameinfo failed");
1585 printf("%s/%d if=%s\n", namebuf
, PR
.prefixlen
,
1586 if_indextoname(PR
.if_index
, ifix_buf
));
1588 gettimeofday(&time
, 0);
1590 * meaning of fields, especially flags, is very different
1591 * by origin. notify the difference to the users.
1595 PR
.origin
== PR_ORIG_RA
? "" : "advertise: ");
1598 printf("flags=%s%s%s%s%s",
1599 PR
.raflags
.onlink
? "L" : "",
1600 PR
.raflags
.autonomous
? "A" : "",
1601 (PR
.flags
& NDPRF_ONLINK
) != 0 ? "O" : "",
1602 (PR
.flags
& NDPRF_DETACHED
) != 0 ? "D" : "",
1604 (PR
.flags
& NDPRF_HOME
) != 0 ? "H" : ""
1610 printf("flags=%s%s",
1611 PR
.raflags
.onlink
? "L" : "",
1612 PR
.raflags
.autonomous
? "A" : "");
1614 if (PR
.vltime
== ND6_INFINITE_LIFETIME
)
1615 printf(" vltime=infinity");
1617 printf(" vltime=%ld", (long)PR
.vltime
);
1618 if (PR
.pltime
== ND6_INFINITE_LIFETIME
)
1619 printf(", pltime=infinity");
1621 printf(", pltime=%ld", (long)PR
.pltime
);
1623 printf(", expire=Never");
1624 else if (PR
.expire
>= time
.tv_sec
)
1625 printf(", expire=%s",
1626 sec2str(PR
.expire
- time
.tv_sec
));
1628 printf(", expired");
1630 printf(", ref=%d", PR
.refcnt
);
1633 switch (PR
.origin
) {
1635 printf(", origin=RA");
1638 printf(", origin=RR");
1640 case PR_ORIG_STATIC
:
1641 printf(", origin=static");
1643 case PR_ORIG_KERNEL
:
1644 printf(", origin=kernel");
1647 printf(", origin=?");
1653 * "advertising router" list is meaningful only if the prefix
1654 * information is from RA.
1656 if (0 && /* prefix origin is almost obsolted */
1657 PR
.origin
!= PR_ORIG_RA
)
1659 else if (PR
.advrtrs
) {
1661 printf(" advertised by\n");
1662 for (j
= 0; j
< PR
.advrtrs
; j
++) {
1663 struct sockaddr_in6 sin6
;
1664 struct in6_nbrinfo
*nbi
;
1666 bzero(&sin6
, sizeof(sin6
));
1667 sin6
.sin6_family
= AF_INET6
;
1668 sin6
.sin6_len
= sizeof(sin6
);
1669 sin6
.sin6_addr
= PR
.advrtr
[j
];
1670 sin6
.sin6_scope_id
= PR
.if_index
; /* XXX */
1671 getnameinfo((struct sockaddr
*)&sin6
,
1672 sin6
.sin6_len
, host_buf
,
1673 sizeof(host_buf
), NULL
, 0,
1674 NI_WITHSCOPEID
| (nflag
? NI_NUMERICHOST
: 0));
1675 printf(" %s", host_buf
);
1677 nbi
= getnbrinfo(&sin6
.sin6_addr
, PR
.if_index
,
1680 switch(nbi
->state
) {
1681 case ND6_LLINFO_REACHABLE
:
1682 case ND6_LLINFO_STALE
:
1683 case ND6_LLINFO_DELAY
:
1684 case ND6_LLINFO_PROBE
:
1685 printf(" (reachable)\n");
1688 printf(" (unreachable)\n");
1691 printf(" (no neighbor state)\n");
1693 if (PR
.advrtrs
> DRLSTSIZ
)
1694 printf(" and %d routers\n",
1695 PR
.advrtrs
- DRLSTSIZ
);
1697 printf(" No advertising router\n");
1707 char dummyif
[IFNAMSIZ
+8];
1710 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0)
1712 strlcpy(dummyif
, "lo0", sizeof(dummyif
)); /* dummy */
1713 if (ioctl(s
, SIOCSPFXFLUSH_IN6
, (caddr_t
)&dummyif
) < 0)
1714 err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
1720 char dummyif
[IFNAMSIZ
+8];
1723 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0)
1725 strlcpy(dummyif
, "lo0", sizeof(dummyif
)); /* dummy */
1726 if (ioctl(s
, SIOCSRTRFLUSH_IN6
, (caddr_t
)&dummyif
) < 0)
1727 err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
1735 char dummyif
[IFNAMSIZ
+8];
1738 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0)
1740 strlcpy(dummyif
, "lo0", sizeof(dummyif
)); /* dummy */
1741 if (ioctl(s
, SIOCSNDFLUSH_IN6
, (caddr_t
)&dummyif
) < 0)
1742 err(1, "ioctl (SIOCSNDFLUSH_IN6)");
1747 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */
1752 struct in6_ndifreq ndifreq
;
1753 unsigned int ifindex
;
1755 if (strcasecmp(ifname
, "delete") == 0)
1758 if ((ifindex
= if_nametoindex(ifname
)) == 0)
1759 err(1, "failed to resolve i/f index for %s", ifname
);
1762 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0)
1765 strlcpy(ndifreq
.ifname
, "lo0", sizeof(ndifreq
.ifname
)); /* dummy */
1766 ndifreq
.ifindex
= ifindex
;
1768 if (ioctl(s
, SIOCSDEFIFACE_IN6
, (caddr_t
)&ndifreq
) < 0)
1769 err(1, "ioctl (SIOCSDEFIFACE_IN6)");
1777 struct in6_ndifreq ndifreq
;
1778 char ifname
[IFNAMSIZ
+8];
1780 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0)
1783 memset(&ndifreq
, 0, sizeof(ndifreq
));
1784 strlcpy(ndifreq
.ifname
, "lo0", sizeof(ndifreq
.ifname
)); /* dummy */
1786 if (ioctl(s
, SIOCGDEFIFACE_IN6
, (caddr_t
)&ndifreq
) < 0)
1787 err(1, "ioctl (SIOCGDEFIFACE_IN6)");
1789 if (ndifreq
.ifindex
== 0)
1790 printf("No default interface.\n");
1792 if ((if_indextoname(ndifreq
.ifindex
, ifname
)) == NULL
)
1793 err(1, "failed to resolve ifname for index %lu",
1795 printf("ND default interface = %s\n", ifname
);
1806 static char result
[256];
1807 int days
, hours
, mins
, secs
;
1811 days
= total
/ 3600 / 24;
1812 hours
= (total
/ 3600) % 24;
1813 mins
= (total
/ 60) % 60;
1818 p
+= snprintf(p
, sizeof(result
) - (p
- result
), "%dd", days
);
1820 if (!first
|| hours
) {
1822 p
+= snprintf(p
, sizeof(result
) - (p
- result
), "%dh", hours
);
1824 if (!first
|| mins
) {
1826 p
+= snprintf(p
, sizeof(result
) - (p
- result
), "%dm", mins
);
1828 snprintf(p
, sizeof(result
) - (p
- result
), "%ds", secs
);
1834 * Print the timestamp
1835 * from tcpdump/util.c
1839 const struct timeval
*tvp
;
1844 s
= (tvp
->tv_sec
+ thiszone
) % 86400;
1845 (void)printf("%02d:%02d:%02d.%06u ",
1846 s
/ 3600, (s
% 3600) / 60, s
% 60, (u_int32_t
)tvp
->tv_usec
);