1dea673e9SRodney W. Grimes /* 2dea673e9SRodney W. Grimes * Copyright (c) 1984, 1993 3dea673e9SRodney W. Grimes * The Regents of the University of California. All rights reserved. 4dea673e9SRodney W. Grimes * 5dea673e9SRodney W. Grimes * This code is derived from software contributed to Berkeley by 6dea673e9SRodney W. Grimes * Sun Microsystems, Inc. 7dea673e9SRodney W. Grimes * 8dea673e9SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 9dea673e9SRodney W. Grimes * modification, are permitted provided that the following conditions 10dea673e9SRodney W. Grimes * are met: 11dea673e9SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 12dea673e9SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 13dea673e9SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 14dea673e9SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 15dea673e9SRodney W. Grimes * documentation and/or other materials provided with the distribution. 16dea673e9SRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 17dea673e9SRodney W. Grimes * may be used to endorse or promote products derived from this software 18dea673e9SRodney W. Grimes * without specific prior written permission. 19dea673e9SRodney W. Grimes * 20dea673e9SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21dea673e9SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22dea673e9SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23dea673e9SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24dea673e9SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25dea673e9SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26dea673e9SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27dea673e9SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28dea673e9SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29dea673e9SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30dea673e9SRodney W. Grimes * SUCH DAMAGE. 31dea673e9SRodney W. Grimes */ 32dea673e9SRodney W. Grimes 33b728350eSDavid E. O'Brien #if 0 34dea673e9SRodney W. Grimes #ifndef lint 35a42a667dSPoul-Henning Kamp static char const copyright[] = 36dea673e9SRodney W. Grimes "@(#) Copyright (c) 1984, 1993\n\ 37dea673e9SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 38dea673e9SRodney W. Grimes #endif /* not lint */ 39dea673e9SRodney W. Grimes 40dea673e9SRodney W. Grimes #ifndef lint 41a42a667dSPoul-Henning Kamp static char const sccsid[] = "@(#)from: arp.c 8.2 (Berkeley) 1/2/94"; 42dea673e9SRodney W. Grimes #endif /* not lint */ 43b728350eSDavid E. O'Brien #endif 44b728350eSDavid E. O'Brien #include <sys/cdefs.h> 45b728350eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 46dea673e9SRodney W. Grimes 47dea673e9SRodney W. Grimes /* 48dea673e9SRodney W. Grimes * arp - display, set, and delete arp table entries 49dea673e9SRodney W. Grimes */ 50dea673e9SRodney W. Grimes 51dea673e9SRodney W. Grimes 52dea673e9SRodney W. Grimes #include <sys/param.h> 53dea673e9SRodney W. Grimes #include <sys/file.h> 54dea673e9SRodney W. Grimes #include <sys/socket.h> 55a42a667dSPoul-Henning Kamp #include <sys/sockio.h> 56dea673e9SRodney W. Grimes #include <sys/sysctl.h> 57a42a667dSPoul-Henning Kamp #include <sys/ioctl.h> 58628d2ac1SGarrett Wollman #include <sys/time.h> 59dea673e9SRodney W. Grimes 60dea673e9SRodney W. Grimes #include <net/if.h> 61dea673e9SRodney W. Grimes #include <net/if_dl.h> 62dea673e9SRodney W. Grimes #include <net/if_types.h> 63dea673e9SRodney W. Grimes #include <net/route.h> 642ab778e1SBill Paul #include <net/iso88025.h> 65dea673e9SRodney W. Grimes 66dea673e9SRodney W. Grimes #include <netinet/in.h> 67dea673e9SRodney W. Grimes #include <netinet/if_ether.h> 68dea673e9SRodney W. Grimes 69dea673e9SRodney W. Grimes #include <arpa/inet.h> 70dea673e9SRodney W. Grimes 7144acbc1aSRuslan Ermilov #include <ctype.h> 72c72049e4SPhilippe Charnier #include <err.h> 73dea673e9SRodney W. Grimes #include <errno.h> 74c72049e4SPhilippe Charnier #include <netdb.h> 75dea673e9SRodney W. Grimes #include <nlist.h> 76c72049e4SPhilippe Charnier #include <paths.h> 77dea673e9SRodney W. Grimes #include <stdio.h> 78a42a667dSPoul-Henning Kamp #include <stdlib.h> 79467a0b06SMike Barcroft #include <string.h> 80a42a667dSPoul-Henning Kamp #include <strings.h> 81c72049e4SPhilippe Charnier #include <unistd.h> 82dea673e9SRodney W. Grimes 83bdf932aeSLuigi Rizzo typedef void (action_fn)(struct sockaddr_dl *sdl, 84bdf932aeSLuigi Rizzo struct sockaddr_inarp *s_in, struct rt_msghdr *rtm); 85a42a667dSPoul-Henning Kamp 86bdf932aeSLuigi Rizzo static int search(u_long addr, action_fn *action); 87bdf932aeSLuigi Rizzo static action_fn print_entry; 88bdf932aeSLuigi Rizzo static action_fn nuke_entry; 89bdf932aeSLuigi Rizzo 9068839124SLuigi Rizzo static int delete(char *host, int do_proxy); 91bdf932aeSLuigi Rizzo static void usage(void); 92bdf932aeSLuigi Rizzo static int set(int argc, char **argv); 9368839124SLuigi Rizzo static void get(char *host); 94bdf932aeSLuigi Rizzo static int file(char *name); 9568839124SLuigi Rizzo static struct rt_msghdr *rtmsg(int cmd, 9668839124SLuigi Rizzo struct sockaddr_inarp *dst, struct sockaddr_dl *sdl); 97bdf932aeSLuigi Rizzo static int get_ether_addr(u_int32_t ipaddr, struct ether_addr *hwaddr); 98bdf932aeSLuigi Rizzo 998dc4b495SJulian Elischer static int nflag; /* no reverse dns lookups */ 100b9de94e9SYaroslav Tykhiy static char *rifname; 101dea673e9SRodney W. Grimes 102bdf932aeSLuigi Rizzo static int expire_time, flags, doing_proxy, proxy_only; 10368839124SLuigi Rizzo 1048dc4b495SJulian Elischer /* which function we're supposed to do */ 1058dc4b495SJulian Elischer #define F_GET 1 1068dc4b495SJulian Elischer #define F_SET 2 1078dc4b495SJulian Elischer #define F_FILESET 3 1088dc4b495SJulian Elischer #define F_REPLACE 4 1098dc4b495SJulian Elischer #define F_DELETE 5 1108dc4b495SJulian Elischer 1118dc4b495SJulian Elischer #define SETFUNC(f) { if (func) usage(); func = (f); } 1128dc4b495SJulian Elischer 113a42a667dSPoul-Henning Kamp int 1143f844a22SRuslan Ermilov main(int argc, char *argv[]) 115dea673e9SRodney W. Grimes { 1168dc4b495SJulian Elischer int ch, func = 0; 1178dc4b495SJulian Elischer int rtn = 0; 118bdf932aeSLuigi Rizzo int aflag = 0; /* do it for all entries */ 119dea673e9SRodney W. Grimes 120b9de94e9SYaroslav Tykhiy while ((ch = getopt(argc, argv, "andfsSi:")) != -1) 121dea673e9SRodney W. Grimes switch((char)ch) { 122dea673e9SRodney W. Grimes case 'a': 1238dc4b495SJulian Elischer aflag = 1; 1248dc4b495SJulian Elischer break; 125dea673e9SRodney W. Grimes case 'd': 1268dc4b495SJulian Elischer SETFUNC(F_DELETE); 1278dc4b495SJulian Elischer break; 128dea673e9SRodney W. Grimes case 'n': 129dea673e9SRodney W. Grimes nflag = 1; 1308dc4b495SJulian Elischer break; 131a42a667dSPoul-Henning Kamp case 'S': 1328dc4b495SJulian Elischer SETFUNC(F_REPLACE); 1338dc4b495SJulian Elischer break; 134dea673e9SRodney W. Grimes case 's': 1358dc4b495SJulian Elischer SETFUNC(F_SET); 1368dc4b495SJulian Elischer break; 13795319e17SJordan K. Hubbard case 'f' : 1388dc4b495SJulian Elischer SETFUNC(F_FILESET); 1398dc4b495SJulian Elischer break; 140b9de94e9SYaroslav Tykhiy case 'i': 141b9de94e9SYaroslav Tykhiy rifname = optarg; 142b9de94e9SYaroslav Tykhiy break; 143dea673e9SRodney W. Grimes case '?': 144dea673e9SRodney W. Grimes default: 145dea673e9SRodney W. Grimes usage(); 146dea673e9SRodney W. Grimes } 1478dc4b495SJulian Elischer argc -= optind; 1488dc4b495SJulian Elischer argv += optind; 1498dc4b495SJulian Elischer 1508dc4b495SJulian Elischer if (!func) 1518dc4b495SJulian Elischer func = F_GET; 152b9de94e9SYaroslav Tykhiy if (rifname) { 153b9de94e9SYaroslav Tykhiy if (func != F_GET) 154b9de94e9SYaroslav Tykhiy errx(1, "-i not applicable to this operation"); 155b9de94e9SYaroslav Tykhiy if (if_nametoindex(rifname) == 0) { 156b9de94e9SYaroslav Tykhiy if (errno == ENXIO) 157b9de94e9SYaroslav Tykhiy errx(1, "interface %s does not exist", rifname); 158b9de94e9SYaroslav Tykhiy else 159b9de94e9SYaroslav Tykhiy err(1, "if_nametoindex(%s)", rifname); 160b9de94e9SYaroslav Tykhiy } 161b9de94e9SYaroslav Tykhiy } 1628dc4b495SJulian Elischer switch (func) { 1638dc4b495SJulian Elischer case F_GET: 1648dc4b495SJulian Elischer if (aflag) { 1658dc4b495SJulian Elischer if (argc != 0) 166dea673e9SRodney W. Grimes usage(); 1678dc4b495SJulian Elischer search(0, print_entry); 1688dc4b495SJulian Elischer } else { 1698dc4b495SJulian Elischer if (argc != 1) 1708dc4b495SJulian Elischer usage(); 1718dc4b495SJulian Elischer get(argv[0]); 1728dc4b495SJulian Elischer } 1738dc4b495SJulian Elischer break; 1748dc4b495SJulian Elischer case F_SET: 1758dc4b495SJulian Elischer case F_REPLACE: 1763f844a22SRuslan Ermilov if (argc < 2 || argc > 6) 1778dc4b495SJulian Elischer usage(); 1788dc4b495SJulian Elischer if (func == F_REPLACE) 17968839124SLuigi Rizzo delete(argv[0], 0); 1808dc4b495SJulian Elischer rtn = set(argc, argv) ? 1 : 0; 1818dc4b495SJulian Elischer break; 1828dc4b495SJulian Elischer case F_DELETE: 1838dc4b495SJulian Elischer if (aflag) { 1848dc4b495SJulian Elischer if (argc != 0) 1858dc4b495SJulian Elischer usage(); 1868dc4b495SJulian Elischer search(0, nuke_entry); 1878dc4b495SJulian Elischer } else { 18868839124SLuigi Rizzo if (argc == 2 && strncmp(argv[1], "pub", 3) == 0) 18968839124SLuigi Rizzo ch = SIN_PROXY; 19068839124SLuigi Rizzo else if (argc == 1) 19168839124SLuigi Rizzo ch = 0; 19268839124SLuigi Rizzo else 1938dc4b495SJulian Elischer usage(); 19468839124SLuigi Rizzo rtn = delete(argv[0], ch); 1958dc4b495SJulian Elischer } 1968dc4b495SJulian Elischer break; 1978dc4b495SJulian Elischer case F_FILESET: 1988dc4b495SJulian Elischer if (argc != 1) 1998dc4b495SJulian Elischer usage(); 2008dc4b495SJulian Elischer rtn = file(argv[0]); 2018dc4b495SJulian Elischer break; 2028dc4b495SJulian Elischer } 2038dc4b495SJulian Elischer 2048dc4b495SJulian Elischer return(rtn); 205dea673e9SRodney W. Grimes } 206dea673e9SRodney W. Grimes 207dea673e9SRodney W. Grimes /* 208dea673e9SRodney W. Grimes * Process a file to set standard arp entries 209dea673e9SRodney W. Grimes */ 210bdf932aeSLuigi Rizzo static int 211a42a667dSPoul-Henning Kamp file(char *name) 212dea673e9SRodney W. Grimes { 213dea673e9SRodney W. Grimes FILE *fp; 214dea673e9SRodney W. Grimes int i, retval; 2153adcd042SRuslan Ermilov char line[100], arg[5][50], *args[5], *p; 216dea673e9SRodney W. Grimes 217c72049e4SPhilippe Charnier if ((fp = fopen(name, "r")) == NULL) 218e2416749SMaxime Henrion err(1, "cannot open %s", name); 219dea673e9SRodney W. Grimes args[0] = &arg[0][0]; 220dea673e9SRodney W. Grimes args[1] = &arg[1][0]; 221dea673e9SRodney W. Grimes args[2] = &arg[2][0]; 222dea673e9SRodney W. Grimes args[3] = &arg[3][0]; 223dea673e9SRodney W. Grimes args[4] = &arg[4][0]; 224dea673e9SRodney W. Grimes retval = 0; 225dea673e9SRodney W. Grimes while(fgets(line, 100, fp) != NULL) { 2263adcd042SRuslan Ermilov if ((p = strchr(line, '#')) != NULL) 2273adcd042SRuslan Ermilov *p = '\0'; 2283adcd042SRuslan Ermilov for (p = line; isblank(*p); p++); 2294bfc3624SRuslan Ermilov if (*p == '\n' || *p == '\0') 23044acbc1aSRuslan Ermilov continue; 2313adcd042SRuslan Ermilov i = sscanf(p, "%49s %49s %49s %49s %49s", arg[0], arg[1], 232135adb1eSJordan K. Hubbard arg[2], arg[3], arg[4]); 233dea673e9SRodney W. Grimes if (i < 2) { 234c72049e4SPhilippe Charnier warnx("bad line: %s", line); 235dea673e9SRodney W. Grimes retval = 1; 236dea673e9SRodney W. Grimes continue; 237dea673e9SRodney W. Grimes } 238dea673e9SRodney W. Grimes if (set(i, args)) 239dea673e9SRodney W. Grimes retval = 1; 240dea673e9SRodney W. Grimes } 241dea673e9SRodney W. Grimes fclose(fp); 242dea673e9SRodney W. Grimes return (retval); 243dea673e9SRodney W. Grimes } 244dea673e9SRodney W. Grimes 245dea673e9SRodney W. Grimes /* 24668839124SLuigi Rizzo * Given a hostname, fills up a (static) struct sockaddr_inarp with 24768839124SLuigi Rizzo * the address of the host and returns a pointer to the 24868839124SLuigi Rizzo * structure. 249dea673e9SRodney W. Grimes */ 25068839124SLuigi Rizzo static struct sockaddr_inarp * 25168839124SLuigi Rizzo getaddr(char *host) 252dea673e9SRodney W. Grimes { 253dea673e9SRodney W. Grimes struct hostent *hp; 25468839124SLuigi Rizzo static struct sockaddr_inarp reply; 25568839124SLuigi Rizzo 25668839124SLuigi Rizzo bzero(&reply, sizeof(reply)); 25768839124SLuigi Rizzo reply.sin_len = sizeof(reply); 25868839124SLuigi Rizzo reply.sin_family = AF_INET; 25968839124SLuigi Rizzo reply.sin_addr.s_addr = inet_addr(host); 26068839124SLuigi Rizzo if (reply.sin_addr.s_addr == INADDR_NONE) { 26168839124SLuigi Rizzo if (!(hp = gethostbyname(host))) { 26268839124SLuigi Rizzo warnx("%s: %s", host, hstrerror(h_errno)); 26368839124SLuigi Rizzo return NULL; 26468839124SLuigi Rizzo } 26568839124SLuigi Rizzo bcopy((char *)hp->h_addr, (char *)&reply.sin_addr, 26668839124SLuigi Rizzo sizeof reply.sin_addr); 26768839124SLuigi Rizzo } 26868839124SLuigi Rizzo return &reply; 26968839124SLuigi Rizzo } 27068839124SLuigi Rizzo 27168839124SLuigi Rizzo /* 27268839124SLuigi Rizzo * returns true if the type is a valid one for ARP 27368839124SLuigi Rizzo */ 27468839124SLuigi Rizzo static int 27568839124SLuigi Rizzo valid_type(int type) 27668839124SLuigi Rizzo { 27768839124SLuigi Rizzo switch (type) { 27868839124SLuigi Rizzo default: 27968839124SLuigi Rizzo return 0; 28068839124SLuigi Rizzo case IFT_ETHER: 28168839124SLuigi Rizzo case IFT_FDDI: 28268839124SLuigi Rizzo case IFT_ISO88023: 28368839124SLuigi Rizzo case IFT_ISO88024: 28468839124SLuigi Rizzo case IFT_ISO88025: 28568839124SLuigi Rizzo case IFT_L2VLAN: 28668839124SLuigi Rizzo return 1; 28768839124SLuigi Rizzo } 28868839124SLuigi Rizzo } 28968839124SLuigi Rizzo 29068839124SLuigi Rizzo /* 29168839124SLuigi Rizzo * Set an individual arp entry 29268839124SLuigi Rizzo */ 29368839124SLuigi Rizzo static int 29468839124SLuigi Rizzo set(int argc, char **argv) 29568839124SLuigi Rizzo { 29668839124SLuigi Rizzo struct sockaddr_inarp *addr; 29768839124SLuigi Rizzo struct sockaddr_inarp *dst; /* what are we looking for */ 298e2416749SMaxime Henrion struct sockaddr_dl *sdl; 299bdf932aeSLuigi Rizzo struct rt_msghdr *rtm; 300a03b1b7cSRuslan Ermilov struct ether_addr *ea; 301dea673e9SRodney W. Grimes char *host = argv[0], *eaddr = argv[1]; 30268839124SLuigi Rizzo struct sockaddr_dl sdl_m; 303dea673e9SRodney W. Grimes 304dea673e9SRodney W. Grimes argc -= 2; 305dea673e9SRodney W. Grimes argv += 2; 306bdf932aeSLuigi Rizzo 307bdf932aeSLuigi Rizzo bzero(&sdl_m, sizeof(sdl_m)); 308bdf932aeSLuigi Rizzo sdl_m.sdl_len = sizeof(sdl_m); 309bdf932aeSLuigi Rizzo sdl_m.sdl_family = AF_LINK; 310bdf932aeSLuigi Rizzo 31168839124SLuigi Rizzo dst = getaddr(host); 31268839124SLuigi Rizzo if (dst == NULL) 313dea673e9SRodney W. Grimes return (1); 3143f844a22SRuslan Ermilov doing_proxy = flags = proxy_only = expire_time = 0; 315dea673e9SRodney W. Grimes while (argc-- > 0) { 316dea673e9SRodney W. Grimes if (strncmp(argv[0], "temp", 4) == 0) { 3173f844a22SRuslan Ermilov struct timeval tv; 3183f844a22SRuslan Ermilov gettimeofday(&tv, 0); 3193f844a22SRuslan Ermilov expire_time = tv.tv_sec + 20 * 60; 320dea673e9SRodney W. Grimes } 321dea673e9SRodney W. Grimes else if (strncmp(argv[0], "pub", 3) == 0) { 322dea673e9SRodney W. Grimes flags |= RTF_ANNOUNCE; 3233f844a22SRuslan Ermilov doing_proxy = 1; 3243f844a22SRuslan Ermilov if (argc && strncmp(argv[1], "only", 3) == 0) { 3253f844a22SRuslan Ermilov proxy_only = 1; 32668839124SLuigi Rizzo dst->sin_other = SIN_PROXY; 3273f844a22SRuslan Ermilov argc--; argv++; 3283f844a22SRuslan Ermilov } 329dea673e9SRodney W. Grimes } else if (strncmp(argv[0], "trail", 5) == 0) { 33068839124SLuigi Rizzo /* XXX deprecated and undocumented feature */ 331dea673e9SRodney W. Grimes printf("%s: Sending trailers is no longer supported\n", 332dea673e9SRodney W. Grimes host); 333dea673e9SRodney W. Grimes } 334dea673e9SRodney W. Grimes argv++; 335dea673e9SRodney W. Grimes } 336a03b1b7cSRuslan Ermilov ea = (struct ether_addr *)LLADDR(&sdl_m); 337a42a667dSPoul-Henning Kamp if (doing_proxy && !strcmp(eaddr, "auto")) { 33868839124SLuigi Rizzo if (!get_ether_addr(dst->sin_addr.s_addr, ea)) { 339eec827b0SRuslan Ermilov printf("no interface found for %s\n", 34068839124SLuigi Rizzo inet_ntoa(dst->sin_addr)); 341a42a667dSPoul-Henning Kamp return (1); 342a42a667dSPoul-Henning Kamp } 343a03b1b7cSRuslan Ermilov sdl_m.sdl_alen = ETHER_ADDR_LEN; 344a42a667dSPoul-Henning Kamp } else { 34568839124SLuigi Rizzo struct ether_addr *ea1 = ether_aton(eaddr); 34668839124SLuigi Rizzo 34768839124SLuigi Rizzo if (ea1 == NULL) 34868839124SLuigi Rizzo warnx("invalid Ethernet address '%s'", eaddr); 34968839124SLuigi Rizzo else { 35068839124SLuigi Rizzo *ea = *ea1; 351a03b1b7cSRuslan Ermilov sdl_m.sdl_alen = ETHER_ADDR_LEN; 352a42a667dSPoul-Henning Kamp } 35368839124SLuigi Rizzo } 35468839124SLuigi Rizzo for (;;) { /* try at most twice */ 35568839124SLuigi Rizzo rtm = rtmsg(RTM_GET, dst, &sdl_m); 356bdf932aeSLuigi Rizzo if (rtm == NULL) { 357c72049e4SPhilippe Charnier warn("%s", host); 358dea673e9SRodney W. Grimes return (1); 359dea673e9SRodney W. Grimes } 3609d34414bSMike Heffner addr = (struct sockaddr_inarp *)(rtm + 1); 3610b46c085SLuigi Rizzo sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr); 36268839124SLuigi Rizzo if (addr->sin_addr.s_addr != dst->sin_addr.s_addr) 36368839124SLuigi Rizzo break; 364dea673e9SRodney W. Grimes if (sdl->sdl_family == AF_LINK && 365dea673e9SRodney W. Grimes (rtm->rtm_flags & RTF_LLINFO) && 36668839124SLuigi Rizzo !(rtm->rtm_flags & RTF_GATEWAY) && 36768839124SLuigi Rizzo valid_type(sdl->sdl_type) ) 36868839124SLuigi Rizzo break; 369dea673e9SRodney W. Grimes if (doing_proxy == 0) { 370dea673e9SRodney W. Grimes printf("set: can only proxy for %s\n", host); 371dea673e9SRodney W. Grimes return (1); 372dea673e9SRodney W. Grimes } 37368839124SLuigi Rizzo if (dst->sin_other & SIN_PROXY) { 374dea673e9SRodney W. Grimes printf("set: proxy entry exists for non 802 device\n"); 375dea673e9SRodney W. Grimes return(1); 376dea673e9SRodney W. Grimes } 37768839124SLuigi Rizzo dst->sin_other = SIN_PROXY; 3783f844a22SRuslan Ermilov proxy_only = 1; 379dea673e9SRodney W. Grimes } 38068839124SLuigi Rizzo 381dea673e9SRodney W. Grimes if (sdl->sdl_family != AF_LINK) { 382dea673e9SRodney W. Grimes printf("cannot intuit interface index and type for %s\n", host); 383dea673e9SRodney W. Grimes return (1); 384dea673e9SRodney W. Grimes } 385dea673e9SRodney W. Grimes sdl_m.sdl_type = sdl->sdl_type; 386dea673e9SRodney W. Grimes sdl_m.sdl_index = sdl->sdl_index; 38768839124SLuigi Rizzo return (rtmsg(RTM_ADD, dst, &sdl_m) != NULL); 388dea673e9SRodney W. Grimes } 389dea673e9SRodney W. Grimes 390dea673e9SRodney W. Grimes /* 391dea673e9SRodney W. Grimes * Display an individual arp entry 392dea673e9SRodney W. Grimes */ 39368839124SLuigi Rizzo static void 394a42a667dSPoul-Henning Kamp get(char *host) 395dea673e9SRodney W. Grimes { 39668839124SLuigi Rizzo struct sockaddr_inarp *addr; 397dea673e9SRodney W. Grimes 39868839124SLuigi Rizzo addr = getaddr(host); 39968839124SLuigi Rizzo if (addr == NULL) 40068839124SLuigi Rizzo exit(1); 401bdf932aeSLuigi Rizzo if (0 == search(addr->sin_addr.s_addr, print_entry)) { 402b9de94e9SYaroslav Tykhiy printf("%s (%s) -- no entry", 4039d34414bSMike Heffner host, inet_ntoa(addr->sin_addr)); 404b9de94e9SYaroslav Tykhiy if (rifname) 405b9de94e9SYaroslav Tykhiy printf(" on %s", rifname); 406b9de94e9SYaroslav Tykhiy printf("\n"); 407dea673e9SRodney W. Grimes } 408dea673e9SRodney W. Grimes } 409dea673e9SRodney W. Grimes 410dea673e9SRodney W. Grimes /* 411dea673e9SRodney W. Grimes * Delete an arp entry 412dea673e9SRodney W. Grimes */ 413bdf932aeSLuigi Rizzo static int 41468839124SLuigi Rizzo delete(char *host, int do_proxy) 415dea673e9SRodney W. Grimes { 41668839124SLuigi Rizzo struct sockaddr_inarp *addr, *dst; 417bdf932aeSLuigi Rizzo struct rt_msghdr *rtm; 418dea673e9SRodney W. Grimes struct sockaddr_dl *sdl; 419dea673e9SRodney W. Grimes 42068839124SLuigi Rizzo dst = getaddr(host); 42168839124SLuigi Rizzo if (dst == NULL) 42268839124SLuigi Rizzo return 1; 42368839124SLuigi Rizzo dst->sin_other = do_proxy; 42468839124SLuigi Rizzo for (;;) { /* try twice */ 42568839124SLuigi Rizzo rtm = rtmsg(RTM_GET, dst, NULL); 426bdf932aeSLuigi Rizzo if (rtm == NULL) { 427c72049e4SPhilippe Charnier warn("%s", host); 428dea673e9SRodney W. Grimes return (1); 429dea673e9SRodney W. Grimes } 4309d34414bSMike Heffner addr = (struct sockaddr_inarp *)(rtm + 1); 4310b46c085SLuigi Rizzo sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr); 43268839124SLuigi Rizzo if (addr->sin_addr.s_addr == dst->sin_addr.s_addr && 43368839124SLuigi Rizzo sdl->sdl_family == AF_LINK && 434dea673e9SRodney W. Grimes (rtm->rtm_flags & RTF_LLINFO) && 43568839124SLuigi Rizzo !(rtm->rtm_flags & RTF_GATEWAY) && 43668839124SLuigi Rizzo valid_type(sdl->sdl_type) ) 43768839124SLuigi Rizzo break; /* found it */ 43868839124SLuigi Rizzo if (dst->sin_other & SIN_PROXY) { 43968839124SLuigi Rizzo fprintf(stderr, "delete: cannot locate %s\n",host); 440dea673e9SRodney W. Grimes return (1); 441dea673e9SRodney W. Grimes } 44268839124SLuigi Rizzo dst->sin_other = SIN_PROXY; 44368839124SLuigi Rizzo } 44468839124SLuigi Rizzo if (rtmsg(RTM_DELETE, dst, NULL) != NULL) { 4459d34414bSMike Heffner printf("%s (%s) deleted\n", host, inet_ntoa(addr->sin_addr)); 446a42a667dSPoul-Henning Kamp return (0); 447a42a667dSPoul-Henning Kamp } 448a42a667dSPoul-Henning Kamp return (1); 449dea673e9SRodney W. Grimes } 450dea673e9SRodney W. Grimes 451dea673e9SRodney W. Grimes /* 4528dc4b495SJulian Elischer * Search the arp table and do some action on matching entries 453dea673e9SRodney W. Grimes */ 454bdf932aeSLuigi Rizzo static int 455bdf932aeSLuigi Rizzo search(u_long addr, action_fn *action) 456dea673e9SRodney W. Grimes { 457dea673e9SRodney W. Grimes int mib[6]; 458dea673e9SRodney W. Grimes size_t needed; 45966658902SMaxim Konovalov char *lim, *buf, *newbuf, *next; 460dea673e9SRodney W. Grimes struct rt_msghdr *rtm; 4619d34414bSMike Heffner struct sockaddr_inarp *sin2; 462dea673e9SRodney W. Grimes struct sockaddr_dl *sdl; 463b9de94e9SYaroslav Tykhiy char ifname[IF_NAMESIZE]; 46466658902SMaxim Konovalov int st, found_entry = 0; 465dea673e9SRodney W. Grimes 466dea673e9SRodney W. Grimes mib[0] = CTL_NET; 467dea673e9SRodney W. Grimes mib[1] = PF_ROUTE; 468dea673e9SRodney W. Grimes mib[2] = 0; 469dea673e9SRodney W. Grimes mib[3] = AF_INET; 470dea673e9SRodney W. Grimes mib[4] = NET_RT_FLAGS; 471dea673e9SRodney W. Grimes mib[5] = RTF_LLINFO; 472dea673e9SRodney W. Grimes if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 473e2416749SMaxime Henrion err(1, "route-sysctl-estimate"); 47468839124SLuigi Rizzo if (needed == 0) /* empty table */ 475bdf932aeSLuigi Rizzo return 0; 47666658902SMaxim Konovalov buf = NULL; 47719beed5eSMaxim Konovalov for (;;) { 47866658902SMaxim Konovalov newbuf = realloc(buf, needed); 47966658902SMaxim Konovalov if (newbuf == NULL) { 48066658902SMaxim Konovalov if (buf != NULL) 48166658902SMaxim Konovalov free(buf); 48266658902SMaxim Konovalov errx(1, "could not reallocate memory"); 48366658902SMaxim Konovalov } 48466658902SMaxim Konovalov buf = newbuf; 48566658902SMaxim Konovalov st = sysctl(mib, 6, buf, &needed, NULL, 0); 48619beed5eSMaxim Konovalov if (st == 0 || errno != ENOMEM) 48719beed5eSMaxim Konovalov break; 48819beed5eSMaxim Konovalov needed += needed / 8; 48919beed5eSMaxim Konovalov } 49066658902SMaxim Konovalov if (st == -1) 491e2416749SMaxime Henrion err(1, "actual retrieval of routing table"); 492dea673e9SRodney W. Grimes lim = buf + needed; 493dea673e9SRodney W. Grimes for (next = buf; next < lim; next += rtm->rtm_msglen) { 494dea673e9SRodney W. Grimes rtm = (struct rt_msghdr *)next; 4959d34414bSMike Heffner sin2 = (struct sockaddr_inarp *)(rtm + 1); 4961a5ff928SStefan Farfeleder sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2)); 497b9de94e9SYaroslav Tykhiy if (rifname && if_indextoname(sdl->sdl_index, ifname) && 498b9de94e9SYaroslav Tykhiy strcmp(ifname, rifname)) 499b9de94e9SYaroslav Tykhiy continue; 500dea673e9SRodney W. Grimes if (addr) { 5019d34414bSMike Heffner if (addr != sin2->sin_addr.s_addr) 502dea673e9SRodney W. Grimes continue; 503dea673e9SRodney W. Grimes found_entry = 1; 504dea673e9SRodney W. Grimes } 5059d34414bSMike Heffner (*action)(sdl, sin2, rtm); 5068dc4b495SJulian Elischer } 507ae14be20SYaroslav Tykhiy free(buf); 508bdf932aeSLuigi Rizzo return found_entry; 5098dc4b495SJulian Elischer } 5108dc4b495SJulian Elischer 5118dc4b495SJulian Elischer /* 5128dc4b495SJulian Elischer * Display an arp entry 5138dc4b495SJulian Elischer */ 514bdf932aeSLuigi Rizzo static void 5158dc4b495SJulian Elischer print_entry(struct sockaddr_dl *sdl, 5169d34414bSMike Heffner struct sockaddr_inarp *addr, struct rt_msghdr *rtm) 5178dc4b495SJulian Elischer { 5183f844a22SRuslan Ermilov const char *host; 5198dc4b495SJulian Elischer struct hostent *hp; 52097fe20b4SKelly Yancey struct iso88025_sockaddr_dl_data *trld; 521e87a372bSRuslan Ermilov char ifname[IF_NAMESIZE]; 522fda82fc2SJulian Elischer int seg; 5238dc4b495SJulian Elischer 524dea673e9SRodney W. Grimes if (nflag == 0) 5259d34414bSMike Heffner hp = gethostbyaddr((caddr_t)&(addr->sin_addr), 5269d34414bSMike Heffner sizeof addr->sin_addr, AF_INET); 527dea673e9SRodney W. Grimes else 528dea673e9SRodney W. Grimes hp = 0; 529dea673e9SRodney W. Grimes if (hp) 530dea673e9SRodney W. Grimes host = hp->h_name; 531dea673e9SRodney W. Grimes else { 532dea673e9SRodney W. Grimes host = "?"; 533dea673e9SRodney W. Grimes if (h_errno == TRY_AGAIN) 534dea673e9SRodney W. Grimes nflag = 1; 535dea673e9SRodney W. Grimes } 5369d34414bSMike Heffner printf("%s (%s) at ", host, inet_ntoa(addr->sin_addr)); 53721816de3SDoug Rabson if (sdl->sdl_alen) { 538596e374dSRuslan Ermilov if ((sdl->sdl_type == IFT_ETHER || 539596e374dSRuslan Ermilov sdl->sdl_type == IFT_L2VLAN) && 54021816de3SDoug Rabson sdl->sdl_alen == ETHER_ADDR_LEN) 541a03b1b7cSRuslan Ermilov printf("%s", ether_ntoa((struct ether_addr *)LLADDR(sdl))); 54221816de3SDoug Rabson else { 54321816de3SDoug Rabson int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0; 54421816de3SDoug Rabson 54521816de3SDoug Rabson printf("%s", link_ntoa(sdl) + n); 54621816de3SDoug Rabson } 54721816de3SDoug Rabson } else 548dea673e9SRodney W. Grimes printf("(incomplete)"); 549e87a372bSRuslan Ermilov if (if_indextoname(sdl->sdl_index, ifname) != NULL) 550e87a372bSRuslan Ermilov printf(" on %s", ifname); 551dea673e9SRodney W. Grimes if (rtm->rtm_rmx.rmx_expire == 0) 552dea673e9SRodney W. Grimes printf(" permanent"); 5539d34414bSMike Heffner if (addr->sin_other & SIN_PROXY) 554dea673e9SRodney W. Grimes printf(" published (proxy only)"); 555dea673e9SRodney W. Grimes if (rtm->rtm_addrs & RTA_NETMASK) { 5569d34414bSMike Heffner addr = (struct sockaddr_inarp *) 5570b46c085SLuigi Rizzo (SA_SIZE(sdl) + (char *)sdl); 5589d34414bSMike Heffner if (addr->sin_addr.s_addr == 0xffffffff) 559dea673e9SRodney W. Grimes printf(" published"); 5609d34414bSMike Heffner if (addr->sin_len != 8) 5613a6a5ebeSRuslan Ermilov printf("(weird)"); 562dea673e9SRodney W. Grimes } 563fda82fc2SJulian Elischer switch(sdl->sdl_type) { 564fda82fc2SJulian Elischer case IFT_ETHER: 565fda82fc2SJulian Elischer printf(" [ethernet]"); 566fda82fc2SJulian Elischer break; 567fda82fc2SJulian Elischer case IFT_ISO88025: 568fda82fc2SJulian Elischer printf(" [token-ring]"); 56997fe20b4SKelly Yancey trld = SDL_ISO88025(sdl); 57097fe20b4SKelly Yancey if (trld->trld_rcf != 0) { 57197fe20b4SKelly Yancey printf(" rt=%x", ntohs(trld->trld_rcf)); 57297fe20b4SKelly Yancey for (seg = 0; 57397fe20b4SKelly Yancey seg < ((TR_RCF_RIFLEN(trld->trld_rcf) - 2 ) / 2); 57497fe20b4SKelly Yancey seg++) 5752ab778e1SBill Paul printf(":%x", ntohs(*(trld->trld_route[seg]))); 57697fe20b4SKelly Yancey } 577fda82fc2SJulian Elischer break; 57804427472SMatthew N. Dodd case IFT_FDDI: 57904427472SMatthew N. Dodd printf(" [fddi]"); 58004427472SMatthew N. Dodd break; 58104427472SMatthew N. Dodd case IFT_ATM: 58204427472SMatthew N. Dodd printf(" [atm]"); 58304427472SMatthew N. Dodd break; 58488d5b613SYaroslav Tykhiy case IFT_L2VLAN: 58588d5b613SYaroslav Tykhiy printf(" [vlan]"); 58688d5b613SYaroslav Tykhiy break; 58721816de3SDoug Rabson case IFT_IEEE1394: 58821816de3SDoug Rabson printf(" [firewire]"); 58921816de3SDoug Rabson break; 590fda82fc2SJulian Elischer default: 591123b2d4aSMurray Stokely break; 592fda82fc2SJulian Elischer } 593fda82fc2SJulian Elischer 594dea673e9SRodney W. Grimes printf("\n"); 595fda82fc2SJulian Elischer 596dea673e9SRodney W. Grimes } 5978dc4b495SJulian Elischer 5988dc4b495SJulian Elischer /* 5998dc4b495SJulian Elischer * Nuke an arp entry 6008dc4b495SJulian Elischer */ 601bdf932aeSLuigi Rizzo static void 6029d34414bSMike Heffner nuke_entry(struct sockaddr_dl *sdl __unused, 6039d34414bSMike Heffner struct sockaddr_inarp *addr, struct rt_msghdr *rtm __unused) 6048dc4b495SJulian Elischer { 6058dc4b495SJulian Elischer char ip[20]; 6068dc4b495SJulian Elischer 6079d34414bSMike Heffner snprintf(ip, sizeof(ip), "%s", inet_ntoa(addr->sin_addr)); 60868839124SLuigi Rizzo delete(ip, 0); 609dea673e9SRodney W. Grimes } 610dea673e9SRodney W. Grimes 611bdf932aeSLuigi Rizzo static void 612a42a667dSPoul-Henning Kamp usage(void) 613dea673e9SRodney W. Grimes { 6148dc4b495SJulian Elischer fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 615b9de94e9SYaroslav Tykhiy "usage: arp [-n] [-i interface] hostname", 616b9de94e9SYaroslav Tykhiy " arp [-n] [-i interface] -a", 6173f844a22SRuslan Ermilov " arp -d hostname [pub]", 6188dc4b495SJulian Elischer " arp -d -a", 619c72049e4SPhilippe Charnier " arp -s hostname ether_addr [temp] [pub]", 620c72049e4SPhilippe Charnier " arp -S hostname ether_addr [temp] [pub]", 621c72049e4SPhilippe Charnier " arp -f filename"); 622dea673e9SRodney W. Grimes exit(1); 623dea673e9SRodney W. Grimes } 624dea673e9SRodney W. Grimes 625bdf932aeSLuigi Rizzo static struct rt_msghdr * 62668839124SLuigi Rizzo rtmsg(int cmd, struct sockaddr_inarp *dst, struct sockaddr_dl *sdl) 627dea673e9SRodney W. Grimes { 628dea673e9SRodney W. Grimes static int seq; 629dea673e9SRodney W. Grimes int rlen; 630bdf932aeSLuigi Rizzo int l; 631bdf932aeSLuigi Rizzo struct sockaddr_in so_mask; 632bdf932aeSLuigi Rizzo static int s = -1; 633bdf932aeSLuigi Rizzo static pid_t pid; 634bdf932aeSLuigi Rizzo 635bdf932aeSLuigi Rizzo static struct { 636bdf932aeSLuigi Rizzo struct rt_msghdr m_rtm; 637bdf932aeSLuigi Rizzo char m_space[512]; 638bdf932aeSLuigi Rizzo } m_rtmsg; 639bdf932aeSLuigi Rizzo 640e2416749SMaxime Henrion struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 641e2416749SMaxime Henrion char *cp = m_rtmsg.m_space; 642bdf932aeSLuigi Rizzo 643bdf932aeSLuigi Rizzo if (s < 0) { /* first time: open socket, get pid */ 644bdf932aeSLuigi Rizzo s = socket(PF_ROUTE, SOCK_RAW, 0); 645bdf932aeSLuigi Rizzo if (s < 0) 646bdf932aeSLuigi Rizzo err(1, "socket"); 647bdf932aeSLuigi Rizzo pid = getpid(); 648bdf932aeSLuigi Rizzo } 649bdf932aeSLuigi Rizzo bzero(&so_mask, sizeof(so_mask)); 650bdf932aeSLuigi Rizzo so_mask.sin_len = 8; 651bdf932aeSLuigi Rizzo so_mask.sin_addr.s_addr = 0xffffffff; 652dea673e9SRodney W. Grimes 653dea673e9SRodney W. Grimes errno = 0; 65468839124SLuigi Rizzo /* 65568839124SLuigi Rizzo * XXX RTM_DELETE relies on a previous RTM_GET to fill the buffer 65668839124SLuigi Rizzo * appropriately. 65768839124SLuigi Rizzo */ 658dea673e9SRodney W. Grimes if (cmd == RTM_DELETE) 659dea673e9SRodney W. Grimes goto doit; 660dea673e9SRodney W. Grimes bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 661dea673e9SRodney W. Grimes rtm->rtm_flags = flags; 662dea673e9SRodney W. Grimes rtm->rtm_version = RTM_VERSION; 663dea673e9SRodney W. Grimes 664dea673e9SRodney W. Grimes switch (cmd) { 665dea673e9SRodney W. Grimes default: 666c72049e4SPhilippe Charnier errx(1, "internal wrong cmd"); 667dea673e9SRodney W. Grimes case RTM_ADD: 668dea673e9SRodney W. Grimes rtm->rtm_addrs |= RTA_GATEWAY; 669dea673e9SRodney W. Grimes rtm->rtm_rmx.rmx_expire = expire_time; 670dea673e9SRodney W. Grimes rtm->rtm_inits = RTV_EXPIRE; 671dea673e9SRodney W. Grimes rtm->rtm_flags |= (RTF_HOST | RTF_STATIC); 67268839124SLuigi Rizzo dst->sin_other = 0; 673dea673e9SRodney W. Grimes if (doing_proxy) { 6743f844a22SRuslan Ermilov if (proxy_only) 67568839124SLuigi Rizzo dst->sin_other = SIN_PROXY; 676dea673e9SRodney W. Grimes else { 677dea673e9SRodney W. Grimes rtm->rtm_addrs |= RTA_NETMASK; 678dea673e9SRodney W. Grimes rtm->rtm_flags &= ~RTF_HOST; 679dea673e9SRodney W. Grimes } 680dea673e9SRodney W. Grimes } 681dea673e9SRodney W. Grimes /* FALLTHROUGH */ 682dea673e9SRodney W. Grimes case RTM_GET: 683dea673e9SRodney W. Grimes rtm->rtm_addrs |= RTA_DST; 684dea673e9SRodney W. Grimes } 685dea673e9SRodney W. Grimes #define NEXTADDR(w, s) \ 68668839124SLuigi Rizzo if (s && rtm->rtm_addrs & (w)) { \ 68768839124SLuigi Rizzo bcopy(s, cp, sizeof(*s)); cp += SA_SIZE(s);} 688dea673e9SRodney W. Grimes 68968839124SLuigi Rizzo NEXTADDR(RTA_DST, dst); 69068839124SLuigi Rizzo NEXTADDR(RTA_GATEWAY, sdl); 69168839124SLuigi Rizzo NEXTADDR(RTA_NETMASK, &so_mask); 692dea673e9SRodney W. Grimes 693dea673e9SRodney W. Grimes rtm->rtm_msglen = cp - (char *)&m_rtmsg; 694dea673e9SRodney W. Grimes doit: 695dea673e9SRodney W. Grimes l = rtm->rtm_msglen; 696dea673e9SRodney W. Grimes rtm->rtm_seq = ++seq; 697dea673e9SRodney W. Grimes rtm->rtm_type = cmd; 698dea673e9SRodney W. Grimes if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 699dea673e9SRodney W. Grimes if (errno != ESRCH || cmd != RTM_DELETE) { 700c72049e4SPhilippe Charnier warn("writing to routing socket"); 701bdf932aeSLuigi Rizzo return NULL; 702dea673e9SRodney W. Grimes } 703dea673e9SRodney W. Grimes } 704dea673e9SRodney W. Grimes do { 705dea673e9SRodney W. Grimes l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 706dea673e9SRodney W. Grimes } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 707dea673e9SRodney W. Grimes if (l < 0) 708c72049e4SPhilippe Charnier warn("read from routing socket"); 709bdf932aeSLuigi Rizzo return rtm; 710dea673e9SRodney W. Grimes } 711dea673e9SRodney W. Grimes 712a42a667dSPoul-Henning Kamp /* 713a42a667dSPoul-Henning Kamp * get_ether_addr - get the hardware address of an interface on the 714a42a667dSPoul-Henning Kamp * the same subnet as ipaddr. 715a42a667dSPoul-Henning Kamp */ 716a42a667dSPoul-Henning Kamp #define MAX_IFS 32 717a42a667dSPoul-Henning Kamp 718bdf932aeSLuigi Rizzo static int 719a03b1b7cSRuslan Ermilov get_ether_addr(u_int32_t ipaddr, struct ether_addr *hwaddr) 720a42a667dSPoul-Henning Kamp { 721a42a667dSPoul-Henning Kamp struct ifreq *ifr, *ifend, *ifp; 72268839124SLuigi Rizzo uint32_t ina, mask; 723a42a667dSPoul-Henning Kamp struct sockaddr_dl *dla; 724a42a667dSPoul-Henning Kamp struct ifreq ifreq; 725a42a667dSPoul-Henning Kamp struct ifconf ifc; 726a42a667dSPoul-Henning Kamp struct ifreq ifs[MAX_IFS]; 7279d34414bSMike Heffner int sock; 72868839124SLuigi Rizzo int retval = 0; 729a42a667dSPoul-Henning Kamp 7309d34414bSMike Heffner sock = socket(AF_INET, SOCK_DGRAM, 0); 7319d34414bSMike Heffner if (sock < 0) 732c72049e4SPhilippe Charnier err(1, "socket"); 733a42a667dSPoul-Henning Kamp 734a42a667dSPoul-Henning Kamp ifc.ifc_len = sizeof(ifs); 735a42a667dSPoul-Henning Kamp ifc.ifc_req = ifs; 7369cc7cb58SMike Heffner if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { 737c72049e4SPhilippe Charnier warnx("ioctl(SIOCGIFCONF)"); 73868839124SLuigi Rizzo goto done; 739a42a667dSPoul-Henning Kamp } 740a42a667dSPoul-Henning Kamp 74168839124SLuigi Rizzo #define NEXTIFR(i) \ 74268839124SLuigi Rizzo ((struct ifreq *)((char *)&(i)->ifr_addr \ 74368839124SLuigi Rizzo + MAX((i)->ifr_addr.sa_len, sizeof((i)->ifr_addr))) ) 74468839124SLuigi Rizzo 745a42a667dSPoul-Henning Kamp /* 746a42a667dSPoul-Henning Kamp * Scan through looking for an interface with an Internet 747a42a667dSPoul-Henning Kamp * address on the same subnet as `ipaddr'. 748a42a667dSPoul-Henning Kamp */ 749a42a667dSPoul-Henning Kamp ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len); 75068839124SLuigi Rizzo for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr) ) { 75168839124SLuigi Rizzo if (ifr->ifr_addr.sa_family != AF_INET) 75268839124SLuigi Rizzo continue; 75368839124SLuigi Rizzo /* XXX can't we use *ifr instead of ifreq ? */ 754a42a667dSPoul-Henning Kamp strncpy(ifreq.ifr_name, ifr->ifr_name, 755a42a667dSPoul-Henning Kamp sizeof(ifreq.ifr_name)); 756a42a667dSPoul-Henning Kamp /* 757a42a667dSPoul-Henning Kamp * Check that the interface is up, 758a42a667dSPoul-Henning Kamp * and not point-to-point or loopback. 759a42a667dSPoul-Henning Kamp */ 7609cc7cb58SMike Heffner if (ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0) 761a42a667dSPoul-Henning Kamp continue; 762a42a667dSPoul-Henning Kamp if ((ifreq.ifr_flags & 763a42a667dSPoul-Henning Kamp (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT| 764a42a667dSPoul-Henning Kamp IFF_LOOPBACK|IFF_NOARP)) 765a42a667dSPoul-Henning Kamp != (IFF_UP|IFF_BROADCAST)) 76668839124SLuigi Rizzo continue; 767a42a667dSPoul-Henning Kamp /* 768a42a667dSPoul-Henning Kamp * Get its netmask and check that it's on 769a42a667dSPoul-Henning Kamp * the right subnet. 770a42a667dSPoul-Henning Kamp */ 7719cc7cb58SMike Heffner if (ioctl(sock, SIOCGIFNETMASK, &ifreq) < 0) 772a42a667dSPoul-Henning Kamp continue; 773a42a667dSPoul-Henning Kamp mask = ((struct sockaddr_in *) 774a42a667dSPoul-Henning Kamp &ifreq.ifr_addr)->sin_addr.s_addr; 77568839124SLuigi Rizzo ina = ((struct sockaddr_in *) 77668839124SLuigi Rizzo &ifr->ifr_addr)->sin_addr.s_addr; 77768839124SLuigi Rizzo if ((ipaddr & mask) == (ina & mask)) 77868839124SLuigi Rizzo break; /* ok, we got it! */ 779a42a667dSPoul-Henning Kamp } 780a42a667dSPoul-Henning Kamp 78168839124SLuigi Rizzo if (ifr >= ifend) 78268839124SLuigi Rizzo goto done; 783a42a667dSPoul-Henning Kamp 784a42a667dSPoul-Henning Kamp /* 785a42a667dSPoul-Henning Kamp * Now scan through again looking for a link-level address 786a42a667dSPoul-Henning Kamp * for this interface. 787a42a667dSPoul-Henning Kamp */ 788a42a667dSPoul-Henning Kamp ifp = ifr; 78968839124SLuigi Rizzo for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr)) 79068839124SLuigi Rizzo if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 && 79168839124SLuigi Rizzo ifr->ifr_addr.sa_family == AF_LINK) 79268839124SLuigi Rizzo break; 79368839124SLuigi Rizzo if (ifr >= ifend) 79468839124SLuigi Rizzo goto done; 795a42a667dSPoul-Henning Kamp /* 796a42a667dSPoul-Henning Kamp * Found the link-level address - copy it out 797a42a667dSPoul-Henning Kamp */ 798a42a667dSPoul-Henning Kamp dla = (struct sockaddr_dl *) &ifr->ifr_addr; 799a42a667dSPoul-Henning Kamp memcpy(hwaddr, LLADDR(dla), dla->sdl_alen); 800a42a667dSPoul-Henning Kamp printf("using interface %s for proxy with address ", 801a42a667dSPoul-Henning Kamp ifp->ifr_name); 802a03b1b7cSRuslan Ermilov printf("%s\n", ether_ntoa(hwaddr)); 80368839124SLuigi Rizzo retval = dla->sdl_alen; 80468839124SLuigi Rizzo done: 80568839124SLuigi Rizzo close(sock); 80668839124SLuigi Rizzo return retval; 807a42a667dSPoul-Henning Kamp } 808