arp.c revision 32421
1/* 2 * sys-bsd.c - System-dependent procedures for setting up 3 * PPP interfaces on bsd-4.4-ish systems (including 386BSD, NetBSD, etc.) 4 * 5 * Copyright (c) 1989 Carnegie Mellon University. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms are permitted 9 * provided that the above copyright notice and this paragraph are 10 * duplicated in all such forms and that any documentation, 11 * advertising materials, and other materials related to such 12 * distribution and use acknowledge that the software was developed 13 * by Carnegie Mellon University. The name of the 14 * University may not be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 19 * 20 * $Id: arp.c,v 1.20 1997/12/24 09:28:49 brian Exp $ 21 * 22 */ 23 24/* 25 * TODO: 26 */ 27 28#include <sys/types.h> 29#include <sys/time.h> 30#include <sys/socket.h> 31#include <net/if.h> 32#include <net/route.h> 33#include <net/if_dl.h> 34#include <netinet/in.h> 35#include <net/if_types.h> 36#include <netinet/if_ether.h> 37 38#include <fcntl.h> 39#include <stdio.h> 40#include <string.h> 41#include <sys/errno.h> 42#include <sys/ioctl.h> 43#include <sys/uio.h> 44#include <unistd.h> 45 46#include "command.h" 47#include "mbuf.h" 48#include "log.h" 49#include "id.h" 50#include "arp.h" 51 52static int rtm_seq; 53 54static int get_ether_addr(int, u_long, struct sockaddr_dl *); 55 56/* 57 * SET_SA_FAMILY - set the sa_family field of a struct sockaddr, 58 * if it exists. 59 */ 60#define SET_SA_FAMILY(addr, family) \ 61 memset((char *) &(addr), '\0', sizeof(addr)); \ 62 addr.sa_family = (family); \ 63 addr.sa_len = sizeof(addr); 64 65 66#if RTM_VERSION >= 3 67 68/* 69 * sifproxyarp - Make a proxy ARP entry for the peer. 70 */ 71static struct { 72 struct rt_msghdr hdr; 73 struct sockaddr_inarp dst; 74 struct sockaddr_dl hwa; 75 char extra[128]; 76} arpmsg; 77 78static int arpmsg_valid; 79 80int 81sifproxyarp(int unit, u_long hisaddr) 82{ 83 int routes; 84 85 /* 86 * Get the hardware address of an interface on the same subnet as our local 87 * address. 88 */ 89 memset(&arpmsg, 0, sizeof arpmsg); 90 if (!get_ether_addr(unit, hisaddr, &arpmsg.hwa)) { 91 LogPrintf(LogERROR, "Cannot determine ethernet address for proxy ARP\n"); 92 return 0; 93 } 94 routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET); 95 if (routes < 0) { 96 LogPrintf(LogERROR, "sifproxyarp: opening routing socket: %s\n", 97 strerror(errno)); 98 return 0; 99 } 100 arpmsg.hdr.rtm_type = RTM_ADD; 101 arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC; 102 arpmsg.hdr.rtm_version = RTM_VERSION; 103 arpmsg.hdr.rtm_seq = ++rtm_seq; 104 arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; 105 arpmsg.hdr.rtm_inits = RTV_EXPIRE; 106 arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp); 107 arpmsg.dst.sin_family = AF_INET; 108 arpmsg.dst.sin_addr.s_addr = hisaddr; 109 arpmsg.dst.sin_other = SIN_PROXY; 110 111 arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg 112 + arpmsg.hwa.sdl_len; 113 if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { 114 LogPrintf(LogERROR, "Add proxy arp entry: %s\n", strerror(errno)); 115 close(routes); 116 return 0; 117 } 118 close(routes); 119 arpmsg_valid = 1; 120 return 1; 121} 122 123/* 124 * cifproxyarp - Delete the proxy ARP entry for the peer. 125 */ 126int 127cifproxyarp(int unit, u_long hisaddr) 128{ 129 int routes; 130 131 if (!arpmsg_valid) 132 return 0; 133 arpmsg_valid = 0; 134 135 arpmsg.hdr.rtm_type = RTM_DELETE; 136 arpmsg.hdr.rtm_seq = ++rtm_seq; 137 138 routes = ID0socket(PF_ROUTE, SOCK_RAW, AF_INET); 139 if (routes < 0) { 140 LogPrintf(LogERROR, "sifproxyarp: opening routing socket: %s\n", 141 strerror(errno)); 142 return 0; 143 } 144 if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { 145 LogPrintf(LogERROR, "Delete proxy arp entry: %s\n", strerror(errno)); 146 close(routes); 147 return 0; 148 } 149 close(routes); 150 return 1; 151} 152 153#else /* RTM_VERSION */ 154 155/* 156 * sifproxyarp - Make a proxy ARP entry for the peer. 157 */ 158int 159sifproxyarp(int unit, u_long hisaddr) 160{ 161 struct arpreq arpreq; 162 struct { 163 struct sockaddr_dl sdl; 164 char space[128]; 165 } dls; 166 167 memset(&arpreq, '\0', sizeof arpreq); 168 169 /* 170 * Get the hardware address of an interface on the same subnet as our local 171 * address. 172 */ 173 if (!get_ether_addr(unit, hisaddr, &dls.sdl)) { 174 LogPrintf(LOG_PHASE_BIT, "Cannot determine ethernet address for proxy ARP\n"); 175 return 0; 176 } 177 arpreq.arp_ha.sa_len = sizeof(struct sockaddr); 178 arpreq.arp_ha.sa_family = AF_UNSPEC; 179 memcpy(arpreq.arp_ha.sa_data, LLADDR(&dls.sdl), dls.sdl.sdl_alen); 180 SET_SA_FAMILY(arpreq.arp_pa, AF_INET); 181 ((struct sockaddr_in *) & arpreq.arp_pa)->sin_addr.s_addr = hisaddr; 182 arpreq.arp_flags = ATF_PERM | ATF_PUBL; 183 if (ID0ioctl(unit, SIOCSARP, (caddr_t) & arpreq) < 0) { 184 LogPrintf(LogERROR, "sifproxyarp: ioctl(SIOCSARP): %s\n", strerror(errno)); 185 return 0; 186 } 187 return 1; 188} 189 190/* 191 * cifproxyarp - Delete the proxy ARP entry for the peer. 192 */ 193int 194cifproxyarp(int unit, u_long hisaddr) 195{ 196 struct arpreq arpreq; 197 198 memset(&arpreq, '\0', sizeof arpreq); 199 SET_SA_FAMILY(arpreq.arp_pa, AF_INET); 200 ((struct sockaddr_in *) & arpreq.arp_pa)->sin_addr.s_addr = hisaddr; 201 if (ID0ioctl(unit, SIOCDARP, (caddr_t) & arpreq) < 0) { 202 LogPrintf(LogERROR, "cifproxyarp: ioctl(SIOCDARP): %s\n", strerror(errno)); 203 return 0; 204 } 205 return 1; 206} 207 208#endif /* RTM_VERSION */ 209 210 211/* 212 * get_ether_addr - get the hardware address of an interface on the 213 * the same subnet as ipaddr. 214 */ 215#define MAX_IFS 32 216 217static int 218get_ether_addr(int s, u_long ipaddr, struct sockaddr_dl *hwaddr) 219{ 220 struct ifreq *ifr, *ifend, *ifp; 221 u_long ina, mask; 222 struct sockaddr_dl *dla; 223 struct ifreq ifreq; 224 struct ifconf ifc; 225 struct ifreq ifs[MAX_IFS]; 226 227 ifc.ifc_len = sizeof ifs; 228 ifc.ifc_req = ifs; 229 if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { 230 LogPrintf(LogERROR, "get_ether_addr: ioctl(SIOCGIFCONF): %s\n", 231 strerror(errno)); 232 return 0; 233 } 234 235 /* 236 * Scan through looking for an interface with an Internet address on the 237 * same subnet as `ipaddr'. 238 */ 239 ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); 240 for (ifr = ifc.ifc_req; ifr < ifend;) { 241 if (ifr->ifr_addr.sa_family == AF_INET) { 242 ina = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr.s_addr; 243 strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof ifreq.ifr_name - 1); 244 ifreq.ifr_name[sizeof ifreq.ifr_name - 1] = '\0'; 245 246 /* 247 * Check that the interface is up, and not point-to-point or loopback. 248 */ 249 if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0) 250 continue; 251 if ((ifreq.ifr_flags & 252 (IFF_UP | IFF_BROADCAST | IFF_POINTOPOINT | IFF_LOOPBACK | IFF_NOARP)) 253 != (IFF_UP | IFF_BROADCAST)) 254 goto nextif; 255 256 /* 257 * Get its netmask and check that it's on the right subnet. 258 */ 259 if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0) 260 continue; 261 mask = ((struct sockaddr_in *) & ifreq.ifr_addr)->sin_addr.s_addr; 262 if ((ipaddr & mask) != (ina & mask)) 263 goto nextif; 264 265 break; 266 } 267nextif: 268 ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + ifr->ifr_addr.sa_len); 269 } 270 271 if (ifr >= ifend) 272 return 0; 273 LogPrintf(LogPHASE, "Found interface %s for proxy arp\n", ifr->ifr_name); 274 275 /* 276 * Now scan through again looking for a link-level address for this 277 * interface. 278 */ 279 ifp = ifr; 280 for (ifr = ifc.ifc_req; ifr < ifend;) { 281 if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 282 && ifr->ifr_addr.sa_family == AF_LINK) { 283 284 /* 285 * Found the link-level address - copy it out 286 */ 287 dla = (struct sockaddr_dl *) & ifr->ifr_addr; 288 memcpy(hwaddr, dla, dla->sdl_len); 289 return 1; 290 } 291 ifr = (struct ifreq *) ((char *) &ifr->ifr_addr + ifr->ifr_addr.sa_len); 292 } 293 294 return 0; 295} 296 297 298#ifdef DEBUG 299int 300main() 301{ 302 u_long ipaddr; 303 int s; 304 305 s = socket(AF_INET, SOCK_DGRAM, 0); 306 ipaddr = inet_addr("192.168.1.32"); 307 sifproxyarp(s, ipaddr); 308 close(s); 309} 310#endif 311