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