ndp.c revision 1.60 1 1.60 tnn /* $NetBSD: ndp.c,v 1.60 2023/08/18 13:07:38 tnn Exp $ */
2 1.34 rpaulo /* $KAME: ndp.c,v 1.121 2005/07/13 11:30:13 keiichi Exp $ */
3 1.9 itojun
4 1.1 itojun /*
5 1.1 itojun * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
6 1.1 itojun * All rights reserved.
7 1.9 itojun *
8 1.1 itojun * Redistribution and use in source and binary forms, with or without
9 1.1 itojun * modification, are permitted provided that the following conditions
10 1.1 itojun * are met:
11 1.1 itojun * 1. Redistributions of source code must retain the above copyright
12 1.1 itojun * notice, this list of conditions and the following disclaimer.
13 1.1 itojun * 2. Redistributions in binary form must reproduce the above copyright
14 1.1 itojun * notice, this list of conditions and the following disclaimer in the
15 1.1 itojun * documentation and/or other materials provided with the distribution.
16 1.1 itojun * 3. Neither the name of the project nor the names of its contributors
17 1.1 itojun * may be used to endorse or promote products derived from this software
18 1.1 itojun * without specific prior written permission.
19 1.9 itojun *
20 1.1 itojun * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 1.1 itojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 1.1 itojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 1.1 itojun * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 1.1 itojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 1.1 itojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 1.1 itojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 1.1 itojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 1.1 itojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 1.1 itojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 1.1 itojun * SUCH DAMAGE.
31 1.1 itojun */
32 1.1 itojun /*
33 1.1 itojun * Copyright (c) 1984, 1993
34 1.1 itojun * The Regents of the University of California. All rights reserved.
35 1.1 itojun *
36 1.1 itojun * This code is derived from software contributed to Berkeley by
37 1.1 itojun * Sun Microsystems, Inc.
38 1.1 itojun *
39 1.1 itojun * Redistribution and use in source and binary forms, with or without
40 1.1 itojun * modification, are permitted provided that the following conditions
41 1.1 itojun * are met:
42 1.1 itojun * 1. Redistributions of source code must retain the above copyright
43 1.1 itojun * notice, this list of conditions and the following disclaimer.
44 1.1 itojun * 2. Redistributions in binary form must reproduce the above copyright
45 1.1 itojun * notice, this list of conditions and the following disclaimer in the
46 1.1 itojun * documentation and/or other materials provided with the distribution.
47 1.29 agc * 3. Neither the name of the University nor the names of its contributors
48 1.1 itojun * may be used to endorse or promote products derived from this software
49 1.1 itojun * without specific prior written permission.
50 1.1 itojun *
51 1.1 itojun * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 1.1 itojun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 1.1 itojun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 1.1 itojun * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 1.1 itojun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 1.1 itojun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 1.1 itojun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 1.1 itojun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 1.1 itojun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 1.1 itojun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 1.1 itojun * SUCH DAMAGE.
62 1.1 itojun */
63 1.1 itojun
64 1.1 itojun /*
65 1.60 tnn * Copyright (c) 1997
66 1.60 tnn * The Regents of the University of California. All rights reserved.
67 1.60 tnn *
68 1.60 tnn * Redistribution and use in source and binary forms, with or without
69 1.60 tnn * modification, are permitted provided that: (1) source code distributions
70 1.60 tnn * retain the above copyright notice and this paragraph in its entirety, (2)
71 1.60 tnn * distributions including binary code include the above copyright notice and
72 1.60 tnn * this paragraph in its entirety in the documentation or other materials
73 1.60 tnn * provided with the distribution, and (3) all advertising materials mentioning
74 1.60 tnn * features or use of this software display the following acknowledgement:
75 1.60 tnn * ``This product includes software developed by the University of California,
76 1.60 tnn * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
77 1.60 tnn * the University nor the names of its contributors may be used to endorse
78 1.60 tnn * or promote products derived from this software without specific prior
79 1.60 tnn * written permission.
80 1.60 tnn * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
81 1.60 tnn * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
82 1.60 tnn * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
83 1.60 tnn */
84 1.60 tnn
85 1.60 tnn /*
86 1.1 itojun * Based on:
87 1.1 itojun * "@(#) Copyright (c) 1984, 1993\n\
88 1.1 itojun * The Regents of the University of California. All rights reserved.\n";
89 1.1 itojun *
90 1.1 itojun * "@(#)arp.c 8.2 (Berkeley) 1/2/94";
91 1.1 itojun */
92 1.1 itojun
93 1.1 itojun /*
94 1.1 itojun * ndp - display, set, delete and flush neighbor cache
95 1.1 itojun */
96 1.1 itojun
97 1.1 itojun
98 1.1 itojun #include <sys/param.h>
99 1.1 itojun #include <sys/file.h>
100 1.1 itojun #include <sys/ioctl.h>
101 1.1 itojun #include <sys/socket.h>
102 1.1 itojun #include <sys/sysctl.h>
103 1.1 itojun #include <sys/time.h>
104 1.1 itojun
105 1.1 itojun #include <net/if.h>
106 1.1 itojun #include <net/if_dl.h>
107 1.1 itojun #include <net/if_types.h>
108 1.1 itojun #include <net/route.h>
109 1.1 itojun
110 1.1 itojun #include <netinet/in.h>
111 1.1 itojun
112 1.1 itojun #include <netinet/icmp6.h>
113 1.1 itojun #include <netinet6/in6_var.h>
114 1.1 itojun #include <netinet6/nd6.h>
115 1.1 itojun
116 1.1 itojun #include <arpa/inet.h>
117 1.1 itojun
118 1.1 itojun #include <netdb.h>
119 1.1 itojun #include <errno.h>
120 1.1 itojun #include <nlist.h>
121 1.1 itojun #include <stdio.h>
122 1.1 itojun #include <string.h>
123 1.1 itojun #include <paths.h>
124 1.1 itojun #include <err.h>
125 1.1 itojun #include <stdlib.h>
126 1.1 itojun #include <fcntl.h>
127 1.1 itojun #include <unistd.h>
128 1.45 ozaki
129 1.45 ozaki #include "prog_ops.h"
130 1.1 itojun
131 1.19 itojun static pid_t pid;
132 1.1 itojun static int nflag;
133 1.1 itojun static int tflag;
134 1.1 itojun static int32_t thiszone; /* time difference with gmt */
135 1.35 christos static int my_s = -1;
136 1.35 christos static unsigned int repeat = 0;
137 1.1 itojun
138 1.35 christos
139 1.35 christos static char host_buf[NI_MAXHOST]; /* getnameinfo() */
140 1.35 christos static char ifix_buf[IFNAMSIZ]; /* if_indextoname() */
141 1.35 christos
142 1.35 christos static void getsocket(void);
143 1.35 christos static int set(int, char **);
144 1.35 christos static void get(char *);
145 1.50 ozaki static int delete(struct rt_msghdr *, char *);
146 1.50 ozaki static void delete_one(char *);
147 1.50 ozaki static void do_foreach(struct in6_addr *, char *, int);
148 1.35 christos static struct in6_nbrinfo *getnbrinfo(struct in6_addr *, unsigned int, int);
149 1.35 christos static char *ether_str(struct sockaddr_dl *);
150 1.35 christos static int ndp_ether_aton(char *, u_char *);
151 1.40 joerg __dead static void usage(void);
152 1.50 ozaki static int rtmsg(int, struct rt_msghdr *);
153 1.35 christos static void ifinfo(char *, int, char **);
154 1.35 christos static const char *sec2str(time_t);
155 1.35 christos static char *ether_str(struct sockaddr_dl *);
156 1.35 christos static void ts_print(const struct timeval *);
157 1.60 tnn static int32_t gmt2local(time_t t);
158 1.1 itojun
159 1.50 ozaki #define NDP_F_CLEAR 1
160 1.50 ozaki #define NDP_F_DELETE 2
161 1.50 ozaki
162 1.35 christos static int mode = 0;
163 1.35 christos static char *arg = NULL;
164 1.22 itojun
165 1.1 itojun int
166 1.35 christos main(int argc, char **argv)
167 1.1 itojun {
168 1.1 itojun int ch;
169 1.1 itojun
170 1.56 roy while ((ch = getopt(argc, argv, "acd:f:i:nstA:")) != -1)
171 1.22 itojun switch (ch) {
172 1.1 itojun case 'a':
173 1.1 itojun case 'c':
174 1.22 itojun case 's':
175 1.1 itojun case 'd':
176 1.22 itojun case 'f':
177 1.1 itojun case 'i' :
178 1.22 itojun if (mode) {
179 1.1 itojun usage();
180 1.22 itojun /*NOTREACHED*/
181 1.22 itojun }
182 1.22 itojun mode = ch;
183 1.22 itojun arg = optarg;
184 1.22 itojun break;
185 1.1 itojun case 'n':
186 1.1 itojun nflag = 1;
187 1.1 itojun break;
188 1.1 itojun case 't':
189 1.1 itojun tflag = 1;
190 1.1 itojun break;
191 1.1 itojun case 'A':
192 1.22 itojun if (mode) {
193 1.22 itojun usage();
194 1.22 itojun /*NOTREACHED*/
195 1.22 itojun }
196 1.22 itojun mode = 'a';
197 1.1 itojun repeat = atoi(optarg);
198 1.1 itojun break;
199 1.1 itojun default:
200 1.1 itojun usage();
201 1.1 itojun }
202 1.1 itojun
203 1.1 itojun argc -= optind;
204 1.1 itojun argv += optind;
205 1.1 itojun
206 1.45 ozaki if (prog_init && prog_init() == -1)
207 1.45 ozaki err(1, "init failed");
208 1.45 ozaki
209 1.45 ozaki pid = prog_getpid();
210 1.45 ozaki thiszone = gmt2local(0L);
211 1.45 ozaki
212 1.22 itojun switch (mode) {
213 1.22 itojun case 'a':
214 1.22 itojun case 'c':
215 1.22 itojun if (argc != 0) {
216 1.22 itojun usage();
217 1.22 itojun /*NOTREACHED*/
218 1.22 itojun }
219 1.50 ozaki do_foreach(0, NULL, mode == 'c' ? NDP_F_CLEAR : 0);
220 1.22 itojun break;
221 1.22 itojun case 'd':
222 1.22 itojun if (argc != 0) {
223 1.22 itojun usage();
224 1.22 itojun /*NOTREACHED*/
225 1.22 itojun }
226 1.50 ozaki delete_one(arg);
227 1.22 itojun break;
228 1.22 itojun case 'i':
229 1.22 itojun ifinfo(arg, argc, argv);
230 1.22 itojun break;
231 1.22 itojun case 's':
232 1.1 itojun if (argc < 2 || argc > 4)
233 1.1 itojun usage();
234 1.35 christos return(set(argc, argv) ? 1 : 0);
235 1.22 itojun case 0:
236 1.22 itojun if (argc != 1) {
237 1.22 itojun usage();
238 1.22 itojun /*NOTREACHED*/
239 1.22 itojun }
240 1.22 itojun get(argv[0]);
241 1.22 itojun break;
242 1.1 itojun }
243 1.35 christos return(0);
244 1.1 itojun }
245 1.1 itojun
246 1.35 christos static void
247 1.46 christos makeaddr(struct sockaddr_in6 *mysin, const void *resp)
248 1.46 christos {
249 1.46 christos const struct sockaddr_in6 *res = resp;
250 1.46 christos mysin->sin6_addr = res->sin6_addr;
251 1.46 christos mysin->sin6_scope_id = res->sin6_scope_id;
252 1.46 christos inet6_putscopeid(mysin, INET6_IS_ADDR_LINKLOCAL);
253 1.46 christos }
254 1.46 christos
255 1.46 christos static void
256 1.35 christos getsocket(void)
257 1.1 itojun {
258 1.35 christos if (my_s < 0) {
259 1.45 ozaki my_s = prog_socket(PF_ROUTE, SOCK_RAW, 0);
260 1.35 christos if (my_s < 0)
261 1.28 itojun err(1, "socket");
262 1.1 itojun }
263 1.1 itojun }
264 1.1 itojun
265 1.35 christos #ifdef notdef
266 1.36 christos static struct sockaddr_in6 so_mask = {
267 1.36 christos .sin6_len = sizeof(so_mask),
268 1.36 christos .sin6_family = AF_INET6
269 1.36 christos };
270 1.35 christos #endif
271 1.36 christos static struct sockaddr_in6 blank_sin = {
272 1.36 christos .sin6_len = sizeof(blank_sin),
273 1.36 christos .sin6_family = AF_INET6
274 1.36 christos };
275 1.36 christos static struct sockaddr_in6 sin_m;
276 1.36 christos static struct sockaddr_dl blank_sdl = {
277 1.36 christos .sdl_len = sizeof(blank_sdl),
278 1.36 christos .sdl_family = AF_LINK,
279 1.36 christos };
280 1.36 christos static struct sockaddr_dl sdl_m;
281 1.36 christos static int expire_time, flags, found_entry;
282 1.36 christos static struct {
283 1.1 itojun struct rt_msghdr m_rtm;
284 1.1 itojun char m_space[512];
285 1.36 christos } m_rtmsg;
286 1.1 itojun
287 1.1 itojun /*
288 1.1 itojun * Set an individual neighbor cache entry
289 1.1 itojun */
290 1.35 christos static int
291 1.35 christos set(int argc, char **argv)
292 1.1 itojun {
293 1.35 christos register struct sockaddr_in6 *mysin = &sin_m;
294 1.1 itojun register struct sockaddr_dl *sdl;
295 1.1 itojun register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
296 1.1 itojun struct addrinfo hints, *res;
297 1.1 itojun int gai_error;
298 1.1 itojun u_char *ea;
299 1.1 itojun char *host = argv[0], *eaddr = argv[1];
300 1.1 itojun
301 1.1 itojun getsocket();
302 1.1 itojun argc -= 2;
303 1.1 itojun argv += 2;
304 1.1 itojun sdl_m = blank_sdl;
305 1.1 itojun sin_m = blank_sin;
306 1.1 itojun
307 1.35 christos (void)memset(&hints, 0, sizeof(hints));
308 1.1 itojun hints.ai_family = AF_INET6;
309 1.1 itojun gai_error = getaddrinfo(host, NULL, &hints, &res);
310 1.1 itojun if (gai_error) {
311 1.44 christos warnx("%s: %s", host, gai_strerror(gai_error));
312 1.1 itojun return 1;
313 1.1 itojun }
314 1.46 christos makeaddr(mysin, res->ai_addr);
315 1.51 christos freeaddrinfo(res);
316 1.1 itojun ea = (u_char *)LLADDR(&sdl_m);
317 1.1 itojun if (ndp_ether_aton(eaddr, ea) == 0)
318 1.1 itojun sdl_m.sdl_alen = 6;
319 1.1 itojun flags = expire_time = 0;
320 1.1 itojun while (argc-- > 0) {
321 1.1 itojun if (strncmp(argv[0], "temp", 4) == 0) {
322 1.35 christos struct timeval tim;
323 1.21 itojun
324 1.35 christos (void)gettimeofday(&tim, 0);
325 1.35 christos expire_time = tim.tv_sec + 20 * 60;
326 1.6 itojun } else if (strncmp(argv[0], "proxy", 5) == 0)
327 1.6 itojun flags |= RTF_ANNOUNCE;
328 1.1 itojun argv++;
329 1.1 itojun }
330 1.50 ozaki if (rtmsg(RTM_GET, NULL) < 0) {
331 1.16 itojun errx(1, "RTM_GET(%s) failed", host);
332 1.16 itojun /* NOTREACHED */
333 1.1 itojun }
334 1.35 christos mysin = (struct sockaddr_in6 *)(void *)(rtm + 1);
335 1.39 drochner sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(mysin->sin6_len) + (char *)(void *)mysin);
336 1.35 christos if (IN6_ARE_ADDR_EQUAL(&mysin->sin6_addr, &sin_m.sin6_addr)) {
337 1.1 itojun if (sdl->sdl_family == AF_LINK &&
338 1.22 itojun !(rtm->rtm_flags & RTF_GATEWAY)) {
339 1.22 itojun switch (sdl->sdl_type) {
340 1.22 itojun case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
341 1.22 itojun case IFT_ISO88024: case IFT_ISO88025:
342 1.22 itojun goto overwrite;
343 1.22 itojun }
344 1.1 itojun }
345 1.9 itojun /*
346 1.9 itojun * IPv4 arp command retries with sin_other = SIN_PROXY here.
347 1.9 itojun */
348 1.35 christos (void)fprintf(stderr, "set: cannot configure a new entry\n");
349 1.9 itojun return 1;
350 1.1 itojun }
351 1.9 itojun
352 1.1 itojun overwrite:
353 1.1 itojun if (sdl->sdl_family != AF_LINK) {
354 1.35 christos warnx("cannot intuit interface index and type for %s", host);
355 1.1 itojun return (1);
356 1.1 itojun }
357 1.1 itojun sdl_m.sdl_type = sdl->sdl_type;
358 1.1 itojun sdl_m.sdl_index = sdl->sdl_index;
359 1.50 ozaki return (rtmsg(RTM_ADD, NULL));
360 1.1 itojun }
361 1.1 itojun
362 1.1 itojun /*
363 1.1 itojun * Display an individual neighbor cache entry
364 1.1 itojun */
365 1.35 christos static void
366 1.35 christos get(char *host)
367 1.1 itojun {
368 1.35 christos struct sockaddr_in6 *mysin = &sin_m;
369 1.1 itojun struct addrinfo hints, *res;
370 1.1 itojun int gai_error;
371 1.1 itojun
372 1.1 itojun sin_m = blank_sin;
373 1.35 christos (void)memset(&hints, 0, sizeof(hints));
374 1.1 itojun hints.ai_family = AF_INET6;
375 1.1 itojun gai_error = getaddrinfo(host, NULL, &hints, &res);
376 1.1 itojun if (gai_error) {
377 1.44 christos warnx("%s: %s", host, gai_strerror(gai_error));
378 1.1 itojun return;
379 1.1 itojun }
380 1.46 christos makeaddr(mysin, res->ai_addr);
381 1.51 christos freeaddrinfo(res);
382 1.50 ozaki do_foreach(&mysin->sin6_addr, host, 0);
383 1.1 itojun if (found_entry == 0) {
384 1.35 christos (void)getnameinfo((struct sockaddr *)(void *)mysin,
385 1.35 christos (socklen_t)mysin->sin6_len,
386 1.35 christos host_buf, sizeof(host_buf), NULL ,0,
387 1.21 itojun (nflag ? NI_NUMERICHOST : 0));
388 1.35 christos errx(1, "%s (%s) -- no entry", host, host_buf);
389 1.1 itojun }
390 1.1 itojun }
391 1.1 itojun
392 1.50 ozaki static void
393 1.50 ozaki delete_one(char *host)
394 1.1 itojun {
395 1.35 christos struct sockaddr_in6 *mysin = &sin_m;
396 1.1 itojun struct addrinfo hints, *res;
397 1.1 itojun int gai_error;
398 1.1 itojun
399 1.1 itojun sin_m = blank_sin;
400 1.50 ozaki (void)memset(&hints, 0, sizeof(hints));
401 1.1 itojun hints.ai_family = AF_INET6;
402 1.1 itojun gai_error = getaddrinfo(host, NULL, &hints, &res);
403 1.1 itojun if (gai_error) {
404 1.44 christos warnx("%s: %s", host, gai_strerror(gai_error));
405 1.50 ozaki return;
406 1.1 itojun }
407 1.46 christos makeaddr(mysin, res->ai_addr);
408 1.51 christos freeaddrinfo(res);
409 1.50 ozaki do_foreach(&mysin->sin6_addr, host, NDP_F_DELETE);
410 1.50 ozaki }
411 1.50 ozaki
412 1.50 ozaki /*
413 1.50 ozaki * Delete a neighbor cache entry
414 1.50 ozaki */
415 1.50 ozaki static int
416 1.50 ozaki delete(struct rt_msghdr *rtm, char *host)
417 1.50 ozaki {
418 1.53 nonaka char delete_host_buf[NI_MAXHOST];
419 1.50 ozaki struct sockaddr_in6 *mysin = &sin_m;
420 1.50 ozaki struct sockaddr_dl *sdl;
421 1.50 ozaki
422 1.50 ozaki getsocket();
423 1.35 christos mysin = (struct sockaddr_in6 *)(void *)(rtm + 1);
424 1.39 drochner sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(mysin->sin6_len) +
425 1.35 christos (char *)(void *)mysin);
426 1.8 itojun
427 1.1 itojun if (sdl->sdl_family != AF_LINK) {
428 1.35 christos (void)printf("cannot locate %s\n", host);
429 1.1 itojun return (1);
430 1.1 itojun }
431 1.50 ozaki if (rtmsg(RTM_DELETE, rtm) == 0) {
432 1.35 christos struct sockaddr_in6 s6 = *mysin; /* XXX: for safety */
433 1.11 itojun
434 1.54 nonaka s6.sin6_scope_id = 0;
435 1.54 nonaka inet6_putscopeid(&s6, INET6_IS_ADDR_LINKLOCAL);
436 1.35 christos (void)getnameinfo((struct sockaddr *)(void *)&s6,
437 1.53 nonaka (socklen_t)s6.sin6_len, delete_host_buf,
438 1.53 nonaka sizeof(delete_host_buf), NULL, 0,
439 1.21 itojun (nflag ? NI_NUMERICHOST : 0));
440 1.53 nonaka (void)printf("%s (%s) deleted\n", host, delete_host_buf);
441 1.4 itojun }
442 1.4 itojun
443 1.1 itojun return 0;
444 1.1 itojun }
445 1.1 itojun
446 1.48 christos #define W_ADDR (8 * 4 + 7)
447 1.13 itojun #define W_LL 17
448 1.13 itojun #define W_IF 6
449 1.13 itojun
450 1.1 itojun /*
451 1.50 ozaki * Iterate on neighbor caches and do
452 1.50 ozaki * - dump all caches,
453 1.50 ozaki * - clear all caches (NDP_F_CLEAR) or
454 1.50 ozaki * - remove matched caches (NDP_F_DELETE)
455 1.1 itojun */
456 1.35 christos static void
457 1.50 ozaki do_foreach(struct in6_addr *addr, char *host, int _flags)
458 1.1 itojun {
459 1.1 itojun int mib[6];
460 1.1 itojun size_t needed;
461 1.4 itojun char *lim, *buf, *next;
462 1.1 itojun struct rt_msghdr *rtm;
463 1.35 christos struct sockaddr_in6 *mysin;
464 1.1 itojun struct sockaddr_dl *sdl;
465 1.1 itojun struct in6_nbrinfo *nbi;
466 1.35 christos struct timeval tim;
467 1.4 itojun int addrwidth;
468 1.13 itojun int llwidth;
469 1.13 itojun int ifwidth;
470 1.48 christos char flgbuf[8], *fl;
471 1.35 christos const char *ifname;
472 1.50 ozaki int cflag = _flags == NDP_F_CLEAR;
473 1.50 ozaki int dflag = _flags == NDP_F_DELETE;
474 1.1 itojun
475 1.1 itojun /* Print header */
476 1.11 itojun if (!tflag && !cflag)
477 1.48 christos (void)printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %2s\n",
478 1.13 itojun W_ADDR, W_ADDR, "Neighbor", W_LL, W_LL, "Linklayer Address",
479 1.48 christos W_IF, W_IF, "Netif", "Expire", "S", "Fl");
480 1.1 itojun
481 1.1 itojun again:;
482 1.1 itojun mib[0] = CTL_NET;
483 1.1 itojun mib[1] = PF_ROUTE;
484 1.1 itojun mib[2] = 0;
485 1.1 itojun mib[3] = AF_INET6;
486 1.1 itojun mib[4] = NET_RT_FLAGS;
487 1.50 ozaki mib[5] = RTF_LLDATA;
488 1.45 ozaki if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
489 1.3 itojun err(1, "sysctl(PF_ROUTE estimate)");
490 1.3 itojun if (needed > 0) {
491 1.3 itojun if ((buf = malloc(needed)) == NULL)
492 1.28 itojun err(1, "malloc");
493 1.50 ozaki if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
494 1.50 ozaki free(buf);
495 1.50 ozaki if (errno == ENOBUFS)
496 1.50 ozaki goto again;
497 1.3 itojun err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
498 1.50 ozaki }
499 1.3 itojun lim = buf + needed;
500 1.3 itojun } else
501 1.3 itojun buf = lim = NULL;
502 1.1 itojun
503 1.3 itojun for (next = buf; next && next < lim; next += rtm->rtm_msglen) {
504 1.1 itojun int isrouter = 0, prbs = 0;
505 1.1 itojun
506 1.35 christos rtm = (struct rt_msghdr *)(void *)next;
507 1.35 christos mysin = (struct sockaddr_in6 *)(void *)(rtm + 1);
508 1.39 drochner sdl = (struct sockaddr_dl *)(void *)((char *)(void *)mysin + RT_ROUNDUP(mysin->sin6_len));
509 1.16 itojun
510 1.16 itojun /*
511 1.16 itojun * Some OSes can produce a route that has the LINK flag but
512 1.16 itojun * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
513 1.16 itojun * and BSD/OS, where xx is not the interface identifier on
514 1.16 itojun * lo0). Such routes entry would annoy getnbrinfo() below,
515 1.16 itojun * so we skip them.
516 1.16 itojun * XXX: such routes should have the GATEWAY flag, not the
517 1.16 itojun * LINK flag. However, there is rotten routing software
518 1.16 itojun * that advertises all routes that have the GATEWAY flag.
519 1.16 itojun * Thus, KAME kernel intentionally does not set the LINK flag.
520 1.16 itojun * What is to be fixed is not ndp, but such routing software
521 1.16 itojun * (and the kernel workaround)...
522 1.16 itojun */
523 1.16 itojun if (sdl->sdl_family != AF_LINK)
524 1.16 itojun continue;
525 1.16 itojun
526 1.19 itojun if (!(rtm->rtm_flags & RTF_HOST))
527 1.19 itojun continue;
528 1.19 itojun
529 1.1 itojun if (addr) {
530 1.35 christos if (!IN6_ARE_ADDR_EQUAL(addr, &mysin->sin6_addr))
531 1.1 itojun continue;
532 1.1 itojun found_entry = 1;
533 1.35 christos } else if (IN6_IS_ADDR_MULTICAST(&mysin->sin6_addr))
534 1.1 itojun continue;
535 1.50 ozaki if (dflag) {
536 1.50 ozaki (void)delete(rtm, host_buf);
537 1.50 ozaki continue;
538 1.50 ozaki }
539 1.35 christos if (IN6_IS_ADDR_LINKLOCAL(&mysin->sin6_addr) ||
540 1.35 christos IN6_IS_ADDR_MC_LINKLOCAL(&mysin->sin6_addr)) {
541 1.41 christos uint16_t scopeid = mysin->sin6_scope_id;
542 1.41 christos inet6_getscopeid(mysin, INET6_IS_ADDR_LINKLOCAL|
543 1.41 christos INET6_IS_ADDR_MC_LINKLOCAL);
544 1.41 christos if (scopeid == 0)
545 1.35 christos mysin->sin6_scope_id = sdl->sdl_index;
546 1.1 itojun }
547 1.35 christos (void)getnameinfo((struct sockaddr *)(void *)mysin,
548 1.35 christos (socklen_t)mysin->sin6_len,
549 1.35 christos host_buf, sizeof(host_buf), NULL, 0,
550 1.35 christos (nflag ? NI_NUMERICHOST : 0));
551 1.22 itojun if (cflag) {
552 1.50 ozaki /* Restore scopeid */
553 1.50 ozaki if (IN6_IS_ADDR_LINKLOCAL(&mysin->sin6_addr) ||
554 1.50 ozaki IN6_IS_ADDR_MC_LINKLOCAL(&mysin->sin6_addr))
555 1.50 ozaki inet6_putscopeid(mysin, INET6_IS_ADDR_LINKLOCAL|
556 1.50 ozaki INET6_IS_ADDR_MC_LINKLOCAL);
557 1.47 ozaki if ((rtm->rtm_flags & RTF_STATIC) == 0)
558 1.50 ozaki (void)delete(rtm, host_buf);
559 1.11 itojun continue;
560 1.11 itojun }
561 1.35 christos (void)gettimeofday(&tim, 0);
562 1.1 itojun if (tflag)
563 1.35 christos ts_print(&tim);
564 1.1 itojun
565 1.13 itojun addrwidth = strlen(host_buf);
566 1.13 itojun if (addrwidth < W_ADDR)
567 1.13 itojun addrwidth = W_ADDR;
568 1.13 itojun llwidth = strlen(ether_str(sdl));
569 1.13 itojun if (W_ADDR + W_LL - addrwidth > llwidth)
570 1.13 itojun llwidth = W_ADDR + W_LL - addrwidth;
571 1.35 christos ifname = if_indextoname((unsigned int)sdl->sdl_index, ifix_buf);
572 1.14 itojun if (!ifname)
573 1.14 itojun ifname = "?";
574 1.14 itojun ifwidth = strlen(ifname);
575 1.13 itojun if (W_ADDR + W_LL + W_IF - addrwidth - llwidth > ifwidth)
576 1.13 itojun ifwidth = W_ADDR + W_LL + W_IF - addrwidth - llwidth;
577 1.13 itojun
578 1.35 christos (void)printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth,
579 1.35 christos host_buf, llwidth, llwidth, ether_str(sdl), ifwidth,
580 1.35 christos ifwidth, ifname);
581 1.1 itojun
582 1.1 itojun /* Print neighbor discovery specific informations */
583 1.35 christos nbi = getnbrinfo(&mysin->sin6_addr,
584 1.35 christos (unsigned int)sdl->sdl_index, 1);
585 1.1 itojun if (nbi) {
586 1.35 christos if (nbi->expire > tim.tv_sec) {
587 1.35 christos (void)printf(" %-9.9s",
588 1.35 christos sec2str(nbi->expire - tim.tv_sec));
589 1.11 itojun } else if (nbi->expire == 0)
590 1.35 christos (void)printf(" %-9.9s", "permanent");
591 1.1 itojun else
592 1.35 christos (void)printf(" %-9.9s", "expired");
593 1.1 itojun
594 1.21 itojun switch (nbi->state) {
595 1.58 roy case ND_LLINFO_NOSTATE:
596 1.35 christos (void)printf(" N");
597 1.1 itojun break;
598 1.58 roy case ND_LLINFO_WAITDELETE:
599 1.35 christos (void)printf(" W");
600 1.1 itojun break;
601 1.58 roy case ND_LLINFO_INCOMPLETE:
602 1.35 christos (void)printf(" I");
603 1.1 itojun break;
604 1.58 roy case ND_LLINFO_REACHABLE:
605 1.35 christos (void)printf(" R");
606 1.1 itojun break;
607 1.58 roy case ND_LLINFO_STALE:
608 1.35 christos (void)printf(" S");
609 1.1 itojun break;
610 1.58 roy case ND_LLINFO_DELAY:
611 1.35 christos (void)printf(" D");
612 1.1 itojun break;
613 1.58 roy case ND_LLINFO_PROBE:
614 1.35 christos (void)printf(" P");
615 1.1 itojun break;
616 1.58 roy case ND_LLINFO_UNREACHABLE:
617 1.58 roy (void)printf(" U");
618 1.58 roy break;
619 1.19 itojun default:
620 1.35 christos (void)printf(" ?");
621 1.1 itojun break;
622 1.1 itojun }
623 1.1 itojun
624 1.1 itojun isrouter = nbi->isrouter;
625 1.1 itojun prbs = nbi->asked;
626 1.11 itojun } else {
627 1.1 itojun warnx("failed to get neighbor information");
628 1.35 christos (void)printf(" ");
629 1.1 itojun }
630 1.1 itojun
631 1.4 itojun /*
632 1.4 itojun * other flags. R: router, P: proxy, W: ??
633 1.4 itojun */
634 1.48 christos fl = flgbuf;
635 1.48 christos if (isrouter)
636 1.48 christos *fl++ = 'R';
637 1.48 christos if (rtm->rtm_flags & RTF_ANNOUNCE)
638 1.48 christos *fl++ = 'p';
639 1.48 christos *fl++ = '\0';
640 1.35 christos (void)printf(" %s", flgbuf);
641 1.1 itojun
642 1.1 itojun if (prbs)
643 1.35 christos (void)printf(" %d", prbs);
644 1.1 itojun
645 1.35 christos (void)printf("\n");
646 1.1 itojun }
647 1.12 itojun if (buf != NULL)
648 1.12 itojun free(buf);
649 1.1 itojun
650 1.1 itojun if (repeat) {
651 1.35 christos (void)printf("\n");
652 1.35 christos (void)fflush(stdout);
653 1.35 christos (void)sleep(repeat);
654 1.1 itojun goto again;
655 1.1 itojun }
656 1.1 itojun }
657 1.1 itojun
658 1.1 itojun static struct in6_nbrinfo *
659 1.35 christos getnbrinfo(struct in6_addr *addr, unsigned int ifindex, int warning)
660 1.1 itojun {
661 1.1 itojun static struct in6_nbrinfo nbi;
662 1.1 itojun int s;
663 1.1 itojun
664 1.45 ozaki if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
665 1.1 itojun err(1, "socket");
666 1.1 itojun
667 1.35 christos (void)memset(&nbi, 0, sizeof(nbi));
668 1.35 christos (void)if_indextoname(ifindex, nbi.ifname);
669 1.1 itojun nbi.addr = *addr;
670 1.45 ozaki if (prog_ioctl(s, SIOCGNBRINFO_IN6, &nbi) < 0) {
671 1.4 itojun if (warning)
672 1.8 itojun warn("ioctl(SIOCGNBRINFO_IN6)");
673 1.45 ozaki (void)prog_close(s);
674 1.1 itojun return(NULL);
675 1.1 itojun }
676 1.1 itojun
677 1.45 ozaki (void)prog_close(s);
678 1.1 itojun return(&nbi);
679 1.1 itojun }
680 1.1 itojun
681 1.1 itojun static char *
682 1.35 christos ether_str(struct sockaddr_dl *sdl)
683 1.1 itojun {
684 1.17 bjh21 static char hbuf[NI_MAXHOST];
685 1.1 itojun
686 1.1 itojun if (sdl->sdl_alen) {
687 1.35 christos if (getnameinfo((struct sockaddr *)(void *)sdl,
688 1.35 christos (socklen_t)sdl->sdl_len,
689 1.17 bjh21 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
690 1.35 christos (void)snprintf(hbuf, sizeof(hbuf), "<invalid>");
691 1.20 itojun } else
692 1.35 christos (void)snprintf(hbuf, sizeof(hbuf), "(incomplete)");
693 1.1 itojun
694 1.17 bjh21 return(hbuf);
695 1.1 itojun }
696 1.1 itojun
697 1.35 christos static int
698 1.35 christos ndp_ether_aton(char *a, u_char *n)
699 1.1 itojun {
700 1.1 itojun int i, o[6];
701 1.1 itojun
702 1.1 itojun i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
703 1.21 itojun &o[3], &o[4], &o[5]);
704 1.1 itojun if (i != 6) {
705 1.35 christos warnx("invalid Ethernet address '%s'", a);
706 1.1 itojun return (1);
707 1.1 itojun }
708 1.24 itojun for (i = 0; i < 6; i++)
709 1.1 itojun n[i] = o[i];
710 1.1 itojun return (0);
711 1.1 itojun }
712 1.1 itojun
713 1.35 christos static void
714 1.35 christos usage(void)
715 1.1 itojun {
716 1.35 christos const char *pn = getprogname();
717 1.35 christos
718 1.35 christos (void)fprintf(stderr, "Usage: %s [-nt] hostname\n", pn);
719 1.35 christos (void)fprintf(stderr,
720 1.57 roy " %s [-nt] -a | -c\n", pn);
721 1.35 christos (void)fprintf(stderr, " %s [-nt] -A wait\n", pn);
722 1.35 christos (void)fprintf(stderr, " %s [-nt] -d hostname\n", pn);
723 1.35 christos (void)fprintf(stderr, " %s [-nt] -f filename\n", pn);
724 1.35 christos (void)fprintf(stderr, " %s [-nt] -i interface [flags...]\n", pn);
725 1.35 christos (void)fprintf(stderr,
726 1.35 christos " %s [-nt] -s nodename etheraddr [temp] [proxy]\n", pn);
727 1.1 itojun exit(1);
728 1.1 itojun }
729 1.1 itojun
730 1.35 christos static int
731 1.50 ozaki rtmsg(int cmd, struct rt_msghdr *_rtm)
732 1.1 itojun {
733 1.1 itojun static int seq;
734 1.50 ozaki register struct rt_msghdr *rtm = _rtm;
735 1.1 itojun register char *cp = m_rtmsg.m_space;
736 1.1 itojun register int l;
737 1.1 itojun
738 1.1 itojun errno = 0;
739 1.50 ozaki if (rtm != NULL) {
740 1.50 ozaki memcpy(&m_rtmsg, rtm, rtm->rtm_msglen);
741 1.50 ozaki rtm = &m_rtmsg.m_rtm;
742 1.1 itojun goto doit;
743 1.47 ozaki }
744 1.35 christos (void)memset(&m_rtmsg, 0, sizeof(m_rtmsg));
745 1.50 ozaki rtm = &m_rtmsg.m_rtm;
746 1.1 itojun rtm->rtm_flags = flags;
747 1.1 itojun rtm->rtm_version = RTM_VERSION;
748 1.1 itojun
749 1.1 itojun switch (cmd) {
750 1.1 itojun default:
751 1.35 christos errx(1, "internal wrong cmd");
752 1.35 christos /*NOTREACHED*/
753 1.1 itojun case RTM_ADD:
754 1.1 itojun rtm->rtm_addrs |= RTA_GATEWAY;
755 1.19 itojun if (expire_time) {
756 1.19 itojun rtm->rtm_rmx.rmx_expire = expire_time;
757 1.19 itojun rtm->rtm_inits = RTV_EXPIRE;
758 1.19 itojun }
759 1.47 ozaki rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA);
760 1.35 christos #ifdef notdef /* we don't support ipv6addr/128 type proxying. */
761 1.6 itojun if (rtm->rtm_flags & RTF_ANNOUNCE) {
762 1.6 itojun rtm->rtm_flags &= ~RTF_HOST;
763 1.30 itojun rtm->rtm_addrs |= RTA_NETMASK;
764 1.6 itojun }
765 1.34 rpaulo #endif
766 1.47 ozaki rtm->rtm_addrs |= RTA_DST;
767 1.47 ozaki break;
768 1.1 itojun case RTM_GET:
769 1.47 ozaki rtm->rtm_flags |= RTF_LLDATA;
770 1.49 ozaki rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY;
771 1.1 itojun }
772 1.1 itojun #define NEXTADDR(w, s) \
773 1.1 itojun if (rtm->rtm_addrs & (w)) { \
774 1.35 christos (void)memcpy(cp, &s, sizeof(s)); \
775 1.39 drochner RT_ADVANCE(cp, (struct sockaddr *)(void *)&s); \
776 1.35 christos }
777 1.1 itojun
778 1.1 itojun NEXTADDR(RTA_DST, sin_m);
779 1.1 itojun NEXTADDR(RTA_GATEWAY, sdl_m);
780 1.35 christos #ifdef notdef /* we don't support ipv6addr/128 type proxying. */
781 1.35 christos (void)memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr));
782 1.1 itojun NEXTADDR(RTA_NETMASK, so_mask);
783 1.34 rpaulo #endif
784 1.1 itojun
785 1.35 christos rtm->rtm_msglen = cp - (char *)(void *)&m_rtmsg;
786 1.1 itojun doit:
787 1.1 itojun l = rtm->rtm_msglen;
788 1.1 itojun rtm->rtm_seq = ++seq;
789 1.1 itojun rtm->rtm_type = cmd;
790 1.45 ozaki if (prog_write(my_s, &m_rtmsg, (size_t)l) == -1) {
791 1.35 christos if (errno != ESRCH || cmd != RTM_DELETE)
792 1.16 itojun err(1, "writing to routing socket");
793 1.1 itojun }
794 1.1 itojun do {
795 1.45 ozaki l = prog_read(my_s, &m_rtmsg, sizeof(m_rtmsg));
796 1.1 itojun } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
797 1.1 itojun if (l < 0)
798 1.35 christos warn("read from routing socket");
799 1.1 itojun return (0);
800 1.1 itojun }
801 1.1 itojun
802 1.35 christos static void
803 1.35 christos ifinfo(char *ifname, int argc, char **argv)
804 1.1 itojun {
805 1.1 itojun struct in6_ndireq nd;
806 1.8 itojun int i, s;
807 1.8 itojun u_int32_t newflags;
808 1.56 roy bool valset = false, flagset = false;
809 1.1 itojun
810 1.45 ozaki if ((s = prog_socket(AF_INET6, SOCK_DGRAM, 0)) < 0)
811 1.16 itojun err(1, "socket");
812 1.35 christos (void)memset(&nd, 0, sizeof(nd));
813 1.35 christos (void)strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
814 1.45 ozaki if (prog_ioctl(s, SIOCGIFINFO_IN6, &nd) < 0)
815 1.21 itojun err(1, "ioctl(SIOCGIFINFO_IN6)");
816 1.1 itojun #define ND nd.ndi
817 1.8 itojun newflags = ND.flags;
818 1.22 itojun for (i = 0; i < argc; i++) {
819 1.8 itojun int clear = 0;
820 1.8 itojun char *cp = argv[i];
821 1.8 itojun
822 1.8 itojun if (*cp == '-') {
823 1.8 itojun clear = 1;
824 1.8 itojun cp++;
825 1.8 itojun }
826 1.8 itojun
827 1.8 itojun #define SETFLAG(s, f) \
828 1.8 itojun do {\
829 1.8 itojun if (strcmp(cp, (s)) == 0) {\
830 1.8 itojun if (clear)\
831 1.8 itojun newflags &= ~(f);\
832 1.8 itojun else\
833 1.8 itojun newflags |= (f);\
834 1.56 roy flagset = true; \
835 1.8 itojun }\
836 1.59 rillig } while (0)
837 1.34 rpaulo /*
838 1.34 rpaulo * XXX: this macro is not 100% correct, in that it matches "nud" against
839 1.34 rpaulo * "nudbogus". But we just let it go since this is minor.
840 1.34 rpaulo */
841 1.34 rpaulo #define SETVALUE(f, v) \
842 1.34 rpaulo do { \
843 1.34 rpaulo char *valptr; \
844 1.34 rpaulo unsigned long newval; \
845 1.34 rpaulo v = 0; /* unspecified */ \
846 1.34 rpaulo if (strncmp(cp, f, strlen(f)) == 0) { \
847 1.34 rpaulo valptr = strchr(cp, '='); \
848 1.34 rpaulo if (valptr == NULL) \
849 1.34 rpaulo err(1, "syntax error in %s field", (f)); \
850 1.34 rpaulo errno = 0; \
851 1.34 rpaulo newval = strtoul(++valptr, NULL, 0); \
852 1.34 rpaulo if (errno) \
853 1.34 rpaulo err(1, "syntax error in %s's value", (f)); \
854 1.34 rpaulo v = newval; \
855 1.56 roy valset = true; \
856 1.34 rpaulo } \
857 1.59 rillig } while (0)
858 1.34 rpaulo
859 1.34 rpaulo #ifdef ND6_IFF_IFDISABLED
860 1.34 rpaulo SETFLAG("disabled", ND6_IFF_IFDISABLED);
861 1.34 rpaulo #endif
862 1.8 itojun SETFLAG("nud", ND6_IFF_PERFORMNUD);
863 1.19 itojun #ifdef ND6_IFF_ACCEPT_RTADV
864 1.19 itojun SETFLAG("accept_rtadv", ND6_IFF_ACCEPT_RTADV);
865 1.19 itojun #endif
866 1.38 dyoung #ifdef ND6_IFF_OVERRIDE_RTADV
867 1.38 dyoung SETFLAG("override_rtadv", ND6_IFF_OVERRIDE_RTADV);
868 1.38 dyoung #endif
869 1.43 roy #ifdef ND6_IFF_AUTO_LINKLOCAL
870 1.43 roy SETFLAG("auto_linklocal", ND6_IFF_AUTO_LINKLOCAL);
871 1.43 roy #endif
872 1.19 itojun #ifdef ND6_IFF_PREFER_SOURCE
873 1.19 itojun SETFLAG("prefer_source", ND6_IFF_PREFER_SOURCE);
874 1.19 itojun #endif
875 1.34 rpaulo #ifdef ND6_IFF_DONT_SET_IFROUTE
876 1.34 rpaulo SETFLAG("dont_set_ifroute", ND6_IFF_DONT_SET_IFROUTE);
877 1.34 rpaulo #endif
878 1.34 rpaulo SETVALUE("basereachable", ND.basereachable);
879 1.34 rpaulo SETVALUE("retrans", ND.retrans);
880 1.34 rpaulo SETVALUE("curhlim", ND.chlim);
881 1.8 itojun
882 1.8 itojun ND.flags = newflags;
883 1.34 rpaulo #ifdef SIOCSIFINFO_IN6
884 1.56 roy if (valset && prog_ioctl(s, SIOCSIFINFO_IN6, &nd) < 0)
885 1.34 rpaulo err(1, "ioctl(SIOCSIFINFO_IN6)");
886 1.56 roy #endif
887 1.56 roy if (flagset && prog_ioctl(s, SIOCSIFINFO_FLAGS, &nd) < 0)
888 1.16 itojun err(1, "ioctl(SIOCSIFINFO_FLAGS)");
889 1.8 itojun #undef SETFLAG
890 1.34 rpaulo #undef SETVALUE
891 1.8 itojun }
892 1.8 itojun
893 1.45 ozaki if (prog_ioctl(s, SIOCGIFINFO_IN6, &nd) < 0)
894 1.34 rpaulo err(1, "ioctl(SIOCGIFINFO_IN6)");
895 1.56 roy (void)printf("curhlim=%d", ND.chlim);
896 1.35 christos (void)printf(", basereachable=%ds%dms",
897 1.21 itojun ND.basereachable / 1000, ND.basereachable % 1000);
898 1.35 christos (void)printf(", retrans=%ds%dms", ND.retrans / 1000, ND.retrans % 1000);
899 1.8 itojun if (ND.flags) {
900 1.35 christos (void)printf("\nFlags: ");
901 1.19 itojun if ((ND.flags & ND6_IFF_PERFORMNUD))
902 1.35 christos (void)printf("nud ");
903 1.34 rpaulo #ifdef ND6_IFF_IFDISABLED
904 1.34 rpaulo if ((ND.flags & ND6_IFF_IFDISABLED))
905 1.35 christos (void)printf("disabled ");
906 1.34 rpaulo #endif
907 1.43 roy #ifdef ND6_IFF_AUTO_LINKLOCAL
908 1.43 roy if ((ND.flags & ND6_IFF_AUTO_LINKLOCAL))
909 1.43 roy (void)printf("auto_linklocal ");
910 1.43 roy #endif
911 1.19 itojun #ifdef ND6_IFF_PREFER_SOURCE
912 1.19 itojun if ((ND.flags & ND6_IFF_PREFER_SOURCE))
913 1.35 christos (void)printf("prefer_source ");
914 1.19 itojun #endif
915 1.8 itojun }
916 1.35 christos (void)putc('\n', stdout);
917 1.1 itojun #undef ND
918 1.21 itojun
919 1.45 ozaki (void)prog_close(s);
920 1.1 itojun }
921 1.1 itojun
922 1.35 christos static const char *
923 1.35 christos sec2str(time_t total)
924 1.1 itojun {
925 1.1 itojun static char result[256];
926 1.1 itojun int days, hours, mins, secs;
927 1.1 itojun int first = 1;
928 1.1 itojun char *p = result;
929 1.19 itojun char *ep = &result[sizeof(result)];
930 1.19 itojun int n;
931 1.1 itojun
932 1.1 itojun days = total / 3600 / 24;
933 1.1 itojun hours = (total / 3600) % 24;
934 1.1 itojun mins = (total / 60) % 60;
935 1.1 itojun secs = total % 60;
936 1.1 itojun
937 1.1 itojun if (days) {
938 1.1 itojun first = 0;
939 1.35 christos n = snprintf(p, (size_t)(ep - p), "%dd", days);
940 1.19 itojun if (n < 0 || n >= ep - p)
941 1.19 itojun return "?";
942 1.19 itojun p += n;
943 1.1 itojun }
944 1.1 itojun if (!first || hours) {
945 1.1 itojun first = 0;
946 1.35 christos n = snprintf(p, (size_t)(ep - p), "%dh", hours);
947 1.19 itojun if (n < 0 || n >= ep - p)
948 1.19 itojun return "?";
949 1.19 itojun p += n;
950 1.1 itojun }
951 1.1 itojun if (!first || mins) {
952 1.1 itojun first = 0;
953 1.35 christos n = snprintf(p, (size_t)(ep - p), "%dm", mins);
954 1.19 itojun if (n < 0 || n >= ep - p)
955 1.19 itojun return "?";
956 1.19 itojun p += n;
957 1.1 itojun }
958 1.35 christos (void)snprintf(p, (size_t)(ep - p), "%ds", secs);
959 1.1 itojun
960 1.1 itojun return(result);
961 1.1 itojun }
962 1.1 itojun
963 1.1 itojun /*
964 1.1 itojun * Print the timestamp
965 1.1 itojun * from tcpdump/util.c
966 1.1 itojun */
967 1.1 itojun static void
968 1.35 christos ts_print(const struct timeval *tvp)
969 1.1 itojun {
970 1.1 itojun int s;
971 1.1 itojun
972 1.1 itojun /* Default */
973 1.1 itojun s = (tvp->tv_sec + thiszone) % 86400;
974 1.1 itojun (void)printf("%02d:%02d:%02d.%06u ",
975 1.1 itojun s / 3600, (s % 3600) / 60, s % 60, (u_int32_t)tvp->tv_usec);
976 1.1 itojun }
977 1.60 tnn
978 1.60 tnn /*
979 1.60 tnn * Returns the difference between gmt and local time in seconds.
980 1.60 tnn * Use gmtime() and localtime() to keep things simple.
981 1.60 tnn */
982 1.60 tnn static int32_t
983 1.60 tnn gmt2local(time_t t)
984 1.60 tnn {
985 1.60 tnn int dt, dir;
986 1.60 tnn struct tm *gmt, *loc;
987 1.60 tnn struct tm sgmt;
988 1.60 tnn
989 1.60 tnn if (t == 0)
990 1.60 tnn t = time(NULL);
991 1.60 tnn gmt = &sgmt;
992 1.60 tnn *gmt = *gmtime(&t);
993 1.60 tnn loc = localtime(&t);
994 1.60 tnn dt = (loc->tm_hour - gmt->tm_hour) * 60 * 60 +
995 1.60 tnn (loc->tm_min - gmt->tm_min) * 60;
996 1.60 tnn
997 1.60 tnn /*
998 1.60 tnn * If the year or julian day is different, we span 00:00 GMT
999 1.60 tnn * and must add or subtract a day. Check the year first to
1000 1.60 tnn * avoid problems when the julian day wraps.
1001 1.60 tnn */
1002 1.60 tnn dir = loc->tm_year - gmt->tm_year;
1003 1.60 tnn if (dir == 0)
1004 1.60 tnn dir = loc->tm_yday - gmt->tm_yday;
1005 1.60 tnn dt += dir * 24 * 60 * 60;
1006 1.60 tnn
1007 1.60 tnn return (dt);
1008 1.60 tnn }
1009