Bug Summary

File:src/usr.sbin/ndp/ndp.c
Warning:line 930, column 3
Value stored to 'first' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ndp.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/ndp/obj -resource-dir /usr/local/lib/clang/13.0.0 -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/ndp/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/ndp/ndp.c
1/* $OpenBSD: ndp.c,v 1.103 2021/03/02 05:34:20 jsg Exp $ */
2/* $KAME: ndp.c,v 1.101 2002/07/17 08:46:33 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. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 */
63
64/*
65 * Based on:
66 * "@(#) Copyright (c) 1984, 1993\n\
67 * The Regents of the University of California. All rights reserved.\n";
68 *
69 * "@(#)arp.c 8.2 (Berkeley) 1/2/94";
70 */
71
72/*
73 * ndp - display, set, delete and flush neighbor cache
74 */
75
76
77#include <sys/ioctl.h>
78#include <sys/socket.h>
79#include <sys/sysctl.h>
80#include <sys/time.h>
81#include <sys/queue.h>
82
83#include <net/if.h>
84#include <net/if_dl.h>
85#include <net/if_types.h>
86#include <net/route.h>
87
88#include <netinet/in.h>
89
90#include <netinet/icmp6.h>
91#include <netinet6/in6_var.h>
92#include <netinet6/nd6.h>
93
94#include <arpa/inet.h>
95
96#include <stdio.h>
97#include <errno(*__errno()).h>
98#include <fcntl.h>
99#include <netdb.h>
100#include <stdlib.h>
101#include <string.h>
102#include <unistd.h>
103#include <limits.h>
104#include <err.h>
105
106/* packing rule for routing socket */
107#define ROUNDUP(a)((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof
(long))
\
108 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
109#define ADVANCE(x, n)(x += (((n)->sa_len) > 0 ? (1 + ((((n)->sa_len) - 1)
| (sizeof(long) - 1))) : sizeof(long)))
(x += ROUNDUP((n)->sa_len)(((n)->sa_len) > 0 ? (1 + ((((n)->sa_len) - 1) | (sizeof
(long) - 1))) : sizeof(long))
)
110
111static pid_t pid;
112static int nflag;
113static int tflag;
114static int rtsock = -1;
115static int repeat = 0;
116
117char host_buf[NI_MAXHOST256]; /* getnameinfo() */
118char ifix_buf[IFNAMSIZ16]; /* if_indextoname() */
119
120int file(char *);
121void getsocket(void);
122int parse_host(const char *, struct sockaddr_in6 *);
123int set(int, char **);
124void get(const char *);
125int delete(const char *);
126void dump(struct sockaddr_in6 *, int);
127static struct in6_nbrinfo *getnbrinfo(struct in6_addr *, int, int);
128static char *ether_str(struct sockaddr_dl *);
129int ndp_ether_aton(const char *, u_char *);
130void usage(void);
131int rtmsg(int);
132int rtget(struct sockaddr_in6 **, struct sockaddr_dl **);
133void ifinfo(const char *);
134static char *sec2str(time_t);
135static int rdomain;
136
137int
138main(int argc, char *argv[])
139{
140 int ch;
141 int mode = 0;
142 char *arg = NULL((void *)0);
143 const char *errstr;
144
145 pid = getpid();
146 rdomain = getrtable();
147 while ((ch = getopt(argc, argv, "acd:f:i:nstA:V:")) != -1) {
148 switch (ch) {
149 case 'a':
150 case 'c':
151 case 'p':
152 case 'r':
153 case 'P':
154 case 's':
155 if (mode) {
156 usage();
157 }
158 mode = ch;
159 arg = NULL((void *)0);
160 break;
161 case 'd':
162 case 'f':
163 case 'i' :
164 if (mode) {
165 usage();
166 }
167 mode = ch;
168 arg = optarg;
169 break;
170 case 'n':
171 nflag = 1;
172 break;
173 case 't':
174 tflag = 1;
175 break;
176 case 'A':
177 if (mode) {
178 usage();
179 }
180 mode = 'a';
181 repeat = strtonum(optarg, 1, INT_MAX2147483647, &errstr);
182 if (errstr) {
183 usage();
184 }
185 break;
186 case 'V':
187 rdomain = strtonum(optarg, 0, RT_TABLEID_MAX255, &errstr);
188 if (errstr != NULL((void *)0)) {
189 warn("bad rdomain: %s", errstr);
190 usage();
191 }
192 break;
193 default:
194 usage();
195 }
196 }
197 argc -= optind;
198 argv += optind;
199
200 switch (mode) {
201 case 'a':
202 case 'c':
203 if (argc != 0) {
204 usage();
205 }
206 dump(NULL((void *)0), mode == 'c');
207 break;
208 case 'd':
209 if (argc != 0) {
210 usage();
211 }
212 delete(arg);
213 break;
214 case 'f':
215 if (argc != 0)
216 usage();
217 file(arg);
218 break;
219 case 'i':
220 if (argc != 0)
221 usage();
222 ifinfo(arg);
223 break;
224 case 's':
225 if (argc < 2 || argc > 4)
226 usage();
227 exit(set(argc, argv) ? 1 : 0);
228 case 0:
229 if (argc != 1) {
230 usage();
231 }
232 get(argv[0]);
233 break;
234 }
235 exit(0);
236}
237
238/*
239 * Process a file to set standard ndp entries
240 */
241int
242file(char *name)
243{
244 FILE *fp;
245 int i, retval;
246 char line[100], arg[5][50], *args[5];
247
248 if ((fp = fopen(name, "r")) == NULL((void *)0)) {
249 err(1, "cannot open %s", name);
250 }
251 args[0] = &arg[0][0];
252 args[1] = &arg[1][0];
253 args[2] = &arg[2][0];
254 args[3] = &arg[3][0];
255 args[4] = &arg[4][0];
256 retval = 0;
257 while (fgets(line, sizeof(line), fp) != NULL((void *)0)) {
258 i = sscanf(line, "%49s %49s %49s %49s %49s",
259 arg[0], arg[1], arg[2], arg[3], arg[4]);
260 if (i < 2) {
261 warnx("bad line: %s", line);
262 retval = 1;
263 continue;
264 }
265 if (set(i, args))
266 retval = 1;
267 }
268 fclose(fp);
269 return (retval);
270}
271
272void
273getsocket(void)
274{
275 socklen_t len = sizeof(rdomain);
276
277 if (rtsock >= 0)
278 return;
279 rtsock = socket(AF_ROUTE17, SOCK_RAW3, 0);
280 if (rtsock == -1)
281 err(1, "routing socket");
282 if (setsockopt(rtsock, AF_ROUTE17, ROUTE_TABLEFILTER2, &rdomain, len) == -1)
283 err(1, "ROUTE_TABLEFILTER");
284
285 if (pledge("stdio dns", NULL((void *)0)) == -1)
286 err(1, "pledge");
287}
288
289int
290parse_host(const char *host, struct sockaddr_in6 *sin6)
291{
292 struct addrinfo hints, *res;
293 int gai_error;
294
295 bzero(&hints, sizeof(hints));
296 hints.ai_family = AF_INET624;
297 if (nflag)
298 hints.ai_flags = AI_NUMERICHOST4;
299
300 gai_error = getaddrinfo(host, NULL((void *)0), &hints, &res);
301 if (gai_error) {
302 warnx("%s: %s", host, gai_strerror(gai_error));
303 return 1;
304 }
305 *sin6 = *(struct sockaddr_in6 *)res->ai_addr;
306 freeaddrinfo(res);
307 return 0;
308}
309
310struct sockaddr_in6 so_mask = {sizeof(so_mask), AF_INET624 };
311struct sockaddr_in6 blank_sin = {sizeof(blank_sin), AF_INET624 }, sin_m;
312struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK18 }, sdl_m;
313struct sockaddr_dl ifp_m = { sizeof(ifp_m), AF_LINK18 };
314time_t expire_time;
315int flags, found_entry;
316struct {
317 struct rt_msghdr m_rtm;
318 char m_space[512];
319} m_rtmsg;
320
321/*
322 * Set an individual neighbor cache entry
323 */
324int
325set(int argc, char *argv[])
326{
327 struct sockaddr_in6 *sin = &sin_m;
328 struct sockaddr_dl *sdl;
329 struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
330 u_char *ea;
331 const char *host = argv[0], *eaddr = argv[1];
332
333 getsocket();
334 argc -= 2;
335 argv += 2;
336 sdl_m = blank_sdl;
337 sin_m = blank_sin;
338
339 if (parse_host(host, sin))
340 return 1;
341 ea = (u_char *)LLADDR(&sdl_m)((caddr_t)((&sdl_m)->sdl_data + (&sdl_m)->sdl_nlen
))
;
342 if (ndp_ether_aton(eaddr, ea) == 0)
343 sdl_m.sdl_alen = 6;
344 expire_time = 0;
345 flags = 0;
346 while (argc-- > 0) {
347 if (strncmp(argv[0], "temp", 4) == 0) {
348 struct timeval now;
349
350 gettimeofday(&now, 0);
351 expire_time = now.tv_sec + 20 * 60;
352 } else if (strncmp(argv[0], "proxy", 5) == 0)
353 flags |= RTF_ANNOUNCE0x4000;
354 argv++;
355 }
356
357 if (rtget(&sin, &sdl)) {
358 errx(1, "RTM_GET(%s) failed", host);
359 }
360
361 if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)(memcmp(&(&sin->sin6_addr)->__u6_addr.__u6_addr8
[0], &(&sin_m.sin6_addr)->__u6_addr.__u6_addr8[0],
sizeof(struct in6_addr)) == 0)
&&
362 sin->sin6_scope_id == sin_m.sin6_scope_id) {
363 if (sdl->sdl_family == AF_LINK18 &&
364 (rtm->rtm_flags & RTF_LLINFO0x400) &&
365 !(rtm->rtm_flags & RTF_GATEWAY0x2)) {
366 switch (sdl->sdl_type) {
367 case IFT_ETHER0x06: case IFT_FDDI0x0f: case IFT_ISO880230x07:
368 case IFT_ISO880240x08: case IFT_ISO880250x09:
369 goto overwrite;
370 }
371 }
372 /*
373 * IPv4 arp command retries with sin_other = SIN_PROXY here.
374 */
375 warnx("set: cannot configure a new entry");
376 return 1;
377 }
378
379overwrite:
380 if (sdl->sdl_family != AF_LINK18) {
381 printf("cannot intuit interface index and type for %s\n", host);
382 return (1);
383 }
384 sdl_m.sdl_type = sdl->sdl_type;
385 sdl_m.sdl_index = sdl->sdl_index;
386 return (rtmsg(RTM_ADD0x1));
387}
388
389/*
390 * Display an individual neighbor cache entry
391 */
392void
393get(const char *host)
394{
395 struct sockaddr_in6 *sin = &sin_m;
396
397 sin_m = blank_sin;
398 if (parse_host(host, sin))
399 return;
400
401 dump(sin, 0);
402 if (found_entry == 0) {
403 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
404 sizeof(host_buf), NULL((void *)0) ,0,
405 (nflag ? NI_NUMERICHOST1 : 0));
406 printf("%s (%s) -- no entry\n", host, host_buf);
407 exit(1);
408 }
409}
410
411/*
412 * Delete a neighbor cache entry
413 */
414int
415delete(const char *host)
416{
417 struct sockaddr_in6 *sin = &sin_m;
418 struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
419 struct sockaddr_dl *sdl;
420
421 getsocket();
422 sin_m = blank_sin;
423 if (parse_host(host, sin))
424 return 1;
425 if (rtget(&sin, &sdl)) {
426 errx(1, "RTM_GET(%s) failed", host);
427 }
428
429 if (IN6_ARE_ADDR_EQUAL(&sin->sin6_addr, &sin_m.sin6_addr)(memcmp(&(&sin->sin6_addr)->__u6_addr.__u6_addr8
[0], &(&sin_m.sin6_addr)->__u6_addr.__u6_addr8[0],
sizeof(struct in6_addr)) == 0)
&&
430 sin->sin6_scope_id == sin_m.sin6_scope_id) {
431 if (sdl->sdl_family == AF_LINK18 && rtm->rtm_flags & RTF_LLINFO0x400) {
432 if (rtm->rtm_flags & RTF_LOCAL0x200000)
433 return (0);
434 if (!(rtm->rtm_flags & RTF_GATEWAY0x2))
435 goto delete;
436 }
437 /*
438 * IPv4 arp command retries with sin_other = SIN_PROXY here.
439 */
440 warnx("delete: cannot delete non-NDP entry");
441 return 1;
442 }
443
444delete:
445 if (sdl->sdl_family != AF_LINK18) {
446 printf("cannot locate %s\n", host);
447 return (1);
448 }
449 if (rtmsg(RTM_DELETE0x2) == 0) {
450 getnameinfo((struct sockaddr *)sin,
451 sin->sin6_len, host_buf,
452 sizeof(host_buf), NULL((void *)0), 0,
453 (nflag ? NI_NUMERICHOST1 : 0));
454 printf("%s (%s) deleted\n", host, host_buf);
455 }
456
457 return 0;
458}
459
460#define W_ADDR36 36
461#define W_LL17 17
462#define W_IF7 7
463
464/*
465 * Dump the entire neighbor cache
466 */
467void
468dump(struct sockaddr_in6 *addr, int cflag)
469{
470 int mib[7];
471 size_t needed;
472 char *lim, *buf = NULL((void *)0), *next;
473 struct rt_msghdr *rtm;
474 struct sockaddr_in6 *sin;
475 struct sockaddr_dl *sdl;
476 struct in6_nbrinfo *nbi;
477 struct timeval now;
478 int addrwidth;
479 int llwidth;
480 int ifwidth;
481 char *ifname;
482
483 /* Print header */
484 if (!tflag && !cflag)
485 printf("%-*.*s %-*.*s %*.*s %-9.9s %1s %5s\n",
486 W_ADDR36, W_ADDR36, "Neighbor", W_LL17, W_LL17, "Linklayer Address",
487 W_IF7, W_IF7, "Netif", "Expire", "S", "Flags");
488
489again:;
490 lim = NULL((void *)0);
491 mib[0] = CTL_NET4;
492 mib[1] = PF_ROUTE17;
493 mib[2] = 0;
494 mib[3] = AF_INET624;
495 mib[4] = NET_RT_FLAGS2;
496 mib[5] = RTF_LLINFO0x400;
497 mib[6] = rdomain;
498 while (1) {
499 if (sysctl(mib, 7, NULL((void *)0), &needed, NULL((void *)0), 0) == -1)
500 err(1, "sysctl(PF_ROUTE estimate)");
501 if (needed == 0)
502 break;
503 if ((buf = realloc(buf, needed)) == NULL((void *)0))
504 err(1, "realloc");
505 if (sysctl(mib, 7, buf, &needed, NULL((void *)0), 0) == -1) {
506 if (errno(*__errno()) == ENOMEM12)
507 continue;
508 err(1, "sysctl(PF_ROUTE, NET_RT_FLAGS)");
509 }
510 lim = buf + needed;
511 break;
512 }
513
514 for (next = buf; next && lim && next < lim; next += rtm->rtm_msglen) {
515 int isrouter = 0, prbs = 0;
516
517 rtm = (struct rt_msghdr *)next;
518 if (rtm->rtm_version != RTM_VERSION5)
519 continue;
520 sin = (struct sockaddr_in6 *)(next + rtm->rtm_hdrlen);
521#ifdef __KAME__
522 {
523 struct in6_addr *in6 = &sin->sin6_addr;
524 if ((IN6_IS_ADDR_LINKLOCAL(in6)(((in6)->__u6_addr.__u6_addr8[0] == 0xfe) && (((in6
)->__u6_addr.__u6_addr8[1] & 0xc0) == 0x80))
||
525 IN6_IS_ADDR_MC_LINKLOCAL(in6)(((in6)->__u6_addr.__u6_addr8[0] == 0xff) && (((in6
)->__u6_addr.__u6_addr8[1] & 0x0f) == 0x02))
||
526 IN6_IS_ADDR_MC_INTFACELOCAL(in6)(((in6)->__u6_addr.__u6_addr8[0] == 0xff) && (((in6
)->__u6_addr.__u6_addr8[1] & 0x0f) == 0x01))
) &&
527 sin->sin6_scope_id == 0) {
528 sin->sin6_scope_id = (u_int32_t)
529 ntohs(*(u_short *)&in6->s6_addr[2])(__uint16_t)(__builtin_constant_p(*(u_short *)&in6->__u6_addr
.__u6_addr8[2]) ? (__uint16_t)(((__uint16_t)(*(u_short *)&
in6->__u6_addr.__u6_addr8[2]) & 0xffU) << 8 | ((
__uint16_t)(*(u_short *)&in6->__u6_addr.__u6_addr8[2])
& 0xff00U) >> 8) : __swap16md(*(u_short *)&in6
->__u6_addr.__u6_addr8[2]))
;
530 *(u_short *)&in6->s6_addr__u6_addr.__u6_addr8[2] = 0;
531 }
532 }
533#endif
534 sdl = (struct sockaddr_dl *)((char *)sin + ROUNDUP(sin->sin6_len)((sin->sin6_len) > 0 ? (1 + (((sin->sin6_len) - 1) |
(sizeof(long) - 1))) : sizeof(long))
);
535
536 /*
537 * Some OSes can produce a route that has the LINK flag but
538 * has a non-AF_LINK gateway (e.g. fe80::xx%lo0 on FreeBSD
539 * and BSD/OS, where xx is not the interface identifier on
540 * lo0). Such routes entry would annoy getnbrinfo() below,
541 * so we skip them.
542 * XXX: such routes should have the GATEWAY flag, not the
543 * LINK flag. However, there is rotten routing software
544 * that advertises all routes that have the GATEWAY flag.
545 * Thus, KAME kernel intentionally does not set the LINK flag.
546 * What is to be fixed is not ndp, but such routing software
547 * (and the kernel workaround)...
548 */
549 if (sdl->sdl_family != AF_LINK18)
550 continue;
551
552 if (!(rtm->rtm_flags & RTF_HOST0x4))
553 continue;
554
555 if (addr) {
556 if (!IN6_ARE_ADDR_EQUAL(&addr->sin6_addr,(memcmp(&(&addr->sin6_addr)->__u6_addr.__u6_addr8
[0], &(&sin->sin6_addr)->__u6_addr.__u6_addr8[0
], sizeof(struct in6_addr)) == 0)
557 &sin->sin6_addr)(memcmp(&(&addr->sin6_addr)->__u6_addr.__u6_addr8
[0], &(&sin->sin6_addr)->__u6_addr.__u6_addr8[0
], sizeof(struct in6_addr)) == 0)
|| addr->sin6_scope_id !=
558 sin->sin6_scope_id)
559 continue;
560 found_entry = 1;
561 } else if (IN6_IS_ADDR_MULTICAST(&sin->sin6_addr)((&sin->sin6_addr)->__u6_addr.__u6_addr8[0] == 0xff
)
)
562 continue;
563 getnameinfo((struct sockaddr *)sin, sin->sin6_len, host_buf,
564 sizeof(host_buf), NULL((void *)0), 0, (nflag ? NI_NUMERICHOST1 : 0));
565 if (cflag) {
566 if (rtm->rtm_flags & RTF_CLONED0x10000)
567 delete(host_buf);
568 continue;
569 }
570 gettimeofday(&now, 0);
571 if (tflag) {
572 char buf[sizeof("00:00:00")];
573 struct tm *tm;
574
575 tm = localtime(&now.tv_sec);
576 if (tm != NULL((void *)0)) {
577 strftime(buf, sizeof(buf), "%H:%M:%S", tm);
578 printf("%s.%06ld ", buf, now.tv_usec);
579 }
580 }
581
582 addrwidth = strlen(host_buf);
583 if (addrwidth < W_ADDR36)
584 addrwidth = W_ADDR36;
585 llwidth = strlen(ether_str(sdl));
586 if (W_ADDR36 + W_LL17 - addrwidth > llwidth)
587 llwidth = W_ADDR36 + W_LL17 - addrwidth;
588 ifname = if_indextoname(sdl->sdl_index, ifix_buf);
589 if (!ifname)
590 ifname = "?";
591 ifwidth = strlen(ifname);
592 if (W_ADDR36 + W_LL17 + W_IF7 - addrwidth - llwidth > ifwidth)
593 ifwidth = W_ADDR36 + W_LL17 + W_IF7 - addrwidth - llwidth;
594
595 printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host_buf,
596 llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
597
598 /* Print neighbor discovery specific informations */
599 nbi = getnbrinfo(&sin->sin6_addr, sdl->sdl_index, 1);
600 if (nbi) {
601 if (nbi->expire > now.tv_sec) {
602 printf(" %-9.9s",
603 sec2str(nbi->expire - now.tv_sec));
604 } else if (nbi->expire == 0)
605 printf(" %-9.9s", "permanent");
606 else
607 printf(" %-9.9s", "expired");
608
609 switch (nbi->state) {
610 case ND6_LLINFO_NOSTATE-2:
611 printf(" N");
612 break;
613 case ND6_LLINFO_INCOMPLETE0:
614 printf(" I");
615 break;
616 case ND6_LLINFO_REACHABLE1:
617 printf(" R");
618 break;
619 case ND6_LLINFO_STALE2:
620 printf(" S");
621 break;
622 case ND6_LLINFO_DELAY3:
623 printf(" D");
624 break;
625 case ND6_LLINFO_PROBE4:
626 printf(" P");
627 break;
628 default:
629 printf(" ?");
630 break;
631 }
632
633 isrouter = nbi->isrouter;
634 prbs = nbi->asked;
635 } else {
636 warnx("failed to get neighbor information");
637 printf(" ");
638 }
639
640 printf(" %s%s%s",
641 (rtm->rtm_flags & RTF_LOCAL0x200000) ? "l" : "",
642 isrouter ? "R" : "",
643 (rtm->rtm_flags & RTF_ANNOUNCE0x4000) ? "p" : "");
644
645 if (prbs)
646 printf(" %d", prbs);
647
648 printf("\n");
649 }
650
651 if (repeat) {
652 printf("\n");
653 fflush(stdout(&__sF[1]));
654 sleep(repeat);
655 goto again;
656 }
657
658 free(buf);
659}
660
661static struct in6_nbrinfo *
662getnbrinfo(struct in6_addr *addr, int ifindex, int warning)
663{
664 static struct in6_nbrinfo nbi;
665 int s;
666
667 if ((s = socket(AF_INET624, SOCK_DGRAM2, 0)) == -1)
668 err(1, "socket");
669
670 bzero(&nbi, sizeof(nbi));
671 if_indextoname(ifindex, nbi.ifname);
672 nbi.addr = *addr;
673 if (ioctl(s, SIOCGNBRINFO_IN6(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct in6_nbrinfo) & 0x1fff) << 16) | ((('i')) <<
8) | ((78)))
, (caddr_t)&nbi) == -1) {
674 if (warning)
675 warn("ioctl(SIOCGNBRINFO_IN6)");
676 close(s);
677 return(NULL((void *)0));
678 }
679
680 close(s);
681 return(&nbi);
682}
683
684static char *
685ether_str(struct sockaddr_dl *sdl)
686{
687 static char hbuf[NI_MAXHOST256];
688 u_char *cp;
689
690 if (sdl->sdl_alen) {
691 cp = (u_char *)LLADDR(sdl)((caddr_t)((sdl)->sdl_data + (sdl)->sdl_nlen));
692 snprintf(hbuf, sizeof(hbuf), "%02x:%02x:%02x:%02x:%02x:%02x",
693 cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
694 } else
695 snprintf(hbuf, sizeof(hbuf), "(incomplete)");
696
697 return(hbuf);
698}
699
700int
701ndp_ether_aton(const char *a, u_char *n)
702{
703 int i, o[6];
704
705 i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
706 &o[3], &o[4], &o[5]);
707 if (i != 6) {
708 warnx("invalid Ethernet address '%s'", a);
709 return (1);
710 }
711 for (i = 0; i < 6; i++)
712 n[i] = o[i];
713 return (0);
714}
715
716void
717usage(void)
718{
719 printf("usage: ndp [-acnt] ");
720 printf("[-A wait] [-d hostname] [-f filename] [-i interface]\n");
721 printf("\t[-s nodename ether_addr [temp] [proxy]] ");
722 printf("[-V rdomain] [hostname]\n");
723 exit(1);
724}
725
726int
727rtmsg(int cmd)
728{
729 static int seq;
730 int rlen;
731 struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
732 char *cp = m_rtmsg.m_space;
733 int l;
734
735 errno(*__errno()) = 0;
736 if (cmd == RTM_DELETE0x2)
737 goto doit;
738 bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
739 rtm->rtm_flags = flags;
740 rtm->rtm_version = RTM_VERSION5;
741 rtm->rtm_tableid = rdomain;
742
743 switch (cmd) {
744 default:
745 errx(1, "internal wrong cmd");
746 case RTM_ADD0x1:
747 rtm->rtm_addrs |= RTA_GATEWAY0x2;
748 if (expire_time) {
749 rtm->rtm_rmx.rmx_expire = expire_time;
750 rtm->rtm_inits = RTV_EXPIRE0x4;
751 }
752 rtm->rtm_flags |= (RTF_HOST0x4 | RTF_STATIC0x800);
753#if 0 /* we don't support ipv6addr/128 type proxying. */
754 if (rtm->rtm_flags & RTF_ANNOUNCE0x4000) {
755 rtm->rtm_flags &= ~RTF_HOST0x4;
756 rtm->rtm_addrs |= RTA_NETMASK0x4;
757 }
758#endif
759 /* FALLTHROUGH */
760 case RTM_GET0x4:
761 rtm->rtm_addrs |= (RTA_DST0x1 | RTA_IFP0x10);
762 }
763
764#define NEXTADDR(w, s)if (rtm->rtm_addrs & (w)) { memcpy(cp, &(s), sizeof
(s)); (cp += ((((struct sockaddr *)&(s))->sa_len) >
0 ? (1 + (((((struct sockaddr *)&(s))->sa_len) - 1) |
(sizeof(long) - 1))) : sizeof(long))); }
\
765 if (rtm->rtm_addrs & (w)) { \
766 memcpy(cp, &(s), sizeof(s)); \
767 ADVANCE(cp, (struct sockaddr *)&(s))(cp += ((((struct sockaddr *)&(s))->sa_len) > 0 ? (
1 + (((((struct sockaddr *)&(s))->sa_len) - 1) | (sizeof
(long) - 1))) : sizeof(long)))
; \
768 }
769
770#ifdef __KAME__
771 {
772 struct sockaddr_in6 sin6 = sin_m;
773 struct in6_addr *in6 = &sin6.sin6_addr;
774 if (IN6_IS_ADDR_LINKLOCAL(in6)(((in6)->__u6_addr.__u6_addr8[0] == 0xfe) && (((in6
)->__u6_addr.__u6_addr8[1] & 0xc0) == 0x80))
||
775 IN6_IS_ADDR_MC_LINKLOCAL(in6)(((in6)->__u6_addr.__u6_addr8[0] == 0xff) && (((in6
)->__u6_addr.__u6_addr8[1] & 0x0f) == 0x02))
||
776 IN6_IS_ADDR_MC_INTFACELOCAL(in6)(((in6)->__u6_addr.__u6_addr8[0] == 0xff) && (((in6
)->__u6_addr.__u6_addr8[1] & 0x0f) == 0x01))
) {
777 *(u_int16_t *)& in6->s6_addr__u6_addr.__u6_addr8[2] =
778 htons(sin6.sin6_scope_id)(__uint16_t)(__builtin_constant_p(sin6.sin6_scope_id) ? (__uint16_t
)(((__uint16_t)(sin6.sin6_scope_id) & 0xffU) << 8 |
((__uint16_t)(sin6.sin6_scope_id) & 0xff00U) >> 8)
: __swap16md(sin6.sin6_scope_id))
;
779 sin6.sin6_scope_id = 0;
780 }
781 NEXTADDR(RTA_DST, sin6)if (rtm->rtm_addrs & (0x1)) { memcpy(cp, &(sin6), sizeof
(sin6)); (cp += ((((struct sockaddr *)&(sin6))->sa_len
) > 0 ? (1 + (((((struct sockaddr *)&(sin6))->sa_len
) - 1) | (sizeof(long) - 1))) : sizeof(long))); }
;
782 }
783#else
784 NEXTADDR(RTA_DST, sin_m)if (rtm->rtm_addrs & (0x1)) { memcpy(cp, &(sin_m),
sizeof(sin_m)); (cp += ((((struct sockaddr *)&(sin_m))->
sa_len) > 0 ? (1 + (((((struct sockaddr *)&(sin_m))->
sa_len) - 1) | (sizeof(long) - 1))) : sizeof(long))); }
;
785#endif
786 NEXTADDR(RTA_GATEWAY, sdl_m)if (rtm->rtm_addrs & (0x2)) { memcpy(cp, &(sdl_m),
sizeof(sdl_m)); (cp += ((((struct sockaddr *)&(sdl_m))->
sa_len) > 0 ? (1 + (((((struct sockaddr *)&(sdl_m))->
sa_len) - 1) | (sizeof(long) - 1))) : sizeof(long))); }
;
787#if 0 /* we don't support ipv6addr/128 type proxying. */
788 memset(&so_mask.sin6_addr, 0xff, sizeof(so_mask.sin6_addr));
789 NEXTADDR(RTA_NETMASK, so_mask)if (rtm->rtm_addrs & (0x4)) { memcpy(cp, &(so_mask
), sizeof(so_mask)); (cp += ((((struct sockaddr *)&(so_mask
))->sa_len) > 0 ? (1 + (((((struct sockaddr *)&(so_mask
))->sa_len) - 1) | (sizeof(long) - 1))) : sizeof(long))); }
;
790#endif
791 NEXTADDR(RTA_IFP, ifp_m)if (rtm->rtm_addrs & (0x10)) { memcpy(cp, &(ifp_m)
, sizeof(ifp_m)); (cp += ((((struct sockaddr *)&(ifp_m))->
sa_len) > 0 ? (1 + (((((struct sockaddr *)&(ifp_m))->
sa_len) - 1) | (sizeof(long) - 1))) : sizeof(long))); }
;
792
793 rtm->rtm_msglen = cp - (char *)&m_rtmsg;
794doit:
795 l = rtm->rtm_msglen;
796 rtm->rtm_seq = ++seq;
797 rtm->rtm_type = cmd;
798 if ((rlen = write(rtsock, (char *)&m_rtmsg, l)) == -1) {
799 if (errno(*__errno()) != ESRCH3 || cmd != RTM_DELETE0x2) {
800 err(1, "writing to routing socket");
801 }
802 }
803 do {
804 l = read(rtsock, (char *)&m_rtmsg, sizeof(m_rtmsg));
805 } while (l > 0 && (rtm->rtm_version != RTM_VERSION5 ||
806 rtm->rtm_seq != seq || rtm->rtm_pid != pid));
807 if (l == -1)
808 warn("read from routing socket");
809 return (0);
810}
811
812int
813rtget(struct sockaddr_in6 **sinp, struct sockaddr_dl **sdlp)
814{
815 struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
816 struct sockaddr_in6 *sin = NULL((void *)0);
817 struct sockaddr_dl *sdl = NULL((void *)0);
818 struct sockaddr *sa;
819 char *cp;
820 unsigned int i;
821
822 if (rtmsg(RTM_GET0x4) < 0)
823 return (1);
824
825 if (rtm->rtm_addrs) {
826 cp = ((char *)rtm + rtm->rtm_hdrlen);
827 for (i = 1; i; i <<= 1) {
828 if (i & rtm->rtm_addrs) {
829 sa = (struct sockaddr *)cp;
830 switch (i) {
831 case RTA_DST0x1:
832 sin = (struct sockaddr_in6 *)sa;
833 break;
834 case RTA_IFP0x10:
835 sdl = (struct sockaddr_dl *)sa;
836 break;
837 default:
838 break;
839 }
840 ADVANCE(cp, sa)(cp += (((sa)->sa_len) > 0 ? (1 + ((((sa)->sa_len) -
1) | (sizeof(long) - 1))) : sizeof(long)))
;
841 }
842 }
843 }
844
845 if (sin == NULL((void *)0) || sdl == NULL((void *)0))
846 return (1);
847
848#ifdef __KAME__
849 {
850 static struct sockaddr_in6 ksin;
851 struct in6_addr *in6;
852
853 /* do not damage the route message, we need it for delete */
854 ksin = *sin;
855 sin = &ksin;
856 in6 = &sin->sin6_addr;
857
858 if ((IN6_IS_ADDR_LINKLOCAL(in6)(((in6)->__u6_addr.__u6_addr8[0] == 0xfe) && (((in6
)->__u6_addr.__u6_addr8[1] & 0xc0) == 0x80))
||
859 IN6_IS_ADDR_MC_LINKLOCAL(in6)(((in6)->__u6_addr.__u6_addr8[0] == 0xff) && (((in6
)->__u6_addr.__u6_addr8[1] & 0x0f) == 0x02))
||
860 IN6_IS_ADDR_MC_INTFACELOCAL(in6)(((in6)->__u6_addr.__u6_addr8[0] == 0xff) && (((in6
)->__u6_addr.__u6_addr8[1] & 0x0f) == 0x01))
) &&
861 sin->sin6_scope_id == 0) {
862 sin->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)(__uint16_t)(__builtin_constant_p(*(u_short *) &in6->__u6_addr
.__u6_addr8[2]) ? (__uint16_t)(((__uint16_t)(*(u_short *) &
in6->__u6_addr.__u6_addr8[2]) & 0xffU) << 8 | ((
__uint16_t)(*(u_short *) &in6->__u6_addr.__u6_addr8[2]
) & 0xff00U) >> 8) : __swap16md(*(u_short *) &in6
->__u6_addr.__u6_addr8[2]))
863 &in6->s6_addr[2])(__uint16_t)(__builtin_constant_p(*(u_short *) &in6->__u6_addr
.__u6_addr8[2]) ? (__uint16_t)(((__uint16_t)(*(u_short *) &
in6->__u6_addr.__u6_addr8[2]) & 0xffU) << 8 | ((
__uint16_t)(*(u_short *) &in6->__u6_addr.__u6_addr8[2]
) & 0xff00U) >> 8) : __swap16md(*(u_short *) &in6
->__u6_addr.__u6_addr8[2]))
;
864 *(u_short *)&in6->s6_addr__u6_addr.__u6_addr8[2] = 0;
865 }
866 }
867#endif
868 *sinp = sin;
869 *sdlp = sdl;
870
871 return (0);
872}
873
874void
875ifinfo(const char *ifname)
876{
877 struct in6_ndireq nd;
878 int s;
879
880 if ((s = socket(AF_INET624, SOCK_DGRAM2, 0)) == -1) {
881 err(1, "socket");
882 }
883 bzero(&nd, sizeof(nd));
884 strlcpy(nd.ifname, ifname, sizeof(nd.ifname));
885 if (ioctl(s, SIOCGIFINFO_IN6(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof
(struct in6_ndireq) & 0x1fff) << 16) | ((('i')) <<
8) | ((108)))
, (caddr_t)&nd) == -1)
886 err(1, "ioctl(SIOCGIFINFO_IN6)");
887
888 if (!nd.ndi.initialized)
889 errx(1, "%s: not initialized yet", ifname);
890
891 printf("basereachable=%ds%dms",
892 nd.ndi.basereachable / 1000, nd.ndi.basereachable % 1000);
893 printf(", reachable=%ds", nd.ndi.reachable);
894 printf(", retrans=%ds%dms\n", nd.ndi.retrans / 1000,
895 nd.ndi.retrans % 1000);
896
897 close(s);
898}
899
900static char *
901sec2str(time_t total)
902{
903 static char result[256];
904 int days, hours, mins, secs;
905 int first = 1;
906 char *p = result;
907 char *ep = &result[sizeof(result)];
908 int n;
909
910 days = total / 3600 / 24;
911 hours = (total / 3600) % 24;
912 mins = (total / 60) % 60;
913 secs = total % 60;
914
915 if (days) {
916 first = 0;
917 n = snprintf(p, ep - p, "%dd", days);
918 if (n < 0 || n >= ep - p)
919 return "?";
920 p += n;
921 }
922 if (!first || hours) {
923 first = 0;
924 n = snprintf(p, ep - p, "%dh", hours);
925 if (n < 0 || n >= ep - p)
926 return "?";
927 p += n;
928 }
929 if (!first || mins) {
930 first = 0;
Value stored to 'first' is never read
931 n = snprintf(p, ep - p, "%dm", mins);
932 if (n < 0 || n >= ep - p)
933 return "?";
934 p += n;
935 }
936 snprintf(p, ep - p, "%ds", secs);
937
938 return(result);
939}