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, 849711a168SGleb Smirnoff struct sockaddr_in *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 909711a168SGleb Smirnoff static int delete(char *host); 91bdf932aeSLuigi Rizzo static void usage(void); 92bdf932aeSLuigi Rizzo static int set(int argc, char **argv); 93f3f8b226SRuslan Ermilov static int get(char *host); 94bdf932aeSLuigi Rizzo static int file(char *name); 9568839124SLuigi Rizzo static struct rt_msghdr *rtmsg(int cmd, 969711a168SGleb Smirnoff struct sockaddr_in *dst, struct sockaddr_dl *sdl); 97f3f8b226SRuslan Ermilov static int get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr); 989711a168SGleb Smirnoff static struct sockaddr_in *getaddr(char *host); 99f3f8b226SRuslan Ermilov static int valid_type(int type); 100bdf932aeSLuigi Rizzo 1018dc4b495SJulian Elischer static int nflag; /* no reverse dns lookups */ 102b9de94e9SYaroslav Tykhiy static char *rifname; 103dea673e9SRodney W. Grimes 10492968305SRuslan Ermilov static time_t expire_time; 1059711a168SGleb Smirnoff static int flags, doing_proxy; 10668839124SLuigi Rizzo 107c1ed96c2SGeorge V. Neville-Neil struct if_nameindex *ifnameindex; 108c1ed96c2SGeorge V. Neville-Neil 1098dc4b495SJulian Elischer /* which function we're supposed to do */ 1108dc4b495SJulian Elischer #define F_GET 1 1118dc4b495SJulian Elischer #define F_SET 2 1128dc4b495SJulian Elischer #define F_FILESET 3 1138dc4b495SJulian Elischer #define F_REPLACE 4 1148dc4b495SJulian Elischer #define F_DELETE 5 1158dc4b495SJulian Elischer 1168dc4b495SJulian Elischer #define SETFUNC(f) { if (func) usage(); func = (f); } 1178dc4b495SJulian Elischer 118a42a667dSPoul-Henning Kamp int 1193f844a22SRuslan Ermilov main(int argc, char *argv[]) 120dea673e9SRodney W. Grimes { 1218dc4b495SJulian Elischer int ch, func = 0; 1228dc4b495SJulian Elischer int rtn = 0; 123bdf932aeSLuigi Rizzo int aflag = 0; /* do it for all entries */ 124dea673e9SRodney W. Grimes 125b9de94e9SYaroslav Tykhiy while ((ch = getopt(argc, argv, "andfsSi:")) != -1) 126eac295c9SRemko Lodder switch(ch) { 127dea673e9SRodney W. Grimes case 'a': 1288dc4b495SJulian Elischer aflag = 1; 1298dc4b495SJulian Elischer break; 130dea673e9SRodney W. Grimes case 'd': 1318dc4b495SJulian Elischer SETFUNC(F_DELETE); 1328dc4b495SJulian Elischer break; 133dea673e9SRodney W. Grimes case 'n': 134dea673e9SRodney W. Grimes nflag = 1; 1358dc4b495SJulian Elischer break; 136a42a667dSPoul-Henning Kamp case 'S': 1378dc4b495SJulian Elischer SETFUNC(F_REPLACE); 1388dc4b495SJulian Elischer break; 139dea673e9SRodney W. Grimes case 's': 1408dc4b495SJulian Elischer SETFUNC(F_SET); 1418dc4b495SJulian Elischer break; 14295319e17SJordan K. Hubbard case 'f' : 1438dc4b495SJulian Elischer SETFUNC(F_FILESET); 1448dc4b495SJulian Elischer break; 145b9de94e9SYaroslav Tykhiy case 'i': 146b9de94e9SYaroslav Tykhiy rifname = optarg; 147b9de94e9SYaroslav Tykhiy break; 148dea673e9SRodney W. Grimes case '?': 149dea673e9SRodney W. Grimes default: 150dea673e9SRodney W. Grimes usage(); 151dea673e9SRodney W. Grimes } 1528dc4b495SJulian Elischer argc -= optind; 1538dc4b495SJulian Elischer argv += optind; 1548dc4b495SJulian Elischer 1558dc4b495SJulian Elischer if (!func) 1568dc4b495SJulian Elischer func = F_GET; 157b9de94e9SYaroslav Tykhiy if (rifname) { 15808369852SBrooks Davis if (func != F_GET && !(func == F_DELETE && aflag)) 159b9de94e9SYaroslav Tykhiy errx(1, "-i not applicable to this operation"); 160b9de94e9SYaroslav Tykhiy if (if_nametoindex(rifname) == 0) { 161b9de94e9SYaroslav Tykhiy if (errno == ENXIO) 162b9de94e9SYaroslav Tykhiy errx(1, "interface %s does not exist", rifname); 163b9de94e9SYaroslav Tykhiy else 164b9de94e9SYaroslav Tykhiy err(1, "if_nametoindex(%s)", rifname); 165b9de94e9SYaroslav Tykhiy } 166b9de94e9SYaroslav Tykhiy } 1678dc4b495SJulian Elischer switch (func) { 1688dc4b495SJulian Elischer case F_GET: 1698dc4b495SJulian Elischer if (aflag) { 1708dc4b495SJulian Elischer if (argc != 0) 171dea673e9SRodney W. Grimes usage(); 1728dc4b495SJulian Elischer search(0, print_entry); 1738dc4b495SJulian Elischer } else { 1748dc4b495SJulian Elischer if (argc != 1) 1758dc4b495SJulian Elischer usage(); 176f3f8b226SRuslan Ermilov rtn = get(argv[0]); 1778dc4b495SJulian Elischer } 1788dc4b495SJulian Elischer break; 1798dc4b495SJulian Elischer case F_SET: 1808dc4b495SJulian Elischer case F_REPLACE: 1813f844a22SRuslan Ermilov if (argc < 2 || argc > 6) 1828dc4b495SJulian Elischer usage(); 1838dc4b495SJulian Elischer if (func == F_REPLACE) 1849711a168SGleb Smirnoff (void)delete(argv[0]); 1858dc4b495SJulian Elischer rtn = set(argc, argv) ? 1 : 0; 1868dc4b495SJulian Elischer break; 1878dc4b495SJulian Elischer case F_DELETE: 1888dc4b495SJulian Elischer if (aflag) { 1898dc4b495SJulian Elischer if (argc != 0) 1908dc4b495SJulian Elischer usage(); 1918dc4b495SJulian Elischer search(0, nuke_entry); 192876fc15dSGleb Smirnoff } else { 193876fc15dSGleb Smirnoff if (argc != 1) 194876fc15dSGleb Smirnoff usage(); 1959711a168SGleb Smirnoff rtn = delete(argv[0]); 196876fc15dSGleb Smirnoff } 1978dc4b495SJulian Elischer break; 1988dc4b495SJulian Elischer case F_FILESET: 1998dc4b495SJulian Elischer if (argc != 1) 2008dc4b495SJulian Elischer usage(); 2018dc4b495SJulian Elischer rtn = file(argv[0]); 2028dc4b495SJulian Elischer break; 2038dc4b495SJulian Elischer } 2048dc4b495SJulian Elischer 205c1ed96c2SGeorge V. Neville-Neil if (ifnameindex != NULL) 206c1ed96c2SGeorge V. Neville-Neil if_freenameindex(ifnameindex); 207c1ed96c2SGeorge V. Neville-Neil 2088dc4b495SJulian Elischer return (rtn); 209dea673e9SRodney W. Grimes } 210dea673e9SRodney W. Grimes 211dea673e9SRodney W. Grimes /* 212dea673e9SRodney W. Grimes * Process a file to set standard arp entries 213dea673e9SRodney W. Grimes */ 214bdf932aeSLuigi Rizzo static int 215a42a667dSPoul-Henning Kamp file(char *name) 216dea673e9SRodney W. Grimes { 217dea673e9SRodney W. Grimes FILE *fp; 218dea673e9SRodney W. Grimes int i, retval; 2193adcd042SRuslan Ermilov char line[100], arg[5][50], *args[5], *p; 220dea673e9SRodney W. Grimes 221c72049e4SPhilippe Charnier if ((fp = fopen(name, "r")) == NULL) 222e2416749SMaxime Henrion err(1, "cannot open %s", name); 223dea673e9SRodney W. Grimes args[0] = &arg[0][0]; 224dea673e9SRodney W. Grimes args[1] = &arg[1][0]; 225dea673e9SRodney W. Grimes args[2] = &arg[2][0]; 226dea673e9SRodney W. Grimes args[3] = &arg[3][0]; 227dea673e9SRodney W. Grimes args[4] = &arg[4][0]; 228dea673e9SRodney W. Grimes retval = 0; 229d0691403SKevin Lo while(fgets(line, sizeof(line), fp) != NULL) { 2303adcd042SRuslan Ermilov if ((p = strchr(line, '#')) != NULL) 2313adcd042SRuslan Ermilov *p = '\0'; 2323adcd042SRuslan Ermilov for (p = line; isblank(*p); p++); 2334bfc3624SRuslan Ermilov if (*p == '\n' || *p == '\0') 23444acbc1aSRuslan Ermilov continue; 2353adcd042SRuslan Ermilov i = sscanf(p, "%49s %49s %49s %49s %49s", arg[0], arg[1], 236135adb1eSJordan K. Hubbard arg[2], arg[3], arg[4]); 237dea673e9SRodney W. Grimes if (i < 2) { 238c72049e4SPhilippe Charnier warnx("bad line: %s", line); 239dea673e9SRodney W. Grimes retval = 1; 240dea673e9SRodney W. Grimes continue; 241dea673e9SRodney W. Grimes } 242dea673e9SRodney W. Grimes if (set(i, args)) 243dea673e9SRodney W. Grimes retval = 1; 244dea673e9SRodney W. Grimes } 245dea673e9SRodney W. Grimes fclose(fp); 246dea673e9SRodney W. Grimes return (retval); 247dea673e9SRodney W. Grimes } 248dea673e9SRodney W. Grimes 249dea673e9SRodney W. Grimes /* 2509711a168SGleb Smirnoff * Given a hostname, fills up a (static) struct sockaddr_in with 25168839124SLuigi Rizzo * the address of the host and returns a pointer to the 25268839124SLuigi Rizzo * structure. 253dea673e9SRodney W. Grimes */ 2549711a168SGleb Smirnoff static struct sockaddr_in * 25568839124SLuigi Rizzo getaddr(char *host) 256dea673e9SRodney W. Grimes { 257dea673e9SRodney W. Grimes struct hostent *hp; 2589711a168SGleb Smirnoff static struct sockaddr_in reply; 25968839124SLuigi Rizzo 26068839124SLuigi Rizzo bzero(&reply, sizeof(reply)); 26168839124SLuigi Rizzo reply.sin_len = sizeof(reply); 26268839124SLuigi Rizzo reply.sin_family = AF_INET; 26368839124SLuigi Rizzo reply.sin_addr.s_addr = inet_addr(host); 26468839124SLuigi Rizzo if (reply.sin_addr.s_addr == INADDR_NONE) { 26568839124SLuigi Rizzo if (!(hp = gethostbyname(host))) { 26668839124SLuigi Rizzo warnx("%s: %s", host, hstrerror(h_errno)); 267f3f8b226SRuslan Ermilov return (NULL); 26868839124SLuigi Rizzo } 26968839124SLuigi Rizzo bcopy((char *)hp->h_addr, (char *)&reply.sin_addr, 27068839124SLuigi Rizzo sizeof reply.sin_addr); 27168839124SLuigi Rizzo } 272f3f8b226SRuslan Ermilov return (&reply); 27368839124SLuigi Rizzo } 27468839124SLuigi Rizzo 27568839124SLuigi Rizzo /* 276f3f8b226SRuslan Ermilov * Returns true if the type is a valid one for ARP. 27768839124SLuigi Rizzo */ 27868839124SLuigi Rizzo static int 27968839124SLuigi Rizzo valid_type(int type) 28068839124SLuigi Rizzo { 281f3f8b226SRuslan Ermilov 28268839124SLuigi Rizzo switch (type) { 28368839124SLuigi Rizzo case IFT_ETHER: 28468839124SLuigi Rizzo case IFT_FDDI: 285595f03feSMark Johnston case IFT_INFINIBAND: 28668839124SLuigi Rizzo case IFT_ISO88023: 28768839124SLuigi Rizzo case IFT_ISO88024: 28868839124SLuigi Rizzo case IFT_ISO88025: 28968839124SLuigi Rizzo case IFT_L2VLAN: 2909af9b983SAndrew Thompson case IFT_BRIDGE: 291f3f8b226SRuslan Ermilov return (1); 292f3f8b226SRuslan Ermilov default: 293f3f8b226SRuslan Ermilov return (0); 29468839124SLuigi Rizzo } 29568839124SLuigi Rizzo } 29668839124SLuigi Rizzo 29768839124SLuigi Rizzo /* 29868839124SLuigi Rizzo * Set an individual arp entry 29968839124SLuigi Rizzo */ 30068839124SLuigi Rizzo static int 30168839124SLuigi Rizzo set(int argc, char **argv) 30268839124SLuigi Rizzo { 3039711a168SGleb Smirnoff struct sockaddr_in *addr; 3049711a168SGleb Smirnoff struct sockaddr_in *dst; /* what are we looking for */ 305e2416749SMaxime Henrion struct sockaddr_dl *sdl; 306bdf932aeSLuigi Rizzo struct rt_msghdr *rtm; 307a03b1b7cSRuslan Ermilov struct ether_addr *ea; 308dea673e9SRodney W. Grimes char *host = argv[0], *eaddr = argv[1]; 30968839124SLuigi Rizzo struct sockaddr_dl sdl_m; 310dea673e9SRodney W. Grimes 311dea673e9SRodney W. Grimes argc -= 2; 312dea673e9SRodney W. Grimes argv += 2; 313bdf932aeSLuigi Rizzo 314bdf932aeSLuigi Rizzo bzero(&sdl_m, sizeof(sdl_m)); 315bdf932aeSLuigi Rizzo sdl_m.sdl_len = sizeof(sdl_m); 316bdf932aeSLuigi Rizzo sdl_m.sdl_family = AF_LINK; 317bdf932aeSLuigi Rizzo 31868839124SLuigi Rizzo dst = getaddr(host); 31968839124SLuigi Rizzo if (dst == NULL) 320dea673e9SRodney W. Grimes return (1); 3219711a168SGleb Smirnoff doing_proxy = flags = expire_time = 0; 322dea673e9SRodney W. Grimes while (argc-- > 0) { 323dea673e9SRodney W. Grimes if (strncmp(argv[0], "temp", 4) == 0) { 3245d067f6cSGleb Smirnoff struct timespec tp; 32584d8f5b8SGleb Smirnoff int max_age; 32684d8f5b8SGleb Smirnoff size_t len = sizeof(max_age); 32784d8f5b8SGleb Smirnoff 3285d067f6cSGleb Smirnoff clock_gettime(CLOCK_MONOTONIC, &tp); 32984d8f5b8SGleb Smirnoff if (sysctlbyname("net.link.ether.inet.max_age", 33084d8f5b8SGleb Smirnoff &max_age, &len, NULL, 0) != 0) 33184d8f5b8SGleb Smirnoff err(1, "sysctlbyname"); 33284d8f5b8SGleb Smirnoff expire_time = tp.tv_sec + max_age; 333e653f1f0SSam Leffler } else if (strncmp(argv[0], "pub", 3) == 0) { 334dea673e9SRodney W. Grimes flags |= RTF_ANNOUNCE; 3353f844a22SRuslan Ermilov doing_proxy = 1; 3363f844a22SRuslan Ermilov if (argc && strncmp(argv[1], "only", 3) == 0) { 3379711a168SGleb Smirnoff /* 3389711a168SGleb Smirnoff * Compatibility: in pre FreeBSD 8 times 3399711a168SGleb Smirnoff * the "only" keyword used to mean that 3409711a168SGleb Smirnoff * an ARP entry should be announced, but 3419711a168SGleb Smirnoff * not installed into routing table. 3429711a168SGleb Smirnoff */ 3433f844a22SRuslan Ermilov argc--; argv++; 3443f844a22SRuslan Ermilov } 345e653f1f0SSam Leffler } else if (strncmp(argv[0], "blackhole", 9) == 0) { 3462293dac2STom Rhodes if (flags & RTF_REJECT) { 3472293dac2STom Rhodes printf("Choose one of blackhole or reject, not both.\n"); 3482293dac2STom Rhodes } 349e653f1f0SSam Leffler flags |= RTF_BLACKHOLE; 350e653f1f0SSam Leffler } else if (strncmp(argv[0], "reject", 6) == 0) { 3512293dac2STom Rhodes if (flags & RTF_BLACKHOLE) { 3522293dac2STom Rhodes printf("Choose one of blackhole or reject, not both.\n"); 3532293dac2STom Rhodes } 354e653f1f0SSam Leffler flags |= RTF_REJECT; 355dea673e9SRodney W. Grimes } else if (strncmp(argv[0], "trail", 5) == 0) { 35668839124SLuigi Rizzo /* XXX deprecated and undocumented feature */ 357dea673e9SRodney W. Grimes printf("%s: Sending trailers is no longer supported\n", 358dea673e9SRodney W. Grimes host); 359dea673e9SRodney W. Grimes } 360dea673e9SRodney W. Grimes argv++; 361dea673e9SRodney W. Grimes } 362a03b1b7cSRuslan Ermilov ea = (struct ether_addr *)LLADDR(&sdl_m); 363a42a667dSPoul-Henning Kamp if (doing_proxy && !strcmp(eaddr, "auto")) { 36468839124SLuigi Rizzo if (!get_ether_addr(dst->sin_addr.s_addr, ea)) { 365eec827b0SRuslan Ermilov printf("no interface found for %s\n", 36668839124SLuigi Rizzo inet_ntoa(dst->sin_addr)); 367a42a667dSPoul-Henning Kamp return (1); 368a42a667dSPoul-Henning Kamp } 369a03b1b7cSRuslan Ermilov sdl_m.sdl_alen = ETHER_ADDR_LEN; 370a42a667dSPoul-Henning Kamp } else { 37168839124SLuigi Rizzo struct ether_addr *ea1 = ether_aton(eaddr); 37268839124SLuigi Rizzo 373a47c388cSGleb Smirnoff if (ea1 == NULL) { 37468839124SLuigi Rizzo warnx("invalid Ethernet address '%s'", eaddr); 375a47c388cSGleb Smirnoff return (1); 376a47c388cSGleb Smirnoff } else { 37768839124SLuigi Rizzo *ea = *ea1; 378a03b1b7cSRuslan Ermilov sdl_m.sdl_alen = ETHER_ADDR_LEN; 379a42a667dSPoul-Henning Kamp } 38068839124SLuigi Rizzo } 381c7ab6602SQing Li 382c7ab6602SQing Li /* 383c7ab6602SQing Li * In the case a proxy-arp entry is being added for 384c7ab6602SQing Li * a remote end point, the RTF_ANNOUNCE flag in the 385c7ab6602SQing Li * RTM_GET command is an indication to the kernel 386c7ab6602SQing Li * routing code that the interface associated with 387c7ab6602SQing Li * the prefix route covering the local end of the 388c7ab6602SQing Li * PPP link should be returned, on which ARP applies. 389c7ab6602SQing Li */ 39068839124SLuigi Rizzo rtm = rtmsg(RTM_GET, dst, &sdl_m); 391bdf932aeSLuigi Rizzo if (rtm == NULL) { 392c72049e4SPhilippe Charnier warn("%s", host); 393dea673e9SRodney W. Grimes return (1); 394dea673e9SRodney W. Grimes } 3959711a168SGleb Smirnoff addr = (struct sockaddr_in *)(rtm + 1); 3960b46c085SLuigi Rizzo sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr); 39768839124SLuigi Rizzo 398c7ab6602SQing Li if ((sdl->sdl_family != AF_LINK) || 399c7ab6602SQing Li (rtm->rtm_flags & RTF_GATEWAY) || 400c7ab6602SQing Li !valid_type(sdl->sdl_type)) { 401dea673e9SRodney W. Grimes printf("cannot intuit interface index and type for %s\n", host); 402dea673e9SRodney W. Grimes return (1); 403dea673e9SRodney W. Grimes } 404dea673e9SRodney W. Grimes sdl_m.sdl_type = sdl->sdl_type; 405dea673e9SRodney W. Grimes sdl_m.sdl_index = sdl->sdl_index; 406cf779589SGleb Smirnoff return (rtmsg(RTM_ADD, dst, &sdl_m) == NULL); 407dea673e9SRodney W. Grimes } 408dea673e9SRodney W. Grimes 409dea673e9SRodney W. Grimes /* 410dea673e9SRodney W. Grimes * Display an individual arp entry 411dea673e9SRodney W. Grimes */ 412f3f8b226SRuslan Ermilov static int 413a42a667dSPoul-Henning Kamp get(char *host) 414dea673e9SRodney W. Grimes { 4159711a168SGleb Smirnoff struct sockaddr_in *addr; 416dea673e9SRodney W. Grimes 41768839124SLuigi Rizzo addr = getaddr(host); 41868839124SLuigi Rizzo if (addr == NULL) 419f3f8b226SRuslan Ermilov return (1); 420bdf932aeSLuigi Rizzo if (0 == search(addr->sin_addr.s_addr, print_entry)) { 421b9de94e9SYaroslav Tykhiy printf("%s (%s) -- no entry", 4229d34414bSMike Heffner host, inet_ntoa(addr->sin_addr)); 423b9de94e9SYaroslav Tykhiy if (rifname) 424b9de94e9SYaroslav Tykhiy printf(" on %s", rifname); 425b9de94e9SYaroslav Tykhiy printf("\n"); 426f3f8b226SRuslan Ermilov return (1); 427dea673e9SRodney W. Grimes } 428f3f8b226SRuslan Ermilov return (0); 429dea673e9SRodney W. Grimes } 430dea673e9SRodney W. Grimes 431dea673e9SRodney W. Grimes /* 432dea673e9SRodney W. Grimes * Delete an arp entry 433dea673e9SRodney W. Grimes */ 434bdf932aeSLuigi Rizzo static int 4359711a168SGleb Smirnoff delete(char *host) 436dea673e9SRodney W. Grimes { 4379711a168SGleb Smirnoff struct sockaddr_in *addr, *dst; 438bdf932aeSLuigi Rizzo struct rt_msghdr *rtm; 439dea673e9SRodney W. Grimes struct sockaddr_dl *sdl; 4406e6b3f7cSQing Li struct sockaddr_dl sdl_m; 441dea673e9SRodney W. Grimes 44268839124SLuigi Rizzo dst = getaddr(host); 44368839124SLuigi Rizzo if (dst == NULL) 444f3f8b226SRuslan Ermilov return (1); 445c7ab6602SQing Li 446c7ab6602SQing Li /* 447c7ab6602SQing Li * Perform a regular entry delete first. 448c7ab6602SQing Li */ 449c7ab6602SQing Li flags &= ~RTF_ANNOUNCE; 4506e6b3f7cSQing Li 4516e6b3f7cSQing Li /* 4526e6b3f7cSQing Li * setup the data structure to notify the kernel 4536e6b3f7cSQing Li * it is the ARP entry the RTM_GET is interested 4546e6b3f7cSQing Li * in 4556e6b3f7cSQing Li */ 4566e6b3f7cSQing Li bzero(&sdl_m, sizeof(sdl_m)); 4576e6b3f7cSQing Li sdl_m.sdl_len = sizeof(sdl_m); 4586e6b3f7cSQing Li sdl_m.sdl_family = AF_LINK; 4596e6b3f7cSQing Li 46068839124SLuigi Rizzo for (;;) { /* try twice */ 4616e6b3f7cSQing Li rtm = rtmsg(RTM_GET, dst, &sdl_m); 462bdf932aeSLuigi Rizzo if (rtm == NULL) { 463c72049e4SPhilippe Charnier warn("%s", host); 464dea673e9SRodney W. Grimes return (1); 465dea673e9SRodney W. Grimes } 4669711a168SGleb Smirnoff addr = (struct sockaddr_in *)(rtm + 1); 4670b46c085SLuigi Rizzo sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr); 4686e6b3f7cSQing Li 4696e6b3f7cSQing Li /* 4706e6b3f7cSQing Li * With the new L2/L3 restructure, the route 4716e6b3f7cSQing Li * returned is a prefix route. The important 4726e6b3f7cSQing Li * piece of information from the previous 4736e6b3f7cSQing Li * RTM_GET is the interface index. In the 4746e6b3f7cSQing Li * case of ECMP, the kernel will traverse 4756e6b3f7cSQing Li * the route group for the given entry. 4766e6b3f7cSQing Li */ 4776e6b3f7cSQing Li if (sdl->sdl_family == AF_LINK && 47868839124SLuigi Rizzo !(rtm->rtm_flags & RTF_GATEWAY) && 4796e6b3f7cSQing Li valid_type(sdl->sdl_type) ) { 4806e6b3f7cSQing Li addr->sin_addr.s_addr = dst->sin_addr.s_addr; 4816e6b3f7cSQing Li break; 4826e6b3f7cSQing Li } 4836e6b3f7cSQing Li 484c7ab6602SQing Li /* 485c7ab6602SQing Li * Regualar entry delete failed, now check if there 486c7ab6602SQing Li * is a proxy-arp entry to remove. 487c7ab6602SQing Li */ 488c7ab6602SQing Li if (flags & RTF_ANNOUNCE) { 48968839124SLuigi Rizzo fprintf(stderr, "delete: cannot locate %s\n",host); 490dea673e9SRodney W. Grimes return (1); 491dea673e9SRodney W. Grimes } 492c7ab6602SQing Li 493c7ab6602SQing Li flags |= RTF_ANNOUNCE; 49468839124SLuigi Rizzo } 4958eca593cSQing Li rtm->rtm_flags |= RTF_LLDATA; 49668839124SLuigi Rizzo if (rtmsg(RTM_DELETE, dst, NULL) != NULL) { 4979d34414bSMike Heffner printf("%s (%s) deleted\n", host, inet_ntoa(addr->sin_addr)); 498a42a667dSPoul-Henning Kamp return (0); 499a42a667dSPoul-Henning Kamp } 500a42a667dSPoul-Henning Kamp return (1); 501dea673e9SRodney W. Grimes } 502dea673e9SRodney W. Grimes 503c7ab6602SQing Li 504dea673e9SRodney W. Grimes /* 5058dc4b495SJulian Elischer * Search the arp table and do some action on matching entries 506dea673e9SRodney W. Grimes */ 507bdf932aeSLuigi Rizzo static int 508bdf932aeSLuigi Rizzo search(u_long addr, action_fn *action) 509dea673e9SRodney W. Grimes { 510dea673e9SRodney W. Grimes int mib[6]; 511dea673e9SRodney W. Grimes size_t needed; 512c34169d4SJohn Baldwin char *lim, *buf, *next; 513dea673e9SRodney W. Grimes struct rt_msghdr *rtm; 5149711a168SGleb Smirnoff struct sockaddr_in *sin2; 515dea673e9SRodney W. Grimes struct sockaddr_dl *sdl; 516b9de94e9SYaroslav Tykhiy char ifname[IF_NAMESIZE]; 51766658902SMaxim Konovalov int st, found_entry = 0; 518dea673e9SRodney W. Grimes 519dea673e9SRodney W. Grimes mib[0] = CTL_NET; 520dea673e9SRodney W. Grimes mib[1] = PF_ROUTE; 521dea673e9SRodney W. Grimes mib[2] = 0; 522dea673e9SRodney W. Grimes mib[3] = AF_INET; 523dea673e9SRodney W. Grimes mib[4] = NET_RT_FLAGS; 5246e6b3f7cSQing Li #ifdef RTF_LLINFO 525dea673e9SRodney W. Grimes mib[5] = RTF_LLINFO; 5266e6b3f7cSQing Li #else 5276e6b3f7cSQing Li mib[5] = 0; 5286e6b3f7cSQing Li #endif 529dea673e9SRodney W. Grimes if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 530e2416749SMaxime Henrion err(1, "route-sysctl-estimate"); 53168839124SLuigi Rizzo if (needed == 0) /* empty table */ 532bdf932aeSLuigi Rizzo return 0; 53366658902SMaxim Konovalov buf = NULL; 53419beed5eSMaxim Konovalov for (;;) { 535c34169d4SJohn Baldwin buf = reallocf(buf, needed); 536c34169d4SJohn Baldwin if (buf == NULL) 53766658902SMaxim Konovalov errx(1, "could not reallocate memory"); 53866658902SMaxim Konovalov st = sysctl(mib, 6, buf, &needed, NULL, 0); 53919beed5eSMaxim Konovalov if (st == 0 || errno != ENOMEM) 54019beed5eSMaxim Konovalov break; 54119beed5eSMaxim Konovalov needed += needed / 8; 54219beed5eSMaxim Konovalov } 54366658902SMaxim Konovalov if (st == -1) 544e2416749SMaxime Henrion err(1, "actual retrieval of routing table"); 545dea673e9SRodney W. Grimes lim = buf + needed; 546dea673e9SRodney W. Grimes for (next = buf; next < lim; next += rtm->rtm_msglen) { 547dea673e9SRodney W. Grimes rtm = (struct rt_msghdr *)next; 5489711a168SGleb Smirnoff sin2 = (struct sockaddr_in *)(rtm + 1); 5491a5ff928SStefan Farfeleder sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2)); 550b9de94e9SYaroslav Tykhiy if (rifname && if_indextoname(sdl->sdl_index, ifname) && 551b9de94e9SYaroslav Tykhiy strcmp(ifname, rifname)) 552b9de94e9SYaroslav Tykhiy continue; 553dea673e9SRodney W. Grimes if (addr) { 5549d34414bSMike Heffner if (addr != sin2->sin_addr.s_addr) 555dea673e9SRodney W. Grimes continue; 556dea673e9SRodney W. Grimes found_entry = 1; 557dea673e9SRodney W. Grimes } 5589d34414bSMike Heffner (*action)(sdl, sin2, rtm); 5598dc4b495SJulian Elischer } 560ae14be20SYaroslav Tykhiy free(buf); 561f3f8b226SRuslan Ermilov return (found_entry); 5628dc4b495SJulian Elischer } 5638dc4b495SJulian Elischer 5648dc4b495SJulian Elischer /* 5658dc4b495SJulian Elischer * Display an arp entry 5668dc4b495SJulian Elischer */ 567e78c7a0aSMax Laier 568bdf932aeSLuigi Rizzo static void 5698dc4b495SJulian Elischer print_entry(struct sockaddr_dl *sdl, 5709711a168SGleb Smirnoff struct sockaddr_in *addr, struct rt_msghdr *rtm) 5718dc4b495SJulian Elischer { 5723f844a22SRuslan Ermilov const char *host; 5738dc4b495SJulian Elischer struct hostent *hp; 57497fe20b4SKelly Yancey struct iso88025_sockaddr_dl_data *trld; 575c1ed96c2SGeorge V. Neville-Neil struct if_nameindex *p; 576fda82fc2SJulian Elischer int seg; 5778dc4b495SJulian Elischer 578c1ed96c2SGeorge V. Neville-Neil if (ifnameindex == NULL) 579c1ed96c2SGeorge V. Neville-Neil if ((ifnameindex = if_nameindex()) == NULL) 580c1ed96c2SGeorge V. Neville-Neil err(1, "cannot retrieve interface names"); 581c1ed96c2SGeorge V. Neville-Neil 582dea673e9SRodney W. Grimes if (nflag == 0) 5839d34414bSMike Heffner hp = gethostbyaddr((caddr_t)&(addr->sin_addr), 5849d34414bSMike Heffner sizeof addr->sin_addr, AF_INET); 585dea673e9SRodney W. Grimes else 586dea673e9SRodney W. Grimes hp = 0; 587dea673e9SRodney W. Grimes if (hp) 588dea673e9SRodney W. Grimes host = hp->h_name; 589dea673e9SRodney W. Grimes else { 590dea673e9SRodney W. Grimes host = "?"; 591dea673e9SRodney W. Grimes if (h_errno == TRY_AGAIN) 592dea673e9SRodney W. Grimes nflag = 1; 593dea673e9SRodney W. Grimes } 5949d34414bSMike Heffner printf("%s (%s) at ", host, inet_ntoa(addr->sin_addr)); 59521816de3SDoug Rabson if (sdl->sdl_alen) { 596596e374dSRuslan Ermilov if ((sdl->sdl_type == IFT_ETHER || 5979af9b983SAndrew Thompson sdl->sdl_type == IFT_L2VLAN || 5989af9b983SAndrew Thompson sdl->sdl_type == IFT_BRIDGE) && 59921816de3SDoug Rabson sdl->sdl_alen == ETHER_ADDR_LEN) 600a03b1b7cSRuslan Ermilov printf("%s", ether_ntoa((struct ether_addr *)LLADDR(sdl))); 60121816de3SDoug Rabson else { 60221816de3SDoug Rabson int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0; 60321816de3SDoug Rabson 60421816de3SDoug Rabson printf("%s", link_ntoa(sdl) + n); 60521816de3SDoug Rabson } 60621816de3SDoug Rabson } else 607dea673e9SRodney W. Grimes printf("(incomplete)"); 608c1ed96c2SGeorge V. Neville-Neil 609c1ed96c2SGeorge V. Neville-Neil for (p = ifnameindex; p && ifnameindex->if_index && 610c1ed96c2SGeorge V. Neville-Neil ifnameindex->if_name; p++) { 611c1ed96c2SGeorge V. Neville-Neil if (p->if_index == sdl->sdl_index) { 612c1ed96c2SGeorge V. Neville-Neil printf(" on %s", p->if_name); 613c1ed96c2SGeorge V. Neville-Neil break; 614c1ed96c2SGeorge V. Neville-Neil } 615c1ed96c2SGeorge V. Neville-Neil } 616c1ed96c2SGeorge V. Neville-Neil 617dea673e9SRodney W. Grimes if (rtm->rtm_rmx.rmx_expire == 0) 618dea673e9SRodney W. Grimes printf(" permanent"); 61992968305SRuslan Ermilov else { 620a98c06f1SGleb Smirnoff static struct timespec tp; 621a98c06f1SGleb Smirnoff if (tp.tv_sec == 0) 622a98c06f1SGleb Smirnoff clock_gettime(CLOCK_MONOTONIC, &tp); 623a98c06f1SGleb Smirnoff if ((expire_time = rtm->rtm_rmx.rmx_expire - tp.tv_sec) > 0) 62492968305SRuslan Ermilov printf(" expires in %d seconds", (int)expire_time); 62592968305SRuslan Ermilov else 62692968305SRuslan Ermilov printf(" expired"); 62792968305SRuslan Ermilov } 6286e6b3f7cSQing Li if (rtm->rtm_flags & RTF_ANNOUNCE) 629dea673e9SRodney W. Grimes printf(" published"); 630fda82fc2SJulian Elischer switch(sdl->sdl_type) { 631fda82fc2SJulian Elischer case IFT_ETHER: 632fda82fc2SJulian Elischer printf(" [ethernet]"); 633fda82fc2SJulian Elischer break; 634fda82fc2SJulian Elischer case IFT_ISO88025: 635fda82fc2SJulian Elischer printf(" [token-ring]"); 63697fe20b4SKelly Yancey trld = SDL_ISO88025(sdl); 63797fe20b4SKelly Yancey if (trld->trld_rcf != 0) { 63897fe20b4SKelly Yancey printf(" rt=%x", ntohs(trld->trld_rcf)); 63997fe20b4SKelly Yancey for (seg = 0; 64097fe20b4SKelly Yancey seg < ((TR_RCF_RIFLEN(trld->trld_rcf) - 2 ) / 2); 64197fe20b4SKelly Yancey seg++) 6422ab778e1SBill Paul printf(":%x", ntohs(*(trld->trld_route[seg]))); 64397fe20b4SKelly Yancey } 644fda82fc2SJulian Elischer break; 64504427472SMatthew N. Dodd case IFT_FDDI: 64604427472SMatthew N. Dodd printf(" [fddi]"); 64704427472SMatthew N. Dodd break; 64804427472SMatthew N. Dodd case IFT_ATM: 64904427472SMatthew N. Dodd printf(" [atm]"); 65004427472SMatthew N. Dodd break; 65188d5b613SYaroslav Tykhiy case IFT_L2VLAN: 65288d5b613SYaroslav Tykhiy printf(" [vlan]"); 65388d5b613SYaroslav Tykhiy break; 65421816de3SDoug Rabson case IFT_IEEE1394: 65521816de3SDoug Rabson printf(" [firewire]"); 65621816de3SDoug Rabson break; 6579af9b983SAndrew Thompson case IFT_BRIDGE: 6589af9b983SAndrew Thompson printf(" [bridge]"); 6599af9b983SAndrew Thompson break; 660595f03feSMark Johnston case IFT_INFINIBAND: 661595f03feSMark Johnston printf(" [infiniband]"); 662595f03feSMark Johnston break; 663fda82fc2SJulian Elischer default: 664123b2d4aSMurray Stokely break; 665fda82fc2SJulian Elischer } 666fda82fc2SJulian Elischer 667dea673e9SRodney W. Grimes printf("\n"); 668fda82fc2SJulian Elischer 669dea673e9SRodney W. Grimes } 6708dc4b495SJulian Elischer 6718dc4b495SJulian Elischer /* 6728dc4b495SJulian Elischer * Nuke an arp entry 6738dc4b495SJulian Elischer */ 674bdf932aeSLuigi Rizzo static void 6759d34414bSMike Heffner nuke_entry(struct sockaddr_dl *sdl __unused, 676*4a336ef4SAlexander V. Chernikov struct sockaddr_in *addr, struct rt_msghdr *rtm) 6778dc4b495SJulian Elischer { 6788dc4b495SJulian Elischer char ip[20]; 6798dc4b495SJulian Elischer 680*4a336ef4SAlexander V. Chernikov if (rtm->rtm_flags & RTF_PINNED) 681*4a336ef4SAlexander V. Chernikov return; 682*4a336ef4SAlexander V. Chernikov 6839d34414bSMike Heffner snprintf(ip, sizeof(ip), "%s", inet_ntoa(addr->sin_addr)); 6849711a168SGleb Smirnoff delete(ip); 685dea673e9SRodney W. Grimes } 686dea673e9SRodney W. Grimes 687bdf932aeSLuigi Rizzo static void 688a42a667dSPoul-Henning Kamp usage(void) 689dea673e9SRodney W. Grimes { 6908dc4b495SJulian Elischer fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 691b9de94e9SYaroslav Tykhiy "usage: arp [-n] [-i interface] hostname", 692b9de94e9SYaroslav Tykhiy " arp [-n] [-i interface] -a", 6933f844a22SRuslan Ermilov " arp -d hostname [pub]", 694582fa422SBrooks Davis " arp -d [-i interface] -a", 6952293dac2STom Rhodes " arp -s hostname ether_addr [temp] [reject | blackhole] [pub [only]]", 6962293dac2STom Rhodes " arp -S hostname ether_addr [temp] [reject | blackhole] [pub [only]]", 697c72049e4SPhilippe Charnier " arp -f filename"); 698dea673e9SRodney W. Grimes exit(1); 699dea673e9SRodney W. Grimes } 700dea673e9SRodney W. Grimes 701bdf932aeSLuigi Rizzo static struct rt_msghdr * 7029711a168SGleb Smirnoff rtmsg(int cmd, struct sockaddr_in *dst, struct sockaddr_dl *sdl) 703dea673e9SRodney W. Grimes { 704dea673e9SRodney W. Grimes static int seq; 705dea673e9SRodney W. Grimes int rlen; 706bdf932aeSLuigi Rizzo int l; 7070c80179cSSam Leffler struct sockaddr_in so_mask, *som = &so_mask; 708bdf932aeSLuigi Rizzo static int s = -1; 709bdf932aeSLuigi Rizzo static pid_t pid; 710bdf932aeSLuigi Rizzo 711bdf932aeSLuigi Rizzo static struct { 712bdf932aeSLuigi Rizzo struct rt_msghdr m_rtm; 713bdf932aeSLuigi Rizzo char m_space[512]; 714bdf932aeSLuigi Rizzo } m_rtmsg; 715bdf932aeSLuigi Rizzo 716e2416749SMaxime Henrion struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 717e2416749SMaxime Henrion char *cp = m_rtmsg.m_space; 718bdf932aeSLuigi Rizzo 719bdf932aeSLuigi Rizzo if (s < 0) { /* first time: open socket, get pid */ 720bdf932aeSLuigi Rizzo s = socket(PF_ROUTE, SOCK_RAW, 0); 721bdf932aeSLuigi Rizzo if (s < 0) 722bdf932aeSLuigi Rizzo err(1, "socket"); 723bdf932aeSLuigi Rizzo pid = getpid(); 724bdf932aeSLuigi Rizzo } 725bdf932aeSLuigi Rizzo bzero(&so_mask, sizeof(so_mask)); 726bdf932aeSLuigi Rizzo so_mask.sin_len = 8; 727bdf932aeSLuigi Rizzo so_mask.sin_addr.s_addr = 0xffffffff; 728dea673e9SRodney W. Grimes 729dea673e9SRodney W. Grimes errno = 0; 73068839124SLuigi Rizzo /* 73168839124SLuigi Rizzo * XXX RTM_DELETE relies on a previous RTM_GET to fill the buffer 73268839124SLuigi Rizzo * appropriately. 73368839124SLuigi Rizzo */ 734dea673e9SRodney W. Grimes if (cmd == RTM_DELETE) 735dea673e9SRodney W. Grimes goto doit; 736dea673e9SRodney W. Grimes bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 737dea673e9SRodney W. Grimes rtm->rtm_flags = flags; 738dea673e9SRodney W. Grimes rtm->rtm_version = RTM_VERSION; 739dea673e9SRodney W. Grimes 740dea673e9SRodney W. Grimes switch (cmd) { 741dea673e9SRodney W. Grimes default: 742c72049e4SPhilippe Charnier errx(1, "internal wrong cmd"); 743dea673e9SRodney W. Grimes case RTM_ADD: 744dea673e9SRodney W. Grimes rtm->rtm_addrs |= RTA_GATEWAY; 745dea673e9SRodney W. Grimes rtm->rtm_rmx.rmx_expire = expire_time; 746dea673e9SRodney W. Grimes rtm->rtm_inits = RTV_EXPIRE; 7478eca593cSQing Li rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA); 748dea673e9SRodney W. Grimes if (doing_proxy) { 749dea673e9SRodney W. Grimes rtm->rtm_addrs |= RTA_NETMASK; 750dea673e9SRodney W. Grimes rtm->rtm_flags &= ~RTF_HOST; 751dea673e9SRodney W. Grimes } 752dea673e9SRodney W. Grimes /* FALLTHROUGH */ 753dea673e9SRodney W. Grimes case RTM_GET: 754dea673e9SRodney W. Grimes rtm->rtm_addrs |= RTA_DST; 755dea673e9SRodney W. Grimes } 756dea673e9SRodney W. Grimes #define NEXTADDR(w, s) \ 757be5d11dcSDag-Erling Smørgrav do { \ 758f3f8b226SRuslan Ermilov if ((s) != NULL && rtm->rtm_addrs & (w)) { \ 759be5d11dcSDag-Erling Smørgrav bcopy((s), cp, sizeof(*(s))); \ 760be5d11dcSDag-Erling Smørgrav cp += SA_SIZE(s); \ 761be5d11dcSDag-Erling Smørgrav } \ 762be5d11dcSDag-Erling Smørgrav } while (0) 763dea673e9SRodney W. Grimes 76468839124SLuigi Rizzo NEXTADDR(RTA_DST, dst); 76568839124SLuigi Rizzo NEXTADDR(RTA_GATEWAY, sdl); 7660c80179cSSam Leffler NEXTADDR(RTA_NETMASK, som); 767dea673e9SRodney W. Grimes 768dea673e9SRodney W. Grimes rtm->rtm_msglen = cp - (char *)&m_rtmsg; 769dea673e9SRodney W. Grimes doit: 770dea673e9SRodney W. Grimes l = rtm->rtm_msglen; 771dea673e9SRodney W. Grimes rtm->rtm_seq = ++seq; 772dea673e9SRodney W. Grimes rtm->rtm_type = cmd; 773dea673e9SRodney W. Grimes if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 774dea673e9SRodney W. Grimes if (errno != ESRCH || cmd != RTM_DELETE) { 775c72049e4SPhilippe Charnier warn("writing to routing socket"); 776f3f8b226SRuslan Ermilov return (NULL); 777dea673e9SRodney W. Grimes } 778dea673e9SRodney W. Grimes } 779dea673e9SRodney W. Grimes do { 780dea673e9SRodney W. Grimes l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 781dea673e9SRodney W. Grimes } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid)); 782dea673e9SRodney W. Grimes if (l < 0) 783c72049e4SPhilippe Charnier warn("read from routing socket"); 784f3f8b226SRuslan Ermilov return (rtm); 785dea673e9SRodney W. Grimes } 786dea673e9SRodney W. Grimes 787a42a667dSPoul-Henning Kamp /* 788a42a667dSPoul-Henning Kamp * get_ether_addr - get the hardware address of an interface on the 789a42a667dSPoul-Henning Kamp * the same subnet as ipaddr. 790a42a667dSPoul-Henning Kamp */ 791a42a667dSPoul-Henning Kamp #define MAX_IFS 32 792a42a667dSPoul-Henning Kamp 793bdf932aeSLuigi Rizzo static int 794f3f8b226SRuslan Ermilov get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr) 795a42a667dSPoul-Henning Kamp { 796a42a667dSPoul-Henning Kamp struct ifreq *ifr, *ifend, *ifp; 797f3f8b226SRuslan Ermilov in_addr_t ina, mask; 798a42a667dSPoul-Henning Kamp struct sockaddr_dl *dla; 799a42a667dSPoul-Henning Kamp struct ifreq ifreq; 800a42a667dSPoul-Henning Kamp struct ifconf ifc; 801a42a667dSPoul-Henning Kamp struct ifreq ifs[MAX_IFS]; 8029d34414bSMike Heffner int sock; 80368839124SLuigi Rizzo int retval = 0; 804a42a667dSPoul-Henning Kamp 8059d34414bSMike Heffner sock = socket(AF_INET, SOCK_DGRAM, 0); 8069d34414bSMike Heffner if (sock < 0) 807c72049e4SPhilippe Charnier err(1, "socket"); 808a42a667dSPoul-Henning Kamp 809a42a667dSPoul-Henning Kamp ifc.ifc_len = sizeof(ifs); 810a42a667dSPoul-Henning Kamp ifc.ifc_req = ifs; 8119cc7cb58SMike Heffner if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { 812c72049e4SPhilippe Charnier warnx("ioctl(SIOCGIFCONF)"); 81368839124SLuigi Rizzo goto done; 814a42a667dSPoul-Henning Kamp } 815a42a667dSPoul-Henning Kamp 81668839124SLuigi Rizzo #define NEXTIFR(i) \ 81768839124SLuigi Rizzo ((struct ifreq *)((char *)&(i)->ifr_addr \ 81868839124SLuigi Rizzo + MAX((i)->ifr_addr.sa_len, sizeof((i)->ifr_addr))) ) 81968839124SLuigi Rizzo 820a42a667dSPoul-Henning Kamp /* 821a42a667dSPoul-Henning Kamp * Scan through looking for an interface with an Internet 822a42a667dSPoul-Henning Kamp * address on the same subnet as `ipaddr'. 823a42a667dSPoul-Henning Kamp */ 824a42a667dSPoul-Henning Kamp ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len); 82568839124SLuigi Rizzo for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr) ) { 82668839124SLuigi Rizzo if (ifr->ifr_addr.sa_family != AF_INET) 82768839124SLuigi Rizzo continue; 828a42a667dSPoul-Henning Kamp strncpy(ifreq.ifr_name, ifr->ifr_name, 829a42a667dSPoul-Henning Kamp sizeof(ifreq.ifr_name)); 83006274ceeSGleb Smirnoff ifreq.ifr_addr = ifr->ifr_addr; 831a42a667dSPoul-Henning Kamp /* 832a42a667dSPoul-Henning Kamp * Check that the interface is up, 833a42a667dSPoul-Henning Kamp * and not point-to-point or loopback. 834a42a667dSPoul-Henning Kamp */ 8359cc7cb58SMike Heffner if (ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0) 836a42a667dSPoul-Henning Kamp continue; 837a42a667dSPoul-Henning Kamp if ((ifreq.ifr_flags & 838a42a667dSPoul-Henning Kamp (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT| 839a42a667dSPoul-Henning Kamp IFF_LOOPBACK|IFF_NOARP)) 840a42a667dSPoul-Henning Kamp != (IFF_UP|IFF_BROADCAST)) 84168839124SLuigi Rizzo continue; 842a42a667dSPoul-Henning Kamp /* 843a42a667dSPoul-Henning Kamp * Get its netmask and check that it's on 844a42a667dSPoul-Henning Kamp * the right subnet. 845a42a667dSPoul-Henning Kamp */ 8469cc7cb58SMike Heffner if (ioctl(sock, SIOCGIFNETMASK, &ifreq) < 0) 847a42a667dSPoul-Henning Kamp continue; 848a42a667dSPoul-Henning Kamp mask = ((struct sockaddr_in *) 849a42a667dSPoul-Henning Kamp &ifreq.ifr_addr)->sin_addr.s_addr; 85068839124SLuigi Rizzo ina = ((struct sockaddr_in *) 85168839124SLuigi Rizzo &ifr->ifr_addr)->sin_addr.s_addr; 85268839124SLuigi Rizzo if ((ipaddr & mask) == (ina & mask)) 85368839124SLuigi Rizzo break; /* ok, we got it! */ 854a42a667dSPoul-Henning Kamp } 855a42a667dSPoul-Henning Kamp 85668839124SLuigi Rizzo if (ifr >= ifend) 85768839124SLuigi Rizzo goto done; 858a42a667dSPoul-Henning Kamp 859a42a667dSPoul-Henning Kamp /* 860a42a667dSPoul-Henning Kamp * Now scan through again looking for a link-level address 861a42a667dSPoul-Henning Kamp * for this interface. 862a42a667dSPoul-Henning Kamp */ 863a42a667dSPoul-Henning Kamp ifp = ifr; 86468839124SLuigi Rizzo for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr)) 86568839124SLuigi Rizzo if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 && 86668839124SLuigi Rizzo ifr->ifr_addr.sa_family == AF_LINK) 86768839124SLuigi Rizzo break; 86868839124SLuigi Rizzo if (ifr >= ifend) 86968839124SLuigi Rizzo goto done; 870a42a667dSPoul-Henning Kamp /* 871a42a667dSPoul-Henning Kamp * Found the link-level address - copy it out 872a42a667dSPoul-Henning Kamp */ 873a42a667dSPoul-Henning Kamp dla = (struct sockaddr_dl *) &ifr->ifr_addr; 874a42a667dSPoul-Henning Kamp memcpy(hwaddr, LLADDR(dla), dla->sdl_alen); 875a42a667dSPoul-Henning Kamp printf("using interface %s for proxy with address ", 876a42a667dSPoul-Henning Kamp ifp->ifr_name); 877a03b1b7cSRuslan Ermilov printf("%s\n", ether_ntoa(hwaddr)); 87868839124SLuigi Rizzo retval = dla->sdl_alen; 87968839124SLuigi Rizzo done: 88068839124SLuigi Rizzo close(sock); 881f3f8b226SRuslan Ermilov return (retval); 882a42a667dSPoul-Henning Kamp } 883