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