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