]> git.cameronkatri.com Git - apple_cmds.git/blob - network_cmds/ndp.tproj/ndp.c
network_cmds: Fix compilation for lower targets
[apple_cmds.git] / network_cmds / ndp.tproj / ndp.c
1 /*
2 * Copyright (c) 2009-2017 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 int ealen;
397
398 getsocket();
399 argc -= 2;
400 argv += 2;
401 sdl_m = blank_sdl;
402 sin_m = blank_sin;
403
404 bzero(&hints, sizeof (hints));
405 hints.ai_family = AF_INET6;
406 gai_error = getaddrinfo(host, NULL, &hints, &res);
407 if (gai_error) {
408 fprintf(stderr, "ndp: %s: %s\n", host,
409 gai_strerror(gai_error));
410 return (1);
411 }
412 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
413 #ifdef __KAME__
414 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
415 *(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
416 htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
417 }
418 #endif
419 ea = (u_char *)LLADDR(&sdl_m);
420
421 ealen = ndp_ether_aton(eaddr, ea);
422 if (ealen != -1)
423 sdl_m.sdl_alen = ealen;
424 flags = expire_time = 0;
425 while (argc-- > 0) {
426 if (strncmp(argv[0], "temp", 4) == 0) {
427 struct timeval time;
428 gettimeofday(&time, 0);
429 expire_time = time.tv_sec + 20 * 60;
430 } else if (strncmp(argv[0], "proxy", 5) == 0)
431 flags |= RTF_ANNOUNCE;
432 argv++;
433 }
434 if (rtmsg(RTM_GET) < 0) {
435 perror(host);
436 return (1);
437 }
438 sin = (struct sockaddr_in6 *)(rtm + 1);
439 sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
440 if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
441 if (sdl->sdl_family == AF_LINK &&
442 (rtm->rtm_flags & RTF_LLINFO) &&
443 !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
444 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
445 case IFT_ISO88024: case IFT_ISO88025:
446 #if defined(IFT_6LOWPAN)
447 case IFT_6LOWPAN:
448 #endif
449 goto overwrite;
450 }
451 /*
452 * IPv4 arp command retries with sin_other = SIN_PROXY here.
453 */
454 fprintf(stderr, "set: cannot configure a new entry\n");
455 return (1);
456 }
457
458 overwrite:
459 if (sdl->sdl_family != AF_LINK) {
460 printf("cannot intuit interface index and type for %s\n", host);
461 return (1);
462 }
463 sdl_m.sdl_type = sdl->sdl_type;
464 sdl_m.sdl_index = sdl->sdl_index;
465 return (rtmsg(RTM_ADD));
466 }
467
468 /*
469 * Display an individual neighbor cache entry
470 */
471 static void
472 get(char *host)
473 {
474 struct sockaddr_in6 *sin = &sin_m;
475 struct addrinfo hints, *res;
476 int gai_error;
477
478 sin_m = blank_sin;
479 bzero(&hints, sizeof (hints));
480 hints.ai_family = AF_INET6;
481 gai_error = getaddrinfo(host, NULL, &hints, &res);
482 if (gai_error) {
483 fprintf(stderr, "ndp: %s: %s\n", host,
484 gai_strerror(gai_error));
485 return;
486 }
487 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
488 #ifdef __KAME__
489 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
490 *(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
491 htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
492 }
493 #endif
494 dump(&sin->sin6_addr);
495 if (found_entry == 0) {
496 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
497 sizeof (host_buf), NULL, 0, NI_WITHSCOPEID | (nflag ?
498 NI_NUMERICHOST : 0));
499 printf("%s (%s) -- no entry\n", host, host_buf);
500 exit(1);
501 }
502 }
503
504 /*
505 * Delete a neighbor cache entry
506 */
507 static int
508 delete(char *host)
509 {
510 struct sockaddr_in6 *sin = &sin_m;
511 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
512 struct sockaddr_dl *sdl;
513 struct addrinfo hints, *res;
514 int gai_error;
515
516 getsocket();
517 sin_m = blank_sin;
518
519 bzero(&hints, sizeof (hints));
520 hints.ai_family = AF_INET6;
521 gai_error = getaddrinfo(host, NULL, &hints, &res);
522 if (gai_error) {
523 fprintf(stderr, "ndp: %s: %s\n", host,
524 gai_strerror(gai_error));
525 return (1);
526 }
527 sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
528 #ifdef __KAME__
529 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
530 *(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
531 htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
532 }
533 #endif
534 if (rtmsg(RTM_GET) < 0) {
535 perror(host);
536 return (1);
537 }
538 sin = (struct sockaddr_in6 *)(rtm + 1);
539 sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
540 if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
541 if (sdl->sdl_family == AF_LINK &&
542 (rtm->rtm_flags & RTF_LLINFO) &&
543 !(rtm->rtm_flags & RTF_GATEWAY)) {
544 goto delete;
545 }
546 /*
547 * IPv4 arp command retries with sin_other = SIN_PROXY here.
548 */
549 fprintf(stderr, "delete: cannot delete non-NDP entry\n");
550 return (1);
551 }
552
553 delete:
554 if (sdl->sdl_family != AF_LINK) {
555 printf("cannot locate %s\n", host);
556 return (1);
557 }
558 if (rtmsg(RTM_DELETE) == 0) {
559 struct sockaddr_in6 s6 = *sin;
560
561 #ifdef __KAME__
562 if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) {
563 s6.sin6_scope_id =
564 ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]);
565 *(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0;
566 }
567 #endif
568 getnameinfo((struct sockaddr *)&s6,
569 s6.sin6_len, host_buf,
570 sizeof (host_buf), NULL, 0,
571 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
572 printf("%s (%s) deleted\n", host, host_buf);
573 }
574
575 return (0);
576 }
577
578 #define W_ADDR 31
579 #define W_LL 17
580 #define W_IF 6
581
582 /*
583 * Dump the entire neighbor cache
584 */
585 static void
586 dump(struct in6_addr *addr)
587 {
588 int mib[6];
589 size_t needed;
590 char *lim, *buf, *next;
591 struct rt_msghdr *rtm;
592 struct sockaddr_in6 *sin;
593 struct sockaddr_dl *sdl;
594 struct in6_nbrinfo *nbi;
595 struct timeval time;
596 int addrwidth;
597 int llwidth;
598 int ifwidth;
599 char flgbuf[8];
600 char *ifname;
601
602 /* Print header */
603 if (!tflag && !cflag)
604 printf("%-*.*s %-*.*s %*.*s %-9.9s %2s %4s %4s\n",
605 W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
606 W_IF, W_IF, "Netif", "Expire", "St", "Flgs", "Prbs");
607
608 again:;
609 mib[0] = CTL_NET;
610 mib[1] = PF_ROUTE;
611 mib[2] = 0;
612 mib[3] = AF_INET6;
613 mib[4] = NET_RT_FLAGS;
614 mib[5] = RTF_LLINFO;
615 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
616 err(1, "sysctl(PF_ROUTE estimate)");
617 if (needed > 0) {
618 if ((buf = malloc(needed)) == NULL)
619 errx(1, "malloc");
620 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
621 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
622 lim = buf + needed;
623 } else
624 buf = lim = NULL;
625
626 for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
627 int isrouter = 0, prbs = 0;
628
629 rtm = (struct rt_msghdr *)next;
630 sin = (struct sockaddr_in6 *)(rtm + 1);
631 sdl = (struct sockaddr_dl *)((char *)sin +
632 ROUNDUP(sin->sin6_len));
633
634 /*
635 * Some OSes can produce a route that has the LINK flag but
636 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
637 * and BSD/OS, where xx is not the interface identifier on
638 * lo0). Such routes entry would annoy getnbrinfo() below,
639 * so we skip them.
640 * XXX: such routes should have the GATEWAY flag, not the
641 * LINK flag. However, there are rotten routing software
642 * that advertises all routes that have the GATEWAY flag.
643 * Thus, KAME kernel intentionally does not set the LINK flag.
644 * What is to be fixed is not ndp, but such routing software
645 * (and the kernel workaround)...
646 */
647 if (sdl->sdl_family != AF_LINK)
648 continue;
649
650 if (addr) {
651 if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
652 continue;
653 found_entry = 1;
654 } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
655 continue;
656 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
657 IN6_IS_ADDR_MC_NODELOCAL(&sin->sin6_addr) ||
658 IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
659 /* should scope id be filled in the kernel? */
660 if (sin->sin6_scope_id == 0)
661 sin->sin6_scope_id = sdl->sdl_index;
662 #ifdef __KAME__
663 /* KAME specific hack; removed the embedded id */
664 *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
665 #endif
666 }
667 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
668 sizeof (host_buf), NULL, 0,
669 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
670 if (cflag == 1) {
671 if (rtm->rtm_flags & RTF_WASCLONED)
672 delete(host_buf);
673 continue;
674 }
675 gettimeofday(&time, 0);
676 if (tflag)
677 ts_print(&time);
678
679 addrwidth = strlen(host_buf);
680 if (addrwidth < W_ADDR)
681 addrwidth = W_ADDR;
682 llwidth = strlen(ether_str(sdl));
683 if (W_ADDR + W_LL - addrwidth > llwidth)
684 llwidth = W_ADDR + W_LL - addrwidth;
685 ifname = if_indextoname(sdl->sdl_index, ifix_buf);
686 if (!ifname)
687 ifname = "?";
688 ifwidth = strlen(ifname);
689 if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
690 ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
691
692 printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
693 llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
694
695 /* Print neighbor discovery specific informations */
696 nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
697 if (nbi) {
698 if (nbi->expire > time.tv_sec) {
699 printf(" %-9.9s", sec2str(nbi->expire -
700 time.tv_sec));
701 } else if (nbi->expire == 0)
702 printf(" %-9.9s", "permanent");
703 else
704 printf(" %-9.9s", "expired");
705
706 switch (nbi->state) {
707 case ND6_LLINFO_NOSTATE:
708 printf(" N");
709 break;
710 case ND6_LLINFO_INCOMPLETE:
711 printf(" I");
712 break;
713 case ND6_LLINFO_REACHABLE:
714 printf(" R");
715 break;
716 case ND6_LLINFO_STALE:
717 printf(" S");
718 break;
719 case ND6_LLINFO_DELAY:
720 printf(" D");
721 break;
722 case ND6_LLINFO_PROBE:
723 printf(" P");
724 break;
725 default:
726 printf(" ?");
727 break;
728 }
729
730 isrouter = nbi->isrouter;
731 prbs = nbi->asked;
732 } else {
733 warnx("failed to get neighbor information");
734 printf(" ");
735 }
736 putchar(' ');
737
738 /*
739 * other flags. R: router, P: proxy, W: ??
740 */
741 if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
742 snprintf(flgbuf, sizeof (flgbuf), "%s%s",
743 isrouter ? "R" : "",
744 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
745 } else {
746 sin = (struct sockaddr_in6 *)
747 (sdl->sdl_len + (char *)sdl);
748 snprintf(flgbuf, sizeof (flgbuf), "%s%s%s%s",
749 isrouter ? "R" : "",
750 !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)
751 ? "P" : "",
752 (sin->sin6_len != sizeof (struct sockaddr_in6))
753 ? "W" : "",
754 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
755 }
756 printf(" %-4.4s", flgbuf);
757
758 if (prbs)
759 printf(" %4d", prbs);
760
761 printf("\n");
762 }
763 if (buf != NULL)
764 free(buf);
765
766 if (repeat) {
767 printf("\n");
768 sleep(repeat);
769 goto again;
770 }
771 }
772
773 /*
774 * Dump the entire neighbor cache (extended)
775 */
776 void
777 dump_ext(addr, xflag)
778 struct in6_addr *addr;
779 int xflag;
780 {
781 int mib[6];
782 size_t needed;
783 char *lim, *buf, *next;
784 struct rt_msghdr_ext *ertm;
785 struct sockaddr_in6 *sin;
786 struct sockaddr_dl *sdl;
787 struct in6_nbrinfo *nbi;
788 struct timeval time;
789 int addrwidth;
790 int llwidth;
791 int ifwidth;
792 char flgbuf[8];
793 char *ifname;
794
795 /* Print header */
796 if (!tflag && !cflag) {
797 printf("%-*.*s %-*.*s %*.*s %-9.9s %-9.9s %2s %4s %4s",
798 W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
799 W_IF, W_IF, "Netif", "Expire(O)", "Expire(I)", "St",
800 "Flgs", "Prbs");
801 if (xflag)
802 printf(" %-7.7s %-7.7s %-7.7s", "RSSI", "LQM", "NPM");
803 printf("\n");
804 }
805
806 again:;
807 mib[0] = CTL_NET;
808 mib[1] = PF_ROUTE;
809 mib[2] = 0;
810 mib[3] = AF_INET6;
811 mib[4] = NET_RT_DUMPX_FLAGS;
812 mib[5] = RTF_LLINFO;
813 if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
814 err(1, "sysctl(PF_ROUTE estimate)");
815 if (needed > 0) {
816 if ((buf = malloc(needed)) == NULL)
817 errx(1, "malloc");
818 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
819 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
820 lim = buf + needed;
821 } else
822 buf = lim = NULL;
823
824 for (next = buf; next && next < lim; next += ertm->rtm_msglen) {
825 int isrouter = 0, prbs = 0;
826
827 ertm = (struct rt_msghdr_ext *)next;
828 sin = (struct sockaddr_in6 *)(ertm + 1);
829 sdl = (struct sockaddr_dl *)((char *)sin +
830 ROUNDUP(sin->sin6_len));
831
832 /*
833 * Some OSes can produce a route that has the LINK flag but
834 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
835 * and BSD/OS, where xx is not the interface identifier on
836 * lo0). Such routes entry would annoy getnbrinfo() below,
837 * so we skip them.
838 * XXX: such routes should have the GATEWAY flag, not the
839 * LINK flag. However, there are rotten routing software
840 * that advertises all routes that have the GATEWAY flag.
841 * Thus, KAME kernel intentionally does not set the LINK flag.
842 * What is to be fixed is not ndp, but such routing software
843 * (and the kernel workaround)...
844 */
845 if (sdl->sdl_family != AF_LINK)
846 continue;
847
848 if (addr) {
849 if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
850 continue;
851 found_entry = 1;
852 } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
853 continue;
854 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
855 IN6_IS_ADDR_MC_NODELOCAL(&sin->sin6_addr) ||
856 IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
857 /* should scope id be filled in the kernel? */
858 if (sin->sin6_scope_id == 0)
859 sin->sin6_scope_id = sdl->sdl_index;
860 #ifdef __KAME__
861 /* KAME specific hack; removed the embedded id */
862 *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
863 #endif
864 }
865 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
866 sizeof (host_buf), NULL, 0,
867 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
868 if (cflag == 1) {
869 if (ertm->rtm_flags & RTF_WASCLONED)
870 delete(host_buf);
871 continue;
872 }
873 gettimeofday(&time, 0);
874 if (tflag)
875 ts_print(&time);
876
877 addrwidth = strlen(host_buf);
878 if (addrwidth < W_ADDR)
879 addrwidth = W_ADDR;
880 llwidth = strlen(ether_str(sdl));
881 if (W_ADDR + W_LL - addrwidth > llwidth)
882 llwidth = W_ADDR + W_LL - addrwidth;
883 ifname = if_indextoname(sdl->sdl_index, ifix_buf);
884 if (!ifname)
885 ifname = "?";
886 ifwidth = strlen(ifname);
887 if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
888 ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
889
890 printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
891 llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
892
893 if (ertm->rtm_ri.ri_refcnt == 0 ||
894 ertm->rtm_ri.ri_snd_expire == 0)
895 printf(" %-9.9s", "(none)");
896 else if (ertm->rtm_ri.ri_snd_expire > time.tv_sec)
897 printf(" %-9.9s",
898 sec2str(ertm->rtm_ri.ri_snd_expire - time.tv_sec));
899 else
900 printf(" %-9.9s", "expired");
901
902 if (ertm->rtm_ri.ri_refcnt == 0 ||
903 ertm->rtm_ri.ri_rcv_expire == 0)
904 printf(" %-9.9s", "(none)");
905 else if (ertm->rtm_ri.ri_rcv_expire > time.tv_sec)
906 printf(" %-9.9s",
907 sec2str(ertm->rtm_ri.ri_rcv_expire - time.tv_sec));
908 else
909 printf(" %-9.9s", "expired");
910
911 /* Print neighbor discovery specific informations */
912 nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
913 if (nbi) {
914 switch (nbi->state) {
915 case ND6_LLINFO_NOSTATE:
916 printf(" N");
917 break;
918 case ND6_LLINFO_INCOMPLETE:
919 printf(" I");
920 break;
921 case ND6_LLINFO_REACHABLE:
922 printf(" R");
923 break;
924 case ND6_LLINFO_STALE:
925 printf(" S");
926 break;
927 case ND6_LLINFO_DELAY:
928 printf(" D");
929 break;
930 case ND6_LLINFO_PROBE:
931 printf(" P");
932 break;
933 default:
934 printf(" ?");
935 break;
936 }
937
938 isrouter = nbi->isrouter;
939 prbs = nbi->asked;
940 } else {
941 warnx("failed to get neighbor information");
942 printf(" ");
943 }
944 putchar(' ');
945
946 /*
947 * other flags. R: router, P: proxy, W: ??
948 */
949 if ((ertm->rtm_addrs & RTA_NETMASK) == 0) {
950 snprintf(flgbuf, sizeof (flgbuf), "%s%s",
951 isrouter ? "R" : "",
952 (ertm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
953 } else {
954 sin = (struct sockaddr_in6 *)
955 (sdl->sdl_len + (char *)sdl);
956 snprintf(flgbuf, sizeof (flgbuf), "%s%s%s%s",
957 isrouter ? "R" : "",
958 !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)
959 ? "P" : "",
960 (sin->sin6_len != sizeof (struct sockaddr_in6))
961 ? "W" : "",
962 (ertm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
963 }
964 printf(" %-4.4s", flgbuf);
965
966 if (prbs)
967 printf(" %4d", prbs);
968
969 if (xflag) {
970 if (!prbs)
971 printf(" %-4.4s", "none");
972
973 if (ertm->rtm_ri.ri_rssi != IFNET_RSSI_UNKNOWN)
974 printf(" %7d", ertm->rtm_ri.ri_rssi);
975 else
976 printf(" %-7.7s", "unknown");
977
978 switch (ertm->rtm_ri.ri_lqm)
979 {
980 case IFNET_LQM_THRESH_OFF:
981 printf(" %-7.7s", "off");
982 break;
983 case IFNET_LQM_THRESH_UNKNOWN:
984 printf(" %-7.7s", "unknown");
985 break;
986 case IFNET_LQM_THRESH_POOR:
987 printf(" %-7.7s", "poor");
988 break;
989 case IFNET_LQM_THRESH_GOOD:
990 printf(" %-7.7s", "good");
991 break;
992 default:
993 printf(" %7d", ertm->rtm_ri.ri_lqm);
994 break;
995 }
996
997 switch (ertm->rtm_ri.ri_npm)
998 {
999 case IFNET_NPM_THRESH_UNKNOWN:
1000 printf(" %-7.7s", "unknown");
1001 break;
1002 case IFNET_NPM_THRESH_NEAR:
1003 printf(" %-7.7s", "near");
1004 break;
1005 case IFNET_NPM_THRESH_GENERAL:
1006 printf(" %-7.7s", "general");
1007 break;
1008 case IFNET_NPM_THRESH_FAR:
1009 printf(" %-7.7s", "far");
1010 break;
1011 default:
1012 printf(" %7d", ertm->rtm_ri.ri_npm);
1013 break;
1014 }
1015 }
1016
1017 printf("\n");
1018 }
1019 if (buf != NULL)
1020 free(buf);
1021
1022 if (repeat) {
1023 printf("\n");
1024 sleep(repeat);
1025 goto again;
1026 }
1027 }
1028
1029 static struct in6_nbrinfo *
1030 getnbrinfo(addr, ifindex, warning)
1031 struct in6_addr *addr;
1032 int ifindex;
1033 int warning;
1034 {
1035 static struct in6_nbrinfo nbi;
1036 int s;
1037
1038 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1039 err(1, "socket");
1040
1041 bzero(&nbi, sizeof (nbi));
1042 if_indextoname(ifindex, nbi.ifname);
1043 nbi.addr = *addr;
1044 if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
1045 if (warning)
1046 warn("ioctl(SIOCGNBRINFO_IN6)");
1047 close(s);
1048 return (NULL);
1049 }
1050
1051 close(s);
1052 return (&nbi);
1053 }
1054
1055 static char *
1056 ether_str(struct sockaddr_dl *sdl)
1057 {
1058 static char ebuf[32];
1059 u_char *cp;
1060
1061 if (sdl->sdl_alen) {
1062 cp = (u_char *)LLADDR(sdl);
1063 snprintf(ebuf, sizeof (ebuf), "%x:%x:%x:%x:%x:%x",
1064 cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
1065 } else {
1066 snprintf(ebuf, sizeof (ebuf), "(incomplete)");
1067 }
1068
1069 return (ebuf);
1070 }
1071
1072 static int
1073 ndp_ether_aton(char *a, u_char *n)
1074 {
1075 int i, o[8];
1076 int len;
1077
1078 len = sscanf(a, "%x:%x:%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], &o[3], &o[4],
1079 &o[5], &o[6], &o[7]);
1080 if (len != 6 && len != 8) {
1081 fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
1082 return (-1);
1083 }
1084 for (i = 0; i < len; i++)
1085 n[i] = o[i];
1086 return (len);
1087 }
1088
1089 static void
1090 usage(void)
1091 {
1092 printf("usage: ndp hostname\n");
1093 printf(" ndp -a[lnt]\n");
1094 printf(" ndp [-nt] -A wait\n");
1095 printf(" ndp -c[nt]\n");
1096 printf(" ndp -d[nt] hostname\n");
1097 printf(" ndp -f[nt] filename\n");
1098 printf(" ndp -i interface [flags...]\n");
1099 printf(" ndp -I [interface|delete]\n");
1100 printf(" ndp -p\n");
1101 printf(" ndp -r\n");
1102 printf(" ndp -s hostname ether_addr [temp] [proxy]\n");
1103 printf(" ndp -H\n");
1104 printf(" ndp -P\n");
1105 printf(" ndp -R\n");
1106 printf(" ndp -w\n");
1107 printf(" ndp -W cfgfile\n");
1108 exit(1);
1109 }
1110
1111 static int
1112 rtmsg(int cmd)
1113 {
1114 static int seq;
1115 int rlen;
1116 register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
1117 register char *cp = m_rtmsg.m_space;
1118 register int l;
1119
1120 errno = 0;
1121 if (cmd == RTM_DELETE)
1122 goto doit;
1123 bzero((char *)&m_rtmsg, sizeof (m_rtmsg));
1124 rtm->rtm_flags = flags;
1125 rtm->rtm_version = RTM_VERSION;
1126
1127 switch (cmd) {
1128 default:
1129 fprintf(stderr, "ndp: internal wrong cmd\n");
1130 exit(1);
1131 case RTM_ADD:
1132 rtm->rtm_addrs |= RTA_GATEWAY;
1133 rtm->rtm_rmx.rmx_expire = expire_time;
1134 rtm->rtm_inits = RTV_EXPIRE;
1135 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
1136 if (rtm->rtm_flags & RTF_ANNOUNCE) {
1137 rtm->rtm_flags &= ~RTF_HOST;
1138 rtm->rtm_flags |= RTA_NETMASK;
1139 }
1140 /* FALLTHROUGH */
1141 case RTM_GET:
1142 rtm->rtm_addrs |= RTA_DST;
1143 }
1144 #define NEXTADDR(w, s) \
1145 if (rtm->rtm_addrs & (w)) { \
1146 bcopy((char *)&s, cp, sizeof (s)); cp += sizeof (s); \
1147 }
1148
1149 NEXTADDR(RTA_DST, sin_m);
1150 NEXTADDR(RTA_GATEWAY, sdl_m);
1151 memset(&so_mask.sin6_addr, 0xff, sizeof (so_mask.sin6_addr));
1152 NEXTADDR(RTA_NETMASK, so_mask);
1153
1154 rtm->rtm_msglen = cp - (char *)&m_rtmsg;
1155 doit:
1156 l = rtm->rtm_msglen;
1157 rtm->rtm_seq = ++seq;
1158 rtm->rtm_type = cmd;
1159 if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
1160 if (errno != ESRCH || cmd != RTM_DELETE) {
1161 perror("writing to routing socket");
1162 return (-1);
1163 }
1164 }
1165 do {
1166 l = read(s, (char *)&m_rtmsg, sizeof (m_rtmsg));
1167 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
1168 if (l < 0)
1169 (void) fprintf(stderr, "ndp: read from routing socket: %s\n",
1170 strerror(errno));
1171 return (0);
1172 }
1173
1174 static void
1175 ifinfo(int argc, char **argv)
1176 {
1177 struct in6_ndireq nd;
1178 int i, s;
1179 char *ifname = argv[0];
1180 u_int32_t newflags;
1181 u_int8_t nullbuf[8];
1182
1183 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
1184 perror("ndp: socket");
1185 exit(1);
1186 }
1187 bzero(&nd, sizeof (nd));
1188 strlcpy(nd.ifname, ifname, sizeof (nd.ifname));
1189 if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
1190 perror("ioctl (SIOCGIFINFO_IN6)");
1191 exit(1);
1192 }
1193 #define ND nd.ndi
1194 newflags = ND.flags;
1195 for (i = 1; i < argc; i++) {
1196 int clear = 0;
1197 char *cp = argv[i];
1198
1199 if (*cp == '-') {
1200 clear = 1;
1201 cp++;
1202 }
1203
1204 #define SETFLAG(s, f) \
1205 do {\
1206 if (strcmp(cp, (s)) == 0) {\
1207 if (clear)\
1208 newflags &= ~(f);\
1209 else\
1210 newflags |= (f);\
1211 }\
1212 } while (0)
1213 SETFLAG("nud", ND6_IFF_PERFORMNUD);
1214 SETFLAG("proxy_prefixes", ND6_IFF_PROXY_PREFIXES);
1215 SETFLAG("disabled", ND6_IFF_IFDISABLED);
1216 SETFLAG("insecure", ND6_IFF_INSECURE);
1217 SETFLAG("replicated", ND6_IFF_REPLICATED);
1218
1219 ND.flags = newflags;
1220 if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) {
1221 perror("ioctl(SIOCSIFINFO_FLAGS)");
1222 exit(1);
1223 }
1224 #undef SETFLAG
1225 }
1226
1227 printf("linkmtu=%d", ND.linkmtu);
1228 printf(", curhlim=%d", ND.chlim);
1229 printf(", basereachable=%ds%dms", ND.basereachable / 1000,
1230 ND.basereachable % 1000);
1231 printf(", reachable=%ds", ND.reachable);
1232 printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000);
1233 memset(nullbuf, 0, sizeof (nullbuf));
1234 if (memcmp(nullbuf, ND.randomid, sizeof (nullbuf)) != 0) {
1235 int j;
1236 u_int8_t *rbuf = NULL;
1237
1238 for (i = 0; i < 3; i++) {
1239 switch (i) {
1240 case 0:
1241 printf("\nRandom seed(0): ");
1242 rbuf = ND.randomseed0;
1243 break;
1244 case 1:
1245 printf("\nRandom seed(1): ");
1246 rbuf = ND.randomseed1;
1247 break;
1248 case 2:
1249 printf("\nRandom ID: ");
1250 rbuf = ND.randomid;
1251 break;
1252 }
1253 for (j = 0; j < 8; j++)
1254 printf("%02x", rbuf[j]);
1255 }
1256 }
1257 if (ND.flags) {
1258 printf("\nFlags: 0x%x ", ND.flags);
1259 if ((ND.flags & ND6_IFF_IFDISABLED) != 0)
1260 printf("IFDISABLED ");
1261 if ((ND.flags & ND6_IFF_INSECURE) != 0)
1262 printf("INSECURE ");
1263 if ((ND.flags & ND6_IFF_PERFORMNUD) != 0)
1264 printf("PERFORMNUD ");
1265 if ((ND.flags & ND6_IFF_PROXY_PREFIXES) != 0)
1266 printf("PROXY_PREFIXES ");
1267 if ((ND.flags & ND6_IFF_REPLICATED) != 0)
1268 printf("REPLICATED ");
1269 if ((ND.flags & ND6_IFF_DAD) != 0)
1270 printf("DAD ");
1271 }
1272 putc('\n', stdout);
1273 #undef ND
1274
1275 close(s);
1276 }
1277
1278 #ifndef ND_RA_FLAG_RTPREF_MASK /* XXX: just for compilation on *BSD release */
1279 #define ND_RA_FLAG_RTPREF_MASK 0x18 /* 00011000 */
1280 #endif
1281
1282 static void
1283 rtrlist(void)
1284 {
1285 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_DRLIST };
1286 char *buf;
1287 struct in6_defrouter *p, *ep;
1288 size_t l;
1289 struct timeval time;
1290
1291 if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), NULL, &l, NULL, 0)
1292 < 0) {
1293 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
1294 /*NOTREACHED*/
1295 }
1296 buf = malloc(l);
1297 if (!buf) {
1298 errx(1, "not enough core");
1299 /*NOTREACHED*/
1300 }
1301 if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), buf, &l, NULL, 0) < 0) {
1302 err(1, "sysctl(ICMPV6CTL_ND6_DRLIST)");
1303 /*NOTREACHED*/
1304 }
1305
1306 ep = (struct in6_defrouter *)(buf + l);
1307 for (p = (struct in6_defrouter *)buf; p < ep; p++) {
1308 int rtpref;
1309
1310 if (getnameinfo((struct sockaddr *)&p->rtaddr,
1311 p->rtaddr.sin6_len, host_buf, sizeof (host_buf), NULL, 0,
1312 NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0)) != 0)
1313 strlcpy(host_buf, "?", sizeof (host_buf));
1314
1315 printf("%s if=%s", host_buf, if_indextoname(p->if_index,
1316 ifix_buf));
1317 printf(", flags=%s%s%s%s%s",
1318 p->stateflags & NDDRF_IFSCOPE ? "I" : "",
1319 p->flags & ND_RA_FLAG_MANAGED ? "M" : "",
1320 p->flags & ND_RA_FLAG_OTHER ? "O" : "",
1321 p->stateflags & NDDRF_STATIC ? "S" : "",
1322 p->stateflags & NDDRF_INSTALLED ? "T" : "");
1323 rtpref = ((p->flags & ND_RA_FLAG_RTPREF_MASK) >> 3) & 0xff;
1324 printf(", pref=%s", rtpref_str[rtpref]);
1325
1326 gettimeofday(&time, 0);
1327 if (p->expire == 0)
1328 printf(", expire=Never\n");
1329 else
1330 printf(", expire=%s\n",
1331 sec2str(p->expire - time.tv_sec));
1332 }
1333 free(buf);
1334 }
1335
1336 static void
1337 plist(void)
1338 {
1339 int mib[] = { CTL_NET, PF_INET6, IPPROTO_ICMPV6, ICMPV6CTL_ND6_PRLIST };
1340 char *buf;
1341 struct in6_prefix *p, *ep, *n;
1342 struct sockaddr_in6 *advrtr;
1343 size_t l;
1344 struct timeval time;
1345 const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID;
1346 int ninflags = (nflag ? NI_NUMERICHOST : 0) | NI_WITHSCOPEID;
1347 char namebuf[NI_MAXHOST];
1348
1349 if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), NULL, &l, NULL, 0)
1350 < 0) {
1351 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
1352 /*NOTREACHED*/
1353 }
1354 buf = malloc(l);
1355 if (!buf) {
1356 errx(1, "not enough core");
1357 /*NOTREACHED*/
1358 }
1359 if (sysctl(mib, sizeof (mib) / sizeof (mib[0]), buf, &l, NULL, 0)
1360 < 0) {
1361 err(1, "sysctl(ICMPV6CTL_ND6_PRLIST)");
1362 /*NOTREACHED*/
1363 }
1364
1365 ep = (struct in6_prefix *)(buf + l);
1366 for (p = (struct in6_prefix *)buf; p < ep; p = n) {
1367 advrtr = (struct sockaddr_in6 *)(p + 1);
1368 n = (struct in6_prefix *)&advrtr[p->advrtrs];
1369
1370 if (getnameinfo((struct sockaddr *)&p->prefix,
1371 p->prefix.sin6_len, namebuf, sizeof (namebuf),
1372 NULL, 0, niflags) != 0)
1373 strlcpy(namebuf, "?", sizeof (namebuf));
1374 printf("%s/%d if=%s\n", namebuf, p->prefixlen,
1375 if_indextoname(p->if_index, ifix_buf));
1376
1377 gettimeofday(&time, 0);
1378 /*
1379 * meaning of fields, especially flags, is very different
1380 * by origin. notify the difference to the users.
1381 */
1382 printf("flags=%s%s%s%s%s%s%s",
1383 p->raflags.autonomous ? "A" : "",
1384 (p->flags & NDPRF_DETACHED) != 0 ? "D" : "",
1385 (p->flags & NDPRF_IFSCOPE) != 0 ? "I" : "",
1386 p->raflags.onlink ? "L" : "",
1387 (p->flags & NDPRF_STATIC) != 0 ? "S" : "",
1388 (p->flags & NDPRF_ONLINK) != 0 ? "O" : "",
1389 (p->flags & NDPRF_PRPROXY) != 0 ? "Y" : "");
1390 if (p->vltime == ND6_INFINITE_LIFETIME)
1391 printf(" vltime=infinity");
1392 else
1393 printf(" vltime=%ld", (long)p->vltime);
1394 if (p->pltime == ND6_INFINITE_LIFETIME)
1395 printf(", pltime=infinity");
1396 else
1397 printf(", pltime=%ld", (long)p->pltime);
1398 if (p->expire == 0)
1399 printf(", expire=Never");
1400 else if (p->expire >= time.tv_sec)
1401 printf(", expire=%s",
1402 sec2str(p->expire - time.tv_sec));
1403 else
1404 printf(", expired");
1405 printf(", ref=%d", p->refcnt);
1406 printf("\n");
1407 /*
1408 * "advertising router" list is meaningful only if the prefix
1409 * information is from RA.
1410 */
1411 if (p->advrtrs) {
1412 int j;
1413 struct sockaddr_in6 *sin6;
1414
1415 sin6 = (struct sockaddr_in6 *)(p + 1);
1416 printf(" advertised by\n");
1417 for (j = 0; j < p->advrtrs; j++) {
1418 struct in6_nbrinfo *nbi;
1419
1420 if (getnameinfo((struct sockaddr *)sin6,
1421 sin6->sin6_len, namebuf, sizeof (namebuf),
1422 NULL, 0, ninflags) != 0)
1423 strlcpy(namebuf, "?", sizeof (namebuf));
1424 printf(" %s", namebuf);
1425
1426 nbi = getnbrinfo(&sin6->sin6_addr, p->if_index,
1427 0);
1428 if (nbi) {
1429 switch (nbi->state) {
1430 case ND6_LLINFO_REACHABLE:
1431 case ND6_LLINFO_STALE:
1432 case ND6_LLINFO_DELAY:
1433 case ND6_LLINFO_PROBE:
1434 printf(" (reachable)\n");
1435 break;
1436 default:
1437 printf(" (unreachable)\n");
1438 }
1439 } else
1440 printf(" (no neighbor state)\n");
1441 sin6++;
1442 }
1443 } else
1444 printf(" No advertising router\n");
1445 }
1446 free(buf);
1447 }
1448
1449 static void
1450 pfx_flush(void)
1451 {
1452 char dummyif[IFNAMSIZ+8];
1453 int s;
1454
1455 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1456 err(1, "socket");
1457 strlcpy(dummyif, "lo0", sizeof (dummyif)); /* dummy */
1458 if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
1459 err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
1460 }
1461
1462 static void
1463 rtr_flush(void)
1464 {
1465 char dummyif[IFNAMSIZ+8];
1466 int s;
1467
1468 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1469 err(1, "socket");
1470 strlcpy(dummyif, "lo0", sizeof (dummyif)); /* dummy */
1471 if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
1472 err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
1473
1474 close(s);
1475 }
1476
1477 static void
1478 harmonize_rtr(void)
1479 {
1480 char dummyif[IFNAMSIZ+8];
1481 int s;
1482
1483 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1484 err(1, "socket");
1485 strlcpy(dummyif, "lo0", sizeof (dummyif)); /* dummy */
1486 if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
1487 err(1, "ioctl (SIOCSNDFLUSH_IN6)");
1488
1489 close(s);
1490 }
1491
1492 static void
1493 setdefif(char *ifname)
1494 {
1495 struct in6_ndifreq ndifreq;
1496 unsigned int ifindex;
1497
1498 if (strcasecmp(ifname, "delete") == 0)
1499 ifindex = 0;
1500 else {
1501 if ((ifindex = if_nametoindex(ifname)) == 0)
1502 err(1, "failed to resolve i/f index for %s", ifname);
1503 }
1504
1505 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1506 err(1, "socket");
1507
1508 strlcpy(ndifreq.ifname, "lo0", sizeof (ndifreq.ifname)); /* dummy */
1509 ndifreq.ifindex = ifindex;
1510
1511 if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1512 err(1, "ioctl (SIOCSDEFIFACE_IN6)");
1513
1514 close(s);
1515 }
1516
1517 static void
1518 getdefif(void)
1519 {
1520 struct in6_ndifreq ndifreq;
1521 char ifname[IFNAMSIZ+8];
1522
1523 if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1524 err(1, "socket");
1525
1526 memset(&ndifreq, 0, sizeof (ndifreq));
1527 strlcpy(ndifreq.ifname, "lo0", sizeof (ndifreq.ifname)); /* dummy */
1528
1529 if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1530 err(1, "ioctl (SIOCGDEFIFACE_IN6)");
1531
1532 if (ndifreq.ifindex == 0)
1533 printf("No default interface.\n");
1534 else {
1535 if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
1536 err(1, "failed to resolve ifname for index %lu",
1537 ndifreq.ifindex);
1538 printf("ND default interface = %s\n", ifname);
1539 }
1540
1541 close(s);
1542 }
1543
1544 static char *
1545 sec2str(time_t total)
1546 {
1547 static char result[256];
1548 int days, hours, mins, secs;
1549 int first = 1;
1550 char *p = result;
1551
1552 days = total / 3600 / 24;
1553 hours = (total / 3600) % 24;
1554 mins = (total / 60) % 60;
1555 secs = total % 60;
1556
1557 if (days) {
1558 first = 0;
1559 p += snprintf(p, sizeof (result) - (p - result), "%dd", days);
1560 }
1561 if (!first || hours) {
1562 first = 0;
1563 p += snprintf(p, sizeof (result) - (p - result), "%dh", hours);
1564 }
1565 if (!first || mins)
1566 p += snprintf(p, sizeof (result) - (p - result), "%dm", mins);
1567 snprintf(p, sizeof (result) - (p - result), "%ds", secs);
1568
1569 return (result);
1570 }
1571
1572 /*
1573 * Print the timestamp
1574 * from tcpdump/util.c
1575 */
1576 static void
1577 ts_print(const struct timeval *tvp)
1578 {
1579 int s;
1580
1581 /* Default */
1582 s = (tvp->tv_sec + thiszone) % 86400;
1583 printf("%02d:%02d:%02d.%06u ", s / 3600, (s % 3600) / 60, s % 60,
1584 (u_int32_t)tvp->tv_usec);
1585 }
1586
1587 #define SYSCTL_CGA_PARAMETERS_BUFFER_SIZE \
1588 2 * (sizeof (size_t) + IN6_CGA_KEY_MAXSIZE) + \
1589 sizeof (struct in6_cga_prepare)
1590
1591 static void
1592 read_cga_parameters(void)
1593 {
1594 static char oldb[SYSCTL_CGA_PARAMETERS_BUFFER_SIZE];
1595
1596 int error;
1597 struct in6_cga_nodecfg cfg;
1598 struct iovec *iov;
1599 const char *oldp;
1600 const char *finp;
1601 size_t oldn;
1602 unsigned int column;
1603 uint16_t u16;
1604
1605 oldn = sizeof oldb;
1606 error = sysctlbyname("net.inet6.send.cga_parameters", oldb, &oldn,
1607 NULL, NULL);
1608 if (error != 0)
1609 err(1, "sysctlbyname");
1610
1611 if (oldn == 0) {
1612 printf("No CGA parameters.\n");
1613 exit(0);
1614 }
1615
1616 oldp = oldb;
1617 finp = &oldb[oldn];
1618 memset(&cfg, 0, sizeof (cfg));
1619
1620 if (oldp + sizeof (cfg.cga_prepare) > finp)
1621 err(1, "format error[1]");
1622
1623 memcpy(&cfg.cga_prepare, oldp, sizeof (cfg.cga_prepare));
1624 oldp += sizeof (cfg.cga_prepare);
1625
1626 iov = &cfg.cga_pubkey;
1627
1628 if (oldp + sizeof (u16) > finp)
1629 err(1, "format error[2]");
1630
1631 memcpy(&u16, oldp, sizeof (u16));
1632 oldp += sizeof (u16);
1633 iov->iov_len = u16;
1634
1635 if (oldp + iov->iov_len > finp)
1636 err(1, "format error[3]");
1637
1638 iov->iov_base = (void *)oldp;
1639 oldp += iov->iov_len;
1640
1641 if (oldp != finp)
1642 err(1, "format error[4]");
1643
1644 puts("Public Key:");
1645 finp = &iov->iov_base[iov->iov_len];
1646 column = 0;
1647 oldp = iov->iov_base;
1648 while (oldp < finp) {
1649 if (column++ != 0)
1650 putchar(':');
1651 printf("%02x", (unsigned char) *oldp++);
1652 if (column >= 32) {
1653 column = 0;
1654 puts("");
1655 }
1656 }
1657 if (column < 32)
1658 puts("");
1659 puts("");
1660 puts("Modifier:");
1661 oldp = (const char*) cfg.cga_prepare.cga_modifier.octets;
1662 finp = &oldp[sizeof (cfg.cga_prepare.cga_modifier.octets)];
1663 column = 0;
1664 while (oldp < finp) {
1665 if (column++ != 0)
1666 putchar(':');
1667 printf("%02x", (unsigned char) *oldp++);
1668 }
1669 puts("\n");
1670 printf("Security Level: %u\n", cfg.cga_prepare.cga_security_level);
1671 }
1672
1673 static void
1674 write_cga_parameters(const char filename[])
1675 {
1676 static char newb[SYSCTL_CGA_PARAMETERS_BUFFER_SIZE];
1677
1678 int error;
1679 FILE* fp;
1680 size_t oldn, newn;
1681
1682 fp = fopen(filename, "r");
1683 if (fp == NULL)
1684 err(1, "opening '%s' for reading.", filename);
1685
1686 newn = fread(newb, 1, sizeof (newb), fp);
1687 if (feof(fp) == 0)
1688 err(1, "parameters too large");
1689
1690 if (fclose(fp) != 0)
1691 err(1, "closing file.");
1692
1693 oldn = 0;
1694 error = sysctlbyname("net.inet6.send.cga_parameters", NULL, NULL, newb,
1695 newn);
1696 if (error != 0)
1697 err(1, "sysctlbyname");
1698 }