Bug Summary

File:src/usr.sbin/ndp/ndp.c
Warning:line 347, column 7
1st function call argument is an uninitialized value

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) {
1
Assuming the condition is true
2
Loop condition is true. Entering loop body
6
Assuming the condition is false
7
Loop condition is false. Execution continues on line 197
148 switch (ch) {
3
Control jumps to 'case 102:' at line 162
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
3.1
'mode' is 0
) {
4
Taking false branch
165 usage();
166 }
167 mode = ch;
168 arg = optarg;
169 break;
5
Execution continues on line 147
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) {
8
Control jumps to 'case 102:' at line 214
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)
9
Assuming 'argc' is equal to 0
10
Taking false branch
216 usage();
217 file(arg);
11
Calling 'file'
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)) {
12
Assuming the condition is false
13
Taking false branch
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)) {
14
Assuming the condition is true
15
Loop condition is true. Entering loop body
258 i = sscanf(line, "%49s %49s %49s %49s %49s",
259 arg[0], arg[1], arg[2], arg[3], arg[4]);
260 if (i < 2) {
16
Assuming 'i' is >= 2
17
Taking false branch
261 warnx("bad line: %s", line);
262 retval = 1;
263 continue;
264 }
265 if (set(i, args))
18
Calling 'set'
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)
20
Assuming 'nflag' is 0
21
Taking false branch
298 hints.ai_flags = AI_NUMERICHOST4;
299
300 gai_error = getaddrinfo(host, NULL((void *)0), &hints, &res);
301 if (gai_error) {
22
Assuming 'gai_error' is 0
23
Taking false branch
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;
24
Returning zero, which participates in a condition later
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))
19
Calling 'parse_host'
25
Returning from 'parse_host'
26
Taking false branch
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)
27
Assuming the condition is false
28
Taking false branch
343 sdl_m.sdl_alen = 6;
344 expire_time = 0;
345 flags = 0;
346 while (argc-- > 0) {
29
Assuming the condition is true
30
Loop condition is true. Entering loop body
35
Assuming the condition is true
36
Loop condition is true. Entering loop body
41
Assuming the condition is true
42
Loop condition is true. Entering loop body
45
Assuming the condition is true
46
Loop condition is true. Entering loop body
347 if (strncmp(argv[0], "temp", 4) == 0) {
31
Assuming the condition is false
32
Taking false branch
37
Assuming the condition is false
38
Taking false branch
43
Assuming the condition is true
44
Taking true branch
47
1st function call argument is an uninitialized value
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)
33
Assuming the condition is false
34
Taking false branch
39
Assuming the condition is false
40
Taking false branch
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;
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}