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