arp.c revision 37019
18097Sjkh/* 28097Sjkh * sys-bsd.c - System-dependent procedures for setting up 38097Sjkh * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.) 48097Sjkh * 58097Sjkh * Copyright (c) 1989 Carnegie Mellon University. 68097Sjkh * All rights reserved. 720064Sjkh * 88097Sjkh * Redistribution and use in source and binary forms are permitted 98097Sjkh * provided that the above copyright notice and this paragraph are 108097Sjkh * duplicated in all such forms and that any documentation, 118097Sjkh * advertising materials, and other materials related to such 128097Sjkh * distribution and use acknowledge that the software was developed 138097Sjkh * by Carnegie Mellon University. The name of the 148097Sjkh * University may not be used to endorse or promote products derived 158097Sjkh * from this software without specific prior written permission. 168881Srgrimes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 178881Srgrimes * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 188097Sjkh * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 198097Sjkh * 208097Sjkh * $Id: arp.c,v 1.28 1998/05/21 21:43:51 brian Exp $ 218097Sjkh * 228097Sjkh */ 238097Sjkh 248097Sjkh/* 258097Sjkh * TODO: 268097Sjkh */ 278097Sjkh 288097Sjkh#include <sys/types.h> 298097Sjkh#include <sys/socket.h> 308097Sjkh#include <net/if.h> 318097Sjkh#include <net/route.h> 328097Sjkh#include <net/if_dl.h> 338097Sjkh#include <netinet/in.h> 348097Sjkh#include <netinet/if_ether.h> 358097Sjkh#include <arpa/inet.h> 368097Sjkh#include <netinet/in_systm.h> 378097Sjkh#include <netinet/ip.h> 3818650Sjkh#include <sys/un.h> 3912661Speter 408347Sjkh#include <stdio.h> 418347Sjkh#include <stdlib.h> 428751Sjkh#include <string.h> 438347Sjkh#include <sys/errno.h> 448641Sjkh#include <sys/sysctl.h> 4512661Speter#include <unistd.h> 4612661Speter 4712661Speter#include "mbuf.h" 4812661Speter#include "log.h" 4910882Speter#include "id.h" 508347Sjkh#include "timer.h" 5112661Speter#include "fsm.h" 528097Sjkh#include "defs.h" 5312661Speter#include "iplist.h" 5418711Sjkh#include "throughput.h" 5518643Sjkh#include "slcompress.h" 5618711Sjkh#include "ipcp.h" 578281Sjkh#include "filter.h" 5812661Speter#include "descriptor.h" 598549Sjkh#include "lqr.h" 6015451Sjkh#include "hdlc.h" 6115451Sjkh#include "lcp.h" 6217362Sjkh#include "ccp.h" 6317368Sjkh#include "link.h" 648702Sjkh#include "mp.h" 658702Sjkh#include "bundle.h" 6612661Speter#include "arp.h" 678702Sjkh 6817362Sjkh/* 698702Sjkh * SET_SA_FAMILY - set the sa_family field of a struct sockaddr, 708702Sjkh * if it exists. 7112661Speter */ 7217362Sjkh#define SET_SA_FAMILY(addr, family) \ 7317027Sjkh memset((char *) &(addr), '\0', sizeof(addr)); \ 7417362Sjkh addr.sa_family = (family); \ 7517027Sjkh addr.sa_len = sizeof(addr); 7617027Sjkh 7717027Sjkh 788702Sjkh#if RTM_VERSION >= 3 798702Sjkh 808702Sjkh/* 818702Sjkh * arp_SetProxy - Make a proxy ARP entry for the peer. 828702Sjkh */ 838702Sjkhstatic struct { 848702Sjkh struct rt_msghdr hdr; 858702Sjkh struct sockaddr_inarp dst; 868702Sjkh struct sockaddr_dl hwa; 878702Sjkh char extra[128]; 888702Sjkh} arpmsg; 898702Sjkh 9014793Sjoergstatic int arpmsg_valid; 919202Srgrimes 929202Srgrimesint 9317368Sjkharp_SetProxy(struct bundle *bundle, struct in_addr addr, int s) 9417368Sjkh{ 9517368Sjkh int routes; 969202Srgrimes 979202Srgrimes /* 9817027Sjkh * Get the hardware address of an interface on the same subnet as our local 9917027Sjkh * address. 10017027Sjkh */ 10117027Sjkh memset(&arpmsg, 0, sizeof arpmsg); 10217027Sjkh if (!get_ether_addr(s, addr, &arpmsg.hwa)) { 1039202Srgrimes log_Printf(LogWARN, "Cannot determine ethernet address for proxy ARP\n"); 10414793Sjoerg return 0; 1059202Srgrimes } 10617368Sjkh routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET); 10717368Sjkh if (routes < 0) { 10817368Sjkh log_Printf(LogERROR, "arp_SetProxy: opening routing socket: %s\n", 1099202Srgrimes strerror(errno)); 1109202Srgrimes return 0; 11117027Sjkh } 11217027Sjkh arpmsg.hdr.rtm_type = RTM_ADD; 11317027Sjkh arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC; 11417027Sjkh arpmsg.hdr.rtm_version = RTM_VERSION; 11517027Sjkh arpmsg.hdr.rtm_seq = ++bundle->routing_seq; 1169202Srgrimes arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; 11717362Sjkh arpmsg.hdr.rtm_inits = RTV_EXPIRE; 11817362Sjkh arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp); 11917368Sjkh arpmsg.dst.sin_family = AF_INET; 12017368Sjkh arpmsg.dst.sin_addr.s_addr = addr.s_addr; 12117368Sjkh arpmsg.dst.sin_other = SIN_PROXY; 12217362Sjkh 12317362Sjkh arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg 12417362Sjkh + arpmsg.hwa.sdl_len; 12517362Sjkh if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { 12617362Sjkh log_Printf(LogERROR, "Add proxy arp entry: %s\n", strerror(errno)); 12717362Sjkh close(routes); 12817362Sjkh return 0; 12917362Sjkh } 1308702Sjkh close(routes); 1318702Sjkh arpmsg_valid = 1; 1328702Sjkh return 1; 1338702Sjkh} 1348702Sjkh 1358702Sjkh/* 1368705Sjkh * arp_ClearProxy - Delete the proxy ARP entry for the peer. 1378702Sjkh */ 13813421Sjkhint 13913421Sjkharp_ClearProxy(struct bundle *bundle, struct in_addr addr, int s) 1408702Sjkh{ 1418702Sjkh int routes; 1428702Sjkh 1438702Sjkh if (!arpmsg_valid) 1448702Sjkh return 0; 1458702Sjkh arpmsg_valid = 0; 1468702Sjkh 14712661Speter arpmsg.hdr.rtm_type = RTM_DELETE; 1488702Sjkh arpmsg.hdr.rtm_seq = ++bundle->routing_seq; 14912661Speter 15012661Speter routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET); 1518702Sjkh if (routes < 0) { 1528702Sjkh log_Printf(LogERROR, "arp_SetProxy: opening routing socket: %s\n", 1538702Sjkh strerror(errno)); 1548702Sjkh return 0; 1558702Sjkh } 1568702Sjkh if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { 1578702Sjkh log_Printf(LogERROR, "Delete proxy arp entry: %s\n", strerror(errno)); 15817027Sjkh close(routes); 15912661Speter return 0; 16017027Sjkh } 16117027Sjkh close(routes); 16217362Sjkh return 1; 16317027Sjkh} 16417368Sjkh 16512661Speter#else /* RTM_VERSION */ 16612661Speter 16712661Speter/* 1688702Sjkh * arp_SetProxy - Make a proxy ARP entry for the peer. 16917368Sjkh */ 17012661Speterint 17112661Speterarp_SetProxy(struct bundle *bundle, struct in_addr addr, int s) 17212661Speter{ 1738702Sjkh struct arpreq arpreq; 17417368Sjkh struct { 17512661Speter struct sockaddr_dl sdl; 17612661Speter char space[128]; 17712661Speter } dls; 17812661Speter 17912661Speter memset(&arpreq, '\0', sizeof arpreq); 18017368Sjkh 18117362Sjkh /* 18217362Sjkh * Get the hardware address of an interface on the same subnet as our local 18317362Sjkh * address. 18417362Sjkh */ 18517362Sjkh if (!get_ether_addr(s, addr, &dls.sdl)) { 18617362Sjkh log_Printf(LOG_PHASE_BIT, "Cannot determine ethernet address for proxy ARP\n"); 18712661Speter return 0; 1888702Sjkh } 1898702Sjkh arpreq.arp_ha.sa_len = sizeof(struct sockaddr); 19012661Speter arpreq.arp_ha.sa_family = AF_UNSPEC; 1918636Sjkh memcpy(arpreq.arp_ha.sa_data, LLADDR(&dls.sdl), dls.sdl.sdl_alen); 1928589Sjkh SET_SA_FAMILY(arpreq.arp_pa, AF_INET); 1938636Sjkh ((struct sockaddr_in *)&arpreq.arp_pa)->sin_addr.s_addr = addr.s_addr; 1948589Sjkh arpreq.arp_flags = ATF_PERM | ATF_PUBL; 1958636Sjkh if (ID0ioctl(s, SIOCSARP, (caddr_t) & arpreq) < 0) { 19615242Sjkh log_Printf(LogERROR, "arp_SetProxy: ioctl(SIOCSARP): %s\n", 1978636Sjkh strerror(errno)); 19812661Speter return 0; 19915439Sjkh } 20015439Sjkh return 1; 20115242Sjkh} 2028677Sjkh 20312661Speter/* 20412661Speter * arp_ClearProxy - Delete the proxy ARP entry for the peer. 20512661Speter */ 2068677Sjkhint 2078677Sjkharp_ClearProxy(struct bundle *bundle, struct in_addr addr, int s) 20817404Sjkh{ 20912661Speter struct arpreq arpreq; 21012661Speter 21112661Speter memset(&arpreq, '\0', sizeof arpreq); 21212661Speter SET_SA_FAMILY(arpreq.arp_pa, AF_INET); 21318830Sjkh ((struct sockaddr_in *)&arpreq.arp_pa)->sin_addr.s_addr = addr.s_addr; 21415451Sjkh if (ID0ioctl(s, SIOCDARP, (caddr_t) & arpreq) < 0) { 2158556Sjkh log_Printf(LogERROR, "arp_ClearProxy: ioctl(SIOCDARP): %s\n", 21615419Sjkh strerror(errno)); 2179202Srgrimes return 0; 21815242Sjkh } 2199202Srgrimes return 1; 22015445Sjkh} 22115445Sjkh 22210882Speter#endif /* RTM_VERSION */ 22312661Speter 22412661Speter 22512661Speter/* 22615242Sjkh * get_ether_addr - get the hardware address of an interface on the 2279202Srgrimes * the same subnet as ipaddr. 22810882Speter */ 22912661Speter 23012661Speterint 23115242Sjkhget_ether_addr(int s, struct in_addr ipaddr, struct sockaddr_dl *hwaddr) 23212661Speter{ 23312661Speter int mib[6], sa_len, skip, b; 2348663Sphk size_t needed; 2358709Sjkh char *buf, *ptr, *end; 23620064Sjkh struct if_msghdr *ifm; 23712661Speter struct ifa_msghdr *ifam; 23814765Sjkh struct sockaddr *sa; 23914765Sjkh struct sockaddr_dl *dl; 24014765Sjkh struct sockaddr_in *ifa, *mask; 24112661Speter 24215242Sjkh mib[0] = CTL_NET; 24312661Speter mib[1] = PF_ROUTE; 2448751Sjkh mib[2] = 0; 24512661Speter mib[3] = 0; 24615242Sjkh mib[4] = NET_RT_IFLIST; 24712661Speter mib[5] = 0; 24815384Sjkh 24915384Sjkh if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 25015384Sjkh log_Printf(LogERROR, "get_ether_addr: sysctl: estimate: %s\n", 25115242Sjkh strerror(errno)); 25215242Sjkh return 0; 25315242Sjkh } 25415242Sjkh 25515242Sjkh if ((buf = malloc(needed)) == NULL) 25615242Sjkh return 0; 25712661Speter 25812661Speter if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) { 25912661Speter free(buf); 26012661Speter return 0; 26115091Sjkh } 26212661Speter end = buf + needed; 26312661Speter 26417005Sjkh ptr = buf; 26512661Speter while (ptr < end) { 26612661Speter ifm = (struct if_msghdr *)ptr; /* On if_msghdr */ 26712661Speter if (ifm->ifm_type != RTM_IFINFO) 26812661Speter break; 26912661Speter dl = (struct sockaddr_dl *)(ifm + 1); /* Single _dl at end */ 27019564Sjoerg skip = (ifm->ifm_flags & (IFF_UP | IFF_BROADCAST | IFF_POINTOPOINT | 27119564Sjoerg IFF_NOARP | IFF_LOOPBACK)) != (IFF_UP | IFF_BROADCAST); 27219564Sjoerg ptr += ifm->ifm_msglen; /* First ifa_msghdr */ 27319564Sjoerg while (ptr < end) { 27418830Sjkh ifam = (struct ifa_msghdr *)ptr; /* Next ifa_msghdr (alias) */ 27515242Sjkh if (ifam->ifam_type != RTM_NEWADDR) /* finished ? */ 27612661Speter break; 27712661Speter sa = (struct sockaddr *)(ifam+1); /* pile of sa's at end */ 27812661Speter ptr += ifam->ifam_msglen; 27912661Speter if (skip || (ifam->ifam_addrs & (RTA_NETMASK|RTA_IFA)) != 28014670Sjkh (RTA_NETMASK|RTA_IFA)) 28112661Speter continue; 28214670Sjkh /* Found a candidate. Do the addresses match ? */ 28317005Sjkh if (log_IsKept(LogDEBUG) && 28412661Speter ptr == (char *)ifm + ifm->ifm_msglen + ifam->ifam_msglen) 28512661Speter log_Printf(LogDEBUG, "%.*s interface is a candidate for proxy\n", 28612661Speter dl->sdl_nlen, dl->sdl_data); 2878825Sjkh b = 1; 28812661Speter ifa = mask = NULL; 28919819Sjoerg while (b < (RTA_NETMASK|RTA_IFA) && sa < (struct sockaddr *)ptr) { 29019819Sjoerg switch (b) { 29119819Sjoerg case RTA_IFA: 29219571Sjoerg ifa = (struct sockaddr_in *)sa; 29317005Sjkh break; 29412661Speter case RTA_NETMASK: 29519571Sjoerg /* 29619571Sjoerg * Careful here ! this sockaddr doesn't have sa_family set to 29719571Sjoerg * AF_INET, and is only 8 bytes big ! I have no idea why ! 29819571Sjoerg */ 29912661Speter mask = (struct sockaddr_in *)sa; 30012661Speter break; 30112661Speter } 30212661Speter if (ifam->ifam_addrs & b) { 30312661Speter#define ALN sizeof(ifa->sin_addr.s_addr) 30412661Speter sa_len = sa->sa_len > 0 ? ((sa->sa_len-1)|(ALN-1))+1 : ALN; 30512661Speter sa = (struct sockaddr *)((char *)sa + sa_len); 30612661Speter } 30712661Speter b <<= 1; 30812661Speter } 30912661Speter if (log_IsKept(LogDEBUG)) { 31012661Speter char a[16]; 31112661Speter strncpy(a, inet_ntoa(mask->sin_addr), sizeof a - 1); 31212661Speter a[sizeof a - 1] = '\0'; 31319571Sjoerg log_Printf(LogDEBUG, "Check addr %s, mask %s\n", 31419571Sjoerg inet_ntoa(ifa->sin_addr), a); 31519571Sjoerg } 3168751Sjkh if (ifa->sin_family == AF_INET && 31712661Speter (ifa->sin_addr.s_addr & mask->sin_addr.s_addr) == 31812661Speter (ipaddr.s_addr & mask->sin_addr.s_addr)) { 3198751Sjkh log_Printf(LogPHASE, "Found interface %.*s for %s\n", 32012661Speter dl->sdl_alen, dl->sdl_data, inet_ntoa(ipaddr)); 32112661Speter memcpy(hwaddr, dl, dl->sdl_len); 32212661Speter free(buf); 32312661Speter return 1; 32412661Speter } 32512661Speter } 32612661Speter } 32712661Speter free(buf); 32815242Sjkh 3298636Sjkh return 0; 33012661Speter} 33110882Speter