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