arp.c revision 32616
150276Speter/* 2174993Srafan * sys-bsd.c - System-dependent procedures for setting up 350276Speter * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.) 450276Speter * 550276Speter * Copyright (c) 1989 Carnegie Mellon University. 650276Speter * All rights reserved. 750276Speter * 850276Speter * Redistribution and use in source and binary forms are permitted 950276Speter * provided that the above copyright notice and this paragraph are 1050276Speter * duplicated in all such forms and that any documentation, 1150276Speter * advertising materials, and other materials related to such 1250276Speter * distribution and use acknowledge that the software was developed 1350276Speter * by Carnegie Mellon University. The name of the 1450276Speter * University may not be used to endorse or promote products derived 1550276Speter * from this software without specific prior written permission. 1650276Speter * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1750276Speter * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1850276Speter * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1950276Speter * 2050276Speter * $Id: arp.c,v 1.21 1998/01/11 04:02:57 brian Exp $ 2150276Speter * 2250276Speter */ 2350276Speter 2450276Speter/* 2550276Speter * TODO: 2650276Speter */ 2750276Speter 2850276Speter#include <sys/types.h> 2950276Speter#include <sys/time.h> 3050276Speter#include <sys/socket.h> 3150276Speter#include <net/if.h> 3250276Speter#include <net/route.h> 3350276Speter#include <net/if_dl.h> 3450276Speter#include <netinet/in.h> 3550276Speter#include <net/if_types.h> 3650276Speter#include <netinet/if_ether.h> 3750276Speter 3850276Speter#include <fcntl.h> 3950276Speter#include <stdio.h> 4050276Speter#include <stdlib.h> 41174993Srafan#include <string.h> 4250276Speter#include <sys/errno.h> 4366963Speter#include <sys/ioctl.h> 4466963Speter#include <sys/sysctl.h> 4550276Speter#include <sys/uio.h> 4650276Speter#include <unistd.h> 4766963Speter 4850276Speter#include "command.h" 49174993Srafan#include "mbuf.h" 5050276Speter#include "log.h" 5150276Speter#include "id.h" 5250276Speter#include "route.h" 5350276Speter#include "arp.h" 5450276Speter 5566963Speter#ifdef DEBUG 5666963Speter/* 5766963Speter * To test the proxy arp stuff, put the following in your Makefile: 5866963Speter * 5966963Speter * arp-test: arp.c 6066963Speter * cp ${.CURDIR}/arp.c arp-test.c 6150276Speter * echo 'const char *' >>arp-test.c 6266963Speter * awk '/^Index2Nam/,/^}/' ${.CURDIR}/route.c >>arp-test.c 6366963Speter * cc -I${.CURDIR} -DDEBUG arp-test.c -o arp-test 6450276Speter * 6562449Speter * and type ``make arp-test''. 6662449Speter * 6750276Speter */ 6862449Speter#define LogIsKept(x) 0 6950276Speter#define LogPrintf fprintf 7062449Speter#undef LogDEBUG 71166124Srafan#define LogDEBUG stderr 7262449Speter#undef LogERROR 7362449Speter#define LogERROR stderr 7462449Speter#undef LogPHASE 75166124Srafan#define LogPHASE stdout 7650276Speter#define ID0socket socket 7750276Speter#define ID0ioctl ioctl 7862449Speter#endif 7962449Speter 8050276Speterstatic int rtm_seq; 8166963Speter 82166124Srafanstatic int get_ether_addr(int, struct in_addr, struct sockaddr_dl *); 8350276Speter 8450276Speter/* 8566963Speter * SET_SA_FAMILY - set the sa_family field of a struct sockaddr, 8666963Speter * if it exists. 8766963Speter */ 8866963Speter#define SET_SA_FAMILY(addr, family) \ 8966963Speter memset((char *) &(addr), '\0', sizeof(addr)); \ 9066963Speter addr.sa_family = (family); \ 9166963Speter addr.sa_len = sizeof(addr); 9266963Speter 9366963Speter 9466963Speter#if RTM_VERSION >= 3 9566963Speter 9666963Speter/* 9766963Speter * sifproxyarp - Make a proxy ARP entry for the peer. 9866963Speter */ 9966963Speterstatic struct { 10066963Speter struct rt_msghdr hdr; 10176726Speter struct sockaddr_inarp dst; 10266963Speter struct sockaddr_dl hwa; 10366963Speter char extra[128]; 10466963Speter} arpmsg; 10566963Speter 10666963Speterstatic int arpmsg_valid; 10766963Speter 10866963Speterint 10966963Spetersifproxyarp(int unit, struct in_addr hisaddr) 11066963Speter{ 11166963Speter int routes; 11266963Speter 11366963Speter /* 11466963Speter * Get the hardware address of an interface on the same subnet as our local 11566963Speter * address. 11666963Speter */ 11766963Speter memset(&arpmsg, 0, sizeof arpmsg); 11866963Speter if (!get_ether_addr(unit, hisaddr, &arpmsg.hwa)) { 11966963Speter LogPrintf(LogERROR, "Cannot determine ethernet address for proxy ARP\n"); 12066963Speter return 0; 12166963Speter } 12266963Speter routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET); 12366963Speter if (routes < 0) { 12466963Speter LogPrintf(LogERROR, "sifproxyarp: opening routing socket: %s\n", 12566963Speter strerror(errno)); 12666963Speter return 0; 12766963Speter } 12862449Speter arpmsg.hdr.rtm_type = RTM_ADD; 129166124Srafan arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC; 130166124Srafan arpmsg.hdr.rtm_version = RTM_VERSION; 131166124Srafan arpmsg.hdr.rtm_seq = ++rtm_seq; 132166124Srafan arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; 133166124Srafan arpmsg.hdr.rtm_inits = RTV_EXPIRE; 134166124Srafan arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp); 135166124Srafan arpmsg.dst.sin_family = AF_INET; 136166124Srafan arpmsg.dst.sin_addr.s_addr = hisaddr.s_addr; 137166124Srafan arpmsg.dst.sin_other = SIN_PROXY; 138166124Srafan 139166124Srafan arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg 140166124Srafan + arpmsg.hwa.sdl_len; 141166124Srafan if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { 142166124Srafan LogPrintf(LogERROR, "Add proxy arp entry: %s\n", strerror(errno)); 143166124Srafan close(routes); 144166124Srafan return 0; 145166124Srafan } 146166124Srafan close(routes); 147166124Srafan arpmsg_valid = 1; 14862449Speter return 1; 14950276Speter} 15062449Speter 15162449Speter/* 15262449Speter * cifproxyarp - Delete the proxy ARP entry for the peer. 15366963Speter */ 15462449Speterint 15550276Spetercifproxyarp(int unit, struct in_addr hisaddr) 15697049Speter{ 15797049Speter int routes; 15897049Speter 15966963Speter if (!arpmsg_valid) 16062449Speter return 0; 16162449Speter arpmsg_valid = 0; 16250276Speter 16362449Speter arpmsg.hdr.rtm_type = RTM_DELETE; 16450276Speter arpmsg.hdr.rtm_seq = ++rtm_seq; 16566963Speter 16662449Speter routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET); 16762449Speter if (routes < 0) { 16862449Speter LogPrintf(LogERROR, "sifproxyarp: opening routing socket: %s\n", 16962449Speter strerror(errno)); 17062449Speter return 0; 17150276Speter } 17266963Speter if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { 17362449Speter LogPrintf(LogERROR, "Delete proxy arp entry: %s\n", strerror(errno)); 17462449Speter close(routes); 17562449Speter return 0; 17662449Speter } 17762449Speter close(routes); 17850276Speter return 1; 17997049Speter} 18062449Speter 181166124Srafan#else /* RTM_VERSION */ 18297049Speter 18397049Speter/* 18497049Speter * sifproxyarp - Make a proxy ARP entry for the peer. 18597049Speter */ 18697049Speterint 187166124Srafansifproxyarp(int unit, struct in_addr hisaddr) 188166124Srafan{ 18997049Speter struct arpreq arpreq; 19097049Speter struct { 19197049Speter struct sockaddr_dl sdl; 19297049Speter char space[128]; 19397049Speter } dls; 19462449Speter 19562449Speter memset(&arpreq, '\0', sizeof arpreq); 19662449Speter 19762449Speter /* 19862449Speter * Get the hardware address of an interface on the same subnet as our local 19962449Speter * address. 20062449Speter */ 20162449Speter if (!get_ether_addr(unit, hisaddr, &dls.sdl)) { 202166124Srafan LogPrintf(LOG_PHASE_BIT, "Cannot determine ethernet address for proxy ARP\n"); 20362449Speter return 0; 20462449Speter } 20562449Speter arpreq.arp_ha.sa_len = sizeof(struct sockaddr); 20650276Speter arpreq.arp_ha.sa_family = AF_UNSPEC; 20762449Speter memcpy(arpreq.arp_ha.sa_data, LLADDR(&dls.sdl), dls.sdl.sdl_alen); 20862449Speter SET_SA_FAMILY(arpreq.arp_pa, AF_INET); 20962449Speter ((struct sockaddr_in *) & arpreq.arp_pa)->sin_addr.s_addr = hisaddr.s_addr; 21062449Speter arpreq.arp_flags = ATF_PERM | ATF_PUBL; 21162449Speter if (ID0ioctl(unit, SIOCSARP, (caddr_t) & arpreq) < 0) { 21262449Speter LogPrintf(LogERROR, "sifproxyarp: ioctl(SIOCSARP): %s\n", strerror(errno)); 21362449Speter return 0; 21462449Speter } 21562449Speter return 1; 21650276Speter} 21762449Speter 21862449Speter/* 21962449Speter * cifproxyarp - Delete the proxy ARP entry for the peer. 22062449Speter */ 221166124Srafanint 22262449Spetercifproxyarp(int unit, struct in_addr hisaddr) 22362449Speter{ 22462449Speter struct arpreq arpreq; 22562449Speter 22662449Speter memset(&arpreq, '\0', sizeof arpreq); 22750276Speter SET_SA_FAMILY(arpreq.arp_pa, AF_INET); 22850276Speter ((struct sockaddr_in *) & arpreq.arp_pa)->sin_addr.s_addr = hisaddr.s_addr; 22962449Speter if (ID0ioctl(unit, SIOCDARP, (caddr_t) & arpreq) < 0) { 23062449Speter LogPrintf(LogERROR, "cifproxyarp: ioctl(SIOCDARP): %s\n", strerror(errno)); 23150276Speter return 0; 23266963Speter } 23362449Speter return 1; 23462449Speter} 235166124Srafan 23662449Speter#endif /* RTM_VERSION */ 23762449Speter 23862449Speter 23962449Speter/* 24062449Speter * get_ether_addr - get the hardware address of an interface on the 24162449Speter * the same subnet as ipaddr. 24262449Speter */ 24362449Speter#define MAX_IFS 32 244166124Srafan 24562449Speterstatic int 24662449Speterget_ether_addr(int s, struct in_addr ipaddr, struct sockaddr_dl *hwaddr) 24762449Speter{ 24862449Speter int idx; 24962449Speter const char *got; 25050276Speter char *sp, *ep, *cp, *wp; 25162449Speter struct ifreq ifrq; 25250276Speter struct in_addr addr, mask; 25366963Speter struct rt_msghdr *rtm; 25462449Speter struct sockaddr *sa_dst, *sa_gw; 255166124Srafan struct sockaddr_dl *dl; 256166124Srafan size_t needed; 25750276Speter int mib[6]; 25862449Speter 25962449Speter idx = 1; 26062449Speter while (strcmp(got = Index2Nam(idx), "???")) { 26150276Speter strncpy(ifrq.ifr_name, got, sizeof ifrq.ifr_name - 1); 26262449Speter ifrq.ifr_name[sizeof ifrq.ifr_name - 1] = '\0'; 26362449Speter if (ID0ioctl(s, SIOCGIFADDR, &ifrq) == 0 && 26462449Speter ifrq.ifr_addr.sa_family == AF_INET) { 26562449Speter addr = ((struct sockaddr_in *)&ifrq.ifr_addr)->sin_addr; 26666963Speter if (ID0ioctl(s, SIOCGIFNETMASK, &ifrq) == 0) { 26762449Speter mask = ((struct sockaddr_in *)&ifrq.ifr_broadaddr)->sin_addr; 26862449Speter if ((ipaddr.s_addr & mask.s_addr) == (addr.s_addr & mask.s_addr)) 26950276Speter break; 27062449Speter } 27162449Speter } 27262449Speter idx++; 27362449Speter } 27462449Speter 27562449Speter if (!strcmp(got, "???")) 27650276Speter return 0; 27762449Speter 27862449Speter LogPrintf(LogPHASE, "Found interface %s for proxy arp\n", got); 27962449Speter 28062449Speter mib[0] = CTL_NET; 28150276Speter mib[1] = PF_ROUTE; 28262449Speter mib[2] = 0; 28362449Speter mib[3] = 0; 28462449Speter mib[4] = NET_RT_DUMP; 28562449Speter mib[5] = 0; 28662449Speter if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) { 28762449Speter LogPrintf(LogERROR, "get_ether_addr: sysctl: estimate: %s\n", 28850276Speter strerror(errno)); 28950276Speter return 0; 29062449Speter } 291166124Srafan if (needed < 0) 29262449Speter return 0; 29362449Speter if ((sp = malloc(needed)) == NULL) 294166124Srafan return 0; 29562449Speter if (sysctl(mib, 6, sp, &needed, NULL, 0) < 0) { 296166124Srafan LogPrintf(LogERROR, "ShowRoute: sysctl: getroute: %s\n", strerror(errno)); 29766963Speter free(sp); 29862449Speter return (1); 29962449Speter } 300166124Srafan ep = sp + needed; 301166124Srafan 302166124Srafan for (cp = sp; cp < ep; cp += rtm->rtm_msglen) { 303166124Srafan rtm = (struct rt_msghdr *) cp; 30450276Speter if (rtm->rtm_index == idx) { 30562449Speter wp = (char *)(rtm+1); 30662449Speter 30762449Speter if (rtm->rtm_addrs & RTA_DST) { 30862449Speter sa_dst = (struct sockaddr *)wp; 30950276Speter wp += sa_dst->sa_len; 31062449Speter } else 31166963Speter sa_dst = NULL; 31266963Speter 31366963Speter if (rtm->rtm_addrs & RTA_GATEWAY) { 31466963Speter sa_gw = (struct sockaddr *)wp; 31566963Speter if (sa_gw->sa_family == AF_LINK) { 31662449Speter dl = (struct sockaddr_dl *)wp; 317166124Srafan if (dl->sdl_alen && dl->sdl_type == IFT_ETHER) { 31866963Speter memcpy(hwaddr, dl, dl->sdl_len); 31966963Speter free(sp); 32066963Speter return 1; 32150276Speter } 32266963Speter } 32366963Speter } 324166124Srafan } 32566963Speter } 32666963Speter free(sp); 327166124Srafan return 0; 32866963Speter} 329174993Srafan 33066963Speter#ifdef DEBUG 331166124Srafanint 332166124Srafanmain(int argc, char **argv) 333166124Srafan{ 334166124Srafan struct in_addr ipaddr; 335166124Srafan int s, f; 336166124Srafan 337166124Srafan s = socket(AF_INET, SOCK_DGRAM, 0); 338166124Srafan for (f = 1; f < argc; f++) { 339166124Srafan if (inet_aton(argv[f], &ipaddr)) 340166124Srafan sifproxyarp(s, ipaddr); 341166124Srafan } 342166124Srafan close(s); 34366963Speter} 34466963Speter#endif 34550276Speter