]> git.saurik.com Git - apple/network_cmds.git/blob - ndp.tproj/ndp.c
76770171c26164fe2934f3b6122a005d970f44a9
[apple/network_cmds.git] / ndp.tproj / ndp.c
1 /*
2 * Copyright (c) 2009-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /* $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 $ */
31
32 /*
33 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
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.
47 *
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
58 * SUCH DAMAGE.
59 */
60 /*
61 * Copyright (c) 1984, 1993
62 * The Regents of the University of California. All rights reserved.
63 *
64 * This code is derived from software contributed to Berkeley by
65 * Sun Microsystems, Inc.
66 *
67 * Redistribution and use in source and binary forms, with or without
68 * modification, are permitted provided that the following conditions
69 * are met:
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.
82 *
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
93 * SUCH DAMAGE.
94 */
95
96 /*
97 * Based on:
98 * "@(#) Copyright (c) 1984, 1993\n\
99 * The Regents of the University of California. All rights reserved.\n";
100 *
101 * "@(#)arp.c 8.2 (Berkeley) 1/2/94";
102 */
103
104 /*
105 * ndp - display, set, delete and flush neighbor cache
106 */
107
108 #include <stdint.h>
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>
116
117 #include <net/if.h>
118 #include <net/if_var.h>
119 #include <net/if_dl.h>
120 #include <net/if_types.h>
121 #include <net/route.h>
122
123 #include <netinet/in.h>
124 #include <netinet/if_ether.h>
125
126 #include <netinet/icmp6.h>
127 #include <netinet6/in6_var.h>
128 #include <netinet6/nd6.h>
129
130 #include <arpa/inet.h>
131
132 #include <netdb.h>
133 #include <errno.h>
134 #include <nlist.h>
135 #include <stdio.h>
136 #include <string.h>
137 #include <paths.h>
138 #include <err.h>
139 #include <stdlib.h>
140 #include <fcntl.h>
141 #include <unistd.h>
142 //#include "gmt2local.h"
143
144 #ifndef NI_WITHSCOPEID
145 #define NI_WITHSCOPEID 0
146 #endif
147
148 /* packing rule for routing socket */
149 #define ROUNDUP(a) \
150 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
151 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
152
153 static int pid;
154 static int cflag;
155 static int nflag;
156 static int tflag;
157 static int32_t thiszone =0 ; /* time difference with gmt */
158 static int s = -1;
159 static int repeat = 0;
160
161 char ntop_buf[INET6_ADDRSTRLEN]; /* inet_ntop() */
162 char host_buf[NI_MAXHOST]; /* getnameinfo() */
163 char ifix_buf[IFNAMSIZ]; /* if_indextoname() */
164
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,
174 int ifindex, int));
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 *));
189 #endif
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 *));
193
194 static char *rtpref_str[] = {
195 "medium", /* 00 */
196 "high", /* 01 */
197 "rsv", /* 10 */
198 "low" /* 11 */
199 };
200
201 int
202 main(argc, argv)
203 int argc;
204 char **argv;
205 {
206 int ch;
207 int aflag = 0, dflag = 0, sflag = 0, Hflag = 0,
208 pflag = 0, rflag = 0, Pflag = 0, Rflag = 0, lflag = 0,
209 xflag = 0;
210
211 pid = getpid();
212 // thiszone = gmt2local(0);
213 while ((ch = getopt(argc, argv, "acndfIilprstA:HPRx")) != -1)
214 switch ((char)ch) {
215 case 'a':
216 aflag = 1;
217 break;
218 case 'c':
219 cflag = 1;
220 break;
221 case 'd':
222 dflag = 1;
223 break;
224 case 'I':
225 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */
226 if (argc > 2)
227 setdefif(argv[2]);
228 getdefif(); /* always call it to print the result */
229 exit(0);
230 #else
231 errx(1, "not supported yet");
232 /*NOTREACHED*/
233 #endif
234 case 'i' :
235 argc -= optind;
236 argv += optind;
237 if (argc < 1)
238 usage();
239 ifinfo(argc, argv);
240 exit(0);
241 case 'n':
242 nflag = 1;
243 continue;
244 case 'p':
245 pflag = 1;
246 break;
247 case 'f' :
248 if (argc != 3)
249 usage();
250 file(argv[2]);
251 exit(0);
252 case 'l' :
253 lflag = 1;
254 break;
255 case 'r' :
256 rflag = 1;
257 break;
258 case 's':
259 sflag = 1;
260 break;
261 case 't':
262 tflag = 1;
263 break;
264 case 'A':
265 aflag = 1;
266 repeat = atoi(optarg);
267 if (repeat < 0)
268 usage();
269 break;
270 case 'H' :
271 Hflag = 1;
272 break;
273 case 'P':
274 Pflag = 1;
275 break;
276 case 'R':
277 Rflag = 1;
278 break;
279 case 'x':
280 xflag = 1;
281 lflag = 1;
282 break;
283 default:
284 usage();
285 }
286
287 argc -= optind;
288 argv += optind;
289
290 if (aflag || cflag) {
291 if (lflag)
292 dump_ext(0, xflag);
293 else
294 dump(0);
295 exit(0);
296 }
297 if (dflag) {
298 if (argc != 1)
299 usage();
300 delete(argv[0]);
301 exit(0);
302 }
303 if (pflag) {
304 plist();
305 exit(0);
306 }
307 if (rflag) {
308 rtrlist();
309 exit(0);
310 }
311 if (sflag) {
312 if (argc < 2 || argc > 4)
313 usage();
314 exit(set(argc, argv) ? 1 : 0);
315 }
316 if (Hflag) {
317 harmonize_rtr();
318 exit(0);
319 }
320 if (Pflag) {
321 pfx_flush();
322 exit(0);
323 }
324 if (Rflag) {
325 rtr_flush();
326 exit(0);
327 }
328
329 if (argc != 1)
330 usage();
331 get(argv[0]);
332 exit(0);
333 }
334
335 /*
336 * Process a file to set standard ndp entries
337 */
338 int
339 file(name)
340 char *name;
341 {
342 FILE *fp;
343 int i, retval;
344 char line[100], arg[5][50], *args[5];
345
346 if ((fp = fopen(name, "r")) == NULL) {
347 fprintf(stderr, "ndp: cannot open %s\n", name);
348 exit(1);
349 }
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];
355 retval = 0;
356 while(fgets(line, 100, fp) != NULL) {
357 i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
358 arg[3], arg[4]);
359 if (i < 2) {
360 fprintf(stderr, "ndp: bad line: %s\n", line);
361 retval = 1;
362 continue;
363 }
364 if (set(i, args))
365 retval = 1;
366 }
367 fclose(fp);
368 return (retval);
369 }
370
371 void
372 getsocket()
373 {
374 if (s < 0) {
375 s = socket(PF_ROUTE, SOCK_RAW, 0);
376 if (s < 0) {
377 perror("ndp: socket");
378 exit(1);
379 }
380 }
381 }
382
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;
387 struct {
388 struct rt_msghdr m_rtm;
389 char m_space[512];
390 } m_rtmsg;
391
392 /*
393 * Set an individual neighbor cache entry
394 */
395 int
396 set(argc, argv)
397 int argc;
398 char **argv;
399 {
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;
404 int gai_error;
405 u_char *ea;
406 char *host = argv[0], *eaddr = argv[1];
407
408 getsocket();
409 argc -= 2;
410 argv += 2;
411 sdl_m = blank_sdl;
412 sin_m = blank_sin;
413
414 bzero(&hints, sizeof(hints));
415 hints.ai_family = AF_INET6;
416 gai_error = getaddrinfo(host, NULL, &hints, &res);
417 if (gai_error) {
418 fprintf(stderr, "ndp: %s: %s\n", host,
419 gai_strerror(gai_error));
420 return 1;
421 }
422 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
423 #ifdef __KAME__
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);
427 }
428 #endif
429 ea = (u_char *)LLADDR(&sdl_m);
430 if (ndp_ether_aton(eaddr, ea) == 0)
431 sdl_m.sdl_alen = 6;
432 flags = expire_time = 0;
433 while (argc-- > 0) {
434 if (strncmp(argv[0], "temp", 4) == 0) {
435 struct timeval time;
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;
440 argv++;
441 }
442 if (rtmsg(RTM_GET) < 0) {
443 perror(host);
444 return (1);
445 }
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:
454 goto overwrite;
455 }
456 /*
457 * IPv4 arp command retries with sin_other = SIN_PROXY here.
458 */
459 fprintf(stderr, "set: cannot configure a new entry\n");
460 return 1;
461 }
462
463 overwrite:
464 if (sdl->sdl_family != AF_LINK) {
465 printf("cannot intuit interface index and type for %s\n", host);
466 return (1);
467 }
468 sdl_m.sdl_type = sdl->sdl_type;
469 sdl_m.sdl_index = sdl->sdl_index;
470 return (rtmsg(RTM_ADD));
471 }
472
473 /*
474 * Display an individual neighbor cache entry
475 */
476 void
477 get(host)
478 char *host;
479 {
480 struct sockaddr_in6 *sin = &sin_m;
481 struct addrinfo hints, *res;
482 int gai_error;
483
484 sin_m = blank_sin;
485 bzero(&hints, sizeof(hints));
486 hints.ai_family = AF_INET6;
487 gai_error = getaddrinfo(host, NULL, &hints, &res);
488 if (gai_error) {
489 fprintf(stderr, "ndp: %s: %s\n", host,
490 gai_strerror(gai_error));
491 return;
492 }
493 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
494 #ifdef __KAME__
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);
498 }
499 #endif
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);
506 exit(1);
507 }
508 }
509
510 /*
511 * Delete a neighbor cache entry
512 */
513 int
514 delete(host)
515 char *host;
516 {
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;
521 int gai_error;
522
523 getsocket();
524 sin_m = blank_sin;
525
526 bzero(&hints, sizeof(hints));
527 hints.ai_family = AF_INET6;
528 gai_error = getaddrinfo(host, NULL, &hints, &res);
529 if (gai_error) {
530 fprintf(stderr, "ndp: %s: %s\n", host,
531 gai_strerror(gai_error));
532 return 1;
533 }
534 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
535 #ifdef __KAME__
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);
539 }
540 #endif
541 if (rtmsg(RTM_GET) < 0) {
542 perror(host);
543 return (1);
544 }
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)) {
551 goto delete;
552 }
553 /*
554 * IPv4 arp command retries with sin_other = SIN_PROXY here.
555 */
556 fprintf(stderr, "delete: cannot delete non-NDP entry\n");
557 return 1;
558 }
559
560 delete:
561 if (sdl->sdl_family != AF_LINK) {
562 printf("cannot locate %s\n", host);
563 return (1);
564 }
565 if (rtmsg(RTM_DELETE) == 0) {
566 struct sockaddr_in6 s6 = *sin; /* XXX: for safety */
567
568 #ifdef __KAME__
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;
572 }
573 #endif
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);
579 }
580
581 return 0;
582 }
583
584 #define W_ADDR 31
585 #define W_LL 17
586 #define W_IF 6
587
588 /*
589 * Dump the entire neighbor cache
590 */
591 void
592 dump(addr)
593 struct in6_addr *addr;
594 {
595 int mib[6];
596 size_t needed;
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;
602 struct timeval time;
603 int addrwidth;
604 int llwidth;
605 int ifwidth;
606 char flgbuf[8];
607 char *ifname;
608
609 /* Print header */
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");
614
615 again:;
616 mib[0] = CTL_NET;
617 mib[1] = PF_ROUTE;
618 mib[2] = 0;
619 mib[3] = AF_INET6;
620 mib[4] = NET_RT_FLAGS;
621 mib[5] = RTF_LLINFO;
622 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
623 err(1, "sysctl(PF_ROUTE estimate)");
624 if (needed > 0) {
625 if ((buf = malloc(needed)) == NULL)
626 errx(1, "malloc");
627 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
628 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
629 lim = buf + needed;
630 } else
631 buf = lim = NULL;
632
633 for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
634 int isrouter = 0, prbs = 0;
635
636 rtm = (struct rt_msghdr *)next;
637 sin = (struct sockaddr_in6 *)(rtm + 1);
638 sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len));
639
640 /*
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,
645 * so we skip them.
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)...
652 */
653 if (sdl->sdl_family != AF_LINK)
654 continue;
655
656 if (addr) {
657 if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
658 continue;
659 found_entry = 1;
660 } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
661 continue;
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;
668 #ifdef __KAME__
669 /* KAME specific hack; removed the embedded id */
670 *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
671 #endif
672 }
673 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
674 sizeof(host_buf), NULL, 0,
675 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
676 if (cflag == 1) {
677 #ifdef RTF_WASCLONED
678 if (rtm->rtm_flags & RTF_WASCLONED)
679 delete(host_buf);
680 #else
681 delete(host_buf);
682 #endif
683 continue;
684 }
685 gettimeofday(&time, 0);
686 if (tflag)
687 ts_print(&time);
688
689 addrwidth = strlen(host_buf);
690 if (addrwidth < W_ADDR)
691 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);
696 if (!ifname)
697 ifname = "?";
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;
701
702 printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
703 llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
704
705 /* Print neighbor discovery specific informations */
706 nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
707 if (nbi) {
708 if (nbi->expire > time.tv_sec) {
709 printf(" %-9.9s",
710 sec2str(nbi->expire - time.tv_sec));
711 } else if (nbi->expire == 0)
712 printf(" %-9.9s", "permanent");
713 else
714 printf(" %-9.9s", "expired");
715
716 switch(nbi->state) {
717 case ND6_LLINFO_NOSTATE:
718 printf(" N");
719 break;
720 #ifdef ND6_LLINFO_WAITDELETE
721 case ND6_LLINFO_WAITDELETE:
722 printf(" W");
723 break;
724 #endif
725 case ND6_LLINFO_INCOMPLETE:
726 printf(" I");
727 break;
728 case ND6_LLINFO_REACHABLE:
729 printf(" R");
730 break;
731 case ND6_LLINFO_STALE:
732 printf(" S");
733 break;
734 case ND6_LLINFO_DELAY:
735 printf(" D");
736 break;
737 case ND6_LLINFO_PROBE:
738 printf(" P");
739 break;
740 default:
741 printf(" ?");
742 break;
743 }
744
745 isrouter = nbi->isrouter;
746 prbs = nbi->asked;
747 } else {
748 warnx("failed to get neighbor information");
749 printf(" ");
750 }
751 putchar(' ');
752
753 /*
754 * other flags. R: router, P: proxy, W: ??
755 */
756 if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
757 snprintf(flgbuf, sizeof(flgbuf), "%s%s",
758 isrouter ? "R" : "",
759 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
760 } else {
761 sin = (struct sockaddr_in6 *)
762 (sdl->sdl_len + (char *)sdl);
763 snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s",
764 isrouter ? "R" : "",
765 !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)
766 ? "P" : "",
767 (sin->sin6_len != sizeof(struct sockaddr_in6))
768 ? "W" : "",
769 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
770 }
771 printf(" %-4.4s", flgbuf);
772
773 if (prbs)
774 printf(" %4d", prbs);
775
776 printf("\n");
777 }
778 if (buf != NULL)
779 free(buf);
780
781 if (repeat) {
782 printf("\n");
783 sleep(repeat);
784 goto again;
785 }
786 }
787
788 /*
789 * Dump the entire neighbor cache (extended)
790 */
791 void
792 dump_ext(addr, xflag)
793 struct in6_addr *addr;
794 int xflag;
795 {
796 int mib[6];
797 size_t needed;
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;
803 struct timeval time;
804 int addrwidth;
805 int llwidth;
806 int ifwidth;
807 char flgbuf[8];
808 char *ifname;
809
810 /* Print header */
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",
815 "Flgs", "Prbs");
816 if (xflag)
817 printf(" %-7.7s %-7.7s %-7.7s", "RSSI", "LQM", "NPM");
818 printf("\n");
819 }
820
821 again:;
822 mib[0] = CTL_NET;
823 mib[1] = PF_ROUTE;
824 mib[2] = 0;
825 mib[3] = AF_INET6;
826 mib[4] = NET_RT_DUMPX_FLAGS;
827 mib[5] = RTF_LLINFO;
828 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
829 err(1, "sysctl(PF_ROUTE estimate)");
830 if (needed > 0) {
831 if ((buf = malloc(needed)) == NULL)
832 errx(1, "malloc");
833 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
834 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
835 lim = buf + needed;
836 } else
837 buf = lim = NULL;
838
839 for (next = buf; next && next < lim; next += ertm->rtm_msglen) {
840 int isrouter = 0, prbs = 0;
841
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));
845
846 /*
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,
851 * so we skip them.
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)...
858 */
859 if (sdl->sdl_family != AF_LINK)
860 continue;
861
862 if (addr) {
863 if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
864 continue;
865 found_entry = 1;
866 } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
867 continue;
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;
874 #ifdef __KAME__
875 /* KAME specific hack; removed the embedded id */
876 *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
877 #endif
878 }
879 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
880 sizeof(host_buf), NULL, 0,
881 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
882 if (cflag == 1) {
883 #ifdef RTF_WASCLONED
884 if (ertm->rtm_flags & RTF_WASCLONED)
885 delete(host_buf);
886 #else
887 delete(host_buf);
888 #endif
889 continue;
890 }
891 gettimeofday(&time, 0);
892 if (tflag)
893 ts_print(&time);
894
895 addrwidth = strlen(host_buf);
896 if (addrwidth < W_ADDR)
897 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);
902 if (!ifname)
903 ifname = "?";
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;
907
908 printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
909 llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
910
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)
915 printf(" %-9.9s",
916 sec2str(ertm->rtm_ri.ri_snd_expire - time.tv_sec));
917 else
918 printf(" %-9.9s", "expired");
919
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)
924 printf(" %-9.9s",
925 sec2str(ertm->rtm_ri.ri_rcv_expire - time.tv_sec));
926 else
927 printf(" %-9.9s", "expired");
928
929 /* Print neighbor discovery specific informations */
930 nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
931 if (nbi) {
932 switch(nbi->state) {
933 case ND6_LLINFO_NOSTATE:
934 printf(" N");
935 break;
936 #ifdef ND6_LLINFO_WAITDELETE
937 case ND6_LLINFO_WAITDELETE:
938 printf(" W");
939 break;
940 #endif
941 case ND6_LLINFO_INCOMPLETE:
942 printf(" I");
943 break;
944 case ND6_LLINFO_REACHABLE:
945 printf(" R");
946 break;
947 case ND6_LLINFO_STALE:
948 printf(" S");
949 break;
950 case ND6_LLINFO_DELAY:
951 printf(" D");
952 break;
953 case ND6_LLINFO_PROBE:
954 printf(" P");
955 break;
956 default:
957 printf(" ?");
958 break;
959 }
960
961 isrouter = nbi->isrouter;
962 prbs = nbi->asked;
963 } else {
964 warnx("failed to get neighbor information");
965 printf(" ");
966 }
967 putchar(' ');
968
969 /*
970 * other flags. R: router, P: proxy, W: ??
971 */
972 if ((ertm->rtm_addrs & RTA_NETMASK) == 0) {
973 snprintf(flgbuf, sizeof(flgbuf), "%s%s",
974 isrouter ? "R" : "",
975 (ertm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
976 } else {
977 sin = (struct sockaddr_in6 *)
978 (sdl->sdl_len + (char *)sdl);
979 snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s",
980 isrouter ? "R" : "",
981 !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)
982 ? "P" : "",
983 (sin->sin6_len != sizeof(struct sockaddr_in6))
984 ? "W" : "",
985 (ertm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
986 }
987 printf(" %-4.4s", flgbuf);
988
989 if (prbs)
990 printf(" %4d", prbs);
991
992 if (xflag) {
993 if (!prbs)
994 printf(" %-4.4s", "none");
995
996 if (ertm->rtm_ri.ri_rssi != IFNET_RSSI_UNKNOWN)
997 printf(" %7d", ertm->rtm_ri.ri_rssi);
998 else
999 printf(" %-7.7s", "unknown");
1000
1001 switch (ertm->rtm_ri.ri_lqm)
1002 {
1003 case IFNET_LQM_THRESH_OFF:
1004 printf(" %-7.7s", "off");
1005 break;
1006 case IFNET_LQM_THRESH_UNKNOWN:
1007 printf(" %-7.7s", "unknown");
1008 break;
1009 case IFNET_LQM_THRESH_POOR:
1010 printf(" %-7.7s", "poor");
1011 break;
1012 case IFNET_LQM_THRESH_GOOD:
1013 printf(" %-7.7s", "good");
1014 break;
1015 default:
1016 printf(" %7d", ertm->rtm_ri.ri_lqm);
1017 break;
1018 }
1019
1020 switch (ertm->rtm_ri.ri_npm)
1021 {
1022 case IFNET_NPM_THRESH_UNKNOWN:
1023 printf(" %-7.7s", "unknown");
1024 break;
1025 case IFNET_NPM_THRESH_NEAR:
1026 printf(" %-7.7s", "near");
1027 break;
1028 case IFNET_NPM_THRESH_GENERAL:
1029 printf(" %-7.7s", "general");
1030 break;
1031 case IFNET_NPM_THRESH_FAR:
1032 printf(" %-7.7s", "far");
1033 break;
1034 default:
1035 printf(" %7d", ertm->rtm_ri.ri_npm);
1036 break;
1037 }
1038 }
1039
1040 printf("\n");
1041 }
1042 if (buf != NULL)
1043 free(buf);
1044
1045 if (repeat) {
1046 printf("\n");
1047 sleep(repeat);
1048 goto again;
1049 }
1050 }
1051
1052 static struct in6_nbrinfo *
1053 getnbrinfo(addr, ifindex, warning)
1054 struct in6_addr *addr;
1055 int ifindex;
1056 int warning;
1057 {
1058 static struct in6_nbrinfo nbi;
1059 int s;
1060
1061 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1062 err(1, "socket");
1063
1064 bzero(&nbi, sizeof(nbi));
1065 if_indextoname(ifindex, nbi.ifname);
1066 nbi.addr = *addr;
1067 if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
1068 if (warning)
1069 warn("ioctl(SIOCGNBRINFO_IN6)");
1070 close(s);
1071 return(NULL);
1072 }
1073
1074 close(s);
1075 return(&nbi);
1076 }
1077
1078 static char *
1079 ether_str(sdl)
1080 struct sockaddr_dl *sdl;
1081 {
1082 static char ebuf[32];
1083 u_char *cp;
1084
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]);
1089 } else {
1090 snprintf(ebuf, sizeof(ebuf), "(incomplete)");
1091 }
1092
1093 return(ebuf);
1094 }
1095
1096 int
1097 ndp_ether_aton(a, n)
1098 char *a;
1099 u_char *n;
1100 {
1101 int i, o[6];
1102
1103 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
1104 &o[3], &o[4], &o[5]);
1105 if (i != 6) {
1106 fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
1107 return (1);
1108 }
1109 for (i=0; i<6; i++)
1110 n[i] = o[i];
1111 return (0);
1112 }
1113
1114 void
1115 usage()
1116 {
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");
1126 #endif
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");
1133 exit(1);
1134 }
1135
1136 int
1137 rtmsg(cmd)
1138 int cmd;
1139 {
1140 static int seq;
1141 int rlen;
1142 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
1143 register char *cp = m_rtmsg.m_space;
1144 register int l;
1145
1146 errno = 0;
1147 if (cmd == RTM_DELETE)
1148 goto doit;
1149 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
1150 rtm->rtm_flags = flags;
1151 rtm->rtm_version = RTM_VERSION;
1152
1153 switch (cmd) {
1154 default:
1155 fprintf(stderr, "ndp: internal wrong cmd\n");
1156 exit(1);
1157 case RTM_ADD:
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;
1165 }
1166 /* FALLTHROUGH */
1167 case RTM_GET:
1168 rtm->rtm_addrs |= RTA_DST;
1169 }
1170 #define NEXTADDR(w, s) \
1171 if (rtm->rtm_addrs & (w)) { \
1172 bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);}
1173
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);
1178
1179 rtm->rtm_msglen = cp - (char *)&m_rtmsg;
1180 doit:
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");
1187 return (-1);
1188 }
1189 }
1190 do {
1191 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
1192 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
1193 if (l < 0)
1194 (void) fprintf(stderr, "ndp: read from routing socket: %s\n",
1195 strerror(errno));
1196 return (0);
1197 }
1198
1199 void
1200 ifinfo(argc, argv)
1201 int argc;
1202 char **argv;
1203 {
1204 struct in6_ndireq nd;
1205 int i, s;
1206 char *ifname = argv[0];
1207 u_int32_t newflags;
1208 #ifdef IPV6CTL_USETEMPADDR
1209 u_int8_t nullbuf[8];
1210 #endif
1211
1212 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1213 perror("ndp: socket");
1214 exit(1);
1215 }
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)");
1220 exit(1);
1221 }
1222 #define ND nd.ndi
1223 newflags = ND.flags;
1224 for (i = 1; i < argc; i++) {
1225 int clear = 0;
1226 char *cp = argv[i];
1227
1228 if (*cp == '-') {
1229 clear = 1;
1230 cp++;
1231 }
1232
1233 #define SETFLAG(s, f) \
1234 do {\
1235 if (strcmp(cp, (s)) == 0) {\
1236 if (clear)\
1237 newflags &= ~(f);\
1238 else\
1239 newflags |= (f);\
1240 }\
1241 } while (0)
1242 SETFLAG("nud", ND6_IFF_PERFORMNUD);
1243 SETFLAG("proxy_prefixes", ND6_IFF_PROXY_PREFIXES);
1244 SETFLAG("ignore_na", ND6_IFF_IGNORE_NA);
1245
1246 ND.flags = newflags;
1247 if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) {
1248 perror("ioctl(SIOCSIFINFO_FLAGS)");
1249 exit(1);
1250 }
1251 #undef SETFLAG
1252 }
1253
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) {
1263 int j;
1264 u_int8_t *rbuf = NULL;
1265
1266 for (i = 0; i < 3; i++) {
1267 switch(i) {
1268 case 0:
1269 printf("\nRandom seed(0): ");
1270 rbuf = ND.randomseed0;
1271 break;
1272 case 1:
1273 printf("\nRandom seed(1): ");
1274 rbuf = ND.randomseed1;
1275 break;
1276 case 2:
1277 printf("\nRandom ID: ");
1278 rbuf = ND.randomid;
1279 break;
1280 }
1281 for (j = 0; j < 8; j++)
1282 printf("%02x", rbuf[j]);
1283 }
1284 }
1285 #endif
1286 if (ND.flags) {
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 ");
1296 }
1297 putc('\n', stdout);
1298 #undef ND
1299
1300 close(s);
1301 }
1302
1303 #ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */
1304 #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
1305 #endif
1306
1307 void
1308 rtrlist()
1309 {
1310 #ifdef ICMPV6CTL_ND6_DRLIST
1311 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };
1312 char *buf;
1313 struct in6_defrouter *p, *ep;
1314 size_t l;
1315 struct timeval time;
1316
1317 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
1318 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
1319 /*NOTREACHED*/
1320 }
1321 buf = malloc(l);
1322 if (!buf) {
1323 errx(1, "not enough core");
1324 /*NOTREACHED*/
1325 }
1326 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
1327 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
1328 /*NOTREACHED*/
1329 }
1330
1331 ep = (struct in6_defrouter *)(buf + l);
1332 for (p = (struct in6_defrouter *)buf; p < ep; p++) {
1333 int rtpref;
1334
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));
1339
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]);
1350
1351 gettimeofday(&time, 0);
1352 if (p->expire == 0)
1353 printf(", expire=Never\n");
1354 else
1355 printf(", expire=%s\n",
1356 sec2str(p->expire - time.tv_sec));
1357 }
1358 free(buf);
1359 #else
1360 struct in6_drlist dr;
1361 int s, i;
1362 struct timeval time;
1363
1364 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1365 perror("ndp: socket");
1366 exit(1);
1367 }
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)");
1372 exit(1);
1373 }
1374 #define DR dr.defrouter[i]
1375 for (i = 0 ; DR.if_index && i < DRLSTSIZ ; i++) {
1376 struct sockaddr_in6 sin6;
1377
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));
1385
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);
1392 if (DR.expire == 0)
1393 printf(", expire=Never\n");
1394 else
1395 printf(", expire=%s\n",
1396 sec2str(DR.expire - time.tv_sec));
1397 }
1398 #undef DR
1399 close(s);
1400 #endif
1401 }
1402
1403 void
1404 plist()
1405 {
1406 #ifdef ICMPV6CTL_ND6_PRLIST
1407 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST };
1408 char *buf;
1409 struct in6_prefix *p, *ep, *n;
1410 struct sockaddr_in6 *advrtr;
1411 size_t l;
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;
1416 #else
1417 const int niflags = NI_NUMERICHOST;
1418 int ninflags = nflag ? NI_NUMERICHOST : 0;
1419 #endif
1420 char namebuf[NI_MAXHOST];
1421
1422 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), NULL, &l, NULL, 0) < 0) {
1423 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
1424 /*NOTREACHED*/
1425 }
1426 buf = malloc(l);
1427 if (!buf) {
1428 errx(1, "not enough core");
1429 /*NOTREACHED*/
1430 }
1431 if (sysctl(mib, sizeof(mib) / sizeof(mib[0]), buf, &l, NULL, 0) < 0) {
1432 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
1433 /*NOTREACHED*/
1434 }
1435
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];
1440
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));
1447
1448 gettimeofday(&time, 0);
1449 /*
1450 * meaning of fields, especially flags, is very different
1451 * by origin. notify the difference to the users.
1452 */
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" : "",
1460 #ifdef NDPRF_HOME
1461 (p->flags & NDPRF_HOME) != 0 ? "H" : "",
1462 #else
1463 "",
1464 #endif
1465 #ifdef NDPRF_STATIC
1466 (p->flags & NDPRF_STATIC) != 0 ? "S" : ""
1467 #else
1468 ""
1469 #endif
1470 );
1471 if (p->vltime == ND6_INFINITE_LIFETIME)
1472 printf(" vltime=infinity");
1473 else
1474 printf(" vltime=%ld", (long)p->vltime);
1475 if (p->pltime == ND6_INFINITE_LIFETIME)
1476 printf(", pltime=infinity");
1477 else
1478 printf(", pltime=%ld", (long)p->pltime);
1479 if (p->expire == 0)
1480 printf(", expire=Never");
1481 else if (p->expire >= time.tv_sec)
1482 printf(", expire=%s",
1483 sec2str(p->expire - time.tv_sec));
1484 else
1485 printf(", expired");
1486 printf(", ref=%d", p->refcnt);
1487 printf("\n");
1488 /*
1489 * "advertising router" list is meaningful only if the prefix
1490 * information is from RA.
1491 */
1492 if (p->advrtrs) {
1493 int j;
1494 struct sockaddr_in6 *sin6;
1495
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;
1500
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);
1506
1507 nbi = getnbrinfo(&sin6->sin6_addr, p->if_index,
1508 0);
1509 if (nbi) {
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");
1516 break;
1517 default:
1518 printf(" (unreachable)\n");
1519 }
1520 } else
1521 printf(" (no neighbor state)\n");
1522 sin6++;
1523 }
1524 } else
1525 printf(" No advertising router\n");
1526 }
1527 free(buf);
1528 #else
1529 struct in6_prlist pr;
1530 int s, i;
1531 struct timeval time;
1532
1533 gettimeofday(&time, 0);
1534
1535 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1536 perror("ndp: socket");
1537 exit(1);
1538 }
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)");
1543 exit(1);
1544 }
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];
1549 int niflags;
1550
1551 #ifdef NDPRF_ONLINK
1552 p6 = PR.prefix;
1553 #else
1554 memset(&p6, 0, sizeof(p6));
1555 p6.sin6_family = AF_INET6;
1556 p6.sin6_len = sizeof(p6);
1557 p6.sin6_addr = PR.prefix;
1558 #endif
1559
1560 /*
1561 * copy link index to sin6_scope_id field.
1562 * XXX: KAME specific.
1563 */
1564 if (IN6_IS_ADDR_LINKLOCAL(&p6.sin6_addr)) {
1565 u_int16_t linkid;
1566
1567 memcpy(&linkid, &p6.sin6_addr.s6_addr[2],
1568 sizeof(linkid));
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;
1573 }
1574
1575 niflags = NI_NUMERICHOST;
1576 #ifdef __KAME__
1577 niflags |= NI_WITHSCOPEID;
1578 #endif
1579 if (getnameinfo((struct sockaddr *)&p6,
1580 sizeof(p6), namebuf, sizeof(namebuf),
1581 NULL, 0, niflags)) {
1582 warnx("getnameinfo failed");
1583 continue;
1584 }
1585 printf("%s/%d if=%s\n", namebuf, PR.prefixlen,
1586 if_indextoname(PR.if_index, ifix_buf));
1587
1588 gettimeofday(&time, 0);
1589 /*
1590 * meaning of fields, especially flags, is very different
1591 * by origin. notify the difference to the users.
1592 */
1593 #if 0
1594 printf(" %s",
1595 PR.origin == PR_ORIG_RA ? "" : "advertise: ");
1596 #endif
1597 #ifdef NDPRF_ONLINK
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" : "",
1603 #ifdef NDPRF_HOME
1604 (PR.flags & NDPRF_HOME) != 0 ? "H" : ""
1605 #else
1606 ""
1607 #endif
1608 );
1609 #else
1610 printf("flags=%s%s",
1611 PR.raflags.onlink ? "L" : "",
1612 PR.raflags.autonomous ? "A" : "");
1613 #endif
1614 if (PR.vltime == ND6_INFINITE_LIFETIME)
1615 printf(" vltime=infinity");
1616 else
1617 printf(" vltime=%ld", (long)PR.vltime);
1618 if (PR.pltime == ND6_INFINITE_LIFETIME)
1619 printf(", pltime=infinity");
1620 else
1621 printf(", pltime=%ld", (long)PR.pltime);
1622 if (PR.expire == 0)
1623 printf(", expire=Never");
1624 else if (PR.expire >= time.tv_sec)
1625 printf(", expire=%s",
1626 sec2str(PR.expire - time.tv_sec));
1627 else
1628 printf(", expired");
1629 #ifdef NDPRF_ONLINK
1630 printf(", ref=%d", PR.refcnt);
1631 #endif
1632 #if 0
1633 switch (PR.origin) {
1634 case PR_ORIG_RA:
1635 printf(", origin=RA");
1636 break;
1637 case PR_ORIG_RR:
1638 printf(", origin=RR");
1639 break;
1640 case PR_ORIG_STATIC:
1641 printf(", origin=static");
1642 break;
1643 case PR_ORIG_KERNEL:
1644 printf(", origin=kernel");
1645 break;
1646 default:
1647 printf(", origin=?");
1648 break;
1649 }
1650 #endif
1651 printf("\n");
1652 /*
1653 * "advertising router" list is meaningful only if the prefix
1654 * information is from RA.
1655 */
1656 if (0 && /* prefix origin is almost obsolted */
1657 PR.origin != PR_ORIG_RA)
1658 ;
1659 else if (PR.advrtrs) {
1660 int j;
1661 printf(" advertised by\n");
1662 for (j = 0; j < PR.advrtrs; j++) {
1663 struct sockaddr_in6 sin6;
1664 struct in6_nbrinfo *nbi;
1665
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);
1676
1677 nbi = getnbrinfo(&sin6.sin6_addr, PR.if_index,
1678 0);
1679 if (nbi) {
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");
1686 break;
1687 default:
1688 printf(" (unreachable)\n");
1689 }
1690 } else
1691 printf(" (no neighbor state)\n");
1692 }
1693 if (PR.advrtrs > DRLSTSIZ)
1694 printf(" and %d routers\n",
1695 PR.advrtrs - DRLSTSIZ);
1696 } else
1697 printf(" No advertising router\n");
1698 }
1699 #undef PR
1700 close(s);
1701 #endif
1702 }
1703
1704 void
1705 pfx_flush()
1706 {
1707 char dummyif[IFNAMSIZ+8];
1708 int s;
1709
1710 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1711 err(1, "socket");
1712 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
1713 if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
1714 err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
1715 }
1716
1717 void
1718 rtr_flush()
1719 {
1720 char dummyif[IFNAMSIZ+8];
1721 int s;
1722
1723 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1724 err(1, "socket");
1725 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
1726 if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
1727 err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
1728
1729 close(s);
1730 }
1731
1732 void
1733 harmonize_rtr()
1734 {
1735 char dummyif[IFNAMSIZ+8];
1736 int s;
1737
1738 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1739 err(1, "socket");
1740 strlcpy(dummyif, "lo0", sizeof(dummyif)); /* dummy */
1741 if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
1742 err(1, "ioctl (SIOCSNDFLUSH_IN6)");
1743
1744 close(s);
1745 }
1746
1747 #ifdef SIOCSDEFIFACE_IN6 /* XXX: check SIOCGDEFIFACE_IN6 as well? */
1748 static void
1749 setdefif(ifname)
1750 char *ifname;
1751 {
1752 struct in6_ndifreq ndifreq;
1753 unsigned int ifindex;
1754
1755 if (strcasecmp(ifname, "delete") == 0)
1756 ifindex = 0;
1757 else {
1758 if ((ifindex = if_nametoindex(ifname)) == 0)
1759 err(1, "failed to resolve i/f index for %s", ifname);
1760 }
1761
1762 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1763 err(1, "socket");
1764
1765 strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
1766 ndifreq.ifindex = ifindex;
1767
1768 if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1769 err(1, "ioctl (SIOCSDEFIFACE_IN6)");
1770
1771 close(s);
1772 }
1773
1774 static void
1775 getdefif()
1776 {
1777 struct in6_ndifreq ndifreq;
1778 char ifname[IFNAMSIZ+8];
1779
1780 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1781 err(1, "socket");
1782
1783 memset(&ndifreq, 0, sizeof(ndifreq));
1784 strlcpy(ndifreq.ifname, "lo0", sizeof(ndifreq.ifname)); /* dummy */
1785
1786 if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1787 err(1, "ioctl (SIOCGDEFIFACE_IN6)");
1788
1789 if (ndifreq.ifindex == 0)
1790 printf("No default interface.\n");
1791 else {
1792 if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
1793 err(1, "failed to resolve ifname for index %lu",
1794 ndifreq.ifindex);
1795 printf("ND default interface = %s\n", ifname);
1796 }
1797
1798 close(s);
1799 }
1800 #endif
1801
1802 static char *
1803 sec2str(total)
1804 time_t total;
1805 {
1806 static char result[256];
1807 int days, hours, mins, secs;
1808 int first = 1;
1809 char *p = result;
1810
1811 days = total / 3600 / 24;
1812 hours = (total / 3600) % 24;
1813 mins = (total / 60) % 60;
1814 secs = total % 60;
1815
1816 if (days) {
1817 first = 0;
1818 p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
1819 }
1820 if (!first || hours) {
1821 first = 0;
1822 p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
1823 }
1824 if (!first || mins) {
1825 first = 0;
1826 p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
1827 }
1828 snprintf(p, sizeof(result) - (p - result), "%ds", secs);
1829
1830 return(result);
1831 }
1832
1833 /*
1834 * Print the timestamp
1835 * from tcpdump/util.c
1836 */
1837 static void
1838 ts_print(tvp)
1839 const struct timeval *tvp;
1840 {
1841 int s;
1842
1843 /* Default */
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);
1847 }