13229Spst/* 23229Spst * Copyright (c) 1984, 1993 33229Spst * The Regents of the University of California. All rights reserved. 43229Spst * Copyright (c) 1994 53229Spst * Geoffrey M. Rehmet, All rights reserved. 63229Spst * 73229Spst * This code is derived from software which forms part of the 4.4-Lite 83229Spst * Berkeley software distribution, which was in derived from software 93229Spst * contributed to Berkeley by Sun Microsystems, Inc. 103229Spst * 113229Spst * Redistribution and use in source and binary forms, with or without 123229Spst * modification, are permitted provided that the following conditions 133229Spst * are met: 143229Spst * 1. Redistributions of source code must retain the above copyright 153229Spst * notice, this list of conditions and the following disclaimer. 163229Spst * 2. Redistributions in binary form must reproduce the above copyright 173229Spst * notice, this list of conditions and the following disclaimer in the 183229Spst * documentation and/or other materials provided with the distribution. 19262435Sbrueffer * 3. Neither the name of the University nor the names of its contributors 203229Spst * may be used to endorse or promote products derived from this software 213229Spst * without specific prior written permission. 223229Spst * 233229Spst * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 243229Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 253229Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 263229Spst * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 273229Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 283229Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 293229Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 303229Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 313229Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 323229Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 333229Spst * SUCH DAMAGE. 343229Spst */ 353229Spst 363229Spst/* 373229Spst * from arp.c 8.2 (Berkeley) 1/2/94 383229Spst */ 393229Spst 40110395Scharnier#include <sys/cdefs.h> 41110395Scharnier__FBSDID("$FreeBSD$"); 42110395Scharnier 433229Spst#include <sys/param.h> 443229Spst/* 453229Spst * Verify that we are at least 4.4 BSD 463229Spst */ 473229Spst#if defined(BSD) 483229Spst#if BSD >= 199306 493229Spst 503229Spst#include <sys/socket.h> 516034Sdfr#include <sys/filio.h> 5220287Swollman#include <sys/time.h> 533229Spst 543229Spst#include <net/if.h> 553229Spst#include <net/if_dl.h> 563229Spst#include <net/if_types.h> 573229Spst#include <net/route.h> 583229Spst 593229Spst#include <netinet/in.h> 603229Spst#include <netinet/if_ether.h> 613229Spst 623229Spst#include <arpa/inet.h> 633229Spst 643229Spst#include <errno.h> 653229Spst#include <stdio.h> 66110395Scharnier#include <stdlib.h> 673229Spst#include <string.h> 683229Spst#include <syslog.h> 693229Spst#include <unistd.h> 703229Spst 713229Spst#include "report.h" 723229Spst 733229Spst 74104742Salfredstatic int rtmsg(int); 753229Spst 763229Spststatic int s = -1; /* routing socket */ 773229Spst 783229Spst 793229Spst/* 803229Spst * Open the routing socket 813229Spst */ 823229Spststatic void getsocket () { 833229Spst if (s < 0) { 843229Spst s = socket(PF_ROUTE, SOCK_RAW, 0); 853229Spst if (s < 0) { 863229Spst report(LOG_ERR, "socket %s", strerror(errno)); 873229Spst exit(1); 883229Spst } 896034Sdfr } else { 906034Sdfr /* 916034Sdfr * Drain the socket of any unwanted routing messages. 926034Sdfr */ 936034Sdfr int n; 946034Sdfr char buf[512]; 956034Sdfr 966034Sdfr ioctl(s, FIONREAD, &n); 976034Sdfr while (n > 0) { 986034Sdfr read(s, buf, sizeof buf); 996034Sdfr ioctl(s, FIONREAD, &n); 1006034Sdfr } 1013229Spst } 1023229Spst} 1033229Spst 1043229Spststatic struct sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}}; 105246143Sglebiusstatic struct sockaddr_in blank_sin = {sizeof(blank_sin), AF_INET }, sin_m; 1063229Spststatic struct sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m; 107246143Sglebiusstatic int expire_time, flags, doing_proxy; 1083229Spststatic struct { 1093229Spst struct rt_msghdr m_rtm; 1103229Spst char m_space[512]; 1113229Spst} m_rtmsg; 1123229Spst 1133229Spst/* 1148870Srgrimes * Set an individual arp entry 1153229Spst */ 1163229Spstint bsd_arp_set(ia, eaddr, len) 1173229Spst struct in_addr *ia; 1183229Spst char *eaddr; 1193229Spst int len; 1203229Spst{ 121246143Sglebius register struct sockaddr_in *sin = &sin_m; 1223229Spst register struct sockaddr_dl *sdl; 1233229Spst register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm); 1243229Spst u_char *ea; 125216226Sglebius struct timespec tp; 1265661Sdfr int op = RTM_ADD; 1273229Spst 1283229Spst getsocket(); 1293229Spst sdl_m = blank_sdl; 1303229Spst sin_m = blank_sin; 1313229Spst sin->sin_addr = *ia; 1323229Spst 1333229Spst ea = (u_char *)LLADDR(&sdl_m); 1343229Spst bcopy(eaddr, ea, len); 1353229Spst sdl_m.sdl_alen = len; 136246143Sglebius doing_proxy = flags = expire_time = 0; 1373229Spst 1383229Spst /* make arp entry temporary */ 139216226Sglebius clock_gettime(CLOCK_MONOTONIC, &tp); 140216226Sglebius expire_time = tp.tv_sec + 20 * 60; 1413229Spst 1423229Spsttryagain: 1433229Spst if (rtmsg(RTM_GET) < 0) { 1443229Spst report(LOG_WARNING, "rtmget: %s", strerror(errno)); 1453229Spst return (1); 1463229Spst } 147246143Sglebius sin = (struct sockaddr_in *)(rtm + 1); 1483229Spst sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin); 1493229Spst if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) { 1503229Spst if (sdl->sdl_family == AF_LINK && 1513229Spst !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) { 1523229Spst case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023: 1533229Spst case IFT_ISO88024: case IFT_ISO88025: 1545661Sdfr op = RTM_CHANGE; 1553229Spst goto overwrite; 1563229Spst } 1573229Spst if (doing_proxy == 0) { 1588870Srgrimes report(LOG_WARNING, "set: can only proxy for %s\n", 1593229Spst inet_ntoa(sin->sin_addr)); 1603229Spst return (1); 1613229Spst } 1623229Spst goto tryagain; 1633229Spst } 1643229Spstoverwrite: 1653229Spst if (sdl->sdl_family != AF_LINK) { 1663229Spst report(LOG_WARNING, 1678870Srgrimes "cannot intuit interface index and type for %s\n", 1683229Spst inet_ntoa(sin->sin_addr)); 1693229Spst return (1); 1703229Spst } 1713229Spst sdl_m.sdl_type = sdl->sdl_type; 1723229Spst sdl_m.sdl_index = sdl->sdl_index; 1735661Sdfr return (rtmsg(op)); 1743229Spst} 1753229Spst 1763229Spst 1773229Spststatic int rtmsg(cmd) 1783229Spst int cmd; 1793229Spst{ 1803229Spst static int seq; 1813229Spst int rlen; 1823229Spst register struct rt_msghdr *rtm = &m_rtmsg.m_rtm; 1833229Spst register char *cp = m_rtmsg.m_space; 1843229Spst register int l; 1853229Spst 1863229Spst errno = 0; 1873229Spst bzero((char *)&m_rtmsg, sizeof(m_rtmsg)); 1883229Spst rtm->rtm_flags = flags; 1893229Spst rtm->rtm_version = RTM_VERSION; 1903229Spst 1913229Spst switch (cmd) { 1923229Spst default: 1933229Spst report(LOG_ERR, "set_arp: internal wrong cmd - exiting"); 1943229Spst exit(1); 1953229Spst case RTM_ADD: 1965661Sdfr case RTM_CHANGE: 1973229Spst rtm->rtm_addrs |= RTA_GATEWAY; 1983229Spst rtm->rtm_rmx.rmx_expire = expire_time; 1993229Spst rtm->rtm_inits = RTV_EXPIRE; 200190601Scognet rtm->rtm_flags |= (RTF_HOST | RTF_STATIC | RTF_LLDATA); 2013229Spst if (doing_proxy) { 202246143Sglebius rtm->rtm_addrs |= RTA_NETMASK; 203246143Sglebius rtm->rtm_flags &= ~RTF_HOST; 2043229Spst } 2053229Spst /* FALLTHROUGH */ 2063229Spst case RTM_GET: 2073229Spst rtm->rtm_addrs |= RTA_DST; 2083229Spst } 2093229Spst#define NEXTADDR(w, s) \ 2103229Spst if (rtm->rtm_addrs & (w)) { \ 2113229Spst bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);} 2123229Spst 2133229Spst NEXTADDR(RTA_DST, sin_m); 2143229Spst NEXTADDR(RTA_GATEWAY, sdl_m); 2153229Spst NEXTADDR(RTA_NETMASK, so_mask); 2163229Spst 2173229Spst rtm->rtm_msglen = cp - (char *)&m_rtmsg; 2183229Spst 2193229Spst l = rtm->rtm_msglen; 2203229Spst rtm->rtm_seq = ++seq; 2213229Spst rtm->rtm_type = cmd; 2223229Spst if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) { 2233229Spst if ((errno != ESRCH) && !(errno == EEXIST && cmd == RTM_ADD)){ 2243229Spst report(LOG_WARNING, "writing to routing socket: %s", 2253229Spst strerror(errno)); 2263229Spst return (-1); 2273229Spst } 2283229Spst } 2293229Spst do { 2303229Spst l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg)); 2316034Sdfr } while (l > 0 && (rtm->rtm_type != cmd || rtm->rtm_seq != seq || rtm->rtm_pid != getpid())); 2323229Spst if (l < 0) 2333229Spst report(LOG_WARNING, "arp: read from routing socket: %s\n", 2343229Spst strerror(errno)); 2353229Spst return (0); 2363229Spst} 2373229Spst 2383229Spst#endif /* BSD */ 2393229Spst#endif /* BSD >= 199306 */ 240