]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ndp/ndp.c
This commit was generated by cvs2svn to compensate for changes in r77424,
[FreeBSD/FreeBSD.git] / usr.sbin / ndp / ndp.c
1 /*      $FreeBSD$       */
2 /*      $KAME: ndp.c,v 1.46 2000/10/09 09:17:10 sumikawa Exp $  */
3
4 /*
5  * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the project nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 /*
33  * Copyright (c) 1984, 1993
34  *      The Regents of the University of California.  All rights reserved.
35  *
36  * This code is derived from software contributed to Berkeley by
37  * Sun Microsystems, Inc.
38  *
39  * Redistribution and use in source and binary forms, with or without
40  * modification, are permitted provided that the following conditions
41  * are met:
42  * 1. Redistributions of source code must retain the above copyright
43  *    notice, this list of conditions and the following disclaimer.
44  * 2. Redistributions in binary form must reproduce the above copyright
45  *    notice, this list of conditions and the following disclaimer in the
46  *    documentation and/or other materials provided with the distribution.
47  * 3. All advertising materials mentioning features or use of this software
48  *    must display the following acknowledgement:
49  *      This product includes software developed by the University of
50  *      California, Berkeley and its contributors.
51  * 4. Neither the name of the University nor the names of its contributors
52  *    may be used to endorse or promote products derived from this software
53  *    without specific prior written permission.
54  *
55  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
56  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
57  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
58  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
59  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
60  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
61  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
63  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
64  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
65  * SUCH DAMAGE.
66  */
67
68 /*
69  * Based on:
70  * "@(#) Copyright (c) 1984, 1993\n\
71  *      The Regents of the University of California.  All rights reserved.\n";
72  *
73  * "@(#)arp.c   8.2 (Berkeley) 1/2/94";
74  */
75
76 /*
77  * ndp - display, set, delete and flush neighbor cache
78  */
79
80
81 #include <sys/param.h>
82 #include <sys/file.h>
83 #include <sys/ioctl.h>
84 #include <sys/socket.h>
85 #include <sys/sysctl.h>
86 #include <sys/time.h>
87
88 #include <net/if.h>
89 #include <net/if_var.h>
90 #include <net/if_dl.h>
91 #include <net/if_types.h>
92 #include <net/route.h>
93
94 #include <netinet/in.h>
95 #include <netinet/if_ether.h>
96
97 #include <netinet/icmp6.h>
98 #include <netinet6/in6_var.h>
99 #include <netinet6/nd6.h>
100
101 #include <arpa/inet.h>
102
103 #include <netdb.h>
104 #include <errno.h>
105 #include <nlist.h>
106 #include <stdio.h>
107 #include <string.h>
108 #include <paths.h>
109 #include <err.h>
110 #include <stdlib.h>
111 #include <fcntl.h>
112 #include <unistd.h>
113 #include "gmt2local.h"
114
115 #ifndef NI_WITHSCOPEID
116 #define NI_WITHSCOPEID  0
117 #endif
118
119 /* packing rule for routing socket */
120 #define ROUNDUP(a) \
121         ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
122 #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
123
124 static int pid;
125 static int cflag;
126 static int nflag;
127 static int tflag;
128 static int32_t thiszone;        /* time difference with gmt */
129 static int s = -1;
130 static int repeat = 0;
131 static int lflag = 0;
132
133 char ntop_buf[INET6_ADDRSTRLEN];        /* inet_ntop() */
134 char host_buf[NI_MAXHOST];              /* getnameinfo() */
135 char ifix_buf[IFNAMSIZ];                /* if_indextoname() */
136
137 int main __P((int, char **));
138 int file __P((char *));
139 void getsocket __P((void));
140 int set __P((int, char **));
141 void get __P((char *));
142 int delete __P((char *));
143 void dump __P((struct in6_addr *));
144 static struct in6_nbrinfo *getnbrinfo __P((struct in6_addr *addr,
145                                            int ifindex, int));
146 static char *ether_str __P((struct sockaddr_dl *));
147 int ndp_ether_aton __P((char *, u_char *));
148 void usage __P((void));
149 int rtmsg __P((int));
150 void ifinfo __P((int, char **));
151 void rtrlist __P((void));
152 void plist __P((void));
153 void pfx_flush __P((void));
154 void rtrlist __P((void));
155 void rtr_flush __P((void));
156 void harmonize_rtr __P((void));
157 #ifdef SIOCSDEFIFACE_IN6        /* XXX: check SIOCGDEFIFACE_IN6 as well? */
158 static void getdefif __P((void));
159 static void setdefif __P((char *));
160 #endif
161 static char *sec2str __P((time_t t));
162 static char *ether_str __P((struct sockaddr_dl *sdl));
163 static void ts_print __P((const struct timeval *));
164
165 int
166 main(argc, argv)
167         int argc;
168         char **argv;
169 {
170         int ch;
171         int aflag = 0, dflag = 0, sflag = 0, Hflag = 0,
172                 pflag = 0, rflag = 0, Pflag = 0, Rflag = 0;
173
174         pid = getpid();
175         thiszone = gmt2local(0);
176         while ((ch = getopt(argc, argv, "acndfIilprstA:HPR")) != EOF)
177                 switch ((char)ch) {
178                 case 'a':
179                         aflag = 1;
180                         break;
181                 case 'c':
182                         cflag = 1;
183                         break;
184                 case 'd':
185                         dflag = 1;
186                         break;
187                 case 'I':
188 #ifdef SIOCSDEFIFACE_IN6        /* XXX: check SIOCGDEFIFACE_IN6 as well? */
189                         if (argc > 2)
190                                 setdefif(argv[2]);
191                         getdefif(); /* always call it to print the result */
192                         exit(0);
193 #else
194                         errx(1, "not supported yet");
195                         /*NOTREACHED*/
196 #endif
197                 case 'i' :
198                         argc -= optind;
199                         argv += optind;
200                         if (argc < 1)
201                                 usage();
202                         ifinfo(argc, argv);
203                         exit(0);
204                 case 'n':
205                         nflag = 1;
206                         continue;
207                 case 'p':
208                         pflag = 1;
209                         break;
210                 case 'f' :
211                         if (argc != 3)
212                                 usage();
213                         file(argv[2]);
214                         exit(0);
215                 case 'l' :
216                         lflag = 1;
217                         break;
218                 case 'r' :
219                         rflag = 1;
220                         break;
221                 case 's':
222                         sflag = 1;
223                         break;
224                 case 't':
225                         tflag = 1;
226                         break;
227                 case 'A':
228                         aflag = 1;
229                         repeat = atoi(optarg);
230                         if (repeat < 0)
231                                 usage();
232                         break;
233                 case 'H' :
234                         Hflag = 1;
235                         break;
236                 case 'P':
237                         Pflag = 1;
238                         break;
239                 case 'R':
240                         Rflag = 1;
241                         break;
242                 default:
243                         usage();
244                 }
245
246         argc -= optind;
247         argv += optind;
248
249         if (aflag || cflag) {
250                 dump(0);
251                 exit(0);
252         }
253         if (dflag) {
254                 if (argc != 1)
255                         usage();
256                 delete(argv[0]);
257                 exit(0);
258         }
259         if (pflag) {
260                 plist();
261                 exit(0);
262         }
263         if (rflag) {
264                 rtrlist();
265                 exit(0);
266         }
267         if (sflag) {
268                 if (argc < 2 || argc > 4)
269                         usage();
270                 exit(set(argc, argv) ? 1 : 0);
271         }
272         if (Hflag) {
273                 harmonize_rtr();
274                 exit(0);
275         }
276         if (Pflag) {
277                 pfx_flush();
278                 exit(0);
279         }
280         if (Rflag) {
281                 rtr_flush();
282                 exit(0);
283         }
284
285         if (argc != 1)
286                 usage();
287         get(argv[0]);
288         exit(0);
289 }
290
291 /*
292  * Process a file to set standard ndp entries
293  */
294 int
295 file(name)
296         char *name;
297 {
298         FILE *fp;
299         int i, retval;
300         char line[100], arg[5][50], *args[5];
301
302         if ((fp = fopen(name, "r")) == NULL) {
303                 fprintf(stderr, "ndp: cannot open %s\n", name);
304                 exit(1);
305         }
306         args[0] = &arg[0][0];
307         args[1] = &arg[1][0];
308         args[2] = &arg[2][0];
309         args[3] = &arg[3][0];
310         args[4] = &arg[4][0];
311         retval = 0;
312         while(fgets(line, 100, fp) != NULL) {
313                 i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
314                     arg[3], arg[4]);
315                 if (i < 2) {
316                         fprintf(stderr, "ndp: bad line: %s\n", line);
317                         retval = 1;
318                         continue;
319                 }
320                 if (set(i, args))
321                         retval = 1;
322         }
323         fclose(fp);
324         return (retval);
325 }
326
327 void
328 getsocket()
329 {
330         if (s < 0) {
331                 s = socket(PF_ROUTE, SOCK_RAW, 0);
332                 if (s < 0) {
333                         perror("ndp: socket");
334                         exit(1);
335                 }
336         }
337 }
338
339 struct  sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET6 };
340 struct  sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET6 }, sin_m;
341 struct  sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
342 int     expire_time, flags, found_entry;
343 struct  {
344         struct  rt_msghdr m_rtm;
345         char    m_space[512];
346 }       m_rtmsg;
347
348 /*
349  * Set an individual neighbor cache entry
350  */
351 int
352 set(argc, argv)
353         int argc;
354         char **argv;
355 {
356         register struct sockaddr_in6 *sin = &sin_m;
357         register struct sockaddr_dl *sdl;
358         register 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 = expire_time = 0;
389         while (argc-- > 0) {
390                 if (strncmp(argv[0], "temp", 4) == 0) {
391                         struct timeval time;
392                         gettimeofday(&time, 0);
393                         expire_time = time.tv_sec + 20 * 60;
394                 } else if (strncmp(argv[0], "proxy", 5) == 0)
395                         flags |= RTF_ANNOUNCE;
396                 argv++;
397         }
398         if (rtmsg(RTM_GET) < 0) {
399                 perror(host);
400                 return (1);
401         }
402         sin = (struct sockaddr_in6 *)(rtm + 1);
403         sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin6_len) + (char *)sin);
404         if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)) {
405                 if (sdl->sdl_family == AF_LINK &&
406                     (rtm->rtm_flags & RTF_LLINFO) &&
407                     !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
408                 case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
409                 case IFT_ISO88024: case IFT_ISO88025:
410                         goto overwrite;
411                 }
412                 /*
413                  * IPv4 arp command retries with sin_other = SIN_PROXY here.
414                  */
415                 fprintf(stderr, "set: cannot configure a new entry\n");
416                 return 1;
417         }
418
419 overwrite:
420         if (sdl->sdl_family != AF_LINK) {
421                 printf("cannot intuit interface index and type for %s\n", host);
422                 return (1);
423         }
424         sdl_m.sdl_type = sdl->sdl_type;
425         sdl_m.sdl_index = sdl->sdl_index;
426         return (rtmsg(RTM_ADD));
427 }
428
429 /*
430  * Display an individual neighbor cache entry
431  */
432 void
433 get(host)
434         char *host;
435 {
436         struct sockaddr_in6 *sin = &sin_m;
437         struct addrinfo hints, *res;
438         int gai_error;
439
440         sin_m = blank_sin;
441         bzero(&hints, sizeof(hints));
442         hints.ai_family = AF_INET6;
443         gai_error = getaddrinfo(host, NULL, &hints, &res);
444         if (gai_error) {
445                 fprintf(stderr, "ndp: %s: %s\n", host,
446                         gai_strerror(gai_error));
447                 return;
448         }
449         sin->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr;
450 #ifdef __KAME__
451         if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) {
452                 *(u_int16_t *)&sin->sin6_addr.s6_addr[2] =
453                         htons(((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id);
454         }
455 #endif
456         dump(&sin->sin6_addr);
457         if (found_entry == 0) {
458                 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
459                             sizeof(host_buf), NULL ,0,
460                             NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
461                 printf("%s (%s) -- no entry\n", host, host_buf);
462                 exit(1);
463         }
464 }
465
466 /*
467  * Delete a neighbor cache entry
468  */
469 int
470 delete(host)
471         char *host;
472 {
473         struct sockaddr_in6 *sin = &sin_m;
474         register 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                         switch (sdl->sdl_type) {
508                         case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
509                         case IFT_ISO88024: case IFT_ISO88025:
510                                 goto delete;
511                         }
512                 }
513                 /*
514                  * IPv4 arp command retries with sin_other = SIN_PROXY here.
515                  */
516                 fprintf(stderr, "delete: cannot delete non-NDP entry\n");
517                 return 1;
518         }
519
520 delete:
521         if (sdl->sdl_family != AF_LINK) {
522                 printf("cannot locate %s\n", host);
523                 return (1);
524         }
525         if (rtmsg(RTM_DELETE) == 0) {
526                 struct sockaddr_in6 s6 = *sin; /* XXX: for safety */
527
528 #ifdef __KAME__
529                 if (IN6_IS_ADDR_LINKLOCAL(&s6.sin6_addr)) {
530                         s6.sin6_scope_id = ntohs(*(u_int16_t *)&s6.sin6_addr.s6_addr[2]);
531                         *(u_int16_t *)&s6.sin6_addr.s6_addr[2] = 0;
532                 }
533 #endif
534                 getnameinfo((struct sockaddr *)&s6,
535                             s6.sin6_len, host_buf,
536                             sizeof(host_buf), NULL, 0,
537                             NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
538                 printf("%s (%s) deleted\n", host, host_buf);
539         }
540
541         return 0;
542 }
543
544 /*
545  * Dump the entire neighbor cache
546  */
547 void
548 dump(addr)
549         struct in6_addr *addr;
550 {
551         int mib[6];
552         size_t needed;
553         char *lim, *buf, *next;
554         struct rt_msghdr *rtm;
555         struct sockaddr_in6 *sin;
556         struct sockaddr_dl *sdl;
557         extern int h_errno;
558         struct in6_nbrinfo *nbi;
559         struct timeval time;
560         int addrwidth;
561         char flgbuf[8];
562
563         /* Print header */
564         if (!tflag && !cflag)
565                 printf("%-31.31s %-17.17s %6.6s %-9.9s %2s %4s %4s\n",
566                        "Neighbor", "Linklayer Address", "Netif", "Expire",
567                        "St", "Flgs", "Prbs");
568
569 again:;
570         mib[0] = CTL_NET;
571         mib[1] = PF_ROUTE;
572         mib[2] = 0;
573         mib[3] = AF_INET6;
574         mib[4] = NET_RT_FLAGS;
575         mib[5] = RTF_LLINFO;
576         if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
577                 err(1, "sysctl(PF_ROUTE estimate)");
578         if (needed > 0) {
579                 if ((buf = malloc(needed)) == NULL)
580                         errx(1, "malloc");
581                 if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
582                         err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
583                 lim = buf + needed;
584         } else
585                 buf = lim = NULL;
586
587         for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
588                 int isrouter = 0, prbs = 0;
589
590                 rtm = (struct rt_msghdr *)next;
591                 sin = (struct sockaddr_in6 *)(rtm + 1);
592                 sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len));
593                 if (addr) {
594                         if (!IN6_ARE_ADDR_EQUAL(addr, &sin->sin6_addr))
595                                 continue;
596                         found_entry = 1;
597                 } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr))
598                         continue;
599                 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) ||
600                     IN6_IS_ADDR_MC_LINKLOCAL(&sin->sin6_addr)) {
601                         /* XXX: should scope id be filled in the kernel? */
602                         if (sin->sin6_scope_id == 0)
603                                 sin->sin6_scope_id = sdl->sdl_index;
604 #ifdef __KAME__
605                         /* KAME specific hack; removed the embedded id */
606                         *(u_int16_t *)&sin->sin6_addr.s6_addr[2] = 0;
607 #endif
608                 }
609                 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
610                             sizeof(host_buf), NULL, 0,
611                             NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
612                 if (cflag == 1) {
613                         delete(host_buf);
614                         continue;
615                 }
616                 gettimeofday(&time, 0);
617                 if (tflag)
618                         ts_print(&time);
619
620                 if (lflag) {
621                         addrwidth = strlen(host_buf);
622                         if (addrwidth < 31)
623                                 addrwidth = 31;
624                 } else
625                         addrwidth = 31;
626
627                 printf("%-*.*s %-17.17s %6.6s", addrwidth, addrwidth, host_buf,
628                        ether_str(sdl),
629                        if_indextoname(sdl->sdl_index, ifix_buf));
630
631                 /* Print neighbor discovery specific informations */
632                 nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
633                 if (nbi) {
634                         if (nbi->expire > time.tv_sec) {
635                                 printf(" %-9.9s",
636                                        sec2str(nbi->expire - time.tv_sec));
637                         }
638                         else if (nbi->expire == 0)
639                                 printf(" %-9.9s", "permanent");
640                         else
641                                 printf(" %-9.9s", "expired");
642
643                         switch(nbi->state) {
644                          case ND6_LLINFO_NOSTATE:
645                                  printf(" N");
646                                  break;
647                          case ND6_LLINFO_WAITDELETE:
648                                  printf(" W");
649                                  break;
650                          case ND6_LLINFO_INCOMPLETE:
651                                  printf(" I");
652                                  break;
653                          case ND6_LLINFO_REACHABLE:
654                                  printf(" R");
655                                  break;
656                          case ND6_LLINFO_STALE:
657                                  printf(" S");
658                                  break;
659                          case ND6_LLINFO_DELAY:
660                                  printf(" D");
661                                  break;
662                          case ND6_LLINFO_PROBE:
663                                  printf(" P");
664                                  break;
665                          default:
666                                  printf(" ?");
667                                  break;
668                         }
669
670                         isrouter = nbi->isrouter;
671                         prbs = nbi->asked;
672                 }
673                 else {
674                         warnx("failed to get neighbor information");
675                         printf("  ");
676                 }
677                 putchar(' ');
678
679                 /*
680                  * other flags. R: router, P: proxy, W: ??
681                  */
682                 if ((rtm->rtm_addrs & RTA_NETMASK) == 0) {
683                         snprintf(flgbuf, sizeof(flgbuf), "%s%s",
684                                 isrouter ? "R" : "",
685                                 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
686                 } else {
687                         sin = (struct sockaddr_in6 *)
688                                 (sdl->sdl_len + (char *)sdl);
689                         snprintf(flgbuf, sizeof(flgbuf), "%s%s%s%s",
690                                 isrouter ? "R" : "",
691                                 !IN6_IS_ADDR_UNSPECIFIED(&sin->sin6_addr)
692                                         ? "P" : "",
693                                 (sin->sin6_len != sizeof(struct sockaddr_in6))
694                                         ? "W" : "",
695                                 (rtm->rtm_flags & RTF_ANNOUNCE) ? "p" : "");
696                 }
697                 printf(" %-4.4s", flgbuf);
698
699                 if (prbs)
700                         printf(" %4d", prbs);
701
702                 printf("\n");
703         }
704
705         if (repeat) {
706                 printf("\n");
707                 sleep(repeat);
708                 goto again;
709         }
710 }
711
712 static struct in6_nbrinfo *
713 getnbrinfo(addr, ifindex, warning)
714         struct in6_addr *addr;
715         int ifindex;
716         int warning;
717 {
718         static struct in6_nbrinfo nbi;
719         int s;
720
721         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
722                 err(1, "socket");
723
724         bzero(&nbi, sizeof(nbi));
725         if_indextoname(ifindex, nbi.ifname);
726         nbi.addr = *addr;
727         if (ioctl(s, SIOCGNBRINFO_IN6, (caddr_t)&nbi) < 0) {
728                 if (warning)
729                         warn("ioctl(SIOCGNBRINFO_IN6)");
730                 close(s);
731                 return(NULL);
732         }
733
734         close(s);
735         return(&nbi);
736 }
737
738 static char *
739 ether_str(sdl)
740         struct sockaddr_dl *sdl;
741 {
742         static char ebuf[32];
743         u_char *cp;
744
745         if (sdl->sdl_alen) {
746                 cp = (u_char *)LLADDR(sdl);
747                 sprintf(ebuf, "%x:%x:%x:%x:%x:%x",
748                         cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
749         }
750         else {
751                 sprintf(ebuf, "(incomplete)");
752         }
753
754         return(ebuf);
755 }
756
757 int
758 ndp_ether_aton(a, n)
759         char *a;
760         u_char *n;
761 {
762         int i, o[6];
763
764         i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
765                                            &o[3], &o[4], &o[5]);
766         if (i != 6) {
767                 fprintf(stderr, "ndp: invalid Ethernet address '%s'\n", a);
768                 return (1);
769         }
770         for (i=0; i<6; i++)
771                 n[i] = o[i];
772         return (0);
773 }
774
775 void
776 usage()
777 {
778         printf("usage: ndp hostname\n");
779         printf("       ndp -a[ntl]\n");
780         printf("       ndp [-ntl] -A wait\n");
781         printf("       ndp -c[nt]\n");
782         printf("       ndp -d[nt] hostname\n");
783         printf("       ndp -f[nt] filename\n");
784         printf("       ndp -i interface [flags...]\n");
785 #ifdef SIOCSDEFIFACE_IN6
786         printf("       ndp -I [interface|delete]\n");
787 #endif
788         printf("       ndp -p\n");
789         printf("       ndp -r\n");
790         printf("       ndp -s hostname ether_addr [temp] [proxy]\n");
791         printf("       ndp -H\n");
792         printf("       ndp -P\n");
793         printf("       ndp -R\n");
794         exit(1);
795 }
796
797 int
798 rtmsg(cmd)
799         int cmd;
800 {
801         static int seq;
802         int rlen;
803         register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
804         register char *cp = m_rtmsg.m_space;
805         register int l;
806
807         errno = 0;
808         if (cmd == RTM_DELETE)
809                 goto doit;
810         bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
811         rtm->rtm_flags = flags;
812         rtm->rtm_version = RTM_VERSION;
813
814         switch (cmd) {
815         default:
816                 fprintf(stderr, "ndp: internal wrong cmd\n");
817                 exit(1);
818         case RTM_ADD:
819                 rtm->rtm_addrs |= RTA_GATEWAY;
820                 rtm->rtm_rmx.rmx_expire = expire_time;
821                 rtm->rtm_inits = RTV_EXPIRE;
822                 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
823                 if (rtm->rtm_flags & RTF_ANNOUNCE) {
824                         rtm->rtm_flags &= ~RTF_HOST;
825                         rtm->rtm_flags |= RTA_NETMASK;
826                 }
827                 /* FALLTHROUGH */
828         case RTM_GET:
829                 rtm->rtm_addrs |= RTA_DST;
830         }
831 #define NEXTADDR(w, s) \
832         if (rtm->rtm_addrs & (w)) { \
833                 bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);}
834
835         NEXTADDR(RTA_DST, sin_m);
836         NEXTADDR(RTA_GATEWAY, sdl_m);
837         memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr));
838         NEXTADDR(RTA_NETMASK, so_mask);
839
840         rtm->rtm_msglen = cp - (char *)&m_rtmsg;
841 doit:
842         l = rtm->rtm_msglen;
843         rtm->rtm_seq = ++seq;
844         rtm->rtm_type = cmd;
845         if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
846                 if (errno != ESRCH || cmd != RTM_DELETE) {
847                         perror("writing to routing socket");
848                         return (-1);
849                 }
850         }
851         do {
852                 l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
853         } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
854         if (l < 0)
855                 (void) fprintf(stderr, "ndp: read from routing socket: %s\n",
856                     strerror(errno));
857         return (0);
858 }
859
860 void
861 ifinfo(argc, argv)
862         int argc;
863         char **argv;
864 {
865         struct in6_ndireq nd;
866         int i, s;
867         char *ifname = argv[0];
868         u_int32_t newflags;
869
870         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
871                 perror("ndp: socket");
872                 exit(1);
873         }
874         bzero(&nd, sizeof(nd));
875         strcpy(nd.ifname, ifname);
876         if (ioctl(s, SIOCGIFINFO_IN6, (caddr_t)&nd) < 0) {
877                 perror("ioctl (SIOCGIFINFO_IN6)");
878                 exit(1);
879         }
880 #define ND nd.ndi
881         newflags = ND.flags;
882         for (i = 1; i < argc; i++) {
883                 int clear = 0;
884                 char *cp = argv[i];
885
886                 if (*cp == '-') {
887                         clear = 1;
888                         cp++;
889                 }
890
891 #define SETFLAG(s, f) \
892         do {\
893                 if (strcmp(cp, (s)) == 0) {\
894                         if (clear)\
895                                 newflags &= ~(f);\
896                         else\
897                                 newflags |= (f);\
898                 }\
899         } while (0)
900                 SETFLAG("nud", ND6_IFF_PERFORMNUD);
901
902                 ND.flags = newflags;
903                 if (ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd) < 0) {
904                         perror("ioctl(SIOCSIFINFO_FLAGS)");
905                         exit(1);
906                 }
907 #undef SETFLAG
908         }
909
910         printf("linkmtu=%d", ND.linkmtu);
911         printf(", curhlim=%d", ND.chlim);
912         printf(", basereachable=%ds%dms",
913                ND.basereachable / 1000, ND.basereachable % 1000);
914         printf(", reachable=%ds", ND.reachable);
915         printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000);
916         if (ND.flags) {
917                 printf("\nFlags: ");
918                 if ((ND.flags & ND6_IFF_PERFORMNUD) != 0)
919                         printf("PERFORMNUD ");
920         }
921         putc('\n', stdout);
922 #undef ND
923         
924         close(s);
925 }
926
927 void
928 rtrlist()
929 {
930         struct in6_drlist dr;
931         int s, i;
932         struct timeval time;
933
934         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
935                 perror("ndp: socket");
936                 exit(1);
937         }
938         bzero(&dr, sizeof(dr));
939         strcpy(dr.ifname, "lo0"); /* dummy */
940         if (ioctl(s, SIOCGDRLST_IN6, (caddr_t)&dr) < 0) {
941                 perror("ioctl (SIOCGDRLST_IN6)");
942                 exit(1);
943         }
944 #define DR dr.defrouter[i]
945         for (i = 0 ; DR.if_index && i < PRLSTSIZ ; i++) {
946                 struct sockaddr_in6 sin6;
947
948                 bzero(&sin6, sizeof(sin6));
949                 sin6.sin6_family = AF_INET6;
950                 sin6.sin6_len = sizeof(sin6);
951                 sin6.sin6_addr = DR.rtaddr;
952                 getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len, host_buf,
953                             sizeof(host_buf), NULL, 0,
954                             NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
955                 
956                 printf("%s if=%s", host_buf,
957                        if_indextoname(DR.if_index, ifix_buf));
958                 printf(", flags=%s%s",
959                        DR.flags & ND_RA_FLAG_MANAGED ? "M" : "",
960                        DR.flags & ND_RA_FLAG_OTHER   ? "O" : "");
961                 gettimeofday(&time, 0);
962                 if (DR.expire == 0)
963                         printf(", expire=Never\n");
964                 else
965                         printf(", expire=%s\n",
966                                 sec2str(DR.expire - time.tv_sec));
967         }
968 #undef DR
969         close(s);
970 }
971
972 void
973 plist()
974 {
975         struct in6_prlist pr;
976         int s, i;
977         struct timeval time;
978
979         gettimeofday(&time, 0);
980
981         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
982                 perror("ndp: socket");
983                 exit(1);
984         }
985         bzero(&pr, sizeof(pr));
986         strcpy(pr.ifname, "lo0"); /* dummy */
987         if (ioctl(s, SIOCGPRLST_IN6, (caddr_t)&pr) < 0) {
988                 perror("ioctl (SIOCGPRLST_IN6)");
989                 exit(1);
990         }
991 #define PR pr.prefix[i]
992         for (i = 0; PR.if_index && i < PRLSTSIZ ; i++) {
993                 printf("%s/%d if=%s\n",
994                        inet_ntop(AF_INET6, &PR.prefix, ntop_buf,
995                                  sizeof(ntop_buf)), PR.prefixlen,
996                        if_indextoname(PR.if_index, ifix_buf));
997                 gettimeofday(&time, 0);
998                 /*
999                  * meaning of fields, especially flags, is very different
1000                  * by origin.  notify the difference to the users.
1001                  */
1002                 printf("  %s", PR.origin == PR_ORIG_RA ? "" : "advertise: ");
1003                 printf("flags=%s%s",
1004                        PR.raflags.onlink ? "L" : "",
1005                        PR.raflags.autonomous ? "A" : "");
1006                 if (PR.vltime == ND6_INFINITE_LIFETIME)
1007                         printf(" vltime=infinity");
1008                 else
1009                         printf(" vltime=%ld", (long)PR.vltime);
1010                 if (PR.pltime == ND6_INFINITE_LIFETIME)
1011                         printf(", pltime=infinity");
1012                 else
1013                         printf(", pltime=%ld", (long)PR.pltime);
1014                 if (PR.expire == 0)
1015                         printf(", expire=Never");
1016                 else if (PR.expire >= time.tv_sec)
1017                         printf(", expire=%s",
1018                                 sec2str(PR.expire - time.tv_sec));
1019                 else
1020                         printf(", expired");
1021                 switch (PR.origin) {
1022                 case PR_ORIG_RA:
1023                         printf(", origin=RA");
1024                         break;
1025                 case PR_ORIG_RR:
1026                         printf(", origin=RR");
1027                         break;
1028                 case PR_ORIG_STATIC:
1029                         printf(", origin=static");
1030                         break;
1031                 case PR_ORIG_KERNEL:
1032                         printf(", origin=kernel");
1033                         break;
1034                 default:
1035                         printf(", origin=?");
1036                         break;
1037                 }
1038                 printf("\n");
1039                 /*
1040                  * "advertising router" list is meaningful only if the prefix
1041                  * information is from RA.
1042                  */
1043                 if (PR.origin != PR_ORIG_RA)
1044                         ;
1045                 else if (PR.advrtrs) {
1046                         int j;
1047                         printf("  advertised by\n");
1048                         for (j = 0; j < PR.advrtrs; j++) {
1049                                 struct sockaddr_in6 sin6;
1050                                 struct in6_nbrinfo *nbi;
1051
1052                                 bzero(&sin6, sizeof(sin6));
1053                                 sin6.sin6_family = AF_INET6;
1054                                 sin6.sin6_len = sizeof(sin6);
1055                                 sin6.sin6_addr = PR.advrtr[j];
1056                                 sin6.sin6_scope_id = PR.if_index; /* XXX */
1057                                 getnameinfo((struct sockaddr *)&sin6,
1058                                             sin6.sin6_len, host_buf,
1059                                             sizeof(host_buf), NULL, 0,
1060                                             NI_WITHSCOPEID | (nflag ? NI_NUMERICHOST : 0));
1061                                 printf("    %s", host_buf);
1062
1063                                 nbi = getnbrinfo(&sin6.sin6_addr, PR.if_index,
1064                                                  0);
1065                                 if (nbi) {
1066                                         switch(nbi->state) {
1067                                          case ND6_LLINFO_REACHABLE:
1068                                          case ND6_LLINFO_STALE:
1069                                          case ND6_LLINFO_DELAY:
1070                                          case ND6_LLINFO_PROBE:
1071                                                  printf(" (reachable)\n");
1072                                                  break;
1073                                          default:
1074                                                  printf(" (unreachable)\n");
1075                                         }
1076                                 }
1077                                 else
1078                                         printf(" (no neighbor state)\n");
1079                         }
1080                         if (PR.advrtrs > DRLSTSIZ)
1081                                 printf("    and %d routers\n",
1082                                        PR.advrtrs - DRLSTSIZ);
1083                 } else
1084                         printf("  No advertising router\n");
1085         }
1086 #undef PR
1087         close(s);
1088 }
1089
1090 void
1091 pfx_flush()
1092 {
1093         char dummyif[IFNAMSIZ+8];
1094         int s;
1095
1096         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1097                 err(1, "socket");
1098         strcpy(dummyif, "lo0"); /* dummy */
1099         if (ioctl(s, SIOCSPFXFLUSH_IN6, (caddr_t)&dummyif) < 0)
1100                 err(1, "ioctl(SIOCSPFXFLUSH_IN6)");
1101 }
1102
1103 void
1104 rtr_flush()
1105 {
1106         char dummyif[IFNAMSIZ+8];
1107         int s;
1108
1109         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1110                 err(1, "socket");
1111         strcpy(dummyif, "lo0"); /* dummy */
1112         if (ioctl(s, SIOCSRTRFLUSH_IN6, (caddr_t)&dummyif) < 0)
1113                 err(1, "ioctl(SIOCSRTRFLUSH_IN6)");
1114
1115         close(s);
1116 }
1117
1118 void
1119 harmonize_rtr()
1120 {
1121         char dummyif[IFNAMSIZ+8];
1122         int s;
1123
1124         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1125                 err(1, "socket");
1126         strcpy(dummyif, "lo0"); /* dummy */
1127         if (ioctl(s, SIOCSNDFLUSH_IN6, (caddr_t)&dummyif) < 0)
1128                 err(1, "ioctl (SIOCSNDFLUSH_IN6)");
1129
1130         close(s);
1131 }
1132
1133 #ifdef SIOCSDEFIFACE_IN6        /* XXX: check SIOCGDEFIFACE_IN6 as well? */
1134 static void
1135 setdefif(ifname)
1136         char *ifname;
1137 {
1138         struct in6_ndifreq ndifreq;
1139         unsigned int ifindex;
1140
1141         if (strcasecmp(ifname, "delete") == 0)
1142                 ifindex = 0;
1143         else {
1144                 if ((ifindex = if_nametoindex(ifname)) == 0)
1145                         err(1, "failed to resolve i/f index for %s", ifname);
1146         }
1147
1148         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1149                 err(1, "socket");
1150
1151         strcpy(ndifreq.ifname, "lo0"); /* dummy */
1152         ndifreq.ifindex = ifindex;
1153
1154         if (ioctl(s, SIOCSDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1155                 err(1, "ioctl (SIOCSDEFIFACE_IN6)");
1156
1157         close(s);
1158 }
1159
1160 static void
1161 getdefif()
1162 {
1163         struct in6_ndifreq ndifreq;
1164         char ifname[IFNAMSIZ+8];
1165
1166         if ((s = socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
1167                 err(1, "socket");
1168
1169         memset(&ndifreq, 0, sizeof(ndifreq));
1170         strcpy(ndifreq.ifname, "lo0"); /* dummy */
1171
1172         if (ioctl(s, SIOCGDEFIFACE_IN6, (caddr_t)&ndifreq) < 0)
1173                 err(1, "ioctl (SIOCGDEFIFACE_IN6)");
1174
1175         if (ndifreq.ifindex == 0)
1176                 printf("No default interface.\n");
1177         else {
1178                 if ((if_indextoname(ndifreq.ifindex, ifname)) == NULL)
1179                         err(1, "failed to resolve ifname for index %lu",
1180                             ndifreq.ifindex);
1181                 printf("ND default interface = %s\n", ifname);
1182         }
1183
1184         close(s);
1185 }
1186 #endif
1187
1188 static char *
1189 sec2str(total)
1190         time_t total;
1191 {
1192         static char result[256];
1193         int days, hours, mins, secs;
1194         int first = 1;
1195         char *p = result;
1196
1197         days = total / 3600 / 24;
1198         hours = (total / 3600) % 24;
1199         mins = (total / 60) % 60;
1200         secs = total % 60;
1201
1202         if (days) {
1203                 first = 0;
1204                 p += sprintf(p, "%dd", days);
1205         }
1206         if (!first || hours) {
1207                 first = 0;
1208                 p += sprintf(p, "%dh", hours);
1209         }
1210         if (!first || mins) {
1211                 first = 0;
1212                 p += sprintf(p, "%dm", mins);
1213         }
1214         sprintf(p, "%ds", secs);
1215
1216         return(result);
1217 }
1218
1219 /*
1220  * Print the timestamp
1221  * from tcpdump/util.c
1222  */
1223 static void
1224 ts_print(tvp)
1225         const struct timeval *tvp;
1226 {
1227         int s;
1228
1229         /* Default */
1230         s = (tvp->tv_sec + thiszone) % 86400;
1231         (void)printf("%02d:%02d:%02d.%06u ",
1232             s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec);
1233 }