arp.c revision 57727
1163953Srrs/* 2163953Srrs * Copyright (c) 1984, 1993 3163953Srrs * The Regents of the University of California. All rights reserved. 4163953Srrs * 5163953Srrs * This code is derived from software contributed to Berkeley by 6163953Srrs * Sun Microsystems, Inc. 7163953Srrs * 8163953Srrs * Redistribution and use in source and binary forms, with or without 9163953Srrs * modification, are permitted provided that the following conditions 10163953Srrs * are met: 11163953Srrs * 1. Redistributions of source code must retain the above copyright 12163953Srrs * notice, this list of conditions and the following disclaimer. 13163953Srrs * 2. Redistributions in binary form must reproduce the above copyright 14163953Srrs * notice, this list of conditions and the following disclaimer in the 15163953Srrs * documentation and/or other materials provided with the distribution. 16163953Srrs * 3. All advertising materials mentioning features or use of this software 17163953Srrs * must display the following acknowledgement: 18163953Srrs * This product includes software developed by the University of 19163953Srrs * California, Berkeley and its contributors. 20163953Srrs * 4. Neither the name of the University nor the names of its contributors 21163953Srrs * may be used to endorse or promote products derived from this software 22163953Srrs * without specific prior written permission. 23163953Srrs * 24163953Srrs * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25163953Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26163953Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27163953Srrs * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28163953Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29163953Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30163953Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31163953Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32163953Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33163953Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34163957Srrs * SUCH DAMAGE. 35163953Srrs */ 36163953Srrs 37163957Srrs#ifndef lint 38163953Srrsstatic char const copyright[] = 39163953Srrs"@(#) Copyright (c) 1984, 1993\n\ 40163953Srrs The Regents of the University of California. All rights reserved.\n"; 41163953Srrs#endif /* not lint */ 42163953Srrs 43163953Srrs#ifndef lint 44163953Srrs#if 0 45163953Srrsstatic char const sccsid[] = "@(#)from: arp.c 8.2 (Berkeley) 1/2/94"; 46163953Srrs#endif 47163953Srrsstatic const char rcsid[] = 48163953Srrs "$FreeBSD: head/usr.sbin/arp/arp.c 57727 2000-03-03 13:01:57Z shin $"; 49163953Srrs#endif /* not lint */ 50163953Srrs 51163953Srrs/* 52163953Srrs * arp - display, set, and delete arp table entries 53163953Srrs */ 54163953Srrs 55163953Srrs 56163953Srrs#include <sys/param.h> 57163953Srrs#include <sys/file.h> 58163953Srrs#include <sys/socket.h> 59163953Srrs#include <sys/sockio.h> 60163953Srrs#include <sys/sysctl.h> 61163953Srrs#include <sys/ioctl.h> 62163953Srrs#include <sys/time.h> 63163953Srrs 64163953Srrs#include <net/if.h> 65163953Srrs#include <net/if_dl.h> 66163953Srrs#include <net/if_types.h> 67163953Srrs#include <net/route.h> 68163953Srrs 69163953Srrs#include <netinet/in.h> 70163953Srrs#include <netinet/if_ether.h> 71163953Srrs 72163953Srrs#include <arpa/inet.h> 73163953Srrs 74163953Srrs#include <err.h> 75163953Srrs#include <errno.h> 76163953Srrs#include <netdb.h> 77163953Srrs#include <nlist.h> 78163953Srrs#include <paths.h> 79163953Srrs#include <stdio.h> 80163953Srrs#include <stdlib.h> 81163953Srrs#include <strings.h> 82163953Srrs#include <unistd.h> 83163953Srrs 84163953Srrsvoid search(u_long addr, void (*action)(struct sockaddr_dl *sdl, 85163953Srrs struct sockaddr_inarp *sin, struct rt_msghdr *rtm)); 86163953Srrsvoid print_entry(struct sockaddr_dl *sdl, 87163953Srrs struct sockaddr_inarp *sin, struct rt_msghdr *rtm); 88163953Srrsvoid nuke_entry(struct sockaddr_dl *sdl, 89163953Srrs struct sockaddr_inarp *sin, struct rt_msghdr *rtm); 90163953Srrsint delete(char *host, char *info); 91163953Srrsvoid ether_print(u_char *cp); 92163953Srrsvoid usage(void); 93163953Srrsint set(int argc, char **argv); 94163953Srrsint get(char *host); 95163953Srrsint file(char *name); 96163953Srrsvoid getsocket(void); 97163953Srrsint my_ether_aton(char *a, u_char *n); 98163953Srrsint rtmsg(int cmd); 99163953Srrsint get_ether_addr(u_int32_t ipaddr, u_char *hwaddr); 100163953Srrs 101163953Srrsstatic int pid; 102163953Srrsstatic int nflag; /* no reverse dns lookups */ 103163953Srrsstatic int aflag; /* do it for all entries */ 104163953Srrsstatic int s = -1; 105163953Srrs 106163953Srrs/* which function we're supposed to do */ 107163953Srrs#define F_GET 1 108163953Srrs#define F_SET 2 109163953Srrs#define F_FILESET 3 110163953Srrs#define F_REPLACE 4 111163953Srrs#define F_DELETE 5 112163953Srrs 113163953Srrs#define ROUNDUP(a) \ 114163953Srrs ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) 115163953Srrs#define SETFUNC(f) { if (func) usage(); func = (f); } 116163953Srrs 117163953Srrsint 118163953Srrsmain(argc, argv) 119163953Srrs int argc; 120163953Srrs char **argv; 121163953Srrs{ 122163953Srrs int ch, func = 0; 123163953Srrs int rtn = 0; 124163953Srrs 125163953Srrs pid = getpid(); 126163953Srrs while ((ch = getopt(argc, argv, "andfsS")) != -1) 127163953Srrs switch((char)ch) { 128163953Srrs case 'a': 129163953Srrs aflag = 1; 130163953Srrs break; 131163953Srrs case 'd': 132163953Srrs SETFUNC(F_DELETE); 133163953Srrs break; 134163953Srrs case 'n': 135163953Srrs nflag = 1; 136163953Srrs break; 137163953Srrs case 'S': 138163953Srrs SETFUNC(F_REPLACE); 139163953Srrs break; 140163953Srrs case 's': 141163953Srrs SETFUNC(F_SET); 142163953Srrs break; 143163953Srrs case 'f' : 144163953Srrs SETFUNC(F_FILESET); 145163953Srrs break; 146163953Srrs case '?': 147163953Srrs default: 148163953Srrs usage(); 149163953Srrs } 150163953Srrs argc -= optind; 151163953Srrs argv += optind; 152163953Srrs 153163953Srrs if (!func) 154163953Srrs func = F_GET; 155163953Srrs switch (func) { 156163953Srrs case F_GET: 157163953Srrs if (aflag) { 158163953Srrs if (argc != 0) 159163953Srrs usage(); 160163953Srrs search(0, print_entry); 161163953Srrs } else { 162163953Srrs if (argc != 1) 163163953Srrs usage(); 164163953Srrs get(argv[0]); 165163953Srrs } 166163953Srrs break; 167163953Srrs case F_SET: 168163953Srrs case F_REPLACE: 169163953Srrs if (argc < 2 || argc > 5) 170163953Srrs usage(); 171163953Srrs if (func == F_REPLACE) 172163953Srrs (void) delete(argv[0], NULL); 173163953Srrs rtn = set(argc, argv) ? 1 : 0; 174163953Srrs break; 175163953Srrs case F_DELETE: 176163953Srrs if (aflag) { 177163953Srrs if (argc != 0) 178163953Srrs usage(); 179163953Srrs search(0, nuke_entry); 180163953Srrs } else { 181163953Srrs if (argc < 1 || argc > 2) 182163953Srrs usage(); 183163953Srrs rtn = delete(argv[0], argv[1]); 184163953Srrs } 185163953Srrs break; 186163953Srrs case F_FILESET: 187163953Srrs if (argc != 1) 188163953Srrs usage(); 189163953Srrs rtn = file(argv[0]); 190163953Srrs break; 191163953Srrs } 192163953Srrs 193163953Srrs return(rtn); 194163953Srrs} 195163953Srrs 196163953Srrs/* 197163953Srrs * Process a file to set standard arp entries 198163953Srrs */ 199163953Srrsint 200163953Srrsfile(char *name) 201163953Srrs{ 202163953Srrs FILE *fp; 203163953Srrs int i, retval; 204163953Srrs char line[100], arg[5][50], *args[5]; 205163953Srrs 206163953Srrs if ((fp = fopen(name, "r")) == NULL) 207163953Srrs errx(1, "cannot open %s", name); 208163953Srrs args[0] = &arg[0][0]; 209163953Srrs args[1] = &arg[1][0]; 210163953Srrs args[2] = &arg[2][0]; 211163953Srrs args[3] = &arg[3][0]; 212163953Srrs args[4] = &arg[4][0]; 213163953Srrs retval = 0; 214163953Srrs while(fgets(line, 100, fp) != NULL) { 215163953Srrs i = sscanf(line, "%49s %49s %49s %49s %49s", arg[0], arg[1], 216163953Srrs arg[2], arg[3], arg[4]); 217163953Srrs if (i < 2) { 218163953Srrs warnx("bad line: %s", line); 219163953Srrs retval = 1; 220163953Srrs continue; 221163953Srrs } 222163953Srrs if (set(i, args)) 223163953Srrs retval = 1; 224163953Srrs } 225163953Srrs fclose(fp); 226163953Srrs return (retval); 227163953Srrs} 228163953Srrs 229163953Srrsvoid 230163953Srrsgetsocket(void) 231163953Srrs{ 232163953Srrs if (s < 0) { 233163953Srrs s = socket(PF_ROUTE, SOCK_RAW, 0); 234163953Srrs if (s < 0) 235163953Srrs err(1, "socket"); 236163953Srrs } 237163953Srrs} 238163953Srrs 239163953Srrsstruct sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}}; 240163953Srrsstruct sockaddr_inarp blank_sin = {sizeof(blank_sin), AF_INET }, sin_m; 241163953Srrsstruct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; 242163953Srrsint expire_time, flags, export_only, doing_proxy, found_entry; 243163953Srrsstruct { 244163953Srrs struct rt_msghdr m_rtm; 245163953Srrs char m_space[512]; 246163953Srrs} m_rtmsg; 247163953Srrs 248163953Srrs/* 249163953Srrs * Set an individual arp entry 250163953Srrs */ 251163953Srrsint 252163953Srrsset(int argc, char **argv) 253163953Srrs{ 254163953Srrs struct hostent *hp; 255163953Srrs register struct sockaddr_inarp *sin = &sin_m; 256163953Srrs register struct sockaddr_dl *sdl; 257163953Srrs register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); 258163953Srrs u_char *ea; 259163953Srrs char *host = argv[0], *eaddr = argv[1]; 260163953Srrs 261163953Srrs getsocket(); 262163953Srrs argc -= 2; 263163953Srrs argv += 2; 264163953Srrs sdl_m = blank_sdl; 265163953Srrs sin_m = blank_sin; 266163953Srrs sin->sin_addr.s_addr = inet_addr(host); 267163953Srrs if (sin->sin_addr.s_addr == -1) { 268163953Srrs if (!(hp = gethostbyname(host))) { 269163953Srrs warnx("%s: %s", host, hstrerror(h_errno)); 270163953Srrs return (1); 271163953Srrs } 272163953Srrs bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, 273163953Srrs sizeof sin->sin_addr); 274163953Srrs } 275163953Srrs doing_proxy = flags = export_only = expire_time = 0; 276163953Srrs while (argc-- > 0) { 277163953Srrs if (strncmp(argv[0], "temp", 4) == 0) { 278163953Srrs struct timeval time; 279163953Srrs gettimeofday(&time, 0); 280163953Srrs expire_time = time.tv_sec + 20 * 60; 281163953Srrs } 282163953Srrs else if (strncmp(argv[0], "pub", 3) == 0) { 283163953Srrs flags |= RTF_ANNOUNCE; 284163953Srrs doing_proxy = SIN_PROXY; 285163953Srrs } else if (strncmp(argv[0], "trail", 5) == 0) { 286163953Srrs printf("%s: Sending trailers is no longer supported\n", 287163953Srrs host); 288163953Srrs } 289163953Srrs argv++; 290163953Srrs } 291163953Srrs ea = (u_char *)LLADDR(&sdl_m); 292163953Srrs if (doing_proxy && !strcmp(eaddr, "auto")) { 293163953Srrs if (!get_ether_addr(sin->sin_addr.s_addr, ea)) { 294163953Srrs return (1); 295163953Srrs } 296163953Srrs sdl_m.sdl_alen = 6; 297163953Srrs } else { 298163953Srrs if (my_ether_aton(eaddr, ea) == 0) 299163953Srrs sdl_m.sdl_alen = 6; 300163953Srrs } 301163953Srrstryagain: 302163953Srrs if (rtmsg(RTM_GET) < 0) { 303163953Srrs warn("%s", host); 304163953Srrs return (1); 305163953Srrs } 306163953Srrs sin = (struct sockaddr_inarp *)(rtm + 1); 307163953Srrs sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin_len) + (char *)sin); 308163953Srrs if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) { 309163953Srrs if (sdl->sdl_family == AF_LINK && 310163953Srrs (rtm->rtm_flags & RTF_LLINFO) && 311163953Srrs !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { 312163953Srrs case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 313163953Srrs case IFT_ISO88024: case IFT_ISO88025: 314163953Srrs goto overwrite; 315163953Srrs } 316163953Srrs if (doing_proxy == 0) { 317163953Srrs printf("set: can only proxy for %s\n", host); 318163953Srrs return (1); 319163953Srrs } 320163953Srrs if (sin_m.sin_other & SIN_PROXY) { 321163953Srrs printf("set: proxy entry exists for non 802 device\n"); 322163953Srrs return(1); 323163953Srrs } 324163953Srrs sin_m.sin_other = SIN_PROXY; 325163953Srrs export_only = 1; 326163953Srrs goto tryagain; 327163953Srrs } 328163953Srrsoverwrite: 329163953Srrs if (sdl->sdl_family != AF_LINK) { 330163953Srrs printf("cannot intuit interface index and type for %s\n", host); 331163953Srrs return (1); 332163953Srrs } 333163953Srrs sdl_m.sdl_type = sdl->sdl_type; 334163953Srrs sdl_m.sdl_index = sdl->sdl_index; 335163953Srrs return (rtmsg(RTM_ADD)); 336163953Srrs} 337163953Srrs 338163953Srrs/* 339163953Srrs * Display an individual arp entry 340163953Srrs */ 341163953Srrsint 342163953Srrsget(char *host) 343163953Srrs{ 344163953Srrs struct hostent *hp; 345163953Srrs struct sockaddr_inarp *sin = &sin_m; 346163953Srrs 347163953Srrs sin_m = blank_sin; 348163953Srrs sin->sin_addr.s_addr = inet_addr(host); 349163953Srrs if (sin->sin_addr.s_addr == -1) { 350163953Srrs if (!(hp = gethostbyname(host))) 351163953Srrs errx(1, "%s: %s", host, hstrerror(h_errno)); 352163953Srrs bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, 353163953Srrs sizeof sin->sin_addr); 354163953Srrs } 355163953Srrs search(sin->sin_addr.s_addr, print_entry); 356163953Srrs if (found_entry == 0) { 357163953Srrs printf("%s (%s) -- no entry\n", 358163953Srrs host, inet_ntoa(sin->sin_addr)); 359163953Srrs return(1); 360163953Srrs } 361163953Srrs return(0); 362163953Srrs} 363163953Srrs 364163953Srrs/* 365163953Srrs * Delete an arp entry 366163953Srrs */ 367163953Srrsint 368163953Srrsdelete(char *host, char *info) 369163953Srrs{ 370163953Srrs struct hostent *hp; 371163953Srrs register struct sockaddr_inarp *sin = &sin_m; 372163953Srrs register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 373163953Srrs struct sockaddr_dl *sdl; 374163953Srrs 375163953Srrs if (info && strncmp(info, "pro", 3) ) 376163953Srrs export_only = 1; 377163953Srrs getsocket(); 378163953Srrs sin_m = blank_sin; 379163953Srrs sin->sin_addr.s_addr = inet_addr(host); 380163953Srrs if (sin->sin_addr.s_addr == -1) { 381163953Srrs if (!(hp = gethostbyname(host))) { 382163953Srrs warnx("%s: %s", host, hstrerror(h_errno)); 383163953Srrs return (1); 384163953Srrs } 385163953Srrs bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, 386163953Srrs sizeof sin->sin_addr); 387163953Srrs } 388163953Srrstryagain: 389163953Srrs if (rtmsg(RTM_GET) < 0) { 390163953Srrs warn("%s", host); 391163953Srrs return (1); 392163953Srrs } 393163953Srrs sin = (struct sockaddr_inarp *)(rtm + 1); 394163953Srrs sdl = (struct sockaddr_dl *)(ROUNDUP(sin->sin_len) + (char *)sin); 395163953Srrs if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) { 396163953Srrs if (sdl->sdl_family == AF_LINK && 397163953Srrs (rtm->rtm_flags & RTF_LLINFO) && 398163953Srrs !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { 399163953Srrs case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 400163953Srrs case IFT_ISO88024: case IFT_ISO88025: 401163953Srrs goto delete; 402163953Srrs } 403163953Srrs } 404163953Srrs if (sin_m.sin_other & SIN_PROXY) { 405163953Srrs fprintf(stderr, "delete: can't locate %s\n",host); 406163953Srrs return (1); 407163953Srrs } else { 408163953Srrs sin_m.sin_other = SIN_PROXY; 409163953Srrs goto tryagain; 410163953Srrs } 411163953Srrsdelete: 412163953Srrs if (sdl->sdl_family != AF_LINK) { 413163953Srrs printf("cannot locate %s\n", host); 414163953Srrs return (1); 415163953Srrs } 416163953Srrs if (rtmsg(RTM_DELETE) == 0) { 417163953Srrs printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr)); 418163953Srrs return (0); 419163953Srrs } 420163953Srrs return (1); 421163953Srrs} 422163953Srrs 423163953Srrs/* 424163953Srrs * Search the arp table and do some action on matching entries 425163953Srrs */ 426163953Srrsvoid 427163953Srrssearch(u_long addr, void (*action)(struct sockaddr_dl *sdl, 428163953Srrs struct sockaddr_inarp *sin, struct rt_msghdr *rtm)) 429163953Srrs{ 430163953Srrs int mib[6]; 431163953Srrs size_t needed; 432163953Srrs char *lim, *buf, *next; 433163953Srrs struct rt_msghdr *rtm; 434163953Srrs struct sockaddr_inarp *sin; 435163953Srrs struct sockaddr_dl *sdl; 436163953Srrs extern int h_errno; 437163953Srrs 438163953Srrs mib[0] = CTL_NET; 439163953Srrs mib[1] = PF_ROUTE; 440163953Srrs mib[2] = 0; 441163953Srrs mib[3] = AF_INET; 442163953Srrs mib[4] = NET_RT_FLAGS; 443163953Srrs mib[5] = RTF_LLINFO; 444163953Srrs if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 445163953Srrs errx(1, "route-sysctl-estimate"); 446163953Srrs if ((buf = malloc(needed)) == NULL) 447163953Srrs errx(1, "malloc"); 448163953Srrs if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) 449163953Srrs errx(1, "actual retrieval of routing table"); 450163953Srrs lim = buf + needed; 451163953Srrs for (next = buf; next < lim; next += rtm->rtm_msglen) { 452163953Srrs rtm = (struct rt_msghdr *)next; 453163953Srrs sin = (struct sockaddr_inarp *)(rtm + 1); 454163953Srrs (char *)sdl = (char *)sin + ROUNDUP(sin->sin_len); 455163953Srrs if (addr) { 456163953Srrs if (addr != sin->sin_addr.s_addr) 457163953Srrs continue; 458163953Srrs found_entry = 1; 459163953Srrs } 460163953Srrs (*action)(sdl, sin, rtm); 461163953Srrs } 462163953Srrs} 463163953Srrs 464163953Srrs/* 465163953Srrs * Display an arp entry 466163953Srrs */ 467163953Srrsvoid 468163953Srrsprint_entry(struct sockaddr_dl *sdl, 469163953Srrs struct sockaddr_inarp *sin, struct rt_msghdr *rtm) 470163953Srrs{ 471163953Srrs char *host; 472163953Srrs extern int h_errno; 473163953Srrs struct hostent *hp; 474163953Srrs int seg; 475163953Srrs 476163953Srrs if (nflag == 0) 477163953Srrs hp = gethostbyaddr((caddr_t)&(sin->sin_addr), 478163953Srrs sizeof sin->sin_addr, AF_INET); 479163953Srrs else 480163953Srrs hp = 0; 481163953Srrs if (hp) 482163953Srrs host = hp->h_name; 483163953Srrs else { 484163953Srrs host = "?"; 485163953Srrs if (h_errno == TRY_AGAIN) 486163953Srrs nflag = 1; 487163953Srrs } 488163953Srrs printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr)); 489163953Srrs if (sdl->sdl_alen) 490163953Srrs ether_print(LLADDR(sdl)); 491163953Srrs else 492163953Srrs printf("(incomplete)"); 493163953Srrs if (rtm->rtm_rmx.rmx_expire == 0) 494163953Srrs printf(" permanent"); 495163953Srrs if (sin->sin_other & SIN_PROXY) 496163953Srrs printf(" published (proxy only)"); 497163953Srrs if (rtm->rtm_addrs & RTA_NETMASK) { 498163953Srrs sin = (struct sockaddr_inarp *) 499163953Srrs (ROUNDUP(sdl->sdl_len) + (char *)sdl); 500163953Srrs if (sin->sin_addr.s_addr == 0xffffffff) 501163953Srrs printf(" published"); 502163953Srrs if (sin->sin_len != 8) 503163953Srrs printf("(weird)"); 504163953Srrs } 505163953Srrs switch(sdl->sdl_type) { 506163953Srrs case IFT_ETHER: 507163953Srrs printf(" [ethernet]"); 508163953Srrs break; 509163953Srrs case IFT_ISO88025: 510163953Srrs printf(" [token-ring]"); 511163953Srrs break; 512163953Srrs default: 513163953Srrs } 514163953Srrs if (sdl->sdl_rcf != NULL) { 515163953Srrs printf(" rt=%x", ntohs(sdl->sdl_rcf)); 516163953Srrs for (seg = 0; seg < ((((ntohs(sdl->sdl_rcf) & 0x1f00) >> 8) - 2 ) / 2); seg++) 517163953Srrs printf(":%x", ntohs(sdl->sdl_route[seg])); 518163953Srrs } 519163953Srrs 520163953Srrs printf("\n"); 521163953Srrs 522163953Srrs} 523163953Srrs 524163953Srrs/* 525163953Srrs * Nuke an arp entry 526163953Srrs */ 527163953Srrsvoid 528163953Srrsnuke_entry(struct sockaddr_dl *sdl, 529163953Srrs struct sockaddr_inarp *sin, struct rt_msghdr *rtm) 530163953Srrs{ 531163953Srrs char ip[20]; 532163953Srrs 533163953Srrs snprintf(ip, sizeof(ip), "%s", inet_ntoa(sin->sin_addr)); 534163953Srrs delete(ip, NULL); 535163953Srrs} 536163953Srrs 537163953Srrsvoid 538163953Srrsether_print(u_char *cp) 539163953Srrs{ 540163953Srrs printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); 541163953Srrs} 542163953Srrs 543163953Srrsint 544163953Srrsmy_ether_aton(char *a, u_char *n) 545163953Srrs{ 546163953Srrs int i, o[6]; 547163953Srrs 548163953Srrs i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], 549163953Srrs &o[3], &o[4], &o[5]); 550163953Srrs if (i != 6) { 551163953Srrs warnx("invalid Ethernet address '%s'", a); 552163953Srrs return (1); 553163953Srrs } 554163953Srrs for (i=0; i<6; i++) 555163953Srrs n[i] = o[i]; 556163953Srrs return (0); 557163953Srrs} 558163953Srrs 559163953Srrsvoid 560163953Srrsusage(void) 561163953Srrs{ 562163953Srrs fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 563163953Srrs "usage: arp [-n] hostname", 564163953Srrs " arp [-n] -a", 565163953Srrs " arp -d hostname [proxy]", 566163953Srrs " arp -d -a", 567163953Srrs " arp -s hostname ether_addr [temp] [pub]", 568163953Srrs " arp -S hostname ether_addr [temp] [pub]", 569163953Srrs " arp -f filename"); 570163953Srrs exit(1); 571163953Srrs} 572163953Srrs 573163953Srrsint 574163953Srrsrtmsg(int cmd) 575163953Srrs{ 576163953Srrs static int seq; 577163953Srrs int rlen; 578163953Srrs register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 579163953Srrs register char *cp = m_rtmsg.m_space; 580163953Srrs register int l; 581163953Srrs 582163953Srrs errno = 0; 583163953Srrs if (cmd == RTM_DELETE) 584163953Srrs goto doit; 585163953Srrs bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 586163953Srrs rtm->rtm_flags = flags; 587163953Srrs rtm->rtm_version = RTM_VERSION; 588163953Srrs 589163953Srrs switch (cmd) { 590163953Srrs default: 591163953Srrs errx(1, "internal wrong cmd"); 592163953Srrs case RTM_ADD: 593163953Srrs rtm->rtm_addrs |= RTA_GATEWAY; 594163953Srrs rtm->rtm_rmx.rmx_expire = expire_time; 595163953Srrs rtm->rtm_inits = RTV_EXPIRE; 596163953Srrs rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); 597163953Srrs sin_m.sin_other = 0; 598163953Srrs if (doing_proxy) { 599163953Srrs if (export_only) 600163953Srrs sin_m.sin_other = SIN_PROXY; 601163953Srrs else { 602163953Srrs rtm->rtm_addrs |= RTA_NETMASK; 603163953Srrs rtm->rtm_flags &= ~RTF_HOST; 604163953Srrs } 605163953Srrs } 606163953Srrs /* FALLTHROUGH */ 607163953Srrs case RTM_GET: 608163953Srrs rtm->rtm_addrs |= RTA_DST; 609163953Srrs } 610163953Srrs#define NEXTADDR(w, s) \ 611163953Srrs if (rtm->rtm_addrs & (w)) { \ 612163953Srrs bcopy((char *)&s, cp, sizeof(s)); cp += ROUNDUP(sizeof(s));} 613163953Srrs 614163953Srrs NEXTADDR(RTA_DST, sin_m); 615163953Srrs NEXTADDR(RTA_GATEWAY, sdl_m); 616163953Srrs NEXTADDR(RTA_NETMASK, so_mask); 617163953Srrs 618163953Srrs rtm->rtm_msglen = cp - (char *)&m_rtmsg; 619163953Srrsdoit: 620163953Srrs l = rtm->rtm_msglen; 621163953Srrs rtm->rtm_seq = ++seq; 622163953Srrs rtm->rtm_type = cmd; 623163953Srrs if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 624163953Srrs if (errno != ESRCH || cmd != RTM_DELETE) { 625163953Srrs warn("writing to routing socket"); 626163953Srrs return (-1); 627163953Srrs } 628163953Srrs } 629163953Srrs do { 630163953Srrs l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 631163953Srrs } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 632163953Srrs if (l < 0) 633163953Srrs warn("read from routing socket"); 634163953Srrs return (0); 635163953Srrs} 636163953Srrs 637163953Srrs/* 638163953Srrs * get_ether_addr - get the hardware address of an interface on the 639163953Srrs * the same subnet as ipaddr. 640163953Srrs */ 641163953Srrs#define MAX_IFS 32 642163953Srrs 643163953Srrsint 644163953Srrsget_ether_addr(u_int32_t ipaddr, u_char *hwaddr) 645163953Srrs{ 646163953Srrs struct ifreq *ifr, *ifend, *ifp; 647163953Srrs u_int32_t ina, mask; 648163953Srrs struct sockaddr_dl *dla; 649163953Srrs struct ifreq ifreq; 650163953Srrs struct ifconf ifc; 651163953Srrs struct ifreq ifs[MAX_IFS]; 652163953Srrs int s; 653163953Srrs 654163953Srrs s = socket(AF_INET, SOCK_DGRAM, 0); 655163953Srrs if (s < 0) 656163953Srrs err(1, "socket"); 657163953Srrs 658163953Srrs ifc.ifc_len = sizeof(ifs); 659163953Srrs ifc.ifc_req = ifs; 660163953Srrs if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { 661163953Srrs warnx("ioctl(SIOCGIFCONF)"); 662163953Srrs close(s); 663163953Srrs return 0; 664163953Srrs } 665163953Srrs 666163953Srrs /* 667163953Srrs * Scan through looking for an interface with an Internet 668163953Srrs * address on the same subnet as `ipaddr'. 669163953Srrs */ 670163953Srrs ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); 671163953Srrs for (ifr = ifc.ifc_req; ifr < ifend; ) { 672163953Srrs if (ifr->ifr_addr.sa_family == AF_INET) { 673163953Srrs ina = ((struct sockaddr_in *) 674163953Srrs &ifr->ifr_addr)->sin_addr.s_addr; 675163953Srrs strncpy(ifreq.ifr_name, ifr->ifr_name, 676163953Srrs sizeof(ifreq.ifr_name)); 677163953Srrs /* 678163953Srrs * Check that the interface is up, 679163953Srrs * and not point-to-point or loopback. 680163953Srrs */ 681163953Srrs if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0) 682163953Srrs continue; 683163953Srrs if ((ifreq.ifr_flags & 684163953Srrs (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT| 685163953Srrs IFF_LOOPBACK|IFF_NOARP)) 686163953Srrs != (IFF_UP|IFF_BROADCAST)) 687163953Srrs goto nextif; 688163953Srrs /* 689163953Srrs * Get its netmask and check that it's on 690163953Srrs * the right subnet. 691163953Srrs */ 692163953Srrs if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0) 693163953Srrs continue; 694163953Srrs mask = ((struct sockaddr_in *) 695163953Srrs &ifreq.ifr_addr)->sin_addr.s_addr; 696163953Srrs if ((ipaddr & mask) != (ina & mask)) 697163953Srrs goto nextif; 698163953Srrs break; 699163953Srrs } 700163953Srrsnextif: 701163953Srrs ifr = (struct ifreq *) ((char *)&ifr->ifr_addr 702163953Srrs + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr))); 703163953Srrs } 704163953Srrs 705163953Srrs if (ifr >= ifend) { 706163953Srrs close(s); 707163953Srrs return 0; 708163953Srrs } 709163953Srrs 710163953Srrs /* 711163953Srrs * Now scan through again looking for a link-level address 712163953Srrs * for this interface. 713163953Srrs */ 714163953Srrs ifp = ifr; 715163953Srrs for (ifr = ifc.ifc_req; ifr < ifend; ) { 716163953Srrs if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 717163953Srrs && ifr->ifr_addr.sa_family == AF_LINK) { 718163953Srrs /* 719163953Srrs * Found the link-level address - copy it out 720163953Srrs */ 721163953Srrs dla = (struct sockaddr_dl *) &ifr->ifr_addr; 722163953Srrs memcpy(hwaddr, LLADDR(dla), dla->sdl_alen); 723163953Srrs close (s); 724163953Srrs printf("using interface %s for proxy with address ", 725163953Srrs ifp->ifr_name); 726163953Srrs ether_print(hwaddr); 727163953Srrs printf("\n"); 728163953Srrs return dla->sdl_alen; 729163953Srrs } 730163953Srrs ifr = (struct ifreq *) ((char *)&ifr->ifr_addr 731163953Srrs + MAX(ifr->ifr_addr.sa_len, sizeof(ifr->ifr_addr))); 732163953Srrs } 733163953Srrs return 0; 734163953Srrs} 735163953Srrs