153c9f6c0SAtsushi Murai /* 253c9f6c0SAtsushi Murai * sys-bsd.c - System-dependent procedures for setting up 353c9f6c0SAtsushi Murai * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.) 453c9f6c0SAtsushi Murai * 553c9f6c0SAtsushi Murai * Copyright (c) 1989 Carnegie Mellon University. 653c9f6c0SAtsushi Murai * All rights reserved. 753c9f6c0SAtsushi Murai * 853c9f6c0SAtsushi Murai * Redistribution and use in source and binary forms are permitted 953c9f6c0SAtsushi Murai * provided that the above copyright notice and this paragraph are 1053c9f6c0SAtsushi Murai * duplicated in all such forms and that any documentation, 1153c9f6c0SAtsushi Murai * advertising materials, and other materials related to such 1253c9f6c0SAtsushi Murai * distribution and use acknowledge that the software was developed 1353c9f6c0SAtsushi Murai * by Carnegie Mellon University. The name of the 1453c9f6c0SAtsushi Murai * University may not be used to endorse or promote products derived 1553c9f6c0SAtsushi Murai * from this software without specific prior written permission. 1653c9f6c0SAtsushi Murai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1753c9f6c0SAtsushi Murai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1853c9f6c0SAtsushi Murai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1953c9f6c0SAtsushi Murai * 205106c671SBrian Somers * $Id: arp.c,v 1.16 1997/10/26 01:02:03 brian Exp $ 2153c9f6c0SAtsushi Murai * 2253c9f6c0SAtsushi Murai */ 2353c9f6c0SAtsushi Murai 2453c9f6c0SAtsushi Murai /* 2553c9f6c0SAtsushi Murai * TODO: 2653c9f6c0SAtsushi Murai */ 2753c9f6c0SAtsushi Murai 2853c9f6c0SAtsushi Murai #include <sys/types.h> 2953c9f6c0SAtsushi Murai #include <sys/time.h> 3075240ed1SBrian Somers #include <sys/socket.h> 3153c9f6c0SAtsushi Murai #include <net/if.h> 32702a1d01SGarrett Wollman #include <net/if_var.h> 3353c9f6c0SAtsushi Murai #include <net/route.h> 3453c9f6c0SAtsushi Murai #include <net/if_dl.h> 3553c9f6c0SAtsushi Murai #include <netinet/in.h> 3653c9f6c0SAtsushi Murai #include <net/if_types.h> 3753c9f6c0SAtsushi Murai #include <netinet/in_var.h> 3853c9f6c0SAtsushi Murai #include <netinet/if_ether.h> 3975240ed1SBrian Somers 4075240ed1SBrian Somers #include <fcntl.h> 4175240ed1SBrian Somers #include <stdio.h> 4275240ed1SBrian Somers #include <string.h> 4375240ed1SBrian Somers #include <sys/errno.h> 4475240ed1SBrian Somers #include <sys/ioctl.h> 4575240ed1SBrian Somers #include <sys/uio.h> 4675240ed1SBrian Somers #include <unistd.h> 4775240ed1SBrian Somers 4875240ed1SBrian Somers #include "mbuf.h" 4910a91a42SBrian Somers #include "log.h" 505106c671SBrian Somers #include "id.h" 5175240ed1SBrian Somers #include "arp.h" 5253c9f6c0SAtsushi Murai 5353c9f6c0SAtsushi Murai static int rtm_seq; 5453c9f6c0SAtsushi Murai 55927145beSBrian Somers static int get_ether_addr(int, u_long, struct sockaddr_dl *); 56ed6a16c1SPoul-Henning Kamp 5753c9f6c0SAtsushi Murai /* 5853c9f6c0SAtsushi Murai * SET_SA_FAMILY - set the sa_family field of a struct sockaddr, 5953c9f6c0SAtsushi Murai * if it exists. 6053c9f6c0SAtsushi Murai */ 6153c9f6c0SAtsushi Murai #define SET_SA_FAMILY(addr, family) \ 6275240ed1SBrian Somers memset((char *) &(addr), '\0', sizeof(addr)); \ 6353c9f6c0SAtsushi Murai addr.sa_family = (family); \ 6453c9f6c0SAtsushi Murai addr.sa_len = sizeof(addr); 6553c9f6c0SAtsushi Murai 6653c9f6c0SAtsushi Murai 6753c9f6c0SAtsushi Murai #if RTM_VERSION >= 3 6853c9f6c0SAtsushi Murai 6953c9f6c0SAtsushi Murai /* 7053c9f6c0SAtsushi Murai * sifproxyarp - Make a proxy ARP entry for the peer. 7153c9f6c0SAtsushi Murai */ 7253c9f6c0SAtsushi Murai static struct { 7353c9f6c0SAtsushi Murai struct rt_msghdr hdr; 7453c9f6c0SAtsushi Murai struct sockaddr_inarp dst; 7553c9f6c0SAtsushi Murai struct sockaddr_dl hwa; 7653c9f6c0SAtsushi Murai char extra[128]; 7753c9f6c0SAtsushi Murai } arpmsg; 7853c9f6c0SAtsushi Murai 7953c9f6c0SAtsushi Murai static int arpmsg_valid; 8053c9f6c0SAtsushi Murai 8153c9f6c0SAtsushi Murai int 82944f7098SBrian Somers sifproxyarp(int unit, u_long hisaddr) 8353c9f6c0SAtsushi Murai { 8453c9f6c0SAtsushi Murai int routes; 8553c9f6c0SAtsushi Murai 8653c9f6c0SAtsushi Murai /* 87944f7098SBrian Somers * Get the hardware address of an interface on the same subnet as our local 88944f7098SBrian Somers * address. 8953c9f6c0SAtsushi Murai */ 9053c9f6c0SAtsushi Murai memset(&arpmsg, 0, sizeof(arpmsg)); 9153c9f6c0SAtsushi Murai if (!get_ether_addr(unit, hisaddr, &arpmsg.hwa)) { 92afc7fa2cSBrian Somers LogPrintf(LogERROR, "Cannot determine ethernet address for proxy ARP\n"); 9353c9f6c0SAtsushi Murai return 0; 9453c9f6c0SAtsushi Murai } 955106c671SBrian Somers routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET); 965106c671SBrian Somers if (routes < 0) { 97927145beSBrian Somers LogPrintf(LogERROR, "sifproxyarp: opening routing socket: %s\n", 98927145beSBrian Somers strerror(errno)); 9953c9f6c0SAtsushi Murai return 0; 10053c9f6c0SAtsushi Murai } 10153c9f6c0SAtsushi Murai arpmsg.hdr.rtm_type = RTM_ADD; 10253c9f6c0SAtsushi Murai arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC; 10353c9f6c0SAtsushi Murai arpmsg.hdr.rtm_version = RTM_VERSION; 10453c9f6c0SAtsushi Murai arpmsg.hdr.rtm_seq = ++rtm_seq; 10553c9f6c0SAtsushi Murai arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; 10653c9f6c0SAtsushi Murai arpmsg.hdr.rtm_inits = RTV_EXPIRE; 10753c9f6c0SAtsushi Murai arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp); 10853c9f6c0SAtsushi Murai arpmsg.dst.sin_family = AF_INET; 10953c9f6c0SAtsushi Murai arpmsg.dst.sin_addr.s_addr = hisaddr; 11053c9f6c0SAtsushi Murai arpmsg.dst.sin_other = SIN_PROXY; 11153c9f6c0SAtsushi Murai 11253c9f6c0SAtsushi Murai arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg 11353c9f6c0SAtsushi Murai + arpmsg.hwa.sdl_len; 11453c9f6c0SAtsushi Murai if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { 115927145beSBrian Somers LogPrintf(LogERROR, "Add proxy arp entry: %s\n", strerror(errno)); 11653c9f6c0SAtsushi Murai close(routes); 11753c9f6c0SAtsushi Murai return 0; 11853c9f6c0SAtsushi Murai } 11953c9f6c0SAtsushi Murai close(routes); 12053c9f6c0SAtsushi Murai arpmsg_valid = 1; 12153c9f6c0SAtsushi Murai return 1; 12253c9f6c0SAtsushi Murai } 12353c9f6c0SAtsushi Murai 12453c9f6c0SAtsushi Murai /* 12553c9f6c0SAtsushi Murai * cifproxyarp - Delete the proxy ARP entry for the peer. 12653c9f6c0SAtsushi Murai */ 12753c9f6c0SAtsushi Murai int 128944f7098SBrian Somers cifproxyarp(int unit, u_long hisaddr) 12953c9f6c0SAtsushi Murai { 13053c9f6c0SAtsushi Murai int routes; 13153c9f6c0SAtsushi Murai 13253c9f6c0SAtsushi Murai if (!arpmsg_valid) 13353c9f6c0SAtsushi Murai return 0; 13453c9f6c0SAtsushi Murai arpmsg_valid = 0; 13553c9f6c0SAtsushi Murai 13653c9f6c0SAtsushi Murai arpmsg.hdr.rtm_type = RTM_DELETE; 13753c9f6c0SAtsushi Murai arpmsg.hdr.rtm_seq = ++rtm_seq; 13853c9f6c0SAtsushi Murai 1395106c671SBrian Somers routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET); 1405106c671SBrian Somers if (routes < 0) { 141927145beSBrian Somers LogPrintf(LogERROR, "sifproxyarp: opening routing socket: %s\n", 142927145beSBrian Somers strerror(errno)); 14353c9f6c0SAtsushi Murai return 0; 14453c9f6c0SAtsushi Murai } 14553c9f6c0SAtsushi Murai if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { 146927145beSBrian Somers LogPrintf(LogERROR, "Delete proxy arp entry: %s\n", strerror(errno)); 14753c9f6c0SAtsushi Murai close(routes); 14853c9f6c0SAtsushi Murai return 0; 14953c9f6c0SAtsushi Murai } 15053c9f6c0SAtsushi Murai close(routes); 15153c9f6c0SAtsushi Murai return 1; 15253c9f6c0SAtsushi Murai } 15353c9f6c0SAtsushi Murai 15453c9f6c0SAtsushi Murai #else /* RTM_VERSION */ 15553c9f6c0SAtsushi Murai 15653c9f6c0SAtsushi Murai /* 15753c9f6c0SAtsushi Murai * sifproxyarp - Make a proxy ARP entry for the peer. 15853c9f6c0SAtsushi Murai */ 15953c9f6c0SAtsushi Murai int 160944f7098SBrian Somers sifproxyarp(int unit, u_long hisaddr) 16153c9f6c0SAtsushi Murai { 16253c9f6c0SAtsushi Murai struct arpreq arpreq; 16353c9f6c0SAtsushi Murai struct { 16453c9f6c0SAtsushi Murai struct sockaddr_dl sdl; 16553c9f6c0SAtsushi Murai char space[128]; 16653c9f6c0SAtsushi Murai } dls; 16753c9f6c0SAtsushi Murai 16875240ed1SBrian Somers memset(&arpreq, '\0', sizeof(arpreq)); 16953c9f6c0SAtsushi Murai 17053c9f6c0SAtsushi Murai /* 171944f7098SBrian Somers * Get the hardware address of an interface on the same subnet as our local 172944f7098SBrian Somers * address. 17353c9f6c0SAtsushi Murai */ 17453c9f6c0SAtsushi Murai if (!get_ether_addr(unit, hisaddr, &dls.sdl)) { 1759c749ffbSPoul-Henning Kamp LogPrintf(LOG_PHASE_BIT, "Cannot determine ethernet address for proxy ARP\n"); 17653c9f6c0SAtsushi Murai return 0; 17753c9f6c0SAtsushi Murai } 17853c9f6c0SAtsushi Murai arpreq.arp_ha.sa_len = sizeof(struct sockaddr); 17953c9f6c0SAtsushi Murai arpreq.arp_ha.sa_family = AF_UNSPEC; 18075240ed1SBrian Somers memcpy(arpreq.arp_ha.sa_data, LLADDR(&dls.sdl), dls.sdl.sdl_alen); 18153c9f6c0SAtsushi Murai SET_SA_FAMILY(arpreq.arp_pa, AF_INET); 18253c9f6c0SAtsushi Murai ((struct sockaddr_in *) & arpreq.arp_pa)->sin_addr.s_addr = hisaddr; 18353c9f6c0SAtsushi Murai arpreq.arp_flags = ATF_PERM | ATF_PUBL; 1845106c671SBrian Somers if (ID0ioctl(unit, SIOCSARP, (caddr_t) & arpreq) < 0) { 185afc7fa2cSBrian Somers LogPrintf(LogERROR, "sifproxyarp: ioctl(SIOCSARP): %s\n", strerror(errno)); 18653c9f6c0SAtsushi Murai return 0; 18753c9f6c0SAtsushi Murai } 18853c9f6c0SAtsushi Murai return 1; 18953c9f6c0SAtsushi Murai } 19053c9f6c0SAtsushi Murai 19153c9f6c0SAtsushi Murai /* 19253c9f6c0SAtsushi Murai * cifproxyarp - Delete the proxy ARP entry for the peer. 19353c9f6c0SAtsushi Murai */ 19453c9f6c0SAtsushi Murai int 195944f7098SBrian Somers cifproxyarp(int unit, u_long hisaddr) 19653c9f6c0SAtsushi Murai { 19753c9f6c0SAtsushi Murai struct arpreq arpreq; 19853c9f6c0SAtsushi Murai 19975240ed1SBrian Somers memset(&arpreq, '\0', sizeof(arpreq)); 20053c9f6c0SAtsushi Murai SET_SA_FAMILY(arpreq.arp_pa, AF_INET); 20153c9f6c0SAtsushi Murai ((struct sockaddr_in *) & arpreq.arp_pa)->sin_addr.s_addr = hisaddr; 2025106c671SBrian Somers if (ID0ioctl(unit, SIOCDARP, (caddr_t) & arpreq) < 0) { 203afc7fa2cSBrian Somers LogPrintf(LogERROR, "cifproxyarp: ioctl(SIOCDARP): %s\n", strerror(errno)); 20453c9f6c0SAtsushi Murai return 0; 20553c9f6c0SAtsushi Murai } 20653c9f6c0SAtsushi Murai return 1; 20753c9f6c0SAtsushi Murai } 208944f7098SBrian Somers 20953c9f6c0SAtsushi Murai #endif /* RTM_VERSION */ 21053c9f6c0SAtsushi Murai 21153c9f6c0SAtsushi Murai 21253c9f6c0SAtsushi Murai /* 21353c9f6c0SAtsushi Murai * get_ether_addr - get the hardware address of an interface on the 21453c9f6c0SAtsushi Murai * the same subnet as ipaddr. 21553c9f6c0SAtsushi Murai */ 21653c9f6c0SAtsushi Murai #define MAX_IFS 32 21753c9f6c0SAtsushi Murai 21875240ed1SBrian Somers static int 219944f7098SBrian Somers get_ether_addr(int s, u_long ipaddr, struct sockaddr_dl *hwaddr) 22053c9f6c0SAtsushi Murai { 22153c9f6c0SAtsushi Murai struct ifreq *ifr, *ifend, *ifp; 22253c9f6c0SAtsushi Murai u_long ina, mask; 22353c9f6c0SAtsushi Murai struct sockaddr_dl *dla; 22453c9f6c0SAtsushi Murai struct ifreq ifreq; 22553c9f6c0SAtsushi Murai struct ifconf ifc; 22653c9f6c0SAtsushi Murai struct ifreq ifs[MAX_IFS]; 22753c9f6c0SAtsushi Murai 22853c9f6c0SAtsushi Murai ifc.ifc_len = sizeof(ifs); 22953c9f6c0SAtsushi Murai ifc.ifc_req = ifs; 23053c9f6c0SAtsushi Murai if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { 231afc7fa2cSBrian Somers LogPrintf(LogERROR, "get_ether_addr: ioctl(SIOCGIFCONF): %s\n", 232afc7fa2cSBrian Somers strerror(errno)); 23353c9f6c0SAtsushi Murai return 0; 23453c9f6c0SAtsushi Murai } 23553c9f6c0SAtsushi Murai 23653c9f6c0SAtsushi Murai /* 237944f7098SBrian Somers * Scan through looking for an interface with an Internet address on the 238944f7098SBrian Somers * same subnet as `ipaddr'. 23953c9f6c0SAtsushi Murai */ 24053c9f6c0SAtsushi Murai ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); 24153c9f6c0SAtsushi Murai for (ifr = ifc.ifc_req; ifr < ifend;) { 24253c9f6c0SAtsushi Murai if (ifr->ifr_addr.sa_family == AF_INET) { 24353c9f6c0SAtsushi Murai ina = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr.s_addr; 24453c9f6c0SAtsushi Murai strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); 24599c02d39SWarner Losh ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0'; 246944f7098SBrian Somers 24753c9f6c0SAtsushi Murai /* 248944f7098SBrian Somers * Check that the interface is up, and not point-to-point or loopback. 24953c9f6c0SAtsushi Murai */ 25053c9f6c0SAtsushi Murai if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0) 25153c9f6c0SAtsushi Murai continue; 25253c9f6c0SAtsushi Murai if ((ifreq.ifr_flags & 25353c9f6c0SAtsushi Murai (IFF_UP | IFF_BROADCAST | IFF_POINTOPOINT | IFF_LOOPBACK | IFF_NOARP)) 25453c9f6c0SAtsushi Murai != (IFF_UP | IFF_BROADCAST)) 25553c9f6c0SAtsushi Murai goto nextif; 256944f7098SBrian Somers 25753c9f6c0SAtsushi Murai /* 25853c9f6c0SAtsushi Murai * Get its netmask and check that it's on the right subnet. 25953c9f6c0SAtsushi Murai */ 26053c9f6c0SAtsushi Murai if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0) 26153c9f6c0SAtsushi Murai continue; 26253c9f6c0SAtsushi Murai mask = ((struct sockaddr_in *) & ifreq.ifr_addr)->sin_addr.s_addr; 26353c9f6c0SAtsushi Murai if ((ipaddr & mask) != (ina & mask)) 26453c9f6c0SAtsushi Murai goto nextif; 26553c9f6c0SAtsushi Murai 26653c9f6c0SAtsushi Murai break; 26753c9f6c0SAtsushi Murai } 26853c9f6c0SAtsushi Murai nextif: 26953c9f6c0SAtsushi Murai ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + ifr->ifr_addr.sa_len); 27053c9f6c0SAtsushi Murai } 27153c9f6c0SAtsushi Murai 27253c9f6c0SAtsushi Murai if (ifr >= ifend) 27353c9f6c0SAtsushi Murai return 0; 274927145beSBrian Somers LogPrintf(LogPHASE, "Found interface %s for proxy arp\n", ifr->ifr_name); 27553c9f6c0SAtsushi Murai 27653c9f6c0SAtsushi Murai /* 277944f7098SBrian Somers * Now scan through again looking for a link-level address for this 278944f7098SBrian Somers * interface. 27953c9f6c0SAtsushi Murai */ 28053c9f6c0SAtsushi Murai ifp = ifr; 28153c9f6c0SAtsushi Murai for (ifr = ifc.ifc_req; ifr < ifend;) { 28253c9f6c0SAtsushi Murai if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 28353c9f6c0SAtsushi Murai && ifr->ifr_addr.sa_family == AF_LINK) { 284944f7098SBrian Somers 28553c9f6c0SAtsushi Murai /* 28653c9f6c0SAtsushi Murai * Found the link-level address - copy it out 28753c9f6c0SAtsushi Murai */ 28853c9f6c0SAtsushi Murai dla = (struct sockaddr_dl *) & ifr->ifr_addr; 28975240ed1SBrian Somers memcpy(hwaddr, dla, dla->sdl_len); 29053c9f6c0SAtsushi Murai return 1; 29153c9f6c0SAtsushi Murai } 29253c9f6c0SAtsushi Murai ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + ifr->ifr_addr.sa_len); 29353c9f6c0SAtsushi Murai } 29453c9f6c0SAtsushi Murai 29553c9f6c0SAtsushi Murai return 0; 29653c9f6c0SAtsushi Murai } 29753c9f6c0SAtsushi Murai 29853c9f6c0SAtsushi Murai 29953c9f6c0SAtsushi Murai #ifdef DEBUG 30075240ed1SBrian Somers int 30153c9f6c0SAtsushi Murai main() 30253c9f6c0SAtsushi Murai { 30353c9f6c0SAtsushi Murai u_long ipaddr; 30453c9f6c0SAtsushi Murai int s; 30553c9f6c0SAtsushi Murai 30653c9f6c0SAtsushi Murai s = socket(AF_INET, SOCK_DGRAM, 0); 30753c9f6c0SAtsushi Murai ipaddr = inet_addr("192.168.1.32"); 30853c9f6c0SAtsushi Murai sifproxyarp(s, ipaddr); 30953c9f6c0SAtsushi Murai close(s); 31053c9f6c0SAtsushi Murai } 31153c9f6c0SAtsushi Murai #endif 312