1/* $NetBSD: arp.c,v 1.68 2020/09/15 11:14:16 roy Exp $ */ 2 3/* 4 * Copyright (c) 1984, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Sun Microsystems, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35#include <sys/cdefs.h> 36#ifndef lint 37__COPYRIGHT("@(#) Copyright (c) 1984, 1993\ 38 The Regents of the University of California. All rights reserved."); 39#endif /* not lint */ 40 41#ifndef lint 42#if 0 43static char sccsid[] = "@(#)arp.c 8.3 (Berkeley) 4/28/95"; 44#else 45__RCSID("$NetBSD: arp.c,v 1.68 2020/09/15 11:14:16 roy Exp $"); 46#endif 47#endif /* not lint */ 48 49/* 50 * arp - display, set, and delete arp table entries 51 */ 52 53#include <sys/param.h> 54#include <sys/file.h> 55#include <sys/socket.h> 56#include <sys/sysctl.h> 57#include <sys/ioctl.h> 58 59#include <net/if.h> 60#include <net/if_dl.h> 61#include <net/if_ether.h> 62#include <net/if_types.h> 63#include <net/nd.h> 64#include <net/route.h> 65#include <netinet/in.h> 66#include <netinet/in_var.h> 67#include <netinet/if_inarp.h> 68#include <arpa/inet.h> 69 70#include <err.h> 71#include <errno.h> 72#include <netdb.h> 73#include <nlist.h> 74#include <paths.h> 75#include <stdio.h> 76#include <stdlib.h> 77#include <string.h> 78#include <unistd.h> 79#include <ifaddrs.h> 80 81#include "prog_ops.h" 82 83static int is_llinfo(const struct sockaddr_dl *, int); 84static int delete_one(struct rt_msghdr *); 85static void dump(uint32_t); 86static void delete(const char *, const char *); 87static void sdl_print(const struct sockaddr_dl *); 88static int getifname(u_int16_t, char *, size_t); 89static int atosdl(const char *, struct sockaddr_dl *); 90static int file(const char *); 91static void get(const char *); 92static int getinetaddr(const char *, struct in_addr *); 93static int getsocket(void); 94static int getetheraddr(struct in_addr, struct sockaddr_dl *); 95static struct rt_msghdr * rtmsg(const int, const int, struct rt_msghdr *, 96 const struct sockaddr_inarp *, const struct sockaddr_dl *); 97static struct in_nbrinfo * getnbrinfo(const char *, struct in_addr *); 98static const char * sec2str(time_t); 99static int set(int, char **); 100static void usage(void) __dead; 101 102static int aflag, nflag, vflag; 103static struct sockaddr_in so_mask = { 104 .sin_len = 8, 105 .sin_addr = { 106 .s_addr = 0xffffffff 107 } 108}; 109static struct sockaddr_inarp blank_sin = { 110 .sin_len = sizeof(blank_sin), 111 .sin_family = AF_INET 112}; 113static struct sockaddr_dl blank_sdl = { 114 .sdl_len = sizeof(blank_sdl), 115 .sdl_family = AF_LINK 116}; 117 118static int expire_time, flags, export_only, doing_proxy, found_entry; 119 120int 121main(int argc, char **argv) 122{ 123 int ch; 124 int op = 0; 125 126 setprogname(argv[0]); 127 128 while ((ch = getopt(argc, argv, "andsfv")) != -1) 129 switch((char)ch) { 130 case 'a': 131 aflag = 1; 132 break; 133 case 'd': 134 case 's': 135 case 'f': 136 if (op) 137 usage(); 138 op = ch; 139 break; 140 case 'n': 141 nflag = 1; 142 break; 143 case 'v': 144 vflag = 1; 145 break; 146 default: 147 usage(); 148 } 149 argc -= optind; 150 argv += optind; 151 152 if (!op && aflag) 153 op = 'a'; 154 155 if (prog_init && prog_init() == -1) 156 err(1, "init failed"); 157 158 switch((char)op) { 159 case 'a': 160 dump(0); 161 break; 162 case 'd': 163 if (aflag && argc == 0) 164 delete(NULL, NULL); 165 else { 166 if (aflag || argc < 1 || argc > 2) 167 usage(); 168 delete(argv[0], argv[1]); 169 } 170 break; 171 case 's': 172 if (argc < 2 || argc > 7) 173 usage(); 174 return (set(argc, argv) ? 1 : 0); 175 case 'f': 176 if (argc != 1) 177 usage(); 178 return (file(argv[0])); 179 default: 180 if (argc != 1) 181 usage(); 182 get(argv[0]); 183 break; 184 } 185 return (0); 186} 187 188/* 189 * Process a file to set standard arp entries 190 */ 191static int 192file(const char *name) 193{ 194 char *line, *argv[5]; 195 int i, retval; 196 FILE *fp; 197 198 if (!strcmp(name, "-")) { 199 fp = stdin; 200 } else { 201 fp = fopen(name, "r"); 202 if (fp == NULL) { 203 err(1, "Cannot open %s", name); 204 } 205 } 206 retval = 0; 207 for (; (line = fparseln(fp, NULL, NULL, NULL, 0)) != NULL; free(line)) { 208 char **ap, *inputstring; 209 210 inputstring = line; 211 for (ap = argv; ap < &argv[sizeof(argv) / sizeof(argv[0])] && 212 (*ap = stresep(&inputstring, " \t", '\\')) != NULL;) { 213 if (**ap != '\0') 214 ap++; 215 } 216 i = ap - argv; 217 if (i < 2) { 218 warnx("bad line: %s", line); 219 retval = 1; 220 continue; 221 } 222 if (set(i, argv)) 223 retval = 1; 224 } 225 if (fp != stdin) 226 (void)fclose(fp); 227 return retval; 228} 229 230static int 231getsocket(void) 232{ 233 int s; 234 s = prog_socket(PF_ROUTE, SOCK_RAW, 0); 235 if (s < 0) 236 err(1, "socket"); 237 return s; 238} 239 240static int 241getlink(const char *name, struct sockaddr_dl *sdl) 242{ 243 struct ifaddrs *ifap, *ifa; 244 245 if (getifaddrs(&ifap) != 0) { 246 warn("getifaddrs"); 247 return 0; 248 } 249 250 for (ifa = ifap; ifa; ifa = ifa->ifa_next) { 251 if (ifa->ifa_addr->sa_family != AF_LINK) 252 continue; 253 if (strcmp(ifa->ifa_name, name) != 0) 254 continue; 255 memcpy(sdl, ifa->ifa_addr, sizeof(*sdl)); 256 freeifaddrs(ifap); 257 return 1; 258 } 259 freeifaddrs(ifap); 260 return 0; 261} 262 263/* 264 * Set an individual arp entry 265 */ 266static int 267set(int argc, char **argv) 268{ 269 struct sockaddr_inarp *sina; 270 struct sockaddr_dl *sdl = NULL; 271 struct rt_msghdr *rtm; 272 char *host = argv[0], *eaddr; 273 struct sockaddr_inarp sin_m = blank_sin; /* struct copy */ 274 struct sockaddr_dl sdl_m = blank_sdl; /* struct copy */ 275 int s; 276 277 eaddr = argv[1]; 278 279 s = getsocket(); 280 argc -= 2; 281 argv += 2; 282 283 if (getinetaddr(host, &sin_m.sin_addr) == -1) { 284 prog_close(s); 285 return (1); 286 } 287 if (strcmp(eaddr, "auto") != 0 && atosdl(eaddr, &sdl_m)) 288 warnx("invalid link-level address '%s'", eaddr); 289 doing_proxy = flags = export_only = expire_time = 0; 290 for (; argc-- > 0; argv++) { 291 if (strncmp(argv[0], "temp", 4) == 0) { 292 struct timeval timev; 293 (void)gettimeofday(&timev, 0); 294 expire_time = timev.tv_sec + 20 * 60; 295 } 296 else if (strncmp(argv[0], "pub", 3) == 0) { 297 flags |= RTF_ANNOUNCE; 298 doing_proxy = 1; 299 if (argc && strncmp(argv[1], "pro", 3) == 0) { 300 export_only = 1; 301 argc--; argv++; 302 } 303 } else if (strncmp(argv[0], "trail", 5) == 0) { 304 warnx("%s: Sending trailers is no longer supported", 305 host); 306 } else if (strcmp(argv[0], "ifscope") == 0) { 307 if (argc == 0) { 308 warnx("missing interface for ifscope"); 309 continue; 310 } 311 argc--; 312 argv++; 313 if (!getlink(argv[0], &sdl_m)) 314 warnx("cannot get link address for %s", argv[0]); 315 } 316 317 } 318 if (doing_proxy && strcmp(eaddr, "auto") == 0) { 319 if (getetheraddr(sin_m.sin_addr, &sdl_m) == -1) { 320 prog_close(s); 321 return 1; 322 } 323 } 324tryagain: 325 rtm = rtmsg(s, RTM_GET, NULL, &sin_m, &sdl_m); 326 if (rtm == NULL) { 327 warn("%s", host); 328 prog_close(s); 329 return (1); 330 } 331 sina = (struct sockaddr_inarp *)(void *)(rtm + 1); 332 sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(sina->sin_len) + 333 (char *)(void *)sina); 334 if (sina->sin_addr.s_addr == sin_m.sin_addr.s_addr) { 335 if (is_llinfo(sdl, rtm->rtm_flags)) 336 goto overwrite; 337 if (doing_proxy == 0) { 338 warnx("set: can only proxy for %s", host); 339 prog_close(s); 340 return (1); 341 } 342 if (sin_m.sin_other & SIN_PROXY) { 343 warnx("set: proxy entry exists for non 802 device"); 344 prog_close(s); 345 return (1); 346 } 347 sin_m.sin_other = SIN_PROXY; 348 export_only = 1; 349 goto tryagain; 350 } 351overwrite: 352 if (sdl->sdl_family != AF_LINK) { 353 warnx("cannot intuit interface index and type for %s", 354 host); 355 prog_close(s); 356 return (1); 357 } 358 sdl_m.sdl_type = sdl->sdl_type; 359 sdl_m.sdl_index = sdl->sdl_index; 360 sin_m.sin_other = 0; 361 if (doing_proxy && export_only) 362 sin_m.sin_other = SIN_PROXY; 363 rtm = rtmsg(s, RTM_ADD, NULL, &sin_m, &sdl_m); 364 if (vflag) 365 (void)printf("%s (%s) added\n", host, eaddr); 366 prog_close(s); 367 return (rtm == NULL) ? 1 : 0; 368} 369 370/* 371 * Display an individual arp entry 372 */ 373static void 374get(const char *host) 375{ 376 struct sockaddr_inarp sin = blank_sin; /* struct copy */ 377 378 if (getinetaddr(host, &sin.sin_addr) == -1) 379 exit(1); 380 dump(sin.sin_addr.s_addr); 381 if (found_entry == 0) 382 errx(1, "%s (%s) -- no entry", host, inet_ntoa(sin.sin_addr)); 383} 384 385 386static int 387is_llinfo(const struct sockaddr_dl *sdl, int rtflags) 388{ 389 if (sdl->sdl_family != AF_LINK || 390 (rtflags & (RTF_LLDATA|RTF_GATEWAY)) != RTF_LLDATA) 391 return 0; 392 393 switch (sdl->sdl_type) { 394 case IFT_ETHER: 395 case IFT_FDDI: 396 case IFT_ISO88023: 397 case IFT_ISO88024: 398 case IFT_ISO88025: 399 case IFT_ARCNET: 400 return 1; 401 default: 402 return 0; 403 } 404} 405 406/* 407 * Delete an arp entry 408 */ 409int 410delete_one(struct rt_msghdr *rtm) 411{ 412 struct sockaddr_inarp *sina; 413 struct sockaddr_dl *sdl; 414 int s; 415 416 s = getsocket(); 417 sina = (struct sockaddr_inarp *)(void *)(rtm + 1); 418 sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(sina->sin_len) + 419 (char *)(void *)sina); 420 if (sdl->sdl_family != AF_LINK) { 421 prog_close(s); 422 return (1); 423 } 424 rtm = rtmsg(s, RTM_DELETE, rtm, sina, sdl); 425 prog_close(s); 426 if (rtm == NULL) 427 return (1); 428 return (0); 429} 430 431/* 432 * Dump the entire arp table 433 */ 434void 435dump(uint32_t addr) 436{ 437 int mib[6]; 438 size_t needed; 439 char ifname[IFNAMSIZ]; 440 char *lim, *buf, *next; 441 const char *host; 442 struct rt_msghdr *rtm; 443 struct sockaddr_inarp *sina; 444 struct sockaddr_dl *sdl; 445 struct hostent *hp; 446 struct timeval tim; 447 struct in_nbrinfo *nbi; 448 449 mib[0] = CTL_NET; 450 mib[1] = PF_ROUTE; 451 mib[2] = 0; 452 mib[3] = AF_INET; 453 mib[4] = NET_RT_FLAGS; 454 mib[5] = 0; 455 if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 456 err(1, "route-sysctl-estimate"); 457 if (needed == 0) 458 return; 459 if ((buf = malloc(needed)) == NULL) 460 err(1, "malloc"); 461 if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 462 err(1, "actual retrieval of routing table"); 463 lim = buf + needed; 464 for (next = buf; next < lim; next += rtm->rtm_msglen) { 465 rtm = (struct rt_msghdr *)(void *)next; 466 sina = (struct sockaddr_inarp *)(void *)(rtm + 1); 467 sdl = (struct sockaddr_dl *)(void *) 468 (RT_ROUNDUP(sina->sin_len) + (char *)(void *)sina); 469 if (addr) { 470 if (addr != sina->sin_addr.s_addr) 471 continue; 472 found_entry = 1; 473 } 474 if (nflag == 0) 475 hp = gethostbyaddr((const char *)(void *) 476 &(sina->sin_addr), 477 sizeof sina->sin_addr, AF_INET); 478 else 479 hp = NULL; 480 481 host = hp ? hp->h_name : "?"; 482 483 (void)printf("%s (%s) at ", host, inet_ntoa(sina->sin_addr)); 484 if (sdl->sdl_alen) 485 sdl_print(sdl); 486 else 487 (void)printf("(incomplete)"); 488 489 if (sdl->sdl_index) { 490 if (getifname(sdl->sdl_index, ifname, sizeof(ifname)) == 0) 491 (void)printf(" on %s", ifname); 492 } 493 494 if (sina->sin_other & SIN_PROXY) 495 (void)printf(" published (proxy only)"); 496 if (rtm->rtm_addrs & RTA_NETMASK) { 497 sina = (struct sockaddr_inarp *)(void *) 498 (RT_ROUNDUP(sdl->sdl_len) + (char *)(void *)sdl); 499 if (sina->sin_addr.s_addr == 0xffffffff) 500 (void)printf(" published"); 501 if (sina->sin_len != 8) 502 (void)printf("(weird)"); 503 } 504 505 if (sdl->sdl_index == 0) 506 goto done; 507 (void)gettimeofday(&tim, 0); 508 nbi = getnbrinfo(ifname, &sina->sin_addr); 509 if (nbi != NULL) { 510 if (nbi->expire > tim.tv_sec) { 511 (void)printf(" %s", 512 sec2str(nbi->expire - tim.tv_sec)); 513 } else if (nbi->expire == 0) 514 (void)printf(" %s", "permanent"); 515 else 516 (void)printf(" %s", "expired"); 517 518 switch (nbi->state) { 519 case ND_LLINFO_NOSTATE: 520 (void)printf(" N"); 521 break; 522 case ND_LLINFO_WAITDELETE: 523 (void)printf(" W"); 524 break; 525 case ND_LLINFO_INCOMPLETE: 526 (void)printf(" I"); 527 break; 528 case ND_LLINFO_REACHABLE: 529 (void)printf(" R"); 530 break; 531 case ND_LLINFO_STALE: 532 (void)printf(" S"); 533 break; 534 case ND_LLINFO_DELAY: 535 (void)printf(" D"); 536 break; 537 case ND_LLINFO_PROBE: 538 (void)printf(" P"); 539 break; 540 case ND_LLINFO_UNREACHABLE: 541 (void)printf(" U"); 542 break; 543 default: 544 (void)printf(" ?"); 545 break; 546 } 547 } 548 549done: 550 (void)printf("\n"); 551 } 552 free(buf); 553} 554 555/* 556 * Delete the entire arp table 557 */ 558void 559delete(const char *host, const char *info) 560{ 561 int mib[6]; 562 char addr[sizeof("000.000.000.000\0")]; 563 size_t needed; 564 char *lim, *buf, *next; 565 struct rt_msghdr *rtm; 566 struct sockaddr_inarp *sina; 567 struct sockaddr_inarp sin_m = blank_sin; /* struct copy */ 568 bool found = false; 569 570 if (host != NULL) { 571 int ret = getinetaddr(host, &sin_m.sin_addr); 572 if (ret == -1) 573 return; 574 } 575 if (info && strncmp(info, "pro", 3) == 0) 576 sin_m.sin_other = SIN_PROXY; 577 578retry: 579 mib[0] = CTL_NET; 580 mib[1] = PF_ROUTE; 581 mib[2] = 0; 582 mib[3] = AF_INET; 583 mib[4] = NET_RT_FLAGS; 584 mib[5] = RTF_LLDATA; 585 if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 586 err(1, "route-sysctl-estimate"); 587 if (needed == 0) 588 return; 589 if ((buf = malloc(needed)) == NULL) 590 err(1, "malloc"); 591 if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 592 free(buf); 593 if (errno == ENOBUFS) 594 goto retry; 595 err(1, "actual retrieval of routing table"); 596 } 597 lim = buf + needed; 598 599 for (next = buf; next < lim; next += rtm->rtm_msglen) { 600 int ret; 601 rtm = (struct rt_msghdr *)(void *)next; 602 sina = (struct sockaddr_inarp *)(void *)(rtm + 1); 603 if (host != NULL && 604 sina->sin_addr.s_addr != sin_m.sin_addr.s_addr) 605 continue; 606 found = true; 607 ret = delete_one(rtm); 608 if (vflag && ret == 0) { 609 snprintf(addr, sizeof(addr), "%s", 610 inet_ntoa(sina->sin_addr)); 611 (void)printf("%s (%s) deleted\n", 612 host != NULL ? host : addr, addr); 613 } 614 } 615 if (host != NULL && !found) 616 warnx("delete: can't locate %s", host); 617 free(buf); 618} 619 620void 621sdl_print(const struct sockaddr_dl *sdl) 622{ 623 char hbuf[NI_MAXHOST]; 624 625 if (getnameinfo((const struct sockaddr *)(const void *)sdl, 626 (socklen_t)sdl->sdl_len, 627 hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) 628 (void)printf("<invalid>"); 629 else 630 (void)printf("%s", hbuf); 631} 632 633static int 634atosdl(const char *ss, struct sockaddr_dl *sdl) 635{ 636 int i; 637 unsigned long b; 638 char *endp; 639 char *p; 640 char *t, *r; 641 642 p = LLADDR(sdl); 643 endp = ((char *)(void *)sdl) + sdl->sdl_len; 644 i = 0; 645 646 b = strtoul(ss, &t, 16); 647 if (b > 255 || t == ss) 648 return 1; 649 650 *p++ = (char)b; 651 ++i; 652 while ((p < endp) && (*t++ == ':')) { 653 b = strtoul(t, &r, 16); 654 if (b > 255 || r == t) 655 break; 656 *p++ = (char)b; 657 ++i; 658 t = r; 659 } 660 sdl->sdl_alen = i; 661 662 return 0; 663} 664 665static void 666usage(void) 667{ 668 const char *progname; 669 670 progname = getprogname(); 671 (void)fprintf(stderr, "Usage: %s [-n] hostname\n", progname); 672 (void)fprintf(stderr, " %s [-nv] -a\n", progname); 673 (void)fprintf(stderr, " %s [-v] -d [-a|hostname [proxy]]\n", 674 progname); 675 (void)fprintf(stderr, " %s -s hostname ether_addr [temp] [pub [proxy]]\n", 676 progname); 677 (void)fprintf(stderr, " %s -f filename\n", progname); 678 exit(1); 679} 680 681static struct rt_msghdr * 682rtmsg(const int s, const int cmd, struct rt_msghdr *_rtm, 683 const struct sockaddr_inarp *sin, const struct sockaddr_dl *sdl) 684{ 685 static int seq; 686 struct rt_msghdr *rtm = _rtm; 687 char *cp; 688 int l; 689 static struct { 690 struct rt_msghdr m_rtm; 691 char m_space[512]; 692 } m_rtmsg; 693 pid_t pid; 694 695 errno = 0; 696 if (rtm != NULL) { 697 memcpy(&m_rtmsg, rtm, rtm->rtm_msglen); 698 rtm = &m_rtmsg.m_rtm; 699 goto doit; 700 } 701 (void)memset(&m_rtmsg, 0, sizeof(m_rtmsg)); 702 rtm = &m_rtmsg.m_rtm; 703 cp = m_rtmsg.m_space; 704 705 rtm->rtm_flags = flags; 706 rtm->rtm_version = RTM_VERSION; 707 708 switch (cmd) { 709 default: 710 errx(1, "internal wrong cmd"); 711 /*NOTREACHED*/ 712 case RTM_ADD: 713 rtm->rtm_addrs |= RTA_GATEWAY; 714 rtm->rtm_rmx.rmx_expire = expire_time; 715 rtm->rtm_inits = RTV_EXPIRE; 716 rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA); 717 if (doing_proxy) { 718 if (!export_only) { 719 rtm->rtm_addrs |= RTA_NETMASK; 720 rtm->rtm_flags &= ~RTF_HOST; 721 } 722 } 723 rtm->rtm_addrs |= RTA_DST; 724 break; 725 case RTM_GET: 726 rtm->rtm_flags |= RTF_LLDATA; 727 rtm->rtm_addrs |= RTA_DST | RTA_GATEWAY; 728 } 729 730#define NEXTADDR(w, s) \ 731 if (rtm->rtm_addrs & (w)) { \ 732 (void)memcpy(cp, &s, \ 733 (size_t)((const struct sockaddr *)&s)->sa_len); \ 734 RT_ADVANCE(cp, ((const struct sockaddr *)&s)); \ 735 } 736 737 NEXTADDR(RTA_DST, *sin); 738 NEXTADDR(RTA_GATEWAY, *sdl); 739 NEXTADDR(RTA_NETMASK, so_mask); 740 741 rtm->rtm_msglen = cp - (char *)(void *)&m_rtmsg; 742doit: 743 l = rtm->rtm_msglen; 744 rtm->rtm_seq = ++seq; 745 rtm->rtm_type = cmd; 746 if (prog_write(s, &m_rtmsg, (size_t)l) < 0) { 747 if (errno != ESRCH || cmd != RTM_DELETE) { 748 warn("writing to routing socket"); 749 return NULL; 750 } 751 } 752 753 pid = prog_getpid(); 754 do { 755 l = prog_read(s, &m_rtmsg, sizeof(m_rtmsg)); 756 } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 757 if (l < 0) 758 warn("read from routing socket"); 759 return rtm; 760} 761 762static int 763getinetaddr(const char *host, struct in_addr *inap) 764{ 765 struct hostent *hp; 766 767 if (inet_aton(host, inap) == 1) 768 return (0); 769 if ((hp = gethostbyname(host)) == NULL) { 770 warnx("%s: %s", host, hstrerror(h_errno)); 771 return (-1); 772 } 773 (void)memcpy(inap, hp->h_addr, sizeof(*inap)); 774 return (0); 775} 776 777static int 778getifname(u_int16_t ifindex, char *ifname, size_t l) 779{ 780 int i; 781 struct ifaddrs *addr; 782 const struct sockaddr_dl *sdl; 783 static struct ifaddrs* ifaddrs = NULL; 784 785 if (ifaddrs == NULL) { 786 i = getifaddrs(&ifaddrs); 787 if (i != 0) 788 err(1, "getifaddrs"); 789 } 790 791 for (addr = ifaddrs; addr; addr = addr->ifa_next) { 792 if (addr->ifa_addr == NULL || 793 addr->ifa_addr->sa_family != AF_LINK) 794 continue; 795 796 sdl = (const struct sockaddr_dl *)(void *)addr->ifa_addr; 797 if (sdl && sdl->sdl_index == ifindex) { 798 (void) strlcpy(ifname, addr->ifa_name, l); 799 return 0; 800 } 801 } 802 803 return -1; 804} 805 806static int 807getetheraddr(struct in_addr ipaddr, struct sockaddr_dl *sdl) 808{ 809 struct ifaddrs *ifaddrs, *addr; 810 in_addr_t ina, mask; 811 char ifname[IFNAMSIZ]; 812 813 if (getifaddrs(&ifaddrs) != 0) { 814 warn("getifaddrs"); 815 return -1; 816 } 817 818 for (addr = ifaddrs; addr; addr = addr->ifa_next) { 819 if (addr->ifa_addr == NULL || 820 addr->ifa_addr->sa_family != AF_INET) 821 continue; 822 if ((addr->ifa_flags & (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT| 823 IFF_LOOPBACK|IFF_NOARP)) != (IFF_UP|IFF_BROADCAST)) 824 continue; 825 826 mask = ((struct sockaddr_in *)(void *)addr->ifa_netmask)->sin_addr.s_addr; 827 ina = ((struct sockaddr_in *)(void *)addr->ifa_addr)->sin_addr.s_addr; 828 if ((ipaddr.s_addr & mask) != (ina & mask)) 829 continue; 830 strlcpy(ifname, addr->ifa_name, sizeof(ifname)); 831 break; 832 } 833 if (addr == NULL) { 834 warnx("No interface matched %s", inet_ntoa(ipaddr)); 835 freeifaddrs(ifaddrs); 836 return -1; 837 } 838 839 for (addr = ifaddrs; addr; addr = addr->ifa_next) { 840 if (addr->ifa_addr == NULL || 841 addr->ifa_addr->sa_family != AF_LINK) 842 continue; 843 if (strcmp(ifname, addr->ifa_name) != 0) 844 continue; 845 memcpy(sdl, addr->ifa_addr, sizeof(*sdl)); 846 freeifaddrs(ifaddrs); 847 return 0; 848 } 849 warnx("No link address for interface %s", ifname); 850 freeifaddrs(ifaddrs); 851 return -1; 852} 853 854static struct in_nbrinfo * 855getnbrinfo(const char *ifname, struct in_addr *addr) 856{ 857 static struct in_nbrinfo nbi, *nbip; 858 int s; 859 860 if ((s = prog_socket(AF_INET, SOCK_DGRAM, 0)) == -1) 861 err(1, "socket"); 862 863 (void)memset(&nbi, 0, sizeof(nbi)); 864 (void)strlcpy(nbi.ifname, ifname, sizeof(nbi.ifname)); 865 nbi.addr = *addr; 866 if (prog_ioctl(s, SIOCGNBRINFO, &nbi) == -1) { 867 warn("ioctl(SIOCGNBRINFO)"); 868 nbip = NULL; 869 } else 870 nbip = &nbi; 871 (void)prog_close(s); 872 873 return nbip; 874} 875 876static const char * 877sec2str(time_t total) 878{ 879 static char result[256]; 880 int days, hours, mins, secs; 881 int first = 1; 882 char *p = result; 883 char *ep = &result[sizeof(result)]; 884 int n; 885 886 days = total / 3600 / 24; 887 hours = (total / 3600) % 24; 888 mins = (total / 60) % 60; 889 secs = total % 60; 890 891 if (days) { 892 first = 0; 893 n = snprintf(p, (size_t)(ep - p), "%dd", days); 894 if (n < 0 || n >= ep - p) 895 return "?"; 896 p += n; 897 } 898 if (!first || hours) { 899 first = 0; 900 n = snprintf(p, (size_t)(ep - p), "%dh", hours); 901 if (n < 0 || n >= ep - p) 902 return "?"; 903 p += n; 904 } 905 if (!first || mins) { 906 first = 0; 907 n = snprintf(p, (size_t)(ep - p), "%dm", mins); 908 if (n < 0 || n >= ep - p) 909 return "?"; 910 p += n; 911 } 912 (void)snprintf(p, (size_t)(ep - p), "%ds", secs); 913 914 return(result); 915} 916