Bug Summary

File:src/usr.sbin/arp/arp.c
Warning:line 756, 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 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) {
106 switch (ch) {
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)
118 usage();
119 func = ch;
120 break;
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) {
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)
165 usage();
166 error = file(argv[0]);
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))
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)) {
201 i = sscanf(line, "%49s %49s %49s %49s %49s", arg[0], arg[1],
202 arg[2], arg[3], arg[4]);
203 if (i < 2) {
204 warnx("bad line: %s", line);
205 retval = 1;
206 continue;
207 }
208 if (replace)
209 delete(arg[0]);
210 if (set(i, args))
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)
244 hints.ai_flags = AI_NUMERICHOST4;
245
246 gai_error = getaddrinfo(host, NULL((void *)0), &hints, &res);
247 if (gai_error) {
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;
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))
291 return (1);
292 ea = ether_aton(eaddr);
293 if (ea == NULL((void *)0))
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) {
300 if (strncmp(argv[0], "temp", 4) == 0) {
301 expire_time = time(NULL((void *)0)) + 20 * 60;
302 if (flags & RTF_PERMANENT_ARP0x2000) {
303 /* temp or permanent, not both */
304 usage();
305 return (0);
306 }
307 } else if (strncmp(argv[0], "pub", 3) == 0) {
308 flags |= RTF_ANNOUNCE0x4000;
309 doing_proxy = SIN_PROXY1;
310 } else if (strncmp(argv[0], "permanent", 9) == 0) {
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;
Value stored to 'first' is never read
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}