1*8a16b7a1SPedro F. Giffuni /*- 2*8a16b7a1SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 3*8a16b7a1SPedro F. Giffuni * 4dea673e9SRodney W. Grimes * Copyright (c) 1984, 1993 5dea673e9SRodney W. Grimes * The Regents of the University of California. All rights reserved. 6dea673e9SRodney W. Grimes * 7dea673e9SRodney W. Grimes * This code is derived from software contributed to Berkeley by 8dea673e9SRodney W. Grimes * Sun Microsystems, Inc. 9dea673e9SRodney W. Grimes * 10dea673e9SRodney W. Grimes * Redistribution and use in source and binary forms, with or without 11dea673e9SRodney W. Grimes * modification, are permitted provided that the following conditions 12dea673e9SRodney W. Grimes * are met: 13dea673e9SRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 14dea673e9SRodney W. Grimes * notice, this list of conditions and the following disclaimer. 15dea673e9SRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 16dea673e9SRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 17dea673e9SRodney W. Grimes * documentation and/or other materials provided with the distribution. 18fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 19dea673e9SRodney W. Grimes * may be used to endorse or promote products derived from this software 20dea673e9SRodney W. Grimes * without specific prior written permission. 21dea673e9SRodney W. Grimes * 22dea673e9SRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23dea673e9SRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24dea673e9SRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25dea673e9SRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26dea673e9SRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27dea673e9SRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28dea673e9SRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29dea673e9SRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30dea673e9SRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31dea673e9SRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32dea673e9SRodney W. Grimes * SUCH DAMAGE. 33dea673e9SRodney W. Grimes */ 34dea673e9SRodney W. Grimes 35b728350eSDavid E. O'Brien #if 0 36dea673e9SRodney W. Grimes #ifndef lint 37a42a667dSPoul-Henning Kamp static char const copyright[] = 38dea673e9SRodney W. Grimes "@(#) Copyright (c) 1984, 1993\n\ 39dea673e9SRodney W. Grimes The Regents of the University of California. All rights reserved.\n"; 40dea673e9SRodney W. Grimes #endif /* not lint */ 41dea673e9SRodney W. Grimes 42dea673e9SRodney W. Grimes #ifndef lint 43a42a667dSPoul-Henning Kamp static char const sccsid[] = "@(#)from: arp.c 8.2 (Berkeley) 1/2/94"; 44dea673e9SRodney W. Grimes #endif /* not lint */ 45b728350eSDavid E. O'Brien #endif 46b728350eSDavid E. O'Brien #include <sys/cdefs.h> 47b728350eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 48dea673e9SRodney W. Grimes 49dea673e9SRodney W. Grimes /* 50dea673e9SRodney W. Grimes * arp - display, set, and delete arp table entries 51dea673e9SRodney W. Grimes */ 52dea673e9SRodney W. Grimes 53dea673e9SRodney W. Grimes #include <sys/param.h> 54dea673e9SRodney W. Grimes #include <sys/file.h> 55dea673e9SRodney W. Grimes #include <sys/socket.h> 56a42a667dSPoul-Henning Kamp #include <sys/sockio.h> 57dea673e9SRodney W. Grimes #include <sys/sysctl.h> 58a42a667dSPoul-Henning Kamp #include <sys/ioctl.h> 59628d2ac1SGarrett Wollman #include <sys/time.h> 60dea673e9SRodney W. Grimes 61dea673e9SRodney W. Grimes #include <net/if.h> 62dea673e9SRodney W. Grimes #include <net/if_dl.h> 63dea673e9SRodney W. Grimes #include <net/if_types.h> 64dea673e9SRodney W. Grimes #include <net/route.h> 652ab778e1SBill Paul #include <net/iso88025.h> 66dea673e9SRodney W. Grimes 67dea673e9SRodney W. Grimes #include <netinet/in.h> 68dea673e9SRodney W. Grimes #include <netinet/if_ether.h> 69dea673e9SRodney W. Grimes 70dea673e9SRodney W. Grimes #include <arpa/inet.h> 71dea673e9SRodney W. Grimes 7244acbc1aSRuslan Ermilov #include <ctype.h> 73c72049e4SPhilippe Charnier #include <err.h> 74dea673e9SRodney W. Grimes #include <errno.h> 75c72049e4SPhilippe Charnier #include <netdb.h> 76dea673e9SRodney W. Grimes #include <nlist.h> 77c72049e4SPhilippe Charnier #include <paths.h> 78dea673e9SRodney W. Grimes #include <stdio.h> 79a42a667dSPoul-Henning Kamp #include <stdlib.h> 80467a0b06SMike Barcroft #include <string.h> 81a42a667dSPoul-Henning Kamp #include <strings.h> 82c72049e4SPhilippe Charnier #include <unistd.h> 83a2ac74c1SRenato Botelho #include <libxo/xo.h> 84dea673e9SRodney W. Grimes 8504ae8c64SRenato Botelho typedef void (action_fn)(struct sockaddr_dl *sdl, struct sockaddr_in *s_in, 8604ae8c64SRenato Botelho struct rt_msghdr *rtm); 87a42a667dSPoul-Henning Kamp 88bdf932aeSLuigi Rizzo static int search(u_long addr, action_fn *action); 89bdf932aeSLuigi Rizzo static action_fn print_entry; 90bdf932aeSLuigi Rizzo static action_fn nuke_entry; 91bdf932aeSLuigi Rizzo 929711a168SGleb Smirnoff static int delete(char *host); 93bdf932aeSLuigi Rizzo static void usage(void); 94bdf932aeSLuigi Rizzo static int set(int argc, char **argv); 95f3f8b226SRuslan Ermilov static int get(char *host); 96bdf932aeSLuigi Rizzo static int file(char *name); 9768839124SLuigi Rizzo static struct rt_msghdr *rtmsg(int cmd, 989711a168SGleb Smirnoff struct sockaddr_in *dst, struct sockaddr_dl *sdl); 99f3f8b226SRuslan Ermilov static int get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr); 1009711a168SGleb Smirnoff static struct sockaddr_in *getaddr(char *host); 101f3f8b226SRuslan Ermilov static int valid_type(int type); 102bdf932aeSLuigi Rizzo 1038dc4b495SJulian Elischer static int nflag; /* no reverse dns lookups */ 104b9de94e9SYaroslav Tykhiy static char *rifname; 105dea673e9SRodney W. Grimes 10692968305SRuslan Ermilov static time_t expire_time; 1079711a168SGleb Smirnoff static int flags, doing_proxy; 10868839124SLuigi Rizzo 109c1ed96c2SGeorge V. Neville-Neil struct if_nameindex *ifnameindex; 110c1ed96c2SGeorge V. Neville-Neil 1118dc4b495SJulian Elischer /* which function we're supposed to do */ 1128dc4b495SJulian Elischer #define F_GET 1 1138dc4b495SJulian Elischer #define F_SET 2 1148dc4b495SJulian Elischer #define F_FILESET 3 1158dc4b495SJulian Elischer #define F_REPLACE 4 1168dc4b495SJulian Elischer #define F_DELETE 5 1178dc4b495SJulian Elischer 1188dc4b495SJulian Elischer #define SETFUNC(f) { if (func) usage(); func = (f); } 1198dc4b495SJulian Elischer 120a2ac74c1SRenato Botelho #define ARP_XO_VERSION "1" 121a2ac74c1SRenato Botelho 122a42a667dSPoul-Henning Kamp int 1233f844a22SRuslan Ermilov main(int argc, char *argv[]) 124dea673e9SRodney W. Grimes { 1258dc4b495SJulian Elischer int ch, func = 0; 1268dc4b495SJulian Elischer int rtn = 0; 127bdf932aeSLuigi Rizzo int aflag = 0; /* do it for all entries */ 128dea673e9SRodney W. Grimes 129a2ac74c1SRenato Botelho argc = xo_parse_args(argc, argv); 130a2ac74c1SRenato Botelho if (argc < 0) 131a2ac74c1SRenato Botelho exit(1); 132a2ac74c1SRenato Botelho 133b9de94e9SYaroslav Tykhiy while ((ch = getopt(argc, argv, "andfsSi:")) != -1) 134eac295c9SRemko Lodder switch(ch) { 135dea673e9SRodney W. Grimes case 'a': 1368dc4b495SJulian Elischer aflag = 1; 1378dc4b495SJulian Elischer break; 138dea673e9SRodney W. Grimes case 'd': 1398dc4b495SJulian Elischer SETFUNC(F_DELETE); 1408dc4b495SJulian Elischer break; 141dea673e9SRodney W. Grimes case 'n': 142dea673e9SRodney W. Grimes nflag = 1; 1438dc4b495SJulian Elischer break; 144a42a667dSPoul-Henning Kamp case 'S': 1458dc4b495SJulian Elischer SETFUNC(F_REPLACE); 1468dc4b495SJulian Elischer break; 147dea673e9SRodney W. Grimes case 's': 1488dc4b495SJulian Elischer SETFUNC(F_SET); 1498dc4b495SJulian Elischer break; 15095319e17SJordan K. Hubbard case 'f' : 1518dc4b495SJulian Elischer SETFUNC(F_FILESET); 1528dc4b495SJulian Elischer break; 153b9de94e9SYaroslav Tykhiy case 'i': 154b9de94e9SYaroslav Tykhiy rifname = optarg; 155b9de94e9SYaroslav Tykhiy break; 156dea673e9SRodney W. Grimes case '?': 157dea673e9SRodney W. Grimes default: 158dea673e9SRodney W. Grimes usage(); 159dea673e9SRodney W. Grimes } 1608dc4b495SJulian Elischer argc -= optind; 1618dc4b495SJulian Elischer argv += optind; 1628dc4b495SJulian Elischer 1638dc4b495SJulian Elischer if (!func) 1648dc4b495SJulian Elischer func = F_GET; 165b9de94e9SYaroslav Tykhiy if (rifname) { 16608369852SBrooks Davis if (func != F_GET && !(func == F_DELETE && aflag)) 167a2ac74c1SRenato Botelho xo_errx(1, "-i not applicable to this operation"); 168b9de94e9SYaroslav Tykhiy if (if_nametoindex(rifname) == 0) { 169b9de94e9SYaroslav Tykhiy if (errno == ENXIO) 170a2ac74c1SRenato Botelho xo_errx(1, "interface %s does not exist", 171a2ac74c1SRenato Botelho rifname); 172b9de94e9SYaroslav Tykhiy else 173a2ac74c1SRenato Botelho xo_err(1, "if_nametoindex(%s)", rifname); 174b9de94e9SYaroslav Tykhiy } 175b9de94e9SYaroslav Tykhiy } 1768dc4b495SJulian Elischer switch (func) { 1778dc4b495SJulian Elischer case F_GET: 1788dc4b495SJulian Elischer if (aflag) { 1798dc4b495SJulian Elischer if (argc != 0) 180dea673e9SRodney W. Grimes usage(); 181a2ac74c1SRenato Botelho 182a2ac74c1SRenato Botelho xo_set_version(ARP_XO_VERSION); 183a2ac74c1SRenato Botelho xo_open_container("arp"); 184a2ac74c1SRenato Botelho xo_open_list("arp-cache"); 185a2ac74c1SRenato Botelho 1868dc4b495SJulian Elischer search(0, print_entry); 187a2ac74c1SRenato Botelho 188a2ac74c1SRenato Botelho xo_close_list("arp-cache"); 189a2ac74c1SRenato Botelho xo_close_container("arp"); 190a2ac74c1SRenato Botelho xo_finish(); 1918dc4b495SJulian Elischer } else { 1928dc4b495SJulian Elischer if (argc != 1) 1938dc4b495SJulian Elischer usage(); 194f3f8b226SRuslan Ermilov rtn = get(argv[0]); 1958dc4b495SJulian Elischer } 1968dc4b495SJulian Elischer break; 1978dc4b495SJulian Elischer case F_SET: 1988dc4b495SJulian Elischer case F_REPLACE: 1993f844a22SRuslan Ermilov if (argc < 2 || argc > 6) 2008dc4b495SJulian Elischer usage(); 2018dc4b495SJulian Elischer if (func == F_REPLACE) 2029711a168SGleb Smirnoff (void)delete(argv[0]); 2038dc4b495SJulian Elischer rtn = set(argc, argv) ? 1 : 0; 2048dc4b495SJulian Elischer break; 2058dc4b495SJulian Elischer case F_DELETE: 2068dc4b495SJulian Elischer if (aflag) { 2078dc4b495SJulian Elischer if (argc != 0) 2088dc4b495SJulian Elischer usage(); 2098dc4b495SJulian Elischer search(0, nuke_entry); 210876fc15dSGleb Smirnoff } else { 211876fc15dSGleb Smirnoff if (argc != 1) 212876fc15dSGleb Smirnoff usage(); 2139711a168SGleb Smirnoff rtn = delete(argv[0]); 214876fc15dSGleb Smirnoff } 2158dc4b495SJulian Elischer break; 2168dc4b495SJulian Elischer case F_FILESET: 2178dc4b495SJulian Elischer if (argc != 1) 2188dc4b495SJulian Elischer usage(); 2198dc4b495SJulian Elischer rtn = file(argv[0]); 2208dc4b495SJulian Elischer break; 2218dc4b495SJulian Elischer } 2228dc4b495SJulian Elischer 223c1ed96c2SGeorge V. Neville-Neil if (ifnameindex != NULL) 224c1ed96c2SGeorge V. Neville-Neil if_freenameindex(ifnameindex); 225c1ed96c2SGeorge V. Neville-Neil 2268dc4b495SJulian Elischer return (rtn); 227dea673e9SRodney W. Grimes } 228dea673e9SRodney W. Grimes 229dea673e9SRodney W. Grimes /* 230dea673e9SRodney W. Grimes * Process a file to set standard arp entries 231dea673e9SRodney W. Grimes */ 232bdf932aeSLuigi Rizzo static int 233a42a667dSPoul-Henning Kamp file(char *name) 234dea673e9SRodney W. Grimes { 235dea673e9SRodney W. Grimes FILE *fp; 236dea673e9SRodney W. Grimes int i, retval; 2373adcd042SRuslan Ermilov char line[100], arg[5][50], *args[5], *p; 238dea673e9SRodney W. Grimes 239c72049e4SPhilippe Charnier if ((fp = fopen(name, "r")) == NULL) 240a2ac74c1SRenato Botelho xo_err(1, "cannot open %s", name); 241dea673e9SRodney W. Grimes args[0] = &arg[0][0]; 242dea673e9SRodney W. Grimes args[1] = &arg[1][0]; 243dea673e9SRodney W. Grimes args[2] = &arg[2][0]; 244dea673e9SRodney W. Grimes args[3] = &arg[3][0]; 245dea673e9SRodney W. Grimes args[4] = &arg[4][0]; 246dea673e9SRodney W. Grimes retval = 0; 247d0691403SKevin Lo while(fgets(line, sizeof(line), fp) != NULL) { 2483adcd042SRuslan Ermilov if ((p = strchr(line, '#')) != NULL) 2493adcd042SRuslan Ermilov *p = '\0'; 2503adcd042SRuslan Ermilov for (p = line; isblank(*p); p++); 2514bfc3624SRuslan Ermilov if (*p == '\n' || *p == '\0') 25244acbc1aSRuslan Ermilov continue; 2533adcd042SRuslan Ermilov i = sscanf(p, "%49s %49s %49s %49s %49s", arg[0], arg[1], 254135adb1eSJordan K. Hubbard arg[2], arg[3], arg[4]); 255dea673e9SRodney W. Grimes if (i < 2) { 256a2ac74c1SRenato Botelho xo_warnx("bad line: %s", line); 257dea673e9SRodney W. Grimes retval = 1; 258dea673e9SRodney W. Grimes continue; 259dea673e9SRodney W. Grimes } 260dea673e9SRodney W. Grimes if (set(i, args)) 261dea673e9SRodney W. Grimes retval = 1; 262dea673e9SRodney W. Grimes } 263dea673e9SRodney W. Grimes fclose(fp); 264dea673e9SRodney W. Grimes return (retval); 265dea673e9SRodney W. Grimes } 266dea673e9SRodney W. Grimes 267dea673e9SRodney W. Grimes /* 2689711a168SGleb Smirnoff * Given a hostname, fills up a (static) struct sockaddr_in with 26968839124SLuigi Rizzo * the address of the host and returns a pointer to the 27068839124SLuigi Rizzo * structure. 271dea673e9SRodney W. Grimes */ 2729711a168SGleb Smirnoff static struct sockaddr_in * 27368839124SLuigi Rizzo getaddr(char *host) 274dea673e9SRodney W. Grimes { 275dea673e9SRodney W. Grimes struct hostent *hp; 2769711a168SGleb Smirnoff static struct sockaddr_in reply; 27768839124SLuigi Rizzo 27868839124SLuigi Rizzo bzero(&reply, sizeof(reply)); 27968839124SLuigi Rizzo reply.sin_len = sizeof(reply); 28068839124SLuigi Rizzo reply.sin_family = AF_INET; 28168839124SLuigi Rizzo reply.sin_addr.s_addr = inet_addr(host); 28268839124SLuigi Rizzo if (reply.sin_addr.s_addr == INADDR_NONE) { 28368839124SLuigi Rizzo if (!(hp = gethostbyname(host))) { 284a2ac74c1SRenato Botelho xo_warnx("%s: %s", host, hstrerror(h_errno)); 285f3f8b226SRuslan Ermilov return (NULL); 28668839124SLuigi Rizzo } 28768839124SLuigi Rizzo bcopy((char *)hp->h_addr, (char *)&reply.sin_addr, 28868839124SLuigi Rizzo sizeof reply.sin_addr); 28968839124SLuigi Rizzo } 290f3f8b226SRuslan Ermilov return (&reply); 29168839124SLuigi Rizzo } 29268839124SLuigi Rizzo 29368839124SLuigi Rizzo /* 294f3f8b226SRuslan Ermilov * Returns true if the type is a valid one for ARP. 29568839124SLuigi Rizzo */ 29668839124SLuigi Rizzo static int 29768839124SLuigi Rizzo valid_type(int type) 29868839124SLuigi Rizzo { 299f3f8b226SRuslan Ermilov 30068839124SLuigi Rizzo switch (type) { 30168839124SLuigi Rizzo case IFT_ETHER: 30268839124SLuigi Rizzo case IFT_FDDI: 303595f03feSMark Johnston case IFT_INFINIBAND: 30468839124SLuigi Rizzo case IFT_ISO88023: 30568839124SLuigi Rizzo case IFT_ISO88024: 30668839124SLuigi Rizzo case IFT_ISO88025: 30768839124SLuigi Rizzo case IFT_L2VLAN: 3089af9b983SAndrew Thompson case IFT_BRIDGE: 309f3f8b226SRuslan Ermilov return (1); 310f3f8b226SRuslan Ermilov default: 311f3f8b226SRuslan Ermilov return (0); 31268839124SLuigi Rizzo } 31368839124SLuigi Rizzo } 31468839124SLuigi Rizzo 31568839124SLuigi Rizzo /* 31668839124SLuigi Rizzo * Set an individual arp entry 31768839124SLuigi Rizzo */ 31868839124SLuigi Rizzo static int 31968839124SLuigi Rizzo set(int argc, char **argv) 32068839124SLuigi Rizzo { 3219711a168SGleb Smirnoff struct sockaddr_in *addr; 3229711a168SGleb Smirnoff struct sockaddr_in *dst; /* what are we looking for */ 323e2416749SMaxime Henrion struct sockaddr_dl *sdl; 324bdf932aeSLuigi Rizzo struct rt_msghdr *rtm; 325a03b1b7cSRuslan Ermilov struct ether_addr *ea; 326dea673e9SRodney W. Grimes char *host = argv[0], *eaddr = argv[1]; 32768839124SLuigi Rizzo struct sockaddr_dl sdl_m; 328dea673e9SRodney W. Grimes 329dea673e9SRodney W. Grimes argc -= 2; 330dea673e9SRodney W. Grimes argv += 2; 331bdf932aeSLuigi Rizzo 332bdf932aeSLuigi Rizzo bzero(&sdl_m, sizeof(sdl_m)); 333bdf932aeSLuigi Rizzo sdl_m.sdl_len = sizeof(sdl_m); 334bdf932aeSLuigi Rizzo sdl_m.sdl_family = AF_LINK; 335bdf932aeSLuigi Rizzo 33668839124SLuigi Rizzo dst = getaddr(host); 33768839124SLuigi Rizzo if (dst == NULL) 338dea673e9SRodney W. Grimes return (1); 3399711a168SGleb Smirnoff doing_proxy = flags = expire_time = 0; 340dea673e9SRodney W. Grimes while (argc-- > 0) { 3417814b3b8SRenato Botelho if (strcmp(argv[0], "temp") == 0) { 3425d067f6cSGleb Smirnoff struct timespec tp; 34384d8f5b8SGleb Smirnoff int max_age; 34484d8f5b8SGleb Smirnoff size_t len = sizeof(max_age); 34584d8f5b8SGleb Smirnoff 3465d067f6cSGleb Smirnoff clock_gettime(CLOCK_MONOTONIC, &tp); 34784d8f5b8SGleb Smirnoff if (sysctlbyname("net.link.ether.inet.max_age", 34884d8f5b8SGleb Smirnoff &max_age, &len, NULL, 0) != 0) 349a2ac74c1SRenato Botelho xo_err(1, "sysctlbyname"); 35084d8f5b8SGleb Smirnoff expire_time = tp.tv_sec + max_age; 3517814b3b8SRenato Botelho } else if (strcmp(argv[0], "pub") == 0) { 352dea673e9SRodney W. Grimes flags |= RTF_ANNOUNCE; 3533f844a22SRuslan Ermilov doing_proxy = 1; 3547814b3b8SRenato Botelho if (argc && strcmp(argv[1], "only") == 0) { 3559711a168SGleb Smirnoff /* 3569711a168SGleb Smirnoff * Compatibility: in pre FreeBSD 8 times 3579711a168SGleb Smirnoff * the "only" keyword used to mean that 3589711a168SGleb Smirnoff * an ARP entry should be announced, but 3599711a168SGleb Smirnoff * not installed into routing table. 3609711a168SGleb Smirnoff */ 3613f844a22SRuslan Ermilov argc--; argv++; 3623f844a22SRuslan Ermilov } 3637814b3b8SRenato Botelho } else if (strcmp(argv[0], "blackhole") == 0) { 3642293dac2STom Rhodes if (flags & RTF_REJECT) { 365a2ac74c1SRenato Botelho xo_errx(1, "Choose one of blackhole or reject, " 36604ae8c64SRenato Botelho "not both."); 3672293dac2STom Rhodes } 368e653f1f0SSam Leffler flags |= RTF_BLACKHOLE; 3697814b3b8SRenato Botelho } else if (strcmp(argv[0], "reject") == 0) { 3702293dac2STom Rhodes if (flags & RTF_BLACKHOLE) { 371a2ac74c1SRenato Botelho xo_errx(1, "Choose one of blackhole or reject, " 37204ae8c64SRenato Botelho "not both."); 3732293dac2STom Rhodes } 374e653f1f0SSam Leffler flags |= RTF_REJECT; 3757814b3b8SRenato Botelho } else { 376a2ac74c1SRenato Botelho xo_warnx("Invalid parameter '%s'", argv[0]); 3777814b3b8SRenato Botelho usage(); 378dea673e9SRodney W. Grimes } 379dea673e9SRodney W. Grimes argv++; 380dea673e9SRodney W. Grimes } 381a03b1b7cSRuslan Ermilov ea = (struct ether_addr *)LLADDR(&sdl_m); 382a42a667dSPoul-Henning Kamp if (doing_proxy && !strcmp(eaddr, "auto")) { 38368839124SLuigi Rizzo if (!get_ether_addr(dst->sin_addr.s_addr, ea)) { 384a2ac74c1SRenato Botelho xo_warnx("no interface found for %s", 38568839124SLuigi Rizzo inet_ntoa(dst->sin_addr)); 386a42a667dSPoul-Henning Kamp return (1); 387a42a667dSPoul-Henning Kamp } 388a03b1b7cSRuslan Ermilov sdl_m.sdl_alen = ETHER_ADDR_LEN; 389a42a667dSPoul-Henning Kamp } else { 39068839124SLuigi Rizzo struct ether_addr *ea1 = ether_aton(eaddr); 39168839124SLuigi Rizzo 392a47c388cSGleb Smirnoff if (ea1 == NULL) { 393a2ac74c1SRenato Botelho xo_warnx("invalid Ethernet address '%s'", eaddr); 394a47c388cSGleb Smirnoff return (1); 395a47c388cSGleb Smirnoff } else { 39668839124SLuigi Rizzo *ea = *ea1; 397a03b1b7cSRuslan Ermilov sdl_m.sdl_alen = ETHER_ADDR_LEN; 398a42a667dSPoul-Henning Kamp } 39968839124SLuigi Rizzo } 400c7ab6602SQing Li 401c7ab6602SQing Li /* 402c7ab6602SQing Li * In the case a proxy-arp entry is being added for 403c7ab6602SQing Li * a remote end point, the RTF_ANNOUNCE flag in the 404c7ab6602SQing Li * RTM_GET command is an indication to the kernel 405c7ab6602SQing Li * routing code that the interface associated with 406c7ab6602SQing Li * the prefix route covering the local end of the 407c7ab6602SQing Li * PPP link should be returned, on which ARP applies. 408c7ab6602SQing Li */ 4092f8c6c0aSPatrick Kelsey rtm = rtmsg(RTM_GET, dst, NULL); 410bdf932aeSLuigi Rizzo if (rtm == NULL) { 411a2ac74c1SRenato Botelho xo_warn("%s", host); 412dea673e9SRodney W. Grimes return (1); 413dea673e9SRodney W. Grimes } 4149711a168SGleb Smirnoff addr = (struct sockaddr_in *)(rtm + 1); 4150b46c085SLuigi Rizzo sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr); 41668839124SLuigi Rizzo 417c7ab6602SQing Li if ((sdl->sdl_family != AF_LINK) || 418c7ab6602SQing Li (rtm->rtm_flags & RTF_GATEWAY) || 419c7ab6602SQing Li !valid_type(sdl->sdl_type)) { 420a2ac74c1SRenato Botelho xo_warnx("cannot intuit interface index and type for %s", host); 421dea673e9SRodney W. Grimes return (1); 422dea673e9SRodney W. Grimes } 423dea673e9SRodney W. Grimes sdl_m.sdl_type = sdl->sdl_type; 424dea673e9SRodney W. Grimes sdl_m.sdl_index = sdl->sdl_index; 425cf779589SGleb Smirnoff return (rtmsg(RTM_ADD, dst, &sdl_m) == NULL); 426dea673e9SRodney W. Grimes } 427dea673e9SRodney W. Grimes 428dea673e9SRodney W. Grimes /* 429dea673e9SRodney W. Grimes * Display an individual arp entry 430dea673e9SRodney W. Grimes */ 431f3f8b226SRuslan Ermilov static int 432a42a667dSPoul-Henning Kamp get(char *host) 433dea673e9SRodney W. Grimes { 4349711a168SGleb Smirnoff struct sockaddr_in *addr; 435a2ac74c1SRenato Botelho int found; 436dea673e9SRodney W. Grimes 43768839124SLuigi Rizzo addr = getaddr(host); 43868839124SLuigi Rizzo if (addr == NULL) 439f3f8b226SRuslan Ermilov return (1); 440a2ac74c1SRenato Botelho 441a2ac74c1SRenato Botelho xo_set_version(ARP_XO_VERSION); 442a2ac74c1SRenato Botelho xo_open_container("arp"); 443a2ac74c1SRenato Botelho xo_open_list("arp-cache"); 444a2ac74c1SRenato Botelho 445a2ac74c1SRenato Botelho found = search(addr->sin_addr.s_addr, print_entry); 446a2ac74c1SRenato Botelho 447a2ac74c1SRenato Botelho if (found == 0) { 448a2ac74c1SRenato Botelho xo_emit("{d:hostname/%s} ({d:ip-address/%s}) -- no entry", 4499d34414bSMike Heffner host, inet_ntoa(addr->sin_addr)); 450b9de94e9SYaroslav Tykhiy if (rifname) 451a2ac74c1SRenato Botelho xo_emit(" on {d:interface/%s}", rifname); 452a2ac74c1SRenato Botelho xo_emit("\n"); 453dea673e9SRodney W. Grimes } 454a2ac74c1SRenato Botelho 455a2ac74c1SRenato Botelho xo_close_list("arp-cache"); 456a2ac74c1SRenato Botelho xo_close_container("arp"); 457a2ac74c1SRenato Botelho xo_finish(); 458a2ac74c1SRenato Botelho 459a2ac74c1SRenato Botelho return (found == 0); 460dea673e9SRodney W. Grimes } 461dea673e9SRodney W. Grimes 462dea673e9SRodney W. Grimes /* 463dea673e9SRodney W. Grimes * Delete an arp entry 464dea673e9SRodney W. Grimes */ 465bdf932aeSLuigi Rizzo static int 4669711a168SGleb Smirnoff delete(char *host) 467dea673e9SRodney W. Grimes { 4689711a168SGleb Smirnoff struct sockaddr_in *addr, *dst; 469bdf932aeSLuigi Rizzo struct rt_msghdr *rtm; 470dea673e9SRodney W. Grimes struct sockaddr_dl *sdl; 471dea673e9SRodney W. Grimes 47268839124SLuigi Rizzo dst = getaddr(host); 47368839124SLuigi Rizzo if (dst == NULL) 474f3f8b226SRuslan Ermilov return (1); 475c7ab6602SQing Li 476c7ab6602SQing Li /* 477c7ab6602SQing Li * Perform a regular entry delete first. 478c7ab6602SQing Li */ 479c7ab6602SQing Li flags &= ~RTF_ANNOUNCE; 4806e6b3f7cSQing Li 48168839124SLuigi Rizzo for (;;) { /* try twice */ 4822f8c6c0aSPatrick Kelsey rtm = rtmsg(RTM_GET, dst, NULL); 483bdf932aeSLuigi Rizzo if (rtm == NULL) { 484a2ac74c1SRenato Botelho xo_warn("%s", host); 485dea673e9SRodney W. Grimes return (1); 486dea673e9SRodney W. Grimes } 4879711a168SGleb Smirnoff addr = (struct sockaddr_in *)(rtm + 1); 4880b46c085SLuigi Rizzo sdl = (struct sockaddr_dl *)(SA_SIZE(addr) + (char *)addr); 4896e6b3f7cSQing Li 4906e6b3f7cSQing Li /* 4916e6b3f7cSQing Li * With the new L2/L3 restructure, the route 4926e6b3f7cSQing Li * returned is a prefix route. The important 4936e6b3f7cSQing Li * piece of information from the previous 4946e6b3f7cSQing Li * RTM_GET is the interface index. In the 4956e6b3f7cSQing Li * case of ECMP, the kernel will traverse 4966e6b3f7cSQing Li * the route group for the given entry. 4976e6b3f7cSQing Li */ 4986e6b3f7cSQing Li if (sdl->sdl_family == AF_LINK && 49968839124SLuigi Rizzo !(rtm->rtm_flags & RTF_GATEWAY) && 5006e6b3f7cSQing Li valid_type(sdl->sdl_type) ) { 5016e6b3f7cSQing Li addr->sin_addr.s_addr = dst->sin_addr.s_addr; 5026e6b3f7cSQing Li break; 5036e6b3f7cSQing Li } 5046e6b3f7cSQing Li 505c7ab6602SQing Li /* 5062f8c6c0aSPatrick Kelsey * Regular entry delete failed, now check if there 507c7ab6602SQing Li * is a proxy-arp entry to remove. 508c7ab6602SQing Li */ 509c7ab6602SQing Li if (flags & RTF_ANNOUNCE) { 510a2ac74c1SRenato Botelho xo_warnx("delete: cannot locate %s", host); 511dea673e9SRodney W. Grimes return (1); 512dea673e9SRodney W. Grimes } 513c7ab6602SQing Li 514c7ab6602SQing Li flags |= RTF_ANNOUNCE; 51568839124SLuigi Rizzo } 5168eca593cSQing Li rtm->rtm_flags |= RTF_LLDATA; 51768839124SLuigi Rizzo if (rtmsg(RTM_DELETE, dst, NULL) != NULL) { 5189d34414bSMike Heffner printf("%s (%s) deleted\n", host, inet_ntoa(addr->sin_addr)); 519a42a667dSPoul-Henning Kamp return (0); 520a42a667dSPoul-Henning Kamp } 521a42a667dSPoul-Henning Kamp return (1); 522dea673e9SRodney W. Grimes } 523dea673e9SRodney W. Grimes 524c7ab6602SQing Li 525dea673e9SRodney W. Grimes /* 5268dc4b495SJulian Elischer * Search the arp table and do some action on matching entries 527dea673e9SRodney W. Grimes */ 528bdf932aeSLuigi Rizzo static int 529bdf932aeSLuigi Rizzo search(u_long addr, action_fn *action) 530dea673e9SRodney W. Grimes { 531dea673e9SRodney W. Grimes int mib[6]; 532dea673e9SRodney W. Grimes size_t needed; 533c34169d4SJohn Baldwin char *lim, *buf, *next; 534dea673e9SRodney W. Grimes struct rt_msghdr *rtm; 5359711a168SGleb Smirnoff struct sockaddr_in *sin2; 536dea673e9SRodney W. Grimes struct sockaddr_dl *sdl; 537b9de94e9SYaroslav Tykhiy char ifname[IF_NAMESIZE]; 53866658902SMaxim Konovalov int st, found_entry = 0; 539dea673e9SRodney W. Grimes 540dea673e9SRodney W. Grimes mib[0] = CTL_NET; 541dea673e9SRodney W. Grimes mib[1] = PF_ROUTE; 542dea673e9SRodney W. Grimes mib[2] = 0; 543dea673e9SRodney W. Grimes mib[3] = AF_INET; 544dea673e9SRodney W. Grimes mib[4] = NET_RT_FLAGS; 5456e6b3f7cSQing Li #ifdef RTF_LLINFO 546dea673e9SRodney W. Grimes mib[5] = RTF_LLINFO; 5476e6b3f7cSQing Li #else 5486e6b3f7cSQing Li mib[5] = 0; 5496e6b3f7cSQing Li #endif 550dea673e9SRodney W. Grimes if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) 551a2ac74c1SRenato Botelho xo_err(1, "route-sysctl-estimate"); 55268839124SLuigi Rizzo if (needed == 0) /* empty table */ 553bdf932aeSLuigi Rizzo return 0; 55466658902SMaxim Konovalov buf = NULL; 55519beed5eSMaxim Konovalov for (;;) { 556c34169d4SJohn Baldwin buf = reallocf(buf, needed); 557c34169d4SJohn Baldwin if (buf == NULL) 558a2ac74c1SRenato Botelho xo_errx(1, "could not reallocate memory"); 55966658902SMaxim Konovalov st = sysctl(mib, 6, buf, &needed, NULL, 0); 56019beed5eSMaxim Konovalov if (st == 0 || errno != ENOMEM) 56119beed5eSMaxim Konovalov break; 56219beed5eSMaxim Konovalov needed += needed / 8; 56319beed5eSMaxim Konovalov } 56466658902SMaxim Konovalov if (st == -1) 565a2ac74c1SRenato Botelho xo_err(1, "actual retrieval of routing table"); 566dea673e9SRodney W. Grimes lim = buf + needed; 567dea673e9SRodney W. Grimes for (next = buf; next < lim; next += rtm->rtm_msglen) { 568dea673e9SRodney W. Grimes rtm = (struct rt_msghdr *)next; 5699711a168SGleb Smirnoff sin2 = (struct sockaddr_in *)(rtm + 1); 5701a5ff928SStefan Farfeleder sdl = (struct sockaddr_dl *)((char *)sin2 + SA_SIZE(sin2)); 571b9de94e9SYaroslav Tykhiy if (rifname && if_indextoname(sdl->sdl_index, ifname) && 572b9de94e9SYaroslav Tykhiy strcmp(ifname, rifname)) 573b9de94e9SYaroslav Tykhiy continue; 574dea673e9SRodney W. Grimes if (addr) { 5759d34414bSMike Heffner if (addr != sin2->sin_addr.s_addr) 576dea673e9SRodney W. Grimes continue; 577dea673e9SRodney W. Grimes found_entry = 1; 578dea673e9SRodney W. Grimes } 5799d34414bSMike Heffner (*action)(sdl, sin2, rtm); 5808dc4b495SJulian Elischer } 581ae14be20SYaroslav Tykhiy free(buf); 582f3f8b226SRuslan Ermilov return (found_entry); 5838dc4b495SJulian Elischer } 5848dc4b495SJulian Elischer 5858dc4b495SJulian Elischer /* 5868dc4b495SJulian Elischer * Display an arp entry 5878dc4b495SJulian Elischer */ 588e78c7a0aSMax Laier 589bdf932aeSLuigi Rizzo static void 5908dc4b495SJulian Elischer print_entry(struct sockaddr_dl *sdl, 5919711a168SGleb Smirnoff struct sockaddr_in *addr, struct rt_msghdr *rtm) 5928dc4b495SJulian Elischer { 5933f844a22SRuslan Ermilov const char *host; 5948dc4b495SJulian Elischer struct hostent *hp; 59597fe20b4SKelly Yancey struct iso88025_sockaddr_dl_data *trld; 596c1ed96c2SGeorge V. Neville-Neil struct if_nameindex *p; 597fda82fc2SJulian Elischer int seg; 5988dc4b495SJulian Elischer 599c1ed96c2SGeorge V. Neville-Neil if (ifnameindex == NULL) 600c1ed96c2SGeorge V. Neville-Neil if ((ifnameindex = if_nameindex()) == NULL) 601a2ac74c1SRenato Botelho xo_err(1, "cannot retrieve interface names"); 602a2ac74c1SRenato Botelho 603a2ac74c1SRenato Botelho xo_open_instance("arp-cache"); 604c1ed96c2SGeorge V. Neville-Neil 605dea673e9SRodney W. Grimes if (nflag == 0) 6069d34414bSMike Heffner hp = gethostbyaddr((caddr_t)&(addr->sin_addr), 6079d34414bSMike Heffner sizeof addr->sin_addr, AF_INET); 608dea673e9SRodney W. Grimes else 609dea673e9SRodney W. Grimes hp = 0; 610dea673e9SRodney W. Grimes if (hp) 611dea673e9SRodney W. Grimes host = hp->h_name; 612dea673e9SRodney W. Grimes else { 613dea673e9SRodney W. Grimes host = "?"; 614dea673e9SRodney W. Grimes if (h_errno == TRY_AGAIN) 615dea673e9SRodney W. Grimes nflag = 1; 616dea673e9SRodney W. Grimes } 617a2ac74c1SRenato Botelho xo_emit("{:hostname/%s} ({:ip-address/%s}) at ", host, 618a2ac74c1SRenato Botelho inet_ntoa(addr->sin_addr)); 61921816de3SDoug Rabson if (sdl->sdl_alen) { 620596e374dSRuslan Ermilov if ((sdl->sdl_type == IFT_ETHER || 6219af9b983SAndrew Thompson sdl->sdl_type == IFT_L2VLAN || 6229af9b983SAndrew Thompson sdl->sdl_type == IFT_BRIDGE) && 62321816de3SDoug Rabson sdl->sdl_alen == ETHER_ADDR_LEN) 624a2ac74c1SRenato Botelho xo_emit("{:mac-address/%s}", 62504ae8c64SRenato Botelho ether_ntoa((struct ether_addr *)LLADDR(sdl))); 62621816de3SDoug Rabson else { 62721816de3SDoug Rabson int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0; 62821816de3SDoug Rabson 629a2ac74c1SRenato Botelho xo_emit("{:mac-address/%s}", link_ntoa(sdl) + n); 63021816de3SDoug Rabson } 63121816de3SDoug Rabson } else 632a2ac74c1SRenato Botelho xo_emit("{d:/(incomplete)}{en:incomplete/true}"); 633c1ed96c2SGeorge V. Neville-Neil 634c1ed96c2SGeorge V. Neville-Neil for (p = ifnameindex; p && ifnameindex->if_index && 635c1ed96c2SGeorge V. Neville-Neil ifnameindex->if_name; p++) { 636c1ed96c2SGeorge V. Neville-Neil if (p->if_index == sdl->sdl_index) { 637a2ac74c1SRenato Botelho xo_emit(" on {:interface/%s}", p->if_name); 638c1ed96c2SGeorge V. Neville-Neil break; 639c1ed96c2SGeorge V. Neville-Neil } 640c1ed96c2SGeorge V. Neville-Neil } 641c1ed96c2SGeorge V. Neville-Neil 642dea673e9SRodney W. Grimes if (rtm->rtm_rmx.rmx_expire == 0) 643a2ac74c1SRenato Botelho xo_emit("{d:/ permanent}{en:permanent/true}"); 64492968305SRuslan Ermilov else { 645a98c06f1SGleb Smirnoff static struct timespec tp; 646a98c06f1SGleb Smirnoff if (tp.tv_sec == 0) 647a98c06f1SGleb Smirnoff clock_gettime(CLOCK_MONOTONIC, &tp); 648a98c06f1SGleb Smirnoff if ((expire_time = rtm->rtm_rmx.rmx_expire - tp.tv_sec) > 0) 649a2ac74c1SRenato Botelho xo_emit(" expires in {:expires/%d} seconds", 650a2ac74c1SRenato Botelho (int)expire_time); 65192968305SRuslan Ermilov else 652a2ac74c1SRenato Botelho xo_emit("{d:/ expired}{en:expired/true}"); 65392968305SRuslan Ermilov } 654a2ac74c1SRenato Botelho 6556e6b3f7cSQing Li if (rtm->rtm_flags & RTF_ANNOUNCE) 656a2ac74c1SRenato Botelho xo_emit("{d:/ published}{en:published/true}"); 657a2ac74c1SRenato Botelho 658fda82fc2SJulian Elischer switch(sdl->sdl_type) { 659fda82fc2SJulian Elischer case IFT_ETHER: 660a2ac74c1SRenato Botelho xo_emit(" [{:type/ethernet}]"); 661fda82fc2SJulian Elischer break; 662fda82fc2SJulian Elischer case IFT_ISO88025: 663a2ac74c1SRenato Botelho xo_emit(" [{:type/token-ring}]"); 66497fe20b4SKelly Yancey trld = SDL_ISO88025(sdl); 66597fe20b4SKelly Yancey if (trld->trld_rcf != 0) { 666a2ac74c1SRenato Botelho xo_emit(" rt=%x", ntohs(trld->trld_rcf)); 66797fe20b4SKelly Yancey for (seg = 0; 66897fe20b4SKelly Yancey seg < ((TR_RCF_RIFLEN(trld->trld_rcf) - 2 ) / 2); 66997fe20b4SKelly Yancey seg++) 670a2ac74c1SRenato Botelho xo_emit(":%x", ntohs(*(trld->trld_route[seg]))); 67197fe20b4SKelly Yancey } 672fda82fc2SJulian Elischer break; 67304427472SMatthew N. Dodd case IFT_FDDI: 674a2ac74c1SRenato Botelho xo_emit(" [{:type/fddi}]"); 67504427472SMatthew N. Dodd break; 67604427472SMatthew N. Dodd case IFT_ATM: 677a2ac74c1SRenato Botelho xo_emit(" [{:type/atm}]"); 67804427472SMatthew N. Dodd break; 67988d5b613SYaroslav Tykhiy case IFT_L2VLAN: 680a2ac74c1SRenato Botelho xo_emit(" [{:type/vlan}]"); 68188d5b613SYaroslav Tykhiy break; 68221816de3SDoug Rabson case IFT_IEEE1394: 683a2ac74c1SRenato Botelho xo_emit(" [{:type/firewire}]"); 68421816de3SDoug Rabson break; 6859af9b983SAndrew Thompson case IFT_BRIDGE: 686a2ac74c1SRenato Botelho xo_emit(" [{:type/bridge}]"); 6879af9b983SAndrew Thompson break; 688595f03feSMark Johnston case IFT_INFINIBAND: 689a2ac74c1SRenato Botelho xo_emit(" [{:type/infiniband}]"); 690595f03feSMark Johnston break; 691fda82fc2SJulian Elischer default: 692123b2d4aSMurray Stokely break; 693fda82fc2SJulian Elischer } 694fda82fc2SJulian Elischer 695a2ac74c1SRenato Botelho xo_emit("\n"); 696fda82fc2SJulian Elischer 697a2ac74c1SRenato Botelho xo_close_instance("arp-cache"); 698dea673e9SRodney W. Grimes } 6998dc4b495SJulian Elischer 7008dc4b495SJulian Elischer /* 7018dc4b495SJulian Elischer * Nuke an arp entry 7028dc4b495SJulian Elischer */ 703bdf932aeSLuigi Rizzo static void 7049d34414bSMike Heffner nuke_entry(struct sockaddr_dl *sdl __unused, 7054a336ef4SAlexander V. Chernikov struct sockaddr_in *addr, struct rt_msghdr *rtm) 7068dc4b495SJulian Elischer { 7078dc4b495SJulian Elischer char ip[20]; 7088dc4b495SJulian Elischer 7094a336ef4SAlexander V. Chernikov if (rtm->rtm_flags & RTF_PINNED) 7104a336ef4SAlexander V. Chernikov return; 7114a336ef4SAlexander V. Chernikov 7129d34414bSMike Heffner snprintf(ip, sizeof(ip), "%s", inet_ntoa(addr->sin_addr)); 7139711a168SGleb Smirnoff delete(ip); 714dea673e9SRodney W. Grimes } 715dea673e9SRodney W. Grimes 716bdf932aeSLuigi Rizzo static void 717a42a667dSPoul-Henning Kamp usage(void) 718dea673e9SRodney W. Grimes { 7198dc4b495SJulian Elischer fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n", 720b9de94e9SYaroslav Tykhiy "usage: arp [-n] [-i interface] hostname", 721b9de94e9SYaroslav Tykhiy " arp [-n] [-i interface] -a", 7223f844a22SRuslan Ermilov " arp -d hostname [pub]", 723582fa422SBrooks Davis " arp -d [-i interface] -a", 7242293dac2STom Rhodes " arp -s hostname ether_addr [temp] [reject | blackhole] [pub [only]]", 7252293dac2STom Rhodes " arp -S hostname ether_addr [temp] [reject | blackhole] [pub [only]]", 726c72049e4SPhilippe Charnier " arp -f filename"); 727dea673e9SRodney W. Grimes exit(1); 728dea673e9SRodney W. Grimes } 729dea673e9SRodney W. Grimes 730bdf932aeSLuigi Rizzo static struct rt_msghdr * 7319711a168SGleb Smirnoff rtmsg(int cmd, struct sockaddr_in *dst, struct sockaddr_dl *sdl) 732dea673e9SRodney W. Grimes { 733dea673e9SRodney W. Grimes static int seq; 734dea673e9SRodney W. Grimes int rlen; 735bdf932aeSLuigi Rizzo int l; 7360c80179cSSam Leffler struct sockaddr_in so_mask, *som = &so_mask; 737bdf932aeSLuigi Rizzo static int s = -1; 738bdf932aeSLuigi Rizzo static pid_t pid; 739bdf932aeSLuigi Rizzo 740bdf932aeSLuigi Rizzo static struct { 741bdf932aeSLuigi Rizzo struct rt_msghdr m_rtm; 742bdf932aeSLuigi Rizzo char m_space[512]; 743bdf932aeSLuigi Rizzo } m_rtmsg; 744bdf932aeSLuigi Rizzo 745e2416749SMaxime Henrion struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 746e2416749SMaxime Henrion char *cp = m_rtmsg.m_space; 747bdf932aeSLuigi Rizzo 748bdf932aeSLuigi Rizzo if (s < 0) { /* first time: open socket, get pid */ 749bdf932aeSLuigi Rizzo s = socket(PF_ROUTE, SOCK_RAW, 0); 750bdf932aeSLuigi Rizzo if (s < 0) 751a2ac74c1SRenato Botelho xo_err(1, "socket"); 752bdf932aeSLuigi Rizzo pid = getpid(); 753bdf932aeSLuigi Rizzo } 754bdf932aeSLuigi Rizzo bzero(&so_mask, sizeof(so_mask)); 755bdf932aeSLuigi Rizzo so_mask.sin_len = 8; 756bdf932aeSLuigi Rizzo so_mask.sin_addr.s_addr = 0xffffffff; 757dea673e9SRodney W. Grimes 758dea673e9SRodney W. Grimes errno = 0; 75968839124SLuigi Rizzo /* 76068839124SLuigi Rizzo * XXX RTM_DELETE relies on a previous RTM_GET to fill the buffer 76168839124SLuigi Rizzo * appropriately. 76268839124SLuigi Rizzo */ 763dea673e9SRodney W. Grimes if (cmd == RTM_DELETE) 764dea673e9SRodney W. Grimes goto doit; 765dea673e9SRodney W. Grimes bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 766dea673e9SRodney W. Grimes rtm->rtm_flags = flags; 767dea673e9SRodney W. Grimes rtm->rtm_version = RTM_VERSION; 768dea673e9SRodney W. Grimes 769dea673e9SRodney W. Grimes switch (cmd) { 770dea673e9SRodney W. Grimes default: 771a2ac74c1SRenato Botelho xo_errx(1, "internal wrong cmd"); 772dea673e9SRodney W. Grimes case RTM_ADD: 773dea673e9SRodney W. Grimes rtm->rtm_addrs |= RTA_GATEWAY; 774dea673e9SRodney W. Grimes rtm->rtm_rmx.rmx_expire = expire_time; 775dea673e9SRodney W. Grimes rtm->rtm_inits = RTV_EXPIRE; 7768eca593cSQing Li rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA); 777dea673e9SRodney W. Grimes if (doing_proxy) { 778dea673e9SRodney W. Grimes rtm->rtm_addrs |= RTA_NETMASK; 779dea673e9SRodney W. Grimes rtm->rtm_flags &= ~RTF_HOST; 780dea673e9SRodney W. Grimes } 781dea673e9SRodney W. Grimes /* FALLTHROUGH */ 782dea673e9SRodney W. Grimes case RTM_GET: 783dea673e9SRodney W. Grimes rtm->rtm_addrs |= RTA_DST; 784dea673e9SRodney W. Grimes } 785dea673e9SRodney W. Grimes #define NEXTADDR(w, s) \ 786be5d11dcSDag-Erling Smørgrav do { \ 787f3f8b226SRuslan Ermilov if ((s) != NULL && rtm->rtm_addrs & (w)) { \ 788be5d11dcSDag-Erling Smørgrav bcopy((s), cp, sizeof(*(s))); \ 789be5d11dcSDag-Erling Smørgrav cp += SA_SIZE(s); \ 790be5d11dcSDag-Erling Smørgrav } \ 791be5d11dcSDag-Erling Smørgrav } while (0) 792dea673e9SRodney W. Grimes 79368839124SLuigi Rizzo NEXTADDR(RTA_DST, dst); 79468839124SLuigi Rizzo NEXTADDR(RTA_GATEWAY, sdl); 7950c80179cSSam Leffler NEXTADDR(RTA_NETMASK, som); 796dea673e9SRodney W. Grimes 797dea673e9SRodney W. Grimes rtm->rtm_msglen = cp - (char *)&m_rtmsg; 798dea673e9SRodney W. Grimes doit: 799dea673e9SRodney W. Grimes l = rtm->rtm_msglen; 800dea673e9SRodney W. Grimes rtm->rtm_seq = ++seq; 801dea673e9SRodney W. Grimes rtm->rtm_type = cmd; 802dea673e9SRodney W. Grimes if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 803dea673e9SRodney W. Grimes if (errno != ESRCH || cmd != RTM_DELETE) { 804a2ac74c1SRenato Botelho xo_warn("writing to routing socket"); 805f3f8b226SRuslan Ermilov return (NULL); 806dea673e9SRodney W. Grimes } 807dea673e9SRodney W. Grimes } 808dea673e9SRodney W. Grimes do { 809dea673e9SRodney W. Grimes l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 8102f8c6c0aSPatrick Kelsey } while (l > 0 && (rtm->rtm_type != cmd || rtm->rtm_seq != seq || 8112f8c6c0aSPatrick Kelsey rtm->rtm_pid != pid)); 812dea673e9SRodney W. Grimes if (l < 0) 813a2ac74c1SRenato Botelho xo_warn("read from routing socket"); 814f3f8b226SRuslan Ermilov return (rtm); 815dea673e9SRodney W. Grimes } 816dea673e9SRodney W. Grimes 817a42a667dSPoul-Henning Kamp /* 818a42a667dSPoul-Henning Kamp * get_ether_addr - get the hardware address of an interface on the 819a42a667dSPoul-Henning Kamp * the same subnet as ipaddr. 820a42a667dSPoul-Henning Kamp */ 821a42a667dSPoul-Henning Kamp #define MAX_IFS 32 822a42a667dSPoul-Henning Kamp 823bdf932aeSLuigi Rizzo static int 824f3f8b226SRuslan Ermilov get_ether_addr(in_addr_t ipaddr, struct ether_addr *hwaddr) 825a42a667dSPoul-Henning Kamp { 826a42a667dSPoul-Henning Kamp struct ifreq *ifr, *ifend, *ifp; 827f3f8b226SRuslan Ermilov in_addr_t ina, mask; 828a42a667dSPoul-Henning Kamp struct sockaddr_dl *dla; 829a42a667dSPoul-Henning Kamp struct ifreq ifreq; 830a42a667dSPoul-Henning Kamp struct ifconf ifc; 831a42a667dSPoul-Henning Kamp struct ifreq ifs[MAX_IFS]; 8329d34414bSMike Heffner int sock; 83368839124SLuigi Rizzo int retval = 0; 834a42a667dSPoul-Henning Kamp 8359d34414bSMike Heffner sock = socket(AF_INET, SOCK_DGRAM, 0); 8369d34414bSMike Heffner if (sock < 0) 837a2ac74c1SRenato Botelho xo_err(1, "socket"); 838a42a667dSPoul-Henning Kamp 839a42a667dSPoul-Henning Kamp ifc.ifc_len = sizeof(ifs); 840a42a667dSPoul-Henning Kamp ifc.ifc_req = ifs; 8419cc7cb58SMike Heffner if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) { 842a2ac74c1SRenato Botelho xo_warnx("ioctl(SIOCGIFCONF)"); 84368839124SLuigi Rizzo goto done; 844a42a667dSPoul-Henning Kamp } 845a42a667dSPoul-Henning Kamp 84668839124SLuigi Rizzo #define NEXTIFR(i) \ 84768839124SLuigi Rizzo ((struct ifreq *)((char *)&(i)->ifr_addr \ 84868839124SLuigi Rizzo + MAX((i)->ifr_addr.sa_len, sizeof((i)->ifr_addr))) ) 84968839124SLuigi Rizzo 850a42a667dSPoul-Henning Kamp /* 851a42a667dSPoul-Henning Kamp * Scan through looking for an interface with an Internet 852a42a667dSPoul-Henning Kamp * address on the same subnet as `ipaddr'. 853a42a667dSPoul-Henning Kamp */ 854a42a667dSPoul-Henning Kamp ifend = (struct ifreq *)(ifc.ifc_buf + ifc.ifc_len); 85568839124SLuigi Rizzo for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr) ) { 85668839124SLuigi Rizzo if (ifr->ifr_addr.sa_family != AF_INET) 85768839124SLuigi Rizzo continue; 858a42a667dSPoul-Henning Kamp strncpy(ifreq.ifr_name, ifr->ifr_name, 859a42a667dSPoul-Henning Kamp sizeof(ifreq.ifr_name)); 86006274ceeSGleb Smirnoff ifreq.ifr_addr = ifr->ifr_addr; 861a42a667dSPoul-Henning Kamp /* 862a42a667dSPoul-Henning Kamp * Check that the interface is up, 863a42a667dSPoul-Henning Kamp * and not point-to-point or loopback. 864a42a667dSPoul-Henning Kamp */ 8659cc7cb58SMike Heffner if (ioctl(sock, SIOCGIFFLAGS, &ifreq) < 0) 866a42a667dSPoul-Henning Kamp continue; 867a42a667dSPoul-Henning Kamp if ((ifreq.ifr_flags & 868a42a667dSPoul-Henning Kamp (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT| 86904ae8c64SRenato Botelho IFF_LOOPBACK|IFF_NOARP)) != (IFF_UP|IFF_BROADCAST)) 87068839124SLuigi Rizzo continue; 87104ae8c64SRenato Botelho /* Get its netmask and check that it's on the right subnet. */ 8729cc7cb58SMike Heffner if (ioctl(sock, SIOCGIFNETMASK, &ifreq) < 0) 873a42a667dSPoul-Henning Kamp continue; 874a42a667dSPoul-Henning Kamp mask = ((struct sockaddr_in *) 875a42a667dSPoul-Henning Kamp &ifreq.ifr_addr)->sin_addr.s_addr; 87668839124SLuigi Rizzo ina = ((struct sockaddr_in *) 87768839124SLuigi Rizzo &ifr->ifr_addr)->sin_addr.s_addr; 87868839124SLuigi Rizzo if ((ipaddr & mask) == (ina & mask)) 87968839124SLuigi Rizzo break; /* ok, we got it! */ 880a42a667dSPoul-Henning Kamp } 881a42a667dSPoul-Henning Kamp 88268839124SLuigi Rizzo if (ifr >= ifend) 88368839124SLuigi Rizzo goto done; 884a42a667dSPoul-Henning Kamp 885a42a667dSPoul-Henning Kamp /* 886a42a667dSPoul-Henning Kamp * Now scan through again looking for a link-level address 887a42a667dSPoul-Henning Kamp * for this interface. 888a42a667dSPoul-Henning Kamp */ 889a42a667dSPoul-Henning Kamp ifp = ifr; 89068839124SLuigi Rizzo for (ifr = ifc.ifc_req; ifr < ifend; ifr = NEXTIFR(ifr)) 89168839124SLuigi Rizzo if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 && 89268839124SLuigi Rizzo ifr->ifr_addr.sa_family == AF_LINK) 89368839124SLuigi Rizzo break; 89468839124SLuigi Rizzo if (ifr >= ifend) 89568839124SLuigi Rizzo goto done; 896a42a667dSPoul-Henning Kamp /* 897a42a667dSPoul-Henning Kamp * Found the link-level address - copy it out 898a42a667dSPoul-Henning Kamp */ 899a42a667dSPoul-Henning Kamp dla = (struct sockaddr_dl *) &ifr->ifr_addr; 900a42a667dSPoul-Henning Kamp memcpy(hwaddr, LLADDR(dla), dla->sdl_alen); 9017814b3b8SRenato Botelho printf("using interface %s for proxy with address %s\n", ifp->ifr_name, 9027814b3b8SRenato Botelho ether_ntoa(hwaddr)); 90368839124SLuigi Rizzo retval = dla->sdl_alen; 90468839124SLuigi Rizzo done: 90568839124SLuigi Rizzo close(sock); 906f3f8b226SRuslan Ermilov return (retval); 907a42a667dSPoul-Henning Kamp } 908