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.4 1996/01/11 17:48:34 phk Exp $ 21 * 22 */ 23 24 /* 25 * TODO: 26 */ 27 28 #include <sys/ioctl.h> 29 #include <sys/types.h> 30 #include <sys/uio.h> 31 #include <sys/socket.h> 32 #include <sys/time.h> 33 #include <sys/errno.h> 34 #include <unistd.h> 35 #include <string.h> 36 37 #include <net/if.h> 38 #include <net/route.h> 39 #include <net/if_dl.h> 40 #include <netinet/in.h> 41 #include <stdio.h> 42 #include <fcntl.h> 43 #ifdef __bsdi__ 44 #include <kvm.h> 45 #endif 46 #include <net/if_types.h> 47 #include <netinet/in_var.h> 48 #include <netinet/if_ether.h> 49 #include "log.h" 50 51 #if RTM_VERSION >= 3 52 #include <netinet/if_ether.h> 53 #endif 54 55 static int rtm_seq; 56 57 static int get_ether_addr __P((int, u_long, struct sockaddr_dl *)); 58 59 #define BCOPY(s, d, l) memcpy(d, s, l) 60 #define BZERO(s, n) memset(s, 0, n) 61 /* 62 * SET_SA_FAMILY - set the sa_family field of a struct sockaddr, 63 * if it exists. 64 */ 65 #define SET_SA_FAMILY(addr, family) \ 66 BZERO((char *) &(addr), sizeof(addr)); \ 67 addr.sa_family = (family); \ 68 addr.sa_len = sizeof(addr); 69 70 71 #if RTM_VERSION >= 3 72 73 /* 74 * sifproxyarp - Make a proxy ARP entry for the peer. 75 */ 76 static struct { 77 struct rt_msghdr hdr; 78 struct sockaddr_inarp dst; 79 struct sockaddr_dl hwa; 80 char extra[128]; 81 } arpmsg; 82 83 static int arpmsg_valid; 84 85 int 86 sifproxyarp(unit, hisaddr) 87 int unit; 88 u_long hisaddr; 89 { 90 int routes; 91 92 /* 93 * Get the hardware address of an interface on the same subnet 94 * as our local address. 95 */ 96 memset(&arpmsg, 0, sizeof(arpmsg)); 97 if (!get_ether_addr(unit, hisaddr, &arpmsg.hwa)) { 98 logprintf("Cannot determine ethernet address for proxy ARP\n"); 99 return 0; 100 } 101 102 if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) { 103 logprintf("sifproxyarp: opening routing socket: \n"); 104 return 0; 105 } 106 107 arpmsg.hdr.rtm_type = RTM_ADD; 108 arpmsg.hdr.rtm_flags = RTF_ANNOUNCE | RTF_HOST | RTF_STATIC; 109 arpmsg.hdr.rtm_version = RTM_VERSION; 110 arpmsg.hdr.rtm_seq = ++rtm_seq; 111 arpmsg.hdr.rtm_addrs = RTA_DST | RTA_GATEWAY; 112 arpmsg.hdr.rtm_inits = RTV_EXPIRE; 113 arpmsg.dst.sin_len = sizeof(struct sockaddr_inarp); 114 arpmsg.dst.sin_family = AF_INET; 115 arpmsg.dst.sin_addr.s_addr = hisaddr; 116 arpmsg.dst.sin_other = SIN_PROXY; 117 118 arpmsg.hdr.rtm_msglen = (char *) &arpmsg.hwa - (char *) &arpmsg 119 + arpmsg.hwa.sdl_len; 120 if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { 121 logprintf("add proxy arp entry: \n"); 122 close(routes); 123 return 0; 124 } 125 126 close(routes); 127 arpmsg_valid = 1; 128 return 1; 129 } 130 131 /* 132 * cifproxyarp - Delete the proxy ARP entry for the peer. 133 */ 134 int 135 cifproxyarp(unit, hisaddr) 136 int unit; 137 u_long hisaddr; 138 { 139 int routes; 140 141 if (!arpmsg_valid) 142 return 0; 143 arpmsg_valid = 0; 144 145 arpmsg.hdr.rtm_type = RTM_DELETE; 146 arpmsg.hdr.rtm_seq = ++rtm_seq; 147 148 if ((routes = socket(PF_ROUTE, SOCK_RAW, AF_INET)) < 0) { 149 logprintf("sifproxyarp: opening routing socket: \n"); 150 return 0; 151 } 152 153 if (write(routes, &arpmsg, arpmsg.hdr.rtm_msglen) < 0) { 154 logprintf("delete proxy arp entry: \n"); 155 close(routes); 156 return 0; 157 } 158 159 close(routes); 160 return 1; 161 } 162 163 #else /* RTM_VERSION */ 164 165 /* 166 * sifproxyarp - Make a proxy ARP entry for the peer. 167 */ 168 int 169 sifproxyarp(unit, hisaddr) 170 int unit; 171 u_long hisaddr; 172 { 173 struct arpreq arpreq; 174 struct { 175 struct sockaddr_dl sdl; 176 char space[128]; 177 } dls; 178 179 BZERO(&arpreq, sizeof(arpreq)); 180 181 /* 182 * Get the hardware address of an interface on the same subnet 183 * as our local address. 184 */ 185 if (!get_ether_addr(unit, hisaddr, &dls.sdl)) { 186 LogPrintf(LOG_PHASE_BIT, "Cannot determine ethernet address for proxy ARP\n"); 187 return 0; 188 } 189 190 arpreq.arp_ha.sa_len = sizeof(struct sockaddr); 191 arpreq.arp_ha.sa_family = AF_UNSPEC; 192 BCOPY(LLADDR(&dls.sdl), arpreq.arp_ha.sa_data, dls.sdl.sdl_alen); 193 SET_SA_FAMILY(arpreq.arp_pa, AF_INET); 194 ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr; 195 arpreq.arp_flags = ATF_PERM | ATF_PUBL; 196 if (ioctl(unit, SIOCSARP, (caddr_t)&arpreq) < 0) { 197 fprintf(stderr, "ioctl(SIOCSARP): \n"); 198 return 0; 199 } 200 201 return 1; 202 } 203 204 /* 205 * cifproxyarp - Delete the proxy ARP entry for the peer. 206 */ 207 int 208 cifproxyarp(unit, hisaddr) 209 int unit; 210 u_long hisaddr; 211 { 212 struct arpreq arpreq; 213 214 BZERO(&arpreq, sizeof(arpreq)); 215 SET_SA_FAMILY(arpreq.arp_pa, AF_INET); 216 ((struct sockaddr_in *) &arpreq.arp_pa)->sin_addr.s_addr = hisaddr; 217 if (ioctl(unit, SIOCDARP, (caddr_t)&arpreq) < 0) { 218 fprintf(stderr, "ioctl(SIOCDARP): \n"); 219 return 0; 220 } 221 return 1; 222 } 223 #endif /* RTM_VERSION */ 224 225 226 /* 227 * get_ether_addr - get the hardware address of an interface on the 228 * the same subnet as ipaddr. 229 */ 230 #define MAX_IFS 32 231 232 int 233 get_ether_addr(s, ipaddr, hwaddr) 234 int s; 235 u_long ipaddr; 236 struct sockaddr_dl *hwaddr; 237 { 238 struct ifreq *ifr, *ifend, *ifp; 239 u_long ina, mask; 240 struct sockaddr_dl *dla; 241 struct ifreq ifreq; 242 struct ifconf ifc; 243 struct ifreq ifs[MAX_IFS]; 244 245 ifc.ifc_len = sizeof(ifs); 246 ifc.ifc_req = ifs; 247 if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { 248 fprintf(stderr, "ioctl(SIOCGIFCONF): \n"); 249 return 0; 250 } 251 252 /* 253 * Scan through looking for an interface with an Internet 254 * address on the same subnet as `ipaddr'. 255 */ 256 ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); 257 for (ifr = ifc.ifc_req; ifr < ifend; ) { 258 if (ifr->ifr_addr.sa_family == AF_INET) { 259 ina = ((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr; 260 strncpy(ifreq.ifr_name, ifr->ifr_name, sizeof(ifreq.ifr_name)); 261 /* 262 * Check that the interface is up, and not point-to-point 263 * or loopback. 264 */ 265 if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0) 266 continue; 267 if ((ifreq.ifr_flags & 268 (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|IFF_LOOPBACK|IFF_NOARP)) 269 != (IFF_UP|IFF_BROADCAST)) 270 goto nextif; 271 /* 272 * Get its netmask and check that it's on the right subnet. 273 */ 274 if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0) 275 continue; 276 mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr; 277 if ((ipaddr & mask) != (ina & mask)) 278 goto nextif; 279 280 break; 281 } 282 nextif: 283 ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len); 284 } 285 286 if (ifr >= ifend) 287 return 0; 288 LogPrintf(LOG_PHASE_BIT, "found interface %s for proxy arp\n", ifr->ifr_name); 289 290 /* 291 * Now scan through again looking for a link-level address 292 * for this interface. 293 */ 294 ifp = ifr; 295 for (ifr = ifc.ifc_req; ifr < ifend; ) { 296 if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0 297 && ifr->ifr_addr.sa_family == AF_LINK) { 298 /* 299 * Found the link-level address - copy it out 300 */ 301 dla = (struct sockaddr_dl *) &ifr->ifr_addr; 302 #ifdef __bsdi__ 303 if (dla->sdl_alen == 0) 304 kmemgetether(ifr->ifr_name, dla); 305 #endif 306 BCOPY(dla, hwaddr, dla->sdl_len); 307 return 1; 308 } 309 ifr = (struct ifreq *) ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len); 310 } 311 312 return 0; 313 } 314 315 #ifdef __bsdi__ 316 #include <nlist.h> 317 318 struct nlist nl[] = { 319 #define N_IFNET 0 320 { "_ifnet" }, 321 "", 322 }; 323 324 325 kvm_t *kvmd; 326 327 /* 328 * Read kernel memory, return 0 on success. 329 */ 330 int 331 kread(addr, buf, size) 332 u_long addr; 333 char *buf; 334 int size; 335 { 336 337 if (kvm_read(kvmd, addr, buf, size) != size) { 338 /* XXX this duplicates kvm_read's error printout */ 339 (void)fprintf(stderr, "kvm_read %s\n", 340 kvm_geterr(kvmd)); 341 return (-1); 342 } 343 return (0); 344 } 345 346 kmemgetether(ifname, dlo) 347 char *ifname; 348 struct sockaddr_dl *dlo; 349 { 350 struct ifnet ifnet; 351 int n; 352 u_long addr, ifaddraddr, ifnetfound, ifaddrfound; 353 char name[32]; 354 struct sockaddr *sa; 355 char *cp; 356 struct sockaddr_dl *sdl; 357 union { 358 struct ifaddr ifa; 359 struct in_ifaddr in; 360 } ifaddr; 361 struct arpcom ac; 362 363 kvmd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL); 364 if (kvmd) { 365 n = kvm_nlist(kvmd, nl); 366 if (n >= 0) { 367 addr = nl[N_IFNET].n_value; 368 kread(addr, (char *)&addr, sizeof(addr)); 369 ifaddraddr = ifnetfound = 0; 370 while (addr || ifaddraddr) { 371 ifnetfound = addr; 372 if (ifaddraddr == 0) { 373 if (kread(addr, (char *)&ifnet, sizeof(ifnet)) || 374 kread((u_long)ifnet.if_name, name, 16)) 375 return; 376 name[15] = 0; 377 addr = (u_long) ifnet.if_next; 378 cp = (char *)index(name, '\0'); 379 cp += sprintf(cp, "%d", ifnet.if_unit); 380 *cp = '\0'; 381 ifaddraddr = (u_long)ifnet.if_addrlist; 382 } 383 ifaddrfound = ifaddraddr; 384 if (ifaddraddr) { 385 if (kread(ifaddraddr, (char *)&ifaddr, sizeof ifaddr)) { 386 ifaddraddr = 0; 387 continue; 388 } 389 #define CP(x) ((char *)(x)) 390 cp = (CP(ifaddr.ifa.ifa_addr) - CP(ifaddraddr)) + CP(&ifaddr); 391 sa = (struct sockaddr *)cp; 392 if (sa->sa_family == AF_LINK && strcmp(ifname, name) == 0) { 393 sdl = (struct sockaddr_dl *)sa; 394 cp = (char *)LLADDR(sdl); 395 n = sdl->sdl_alen; 396 if (ifnet.if_type == IFT_ETHER) { 397 if (n == 0) { 398 kread(ifnetfound, (char *)&ac, sizeof(ac)); 399 cp = (char *)LLADDR(sdl); 400 bcopy((char *)ac.ac_enaddr, cp, 6); 401 sdl->sdl_alen = 6; 402 } 403 bcopy(sdl, dlo, sizeof(*sdl)); 404 return; 405 } 406 } 407 ifaddraddr = (u_long)ifaddr.ifa.ifa_next; 408 } 409 } 410 } 411 } 412 } 413 #endif 414 415 #ifdef DEBUG 416 main() 417 { 418 u_long ipaddr; 419 int s; 420 421 s = socket(AF_INET, SOCK_DGRAM, 0); 422 ipaddr = inet_addr("192.168.1.32"); 423 sifproxyarp(s, ipaddr); 424 close(s); 425 } 426 #endif 427