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