arp.c revision 28679
16735Samurai/* 26735Samurai * sys-bsd.c - System-dependent procedures for setting up 36735Samurai * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.) 46735Samurai * 56735Samurai * Copyright (c) 1989 Carnegie Mellon University. 66735Samurai * All rights reserved. 76735Samurai * 86735Samurai * Redistribution and use in source and binary forms are permitted 96735Samurai * provided that the above copyright notice and this paragraph are 106735Samurai * duplicated in all such forms and that any documentation, 116735Samurai * advertising materials, and other materials related to such 126735Samurai * distribution and use acknowledge that the software was developed 136735Samurai * by Carnegie Mellon University. The name of the 146735Samurai * University may not be used to endorse or promote products derived 156735Samurai * from this software without specific prior written permission. 166735Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 176735Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 186735Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 198857Srgrimes * 2028679Sbrian * $Id: arp.c,v 1.12 1997/06/09 03:27:11 brian Exp $ 218857Srgrimes * 226735Samurai */ 236735Samurai 246735Samurai/* 256735Samurai * TODO: 266735Samurai */ 276735Samurai 286735Samurai#include <sys/ioctl.h> 296735Samurai#include <sys/types.h> 3013379Sphk#include <sys/uio.h> 316735Samurai#include <sys/socket.h> 326735Samurai#include <sys/time.h> 336735Samurai#include <sys/errno.h> 3413379Sphk#include <unistd.h> 3513379Sphk#include <string.h> 366735Samurai 376735Samurai#include <net/if.h> 3821264Swollman#include <net/if_var.h> 396735Samurai#include <net/route.h> 406735Samurai#include <net/if_dl.h> 416735Samurai#include <netinet/in.h> 426735Samurai#include <stdio.h> 436735Samurai#include <fcntl.h> 446735Samurai#ifdef __bsdi__ 456735Samurai#include <kvm.h> 466735Samurai#endif 476735Samurai#include <net/if_types.h> 486735Samurai#include <netinet/in_var.h> 496735Samurai#include <netinet/if_ether.h> 506735Samurai#include "log.h" 516735Samurai 526735Samurai#if RTM_VERSION >= 3 536735Samurai#include <netinet/if_ether.h> 546735Samurai#endif 556735Samurai 566735Samuraistatic int rtm_seq; 576735Samurai 5826516Sbrianstatic int get_ether_addr(int, u_long, struct sockaddr_dl *); 5913389Sphk 606735Samurai#define BCOPY(s, d, l) memcpy(d, s, l) 616735Samurai#define BZERO(s, n) memset(s, 0, n) 626735Samurai/* 636735Samurai * SET_SA_FAMILY - set the sa_family field of a struct sockaddr, 646735Samurai * if it exists. 656735Samurai */ 666735Samurai#define SET_SA_FAMILY(addr, family) \ 676735Samurai BZERO((char *) &(addr), sizeof(addr)); \ 686735Samurai addr.sa_family = (family); \ 696735Samurai addr.sa_len = sizeof(addr); 706735Samurai 716735Samurai 726735Samurai#if RTM_VERSION >= 3 736735Samurai 746735Samurai/* 756735Samurai * sifproxyarp - Make a proxy ARP entry for the peer. 766735Samurai */ 776735Samuraistatic struct { 7828679Sbrian struct rt_msghdr hdr; 7928679Sbrian struct sockaddr_inarp dst; 8028679Sbrian struct sockaddr_dl hwa; 8128679Sbrian char extra[128]; 8228679Sbrian} arpmsg; 836735Samurai 846735Samuraistatic int arpmsg_valid; 856735Samurai 866735Samuraiint 8728679Sbriansifproxyarp(int unit, u_long hisaddr) 886735Samurai{ 8928679Sbrian int routes; 906735Samurai 9128679Sbrian /* 9228679Sbrian * Get the hardware address of an interface on the same subnet as our local 9328679Sbrian * address. 9428679Sbrian */ 9528679Sbrian memset(&arpmsg, 0, sizeof(arpmsg)); 9628679Sbrian if (!get_ether_addr(unit, hisaddr, &arpmsg.hwa)) { 9728679Sbrian LogPrintf(LogERROR, "Cannot determine ethernet address" 9828679Sbrian " for proxy ARP\n"); 9928679Sbrian return 0; 10028679Sbrian } 10128679Sbrian if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) { 10228679Sbrian LogPrintf(LogERROR, "sifproxyarp: opening routing socket: %s\n", 10328679Sbrian strerror(errno)); 10428679Sbrian return 0; 10528679Sbrian } 10628679Sbrian arpmsg.hdr.rtm_type = RTM_ADD; 10728679Sbrian arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC; 10828679Sbrian arpmsg.hdr.rtm_version = RTM_VERSION; 10928679Sbrian arpmsg.hdr.rtm_seq = ++rtm_seq; 11028679Sbrian arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; 11128679Sbrian arpmsg.hdr.rtm_inits = RTV_EXPIRE; 11228679Sbrian arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp); 11328679Sbrian arpmsg.dst.sin_family = AF_INET; 11428679Sbrian arpmsg.dst.sin_addr.s_addr = hisaddr; 11528679Sbrian arpmsg.dst.sin_other = SIN_PROXY; 1166735Samurai 11728679Sbrian arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg 11828679Sbrian + arpmsg.hwa.sdl_len; 11928679Sbrian if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { 12028679Sbrian LogPrintf(LogERROR, "Add proxy arp entry: %s\n", strerror(errno)); 1216735Samurai close(routes); 12228679Sbrian return 0; 12328679Sbrian } 12428679Sbrian close(routes); 12528679Sbrian arpmsg_valid = 1; 12628679Sbrian return 1; 1276735Samurai} 1286735Samurai 1296735Samurai/* 1306735Samurai * cifproxyarp - Delete the proxy ARP entry for the peer. 1316735Samurai */ 1326735Samuraiint 13328679Sbriancifproxyarp(int unit, u_long hisaddr) 1346735Samurai{ 13528679Sbrian int routes; 1366735Samurai 13728679Sbrian if (!arpmsg_valid) 13828679Sbrian return 0; 13928679Sbrian arpmsg_valid = 0; 1406735Samurai 14128679Sbrian arpmsg.hdr.rtm_type = RTM_DELETE; 14228679Sbrian arpmsg.hdr.rtm_seq = ++rtm_seq; 1436735Samurai 14428679Sbrian if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) { 14528679Sbrian LogPrintf(LogERROR, "sifproxyarp: opening routing socket: %s\n", 14628679Sbrian strerror(errno)); 14728679Sbrian return 0; 14828679Sbrian } 14928679Sbrian if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { 15028679Sbrian LogPrintf(LogERROR, "Delete proxy arp entry: %s\n", strerror(errno)); 1516735Samurai close(routes); 15228679Sbrian return 0; 15328679Sbrian } 15428679Sbrian close(routes); 15528679Sbrian return 1; 1566735Samurai} 1576735Samurai 15828679Sbrian#else /* RTM_VERSION */ 1596735Samurai 1606735Samurai/* 1616735Samurai * sifproxyarp - Make a proxy ARP entry for the peer. 1626735Samurai */ 1636735Samuraiint 16428679Sbriansifproxyarp(int unit, u_long hisaddr) 1656735Samurai{ 16628679Sbrian struct arpreq arpreq; 16728679Sbrian struct { 16828679Sbrian struct sockaddr_dl sdl; 16928679Sbrian char space[128]; 17028679Sbrian } dls; 1716735Samurai 17228679Sbrian BZERO(&arpreq, sizeof(arpreq)); 1736735Samurai 17428679Sbrian /* 17528679Sbrian * Get the hardware address of an interface on the same subnet as our local 17628679Sbrian * address. 17728679Sbrian */ 17828679Sbrian if (!get_ether_addr(unit, hisaddr, &dls.sdl)) { 17928679Sbrian LogPrintf(LOG_PHASE_BIT, "Cannot determine ethernet address for proxy ARP\n"); 18028679Sbrian return 0; 18128679Sbrian } 18228679Sbrian arpreq.arp_ha.sa_len = sizeof(struct sockaddr); 18328679Sbrian arpreq.arp_ha.sa_family = AF_UNSPEC; 18428679Sbrian BCOPY(LLADDR(&dls.sdl), arpreq.arp_ha.sa_data, dls.sdl.sdl_alen); 18528679Sbrian SET_SA_FAMILY(arpreq.arp_pa, AF_INET); 18628679Sbrian ((struct sockaddr_in *) & arpreq.arp_pa)->sin_addr.s_addr = hisaddr; 18728679Sbrian arpreq.arp_flags = ATF_PERM | ATF_PUBL; 18828679Sbrian if (ioctl(unit, SIOCSARP, (caddr_t) & arpreq) < 0) { 18928679Sbrian LogPrintf(LogERROR, "sifproxyarp: ioctl(SIOCSARP): \n"); 19028679Sbrian return 0; 19128679Sbrian } 19228679Sbrian return 1; 1936735Samurai} 1946735Samurai 1956735Samurai/* 1966735Samurai * cifproxyarp - Delete the proxy ARP entry for the peer. 1976735Samurai */ 1986735Samuraiint 19928679Sbriancifproxyarp(int unit, u_long hisaddr) 2006735Samurai{ 20128679Sbrian struct arpreq arpreq; 2026735Samurai 20328679Sbrian BZERO(&arpreq, sizeof(arpreq)); 20428679Sbrian SET_SA_FAMILY(arpreq.arp_pa, AF_INET); 20528679Sbrian ((struct sockaddr_in *) & arpreq.arp_pa)->sin_addr.s_addr = hisaddr; 20628679Sbrian if (ioctl(unit, SIOCDARP, (caddr_t) & arpreq) < 0) { 20728679Sbrian LogPrintf(LogERROR, "cifproxyarp: ioctl(SIOCDARP): \n"); 20828679Sbrian return 0; 20928679Sbrian } 21028679Sbrian return 1; 2116735Samurai} 2126735Samurai 21328679Sbrian#endif /* RTM_VERSION */ 2146735Samurai 21528679Sbrian 2166735Samurai/* 2176735Samurai * get_ether_addr - get the hardware address of an interface on the 2186735Samurai * the same subnet as ipaddr. 2196735Samurai */ 2206735Samurai#define MAX_IFS 32 2216735Samurai 2226735Samuraiint 22328679Sbrianget_ether_addr(int s, u_long ipaddr, struct sockaddr_dl * hwaddr) 2246735Samurai{ 22528679Sbrian struct ifreq *ifr, *ifend, *ifp; 22628679Sbrian u_long ina, mask; 22728679Sbrian struct sockaddr_dl *dla; 22828679Sbrian struct ifreq ifreq; 22928679Sbrian struct ifconf ifc; 23028679Sbrian struct ifreq ifs[MAX_IFS]; 2316735Samurai 23228679Sbrian ifc.ifc_len = sizeof(ifs); 23328679Sbrian ifc.ifc_req = ifs; 23428679Sbrian if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { 23528679Sbrian LogPrintf(LogERROR, "get_ether_addr: ioctl(SIOCGIFCONF): \n"); 23628679Sbrian return 0; 23728679Sbrian } 2386735Samurai 23928679Sbrian /* 24028679Sbrian * Scan through looking for an interface with an Internet address on the 24128679Sbrian * same subnet as `ipaddr'. 24228679Sbrian */ 24328679Sbrian ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); 24428679Sbrian for (ifr = ifc.ifc_req; ifr < ifend;) { 24528679Sbrian if (ifr->ifr_addr.sa_family == AF_INET) { 24628679Sbrian ina = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr.s_addr; 24728679Sbrian strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); 24828679Sbrian ifreq.ifr_name[sizeof(ifreq.ifr_name) - 1] = '\0'; 2496735Samurai 25028679Sbrian /* 25128679Sbrian * Check that the interface is up, and not point-to-point or loopback. 25228679Sbrian */ 25328679Sbrian if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0) 25428679Sbrian continue; 25528679Sbrian if ((ifreq.ifr_flags & 25628679Sbrian (IFF_UP | IFF_BROADCAST | IFF_POINTOPOINT | IFF_LOOPBACK | IFF_NOARP)) 25728679Sbrian != (IFF_UP | IFF_BROADCAST)) 25828679Sbrian goto nextif; 25928679Sbrian 26028679Sbrian /* 26128679Sbrian * Get its netmask and check that it's on the right subnet. 26228679Sbrian */ 26328679Sbrian if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0) 26428679Sbrian continue; 26528679Sbrian mask = ((struct sockaddr_in *) & ifreq.ifr_addr)->sin_addr.s_addr; 26628679Sbrian if ((ipaddr & mask) != (ina & mask)) 26728679Sbrian goto nextif; 26828679Sbrian 26928679Sbrian break; 27028679Sbrian } 2716735Samurainextif: 27228679Sbrian ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + ifr->ifr_addr.sa_len); 27328679Sbrian } 2746735Samurai 27528679Sbrian if (ifr >= ifend) 27628679Sbrian return 0; 27728679Sbrian LogPrintf(LogPHASE, "Found interface %s for proxy arp\n", ifr->ifr_name); 2786735Samurai 27928679Sbrian /* 28028679Sbrian * Now scan through again looking for a link-level address for this 28128679Sbrian * interface. 28228679Sbrian */ 28328679Sbrian ifp = ifr; 28428679Sbrian for (ifr = ifc.ifc_req; ifr < ifend;) { 28528679Sbrian if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 28628679Sbrian && ifr->ifr_addr.sa_family == AF_LINK) { 28728679Sbrian 28828679Sbrian /* 28928679Sbrian * Found the link-level address - copy it out 29028679Sbrian */ 29128679Sbrian dla = (struct sockaddr_dl *) & ifr->ifr_addr; 2926735Samurai#ifdef __bsdi__ 29328679Sbrian if (dla->sdl_alen == 0) 29428679Sbrian kmemgetether(ifr->ifr_name, dla); 2956735Samurai#endif 29628679Sbrian BCOPY(dla, hwaddr, dla->sdl_len); 29728679Sbrian return 1; 2986735Samurai } 29928679Sbrian ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + ifr->ifr_addr.sa_len); 30028679Sbrian } 3016735Samurai 30228679Sbrian return 0; 3036735Samurai} 3046735Samurai 3056735Samurai#ifdef __bsdi__ 3066735Samurai#include <nlist.h> 3076735Samurai 3086735Samuraistruct nlist nl[] = { 3096735Samurai#define N_IFNET 0 31028679Sbrian {"_ifnet"}, 31128679Sbrian "", 3126735Samurai}; 3136735Samurai 3146735Samurai 3156735Samuraikvm_t *kvmd; 3166735Samurai 3178857Srgrimes/* 3186735Samurai * Read kernel memory, return 0 on success. 3198857Srgrimes */ 3206735Samuraiint 32128679Sbriankread(u_long addr, char *buf, int size) 3228857Srgrimes{ 32326516Sbrian if (kvm_read(kvmd, addr, buf, size) != size) { 32426516Sbrian /* XXX this duplicates kvm_read's error printout */ 32526516Sbrian LogPrintf(LogERROR, "kvm_read %s\n", kvm_geterr(kvmd)); 32626516Sbrian return -1; 32726516Sbrian } 32826516Sbrian return 0; 3296735Samurai} 3306735Samurai 33128679Sbrianvoid 33228679Sbriankmemgetether(char *ifname, struct sockaddr_dl * dlo) 3336735Samurai{ 3346735Samurai struct ifnet ifnet; 3356735Samurai int n; 3366735Samurai u_long addr, ifaddraddr, ifnetfound, ifaddrfound; 33728679Sbrian char name[16 + 32]; 3386735Samurai struct sockaddr *sa; 3396735Samurai char *cp; 3406735Samurai struct sockaddr_dl *sdl; 3418857Srgrimes union { 34228679Sbrian struct ifaddr ifa; 34328679Sbrian struct in_ifaddr in; 34428679Sbrian } ifaddr; 3456735Samurai struct arpcom ac; 3466735Samurai 3476735Samurai kvmd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL); 3486735Samurai if (kvmd) { 3496735Samurai n = kvm_nlist(kvmd, nl); 3506735Samurai if (n >= 0) { 3516735Samurai addr = nl[N_IFNET].n_value; 35228679Sbrian kread(addr, (char *) &addr, sizeof(addr)); 3536735Samurai ifaddraddr = ifnetfound = 0; 3546735Samurai while (addr || ifaddraddr) { 3556735Samurai ifnetfound = addr; 3566735Samurai if (ifaddraddr == 0) { 35728679Sbrian if (kread(addr, (char *) &ifnet, sizeof(ifnet)) || 35828679Sbrian kread((u_long) ifnet.if_name, name, 16)) 35928679Sbrian return; 3606735Samurai name[15] = 0; 3616735Samurai addr = (u_long) ifnet.if_next; 36228679Sbrian cp = (char *) index(name, '\0'); 3636735Samurai cp += sprintf(cp, "%d", ifnet.if_unit); 3646735Samurai *cp = '\0'; 36528679Sbrian ifaddraddr = (u_long) ifnet.if_addrlist; 3666735Samurai } 3676735Samurai ifaddrfound = ifaddraddr; 3686735Samurai if (ifaddraddr) { 36928679Sbrian if (kread(ifaddraddr, (char *) &ifaddr, sizeof ifaddr)) { 3706735Samurai ifaddraddr = 0; 3716735Samurai continue; 3726735Samurai } 3736735Samurai#define CP(x) ((char *)(x)) 3746735Samurai cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + CP(&ifaddr); 37528679Sbrian sa = (struct sockaddr *) cp; 3766735Samurai if (sa->sa_family == AF_LINK && strcmp(ifname, name) == 0) { 37728679Sbrian sdl = (struct sockaddr_dl *) sa; 37828679Sbrian cp = (char *) LLADDR(sdl); 3796735Samurai n = sdl->sdl_alen; 3806735Samurai if (ifnet.if_type == IFT_ETHER) { 38128679Sbrian if (n == 0) { 38228679Sbrian kread(ifnetfound, (char *) &ac, sizeof(ac)); 38328679Sbrian cp = (char *) LLADDR(sdl); 38428679Sbrian bcopy((char *) ac.ac_enaddr, cp, 6); 38528679Sbrian sdl->sdl_alen = 6; 38628679Sbrian } 38728679Sbrian bcopy(sdl, dlo, sizeof(*sdl)); 38828679Sbrian return; 3896735Samurai } 3906735Samurai } 39128679Sbrian ifaddraddr = (u_long) ifaddr.ifa.ifa_next; 3926735Samurai } 3936735Samurai } 3946735Samurai } 3956735Samurai } 3966735Samurai} 39728679Sbrian 3986735Samurai#endif 3996735Samurai 4006735Samurai#ifdef DEBUG 4016735Samuraimain() 4026735Samurai{ 40328679Sbrian u_long ipaddr; 40428679Sbrian int s; 4056735Samurai 40628679Sbrian s = socket(AF_INET, SOCK_DGRAM, 0); 40728679Sbrian ipaddr = inet_addr("192.168.1.32"); 40828679Sbrian sifproxyarp(s, ipaddr); 40928679Sbrian close(s); 4106735Samurai} 41128679Sbrian 4126735Samurai#endif 413