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