Bug Summary

File:src/usr.sbin/arp/arp.c
Warning:line 300, 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 arp.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/arp/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/arp/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/arp/arp.c
1/* $OpenBSD: arp.c,v 1.88 2019/09/16 20:49:28 kn Exp $ */
2/* $NetBSD: arp.c,v 1.12 1995/04/24 13:25:18 cgd Exp $ */
3
4/*
5 * Copyright (c) 1984, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Sun Microsystems, Inc.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36/*
37 * arp - display, set, delete arp table entries and wake up hosts.
38 */
39
40#include <sys/socket.h>
41#include <sys/sysctl.h>
42#include <sys/ioctl.h>
43#include <net/bpf.h>
44#include <net/if.h>
45#include <net/if_dl.h>
46#include <net/if_types.h>
47#include <net/route.h>
48#include <netinet/in.h>
49#include <netinet/if_ether.h>
50#include <arpa/inet.h>
51
52#include <netdb.h>
53#include <errno(*__errno()).h>
54#include <err.h>
55#include <fcntl.h>
56#include <stdio.h>
57#include <stdlib.h>
58#include <string.h>
59#include <time.h>
60#include <unistd.h>
61#include <limits.h>
62#include <ifaddrs.h>
63
64void dump(void);
65int delete(const char *);
66void search(in_addr_t addr, void (*action)(struct sockaddr_dl *sdl,
67 struct sockaddr_inarp *sin, struct rt_msghdr *rtm));
68void print_entry(struct sockaddr_dl *sdl,
69 struct sockaddr_inarp *sin, struct rt_msghdr *rtm);
70void nuke_entry(struct sockaddr_dl *sdl,
71 struct sockaddr_inarp *sin, struct rt_msghdr *rtm);
72static char *ether_str(struct sockaddr_dl *);
73int wake(const char *ether_addr, const char *iface);
74int file(char *);
75int get(const char *);
76void getsocket(void);
77int parse_host(const char *, struct in_addr *);
78int rtget(struct sockaddr_inarp **, struct sockaddr_dl **);
79int rtmsg(int);
80int set(int, char **);
81void usage(void);
82static char *sec2str(time_t);
83
84static pid_t pid;
85static int replace; /* replace entries when adding */
86static int nflag; /* no reverse dns lookups */
87static int aflag; /* do it for all entries */
88static int rtsock = -1;
89static int rdomain;
90
91/* ROUNDUP() is nasty, but it is identical to what's in the kernel. */
92#define ROUNDUP(a)((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof
(long))
\
93 ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
94#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))
)
95
96int
97main(int argc, char *argv[])
98{
99 int ch, func = 0, error = 0;
100 const char *errstr;
101
102 pid = getpid();
103 opterr = 0;
104 rdomain = getrtable();
105 while ((ch = getopt(argc, argv, "andsFfV:W")) != -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 136
106 switch (ch) {
3
Control jumps to 'case 102:' at line 115
107 case 'a':
108 aflag = 1;
109 break;
110 case 'n':
111 nflag = 1;
112 break;
113 case 'd':
114 case 's':
115 case 'f':
116 case 'W':
117 if (func
3.1
'func' is 0
)
4
Taking false branch
118 usage();
119 func = ch;
120 break;
5
Execution continues on line 105
121 case 'F':
122 replace = 1;
123 break;
124 case 'V':
125 rdomain = strtonum(optarg, 0, RT_TABLEID_MAX255, &errstr);
126 if (errstr != NULL((void *)0)) {
127 warn("bad rdomain: %s", errstr);
128 usage();
129 }
130 break;
131 default:
132 usage();
133 break;
134 }
135 }
136 argc -= optind;
137 argv += optind;
138
139 switch (func) {
8
Control jumps to 'case 102:' at line 163
140 case 0:
141 if (aflag && argc == 0)
142 dump();
143 else if (!aflag && argc == 1)
144 error = get(argv[0]);
145 else
146 usage();
147 break;
148 case 's':
149 if (argc < 2 || argc > 5)
150 usage();
151 if (replace)
152 delete(argv[0]);
153 error = set(argc, argv) ? 1 : 0;
154 break;
155 case 'd':
156 if (aflag && argc == 0)
157 search(0, nuke_entry);
158 else if (!aflag && argc == 1)
159 error = delete(argv[0]);
160 else
161 usage();
162 break;
163 case 'f':
164 if (argc != 1)
9
Assuming 'argc' is equal to 1
10
Taking false branch
165 usage();
166 error = file(argv[0]);
11
Calling 'file'
167 break;
168 case 'W':
169 if (aflag || nflag || replace || rdomain > 0)
170 usage();
171 if (argc == 1)
172 error = wake(argv[0], NULL((void *)0));
173 else if (argc == 2)
174 error = wake(argv[0], argv[1]);
175 else
176 usage();
177 break;
178 }
179 return (error);
180}
181
182/*
183 * Process a file to set standard arp entries
184 */
185int
186file(char *name)
187{
188 char line[100], arg[5][50], *args[5];
189 int i, retval;
190 FILE *fp;
191
192 if ((fp = fopen(name, "r")) == NULL((void *)0))
12
Assuming the condition is false
13
Taking false branch
193 err(1, "cannot open %s", name);
194 args[0] = &arg[0][0];
195 args[1] = &arg[1][0];
196 args[2] = &arg[2][0];
197 args[3] = &arg[3][0];
198 args[4] = &arg[4][0];
199 retval = 0;
200 while (fgets(line, sizeof(line), fp) != NULL((void *)0)) {
14
Assuming the condition is true
15
Loop condition is true. Entering loop body
201 i = sscanf(line, "%49s %49s %49s %49s %49s", arg[0], arg[1],
202 arg[2], arg[3], arg[4]);
203 if (i < 2) {
16
Assuming 'i' is >= 2
17
Taking false branch
204 warnx("bad line: %s", line);
205 retval = 1;
206 continue;
207 }
208 if (replace)
18
Assuming 'replace' is 0
19
Taking false branch
209 delete(arg[0]);
210 if (set(i, args))
20
Calling 'set'
211 retval = 1;
212 }
213 fclose(fp);
214 return (retval);
215}
216
217void
218getsocket(void)
219{
220 socklen_t len = sizeof(rdomain);
221
222 if (rtsock >= 0)
223 return;
224 rtsock = socket(AF_ROUTE17, SOCK_RAW3, 0);
225 if (rtsock == -1)
226 err(1, "routing socket");
227 if (setsockopt(rtsock, AF_ROUTE17, ROUTE_TABLEFILTER2, &rdomain, len) == -1)
228 err(1, "ROUTE_TABLEFILTER");
229
230 if (pledge("stdio dns", NULL((void *)0)) == -1)
231 err(1, "pledge");
232}
233
234int
235parse_host(const char *host, struct in_addr *in)
236{
237 struct addrinfo hints, *res;
238 struct sockaddr_in *sin;
239 int gai_error;
240
241 bzero(&hints, sizeof(hints));
242 hints.ai_family = AF_INET2;
243 if (nflag)
22
Assuming 'nflag' is 0
23
Taking false branch
244 hints.ai_flags = AI_NUMERICHOST4;
245
246 gai_error = getaddrinfo(host, NULL((void *)0), &hints, &res);
247 if (gai_error) {
24
Assuming 'gai_error' is 0
25
Taking false branch
248 warnx("%s: %s", host, gai_strerror(gai_error));
249 return 1;
250 }
251
252 sin = (struct sockaddr_in *)res->ai_addr;
253 *in = sin->sin_addr;
254
255 freeaddrinfo(res);
256 return 0;
26
Returning zero, which participates in a condition later
257}
258
259struct sockaddr_in so_mask = { 8, 0, 0, { 0xffffffff } };
260struct sockaddr_inarp blank_sin = { sizeof(blank_sin), AF_INET2 }, sin_m;
261struct sockaddr_dl blank_sdl = { sizeof(blank_sdl), AF_LINK18 }, sdl_m;
262struct sockaddr_dl ifp_m = { sizeof(ifp_m), AF_LINK18 };
263time_t expire_time;
264int flags, export_only, doing_proxy, found_entry;
265struct {
266 struct rt_msghdr m_rtm;
267 char m_space[512];
268} m_rtmsg;
269
270/*
271 * Set an individual arp entry
272 */
273int
274set(int argc, char *argv[])
275{
276 struct sockaddr_inarp *sin;
277 struct sockaddr_dl *sdl;
278 struct rt_msghdr *rtm;
279 const char *host = argv[0], *eaddr = argv[1];
280 struct ether_addr *ea;
281
282 sin = &sin_m;
283 rtm = &(m_rtmsg.m_rtm);
284
285 getsocket();
286 argc -= 2;
287 argv += 2;
288 sdl_m = blank_sdl; /* struct copy */
289 sin_m = blank_sin; /* struct copy */
290 if (parse_host(host, &sin->sin_addr))
21
Calling 'parse_host'
27
Returning from 'parse_host'
28
Taking false branch
291 return (1);
292 ea = ether_aton(eaddr);
293 if (ea == NULL((void *)0))
29
Assuming 'ea' is not equal to NULL
30
Taking false branch
294 errx(1, "invalid ethernet address: %s", eaddr);
295 memcpy(LLADDR(&sdl_m)((caddr_t)((&sdl_m)->sdl_data + (&sdl_m)->sdl_nlen
))
, ea, sizeof(*ea));
296 sdl_m.sdl_alen = 6;
297 expire_time = 0;
298 doing_proxy = flags = export_only = 0;
299 while (argc-- > 0) {
31
Assuming the condition is true
32
Loop condition is true. Entering loop body
39
Assuming the condition is true
40
Loop condition is true. Entering loop body
44
Assuming the condition is true
45
Loop condition is true. Entering loop body
49
Assuming the condition is true
50
Loop condition is true. Entering loop body
300 if (strncmp(argv[0], "temp", 4) == 0) {
33
Assuming the condition is false
34
Taking false branch
41
Assuming the condition is true
42
Taking true branch
46
Assuming the condition is true
47
Taking true branch
51
1st function call argument is an uninitialized value
301 expire_time = time(NULL((void *)0)) + 20 * 60;
302 if (flags & RTF_PERMANENT_ARP0x2000) {
43
Taking false branch
48
Taking false branch
303 /* temp or permanent, not both */
304 usage();
305 return (0);
306 }
307 } else if (strncmp(argv[0], "pub", 3) == 0) {
35
Assuming the condition is false
36
Taking false branch
308 flags |= RTF_ANNOUNCE0x4000;
309 doing_proxy = SIN_PROXY1;
310 } else if (strncmp(argv[0], "permanent", 9) == 0) {
37
Assuming the condition is false
38
Taking false branch
311 flags |= RTF_PERMANENT_ARP0x2000;
312 if (expire_time != 0) {
313 /* temp or permanent, not both */
314 usage();
315 return (0);
316 }
317 }
318
319 argv++;
320 }
321
322tryagain:
323 if (rtget(&sin, &sdl)) {
324 warn("%s", host);
325 return (1);
326 }
327
328 if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
329 if (sdl->sdl_family == AF_LINK18 &&
330 (rtm->rtm_flags & RTF_LLINFO0x400) &&
331 !(rtm->rtm_flags & RTF_GATEWAY0x2))
332 switch (sdl->sdl_type) {
333 case IFT_ETHER0x06:
334 case IFT_FDDI0x0f:
335 case IFT_ISO880230x07:
336 case IFT_ISO880240x08:
337 case IFT_ISO880250x09:
338 case IFT_CARP0xf7:
339 goto overwrite;
340 }
341
342 if (doing_proxy == 0) {
343 printf("set: can only proxy for %s\n", host);
344 return (1);
345 }
346 if (sin_m.sin_other & SIN_PROXY1) {
347 printf("set: proxy entry exists for non 802 device\n");
348 return (1);
349 }
350 sin_m.sin_other = SIN_PROXY1;
351 export_only = 1;
352 goto tryagain;
353 }
354
355overwrite:
356 if (sdl->sdl_family != AF_LINK18) {
357 printf("cannot intuit interface index and type for %s\n", host);
358 return (1);
359 }
360 sdl_m.sdl_type = sdl->sdl_type;
361 sdl_m.sdl_index = sdl->sdl_index;
362 return (rtmsg(RTM_ADD0x1));
363}
364
365#define W_ADDR36 36
366#define W_LL17 17
367#define W_IF7 7
368
369/*
370 * Display an individual arp entry
371 */
372int
373get(const char *host)
374{
375 struct sockaddr_inarp *sin;
376
377 sin = &sin_m;
378 sin_m = blank_sin; /* struct copy */
379 if (parse_host(host, &sin->sin_addr))
380 return (1);
381
382 printf("%-*.*s %-*.*s %*.*s %-9.9s %5s\n",
383 W_ADDR36, W_ADDR36, "Host", W_LL17, W_LL17, "Ethernet Address",
384 W_IF7, W_IF7, "Netif", "Expire", "Flags");
385
386 search(sin->sin_addr.s_addr, print_entry);
387 if (found_entry == 0) {
388 printf("%-*.*s no entry\n", W_ADDR36, W_ADDR36,
389 inet_ntoa(sin->sin_addr));
390 return (1);
391 }
392 return (0);
393}
394
395/*
396 * Delete an arp entry
397 */
398int
399delete(const char *host)
400{
401 struct sockaddr_inarp *sin;
402 struct rt_msghdr *rtm;
403 struct sockaddr_dl *sdl;
404
405 sin = &sin_m;
406 rtm = &m_rtmsg.m_rtm;
407
408 getsocket();
409 sin_m = blank_sin; /* struct copy */
410 if (parse_host(host, &sin->sin_addr))
411 return (1);
412tryagain:
413 if (rtget(&sin, &sdl)) {
414 warn("%s", host);
415 return (1);
416 }
417 if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
418 if (sdl->sdl_family == AF_LINK18 && rtm->rtm_flags & RTF_LLINFO0x400) {
419 if (rtm->rtm_flags & RTF_LOCAL0x200000)
420 return (0);
421 if (!(rtm->rtm_flags & RTF_GATEWAY0x2))
422 switch (sdl->sdl_type) {
423 case IFT_ETHER0x06:
424 case IFT_FDDI0x0f:
425 case IFT_ISO880230x07:
426 case IFT_ISO880240x08:
427 case IFT_ISO880250x09:
428 case IFT_CARP0xf7:
429 goto delete;
430 }
431 }
432 }
433
434 if (sin_m.sin_other & SIN_PROXY1) {
435 warnx("delete: can't locate %s", host);
436 return (1);
437 } else {
438 sin_m.sin_other = SIN_PROXY1;
439 goto tryagain;
440 }
441delete:
442 if (sdl->sdl_family != AF_LINK18) {
443 printf("cannot locate %s\n", host);
444 return (1);
445 }
446 if (rtmsg(RTM_DELETE0x2))
447 return (1);
448 printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
449 return (0);
450}
451
452/*
453 * Search the entire arp table, and do some action on matching entries.
454 */
455void
456search(in_addr_t addr, void (*action)(struct sockaddr_dl *sdl,
457 struct sockaddr_inarp *sin, struct rt_msghdr *rtm))
458{
459 int mib[7];
460 size_t needed;
461 char *lim, *buf = NULL((void *)0), *next;
462 struct rt_msghdr *rtm;
463 struct sockaddr_inarp *sin;
464 struct sockaddr_dl *sdl;
465
466 mib[0] = CTL_NET4;
467 mib[1] = PF_ROUTE17;
468 mib[2] = 0;
469 mib[3] = AF_INET2;
470 mib[4] = NET_RT_FLAGS2;
471 mib[5] = RTF_LLINFO0x400;
472 mib[6] = rdomain;
473 while (1) {
474 if (sysctl(mib, 7, NULL((void *)0), &needed, NULL((void *)0), 0) == -1)
475 err(1, "route-sysctl-estimate");
476 if (needed == 0)
477 return;
478 if ((buf = realloc(buf, needed)) == NULL((void *)0))
479 err(1, "malloc");
480 if (sysctl(mib, 7, buf, &needed, NULL((void *)0), 0) == -1) {
481 if (errno(*__errno()) == ENOMEM12)
482 continue;
483 err(1, "actual retrieval of routing table");
484 }
485 lim = buf + needed;
486 break;
487 }
488 for (next = buf; next < lim; next += rtm->rtm_msglen) {
489 rtm = (struct rt_msghdr *)next;
490 if (rtm->rtm_version != RTM_VERSION5)
491 continue;
492 sin = (struct sockaddr_inarp *)(next + rtm->rtm_hdrlen);
493 sdl = (struct sockaddr_dl *)(sin + 1);
494 if (addr) {
495 if (addr != sin->sin_addr.s_addr)
496 continue;
497 found_entry = 1;
498 }
499 (*action)(sdl, sin, rtm);
500 }
501 free(buf);
502}
503
504/*
505 * Dump the entire ARP table
506 */
507void
508dump(void)
509{
510 printf("%-*.*s %-*.*s %*.*s %-9.9s %5s\n",
511 W_ADDR36, W_ADDR36, "Host", W_LL17, W_LL17, "Ethernet Address",
512 W_IF7, W_IF7, "Netif", "Expire", "Flags");
513
514 search(0, print_entry);
515}
516
517/*
518 * Display an arp entry
519 */
520void
521print_entry(struct sockaddr_dl *sdl, struct sockaddr_inarp *sin,
522 struct rt_msghdr *rtm)
523{
524 char ifix_buf[IFNAMSIZ16], *ifname, *host;
525 struct hostent *hp = NULL((void *)0);
526 int addrwidth, llwidth, ifwidth ;
527 time_t now;
528
529 now = time(NULL((void *)0));
530
531 if (nflag == 0)
532 hp = gethostbyaddr((caddr_t)&(sin->sin_addr),
533 sizeof(sin->sin_addr), AF_INET2);
534 if (hp)
535 host = hp->h_name;
536 else
537 host = inet_ntoa(sin->sin_addr);
538
539 addrwidth = strlen(host);
540 if (addrwidth < W_ADDR36)
541 addrwidth = W_ADDR36;
542 llwidth = strlen(ether_str(sdl));
543 if (W_ADDR36 + W_LL17 - addrwidth > llwidth)
544 llwidth = W_ADDR36 + W_LL17 - addrwidth;
545 ifname = if_indextoname(sdl->sdl_index, ifix_buf);
546 if (!ifname)
547 ifname = "?";
548 ifwidth = strlen(ifname);
549 if (W_ADDR36 + W_LL17 + W_IF7 - addrwidth - llwidth > ifwidth)
550 ifwidth = W_ADDR36 + W_LL17 + W_IF7 - addrwidth - llwidth;
551
552 printf("%-*.*s %-*.*s %*.*s", addrwidth, addrwidth, host,
553 llwidth, llwidth, ether_str(sdl), ifwidth, ifwidth, ifname);
554
555 if (rtm->rtm_flags & (RTF_PERMANENT_ARP0x2000|RTF_LOCAL0x200000))
556 printf(" %-9.9s", "permanent");
557 else if (rtm->rtm_rmx.rmx_expire == 0)
558 printf(" %-9.9s", "static");
559 else if (rtm->rtm_rmx.rmx_expire > now)
560 printf(" %-9.9s",
561 sec2str(rtm->rtm_rmx.rmx_expire - now));
562 else
563 printf(" %-9.9s", "expired");
564
565 printf(" %s%s\n",
566 (rtm->rtm_flags & RTF_LOCAL0x200000) ? "l" : "",
567 (rtm->rtm_flags & RTF_ANNOUNCE0x4000) ? "p" : "");
568}
569
570/*
571 * Nuke an arp entry
572 */
573void
574nuke_entry(struct sockaddr_dl *sdl, struct sockaddr_inarp *sin,
575 struct rt_msghdr *rtm)
576{
577 char ip[20];
578
579 strlcpy(ip, inet_ntoa(sin->sin_addr), sizeof(ip));
580 delete(ip);
581}
582
583static char *
584ether_str(struct sockaddr_dl *sdl)
585{
586 static char hbuf[NI_MAXHOST256];
587 u_char *cp;
588
589 if (sdl->sdl_alen) {
590 cp = (u_char *)LLADDR(sdl)((caddr_t)((sdl)->sdl_data + (sdl)->sdl_nlen));
591 snprintf(hbuf, sizeof(hbuf), "%02x:%02x:%02x:%02x:%02x:%02x",
592 cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
593 } else
594 snprintf(hbuf, sizeof(hbuf), "(incomplete)");
595
596 return(hbuf);
597}
598
599void
600usage(void)
601{
602 fprintf(stderr(&__sF[2]), "usage: arp [-adn] [-V rdomain] hostname\n");
603 fprintf(stderr(&__sF[2]), " arp [-F] [-f file] [-V rdomain] "
604 "-s hostname ether_addr\n"
605 " [temp | permanent] [pub]\n");
606 fprintf(stderr(&__sF[2]), " arp -W ether_addr [iface]\n");
607 exit(1);
608}
609
610int
611rtmsg(int cmd)
612{
613 static int seq;
614 struct rt_msghdr *rtm;
615 char *cp;
616 int l;
617
618 rtm = &m_rtmsg.m_rtm;
619 cp = m_rtmsg.m_space;
620 errno(*__errno()) = 0;
621
622 if (cmd == RTM_DELETE0x2)
623 goto doit;
624 memset(&m_rtmsg, 0, sizeof(m_rtmsg));
625 rtm->rtm_flags = flags;
626 rtm->rtm_version = RTM_VERSION5;
627 rtm->rtm_hdrlen = sizeof(*rtm);
628 rtm->rtm_tableid = rdomain;
629
630 switch (cmd) {
631 default:
632 errx(1, "internal wrong cmd");
633 case RTM_ADD0x1:
634 rtm->rtm_addrs |= RTA_GATEWAY0x2;
635 rtm->rtm_rmx.rmx_expire = expire_time;
636 rtm->rtm_inits = RTV_EXPIRE0x4;
637 rtm->rtm_flags |= (RTF_HOST0x4 | RTF_STATIC0x800);
638 sin_m.sin_other = 0;
639 if (doing_proxy) {
640 if (export_only)
641 sin_m.sin_other = SIN_PROXY1;
642 else {
643 rtm->rtm_addrs |= RTA_NETMASK0x4;
644 rtm->rtm_flags &= ~RTF_HOST0x4;
645 }
646 }
647 /* FALLTHROUGH */
648 case RTM_GET0x4:
649 rtm->rtm_addrs |= (RTA_DST0x1 | RTA_IFP0x10);
650 }
651
652#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))); }
\
653 if (rtm->rtm_addrs & (w)) { \
654 memcpy(cp, &(s), sizeof(s)); \
655 ADVANCE(cp, (struct sockaddr *)&(s))(cp += ((((struct sockaddr *)&(s))->sa_len) > 0 ? (
1 + (((((struct sockaddr *)&(s))->sa_len) - 1) | (sizeof
(long) - 1))) : sizeof(long)))
; \
656 }
657
658 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))); }
;
659 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))); }
;
660 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))); }
;
661 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))); }
;
662
663 rtm->rtm_msglen = cp - (char *)&m_rtmsg;
664doit:
665 l = rtm->rtm_msglen;
666 rtm->rtm_seq = ++seq;
667 rtm->rtm_type = cmd;
668 if (write(rtsock, (char *)&m_rtmsg, l) == -1)
669 if (errno(*__errno()) != ESRCH3 || cmd != RTM_DELETE0x2) {
670 warn("writing to routing socket");
671 return (-1);
672 }
673
674 do {
675 l = read(rtsock, (char *)&m_rtmsg, sizeof(m_rtmsg));
676 } while (l > 0 && (rtm->rtm_version != RTM_VERSION5 ||
677 rtm->rtm_seq != seq || rtm->rtm_pid != pid));
678
679 if (l < 0)
680 warn("read from routing socket");
681 return (0);
682}
683
684int
685rtget(struct sockaddr_inarp **sinp, struct sockaddr_dl **sdlp)
686{
687 struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
688 struct sockaddr_inarp *sin = NULL((void *)0);
689 struct sockaddr_dl *sdl = NULL((void *)0);
690 struct sockaddr *sa;
691 char *cp;
692 unsigned int i;
693
694 if (rtmsg(RTM_GET0x4) < 0)
695 return (1);
696
697 if (rtm->rtm_addrs) {
698 cp = ((char *)rtm + rtm->rtm_hdrlen);
699 for (i = 1; i; i <<= 1) {
700 if (i & rtm->rtm_addrs) {
701 sa = (struct sockaddr *)cp;
702 switch (i) {
703 case RTA_DST0x1:
704 sin = (struct sockaddr_inarp *)sa;
705 break;
706 case RTA_IFP0x10:
707 sdl = (struct sockaddr_dl *)sa;
708 break;
709 default:
710 break;
711 }
712 ADVANCE(cp, sa)(cp += (((sa)->sa_len) > 0 ? (1 + ((((sa)->sa_len) -
1) | (sizeof(long) - 1))) : sizeof(long)))
;
713 }
714 }
715 }
716
717 if (sin == NULL((void *)0) || sdl == NULL((void *)0))
718 return (1);
719
720 *sinp = sin;
721 *sdlp = sdl;
722
723 return (0);
724}
725
726static char *
727sec2str(time_t total)
728{
729 static char result[256];
730 int days, hours, mins, secs;
731 int first = 1;
732 char *p = result;
733 char *ep = &result[sizeof(result)];
734 int n;
735
736 days = total / 3600 / 24;
737 hours = (total / 3600) % 24;
738 mins = (total / 60) % 60;
739 secs = total % 60;
740
741 if (days) {
742 first = 0;
743 n = snprintf(p, ep - p, "%dd", days);
744 if (n < 0 || n >= ep - p)
745 return "?";
746 p += n;
747 }
748 if (!first || hours) {
749 first = 0;
750 n = snprintf(p, ep - p, "%dh", hours);
751 if (n < 0 || n >= ep - p)
752 return "?";
753 p += n;
754 }
755 if (!first || mins) {
756 first = 0;
757 n = snprintf(p, ep - p, "%dm", mins);
758 if (n < 0 || n >= ep - p)
759 return "?";
760 p += n;
761 }
762 snprintf(p, ep - p, "%ds", secs);
763
764 return(result);
765}
766
767/*
768 * Copyright (c) 2011 Jasper Lievisse Adriaanse <jasper@openbsd.org>
769 * Copyright (C) 2006,2007,2008,2009 Marc Balmer <mbalmer@openbsd.org>
770 * Copyright (C) 2000 Eugene M. Kim. All rights reserved.
771 *
772 * Redistribution and use in source and binary forms, with or without
773 * modification, are permitted provided that the following conditions
774 * are met:
775 *
776 * 1. Redistributions of source code must retain the above copyright
777 * notice, this list of conditions and the following disclaimer.
778 * 2. Author's name may not be used endorse or promote products derived
779 * from this software without specific prior written permission.
780 *
781 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
782 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
783 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
784 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
785 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
786 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
787 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
788 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
789 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
790 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
791 * POSSIBILITY OF SUCH DAMAGE.
792 */
793
794int do_wakeup(const char *, const char *, int);
795int bind_if_to_bpf(const char *, int);
796int get_ether(const char *, struct ether_addr *);
797int send_frame(int, const struct ether_addr *);
798
799int
800wake(const char *ether_addr, const char *iface)
801{
802 struct ifaddrs *ifa, *ifap;
803 char *pname = NULL((void *)0);
804 int bpf;
805
806 if ((bpf = open("/dev/bpf", O_RDWR0x0002)) == -1)
807 err(1, "Failed to bind to bpf");
808
809 if (iface == NULL((void *)0)) {
810 if (getifaddrs(&ifa) == -1)
811 errx(1, "Could not get interface addresses.");
812
813 for (ifap = ifa; ifap != NULL((void *)0); ifap = ifap->ifa_next){
814 if (pname && !strcmp(pname, ifap->ifa_name))
815 continue;
816 pname = ifap->ifa_name;
817
818 /*
819 * We're only interested in sending the WoL frame on
820 * certain interfaces. So skip the loopback interface,
821 * as well as point-to-point and down interfaces.
822 */
823 if ((ifap->ifa_flags & IFF_LOOPBACK0x8) ||
824 (ifap->ifa_flags & IFF_POINTOPOINT0x10) ||
825 (!(ifap->ifa_flags & IFF_UP0x1)) ||
826 (!(ifap->ifa_flags & IFF_BROADCAST0x2)))
827 continue;
828
829 do_wakeup(ether_addr, ifap->ifa_name, bpf);
830 }
831 freeifaddrs(ifa);
832 } else {
833 do_wakeup(ether_addr, iface, bpf);
834 }
835
836 (void)close(bpf);
837
838 return 0;
839}
840
841int
842do_wakeup(const char *eaddr, const char *iface, int bpf)
843{
844 struct ether_addr macaddr;
845
846 if (get_ether(eaddr, &macaddr) != 0)
847 errx(1, "Invalid Ethernet address: %s", eaddr);
848 if (bind_if_to_bpf(iface, bpf) != 0)
849 errx(1, "Failed to bind %s to bpf.", iface);
850 if (send_frame(bpf, &macaddr) != 0)
851 errx(1, "Failed to send WoL frame on %s", iface);
852 return 0;
853}
854
855int
856bind_if_to_bpf(const char *ifname, int bpf)
857{
858 struct ifreq ifr;
859 u_int dlt;
860
861 if (strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)) >=
862 sizeof(ifr.ifr_name))
863 return -1;
864 if (ioctl(bpf, BIOCSETIF((unsigned long)0x80000000 | ((sizeof(struct ifreq) & 0x1fff
) << 16) | ((('B')) << 8) | ((108)))
, &ifr) == -1)
865 return -1;
866 if (ioctl(bpf, BIOCGDLT((unsigned long)0x40000000 | ((sizeof(u_int) & 0x1fff) <<
16) | ((('B')) << 8) | ((106)))
, &dlt) == -1)
867 return -1;
868 if (dlt != DLT_EN10MB1)
869 return -1;
870 return 0;
871}
872
873int
874get_ether(const char *text, struct ether_addr *addr)
875{
876 struct ether_addr *eaddr;
877
878 eaddr = ether_aton(text);
879
880 if (eaddr == NULL((void *)0)) {
881 if (ether_hostton(text, addr))
882 return -1;
883 } else {
884 *addr = *eaddr;
885 return 0;
886 }
887
888 return 0;
889}
890
891#define SYNC_LEN6 6
892#define DESTADDR_COUNT16 16
893
894int
895send_frame(int bpf, const struct ether_addr *addr)
896{
897 struct {
898 struct ether_header hdr;
899 u_char sync[SYNC_LEN6];
900 u_char dest[ETHER_ADDR_LEN6 * DESTADDR_COUNT16];
901 } __packed__attribute__((__packed__)) pkt;
902 u_char *p;
903 int i;
904
905 (void)memset(&pkt, 0, sizeof(pkt));
906 (void)memset(&pkt.hdr.ether_dhost, 0xff, sizeof(pkt.hdr.ether_dhost));
907 pkt.hdr.ether_type = htons(0)(__uint16_t)(__builtin_constant_p(0) ? (__uint16_t)(((__uint16_t
)(0) & 0xffU) << 8 | ((__uint16_t)(0) & 0xff00U
) >> 8) : __swap16md(0))
;
908 (void)memset(pkt.sync, 0xff, SYNC_LEN6);
909 for (p = pkt.dest, i = 0; i < DESTADDR_COUNT16; p += ETHER_ADDR_LEN6, i++)
910 bcopy(addr->ether_addr_octet, p, ETHER_ADDR_LEN6);
911 if (write(bpf, &pkt, sizeof(pkt)) != sizeof(pkt))
912 return (errno(*__errno()));
913 return (0);
914}