Annotation of embedaddon/libpdel/net/if_arp.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (c) 2001-2002 Packet Design, LLC.
! 4: * All rights reserved.
! 5: *
! 6: * Subject to the following obligations and disclaimer of warranty,
! 7: * use and redistribution of this software, in source or object code
! 8: * forms, with or without modifications are expressly permitted by
! 9: * Packet Design; provided, however, that:
! 10: *
! 11: * (i) Any and all reproductions of the source or object code
! 12: * must include the copyright notice above and the following
! 13: * disclaimer of warranties; and
! 14: * (ii) No rights are granted, in any manner or form, to use
! 15: * Packet Design trademarks, including the mark "PACKET DESIGN"
! 16: * on advertising, endorsements, or otherwise except as such
! 17: * appears in the above copyright notice or in the software.
! 18: *
! 19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
! 20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
! 21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
! 22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
! 23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
! 24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
! 25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
! 26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
! 27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
! 28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
! 29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
! 30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
! 31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
! 32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
! 33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
! 35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
! 36: * THE POSSIBILITY OF SUCH DAMAGE.
! 37: *
! 38: * Author: Archie Cobbs <archie@freebsd.org>
! 39: */
! 40:
! 41: #include <sys/types.h>
! 42: #include <sys/param.h>
! 43: #include <sys/socket.h>
! 44: #include <sys/sysctl.h>
! 45: #include <sys/sockio.h>
! 46: #include <sys/ioctl.h>
! 47:
! 48: #include <net/if.h>
! 49: #include <net/if_dl.h>
! 50: #include <net/if_types.h>
! 51: #include <net/route.h>
! 52:
! 53: #include <netinet/in.h>
! 54: #include <netinet/if_ether.h>
! 55: #include <arpa/inet.h>
! 56:
! 57: #include <stdio.h>
! 58: #include <stdlib.h>
! 59: #include <stdarg.h>
! 60: #include <unistd.h>
! 61: #include <syslog.h>
! 62: #include <string.h>
! 63: #include <assert.h>
! 64: #include <errno.h>
! 65: #include <time.h>
! 66:
! 67: #include "structs/structs.h"
! 68: #include "structs/type/array.h"
! 69:
! 70: #include "net/if_util.h"
! 71: #include "util/typed_mem.h"
! 72:
! 73: #define ROUNDUP(a) \
! 74: ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
! 75: #define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
! 76:
! 77: #define ADDADDR(cp, s) \
! 78: do { \
! 79: memcpy(cp, &s, sizeof(s)); \
! 80: cp += ROUNDUP(sizeof(s)); \
! 81: } while (0)
! 82:
! 83: #define TEMP_EXPIRE (20 * 60)
! 84:
! 85: struct rt {
! 86: struct rt_msghdr m_rtm;
! 87: char m_space[512];
! 88: };
! 89:
! 90: /*
! 91: * Internal functions
! 92: */
! 93: static int arp_set(int sock, struct in_addr ip,
! 94: const u_char *ether, int temp, int publish);
! 95: static int arp_delete(int sock, struct in_addr ip);
! 96: static int arp_rtmsg(int sock, struct rt *rt, struct sockaddr_inarp *sin,
! 97: struct sockaddr_dl *sdl, int cmd, int flags,
! 98: int export_only, int doing_proxy, u_long expiry);
! 99:
! 100: /*
! 101: * Internal variables
! 102: */
! 103: static const struct sockaddr_in so_mask = { 8, 0, 0, { 0xffffffff} };
! 104: static const struct sockaddr_inarp zero_sin = { sizeof(zero_sin), AF_INET };
! 105: static const struct sockaddr_dl zero_sdl = { sizeof(zero_sdl), AF_LINK };
! 106:
! 107: /*
! 108: * Get an ARP entry.
! 109: */
! 110: int
! 111: if_get_arp(struct in_addr ip, u_char *ether)
! 112: {
! 113: int mib[6];
! 114: size_t needed;
! 115: char *lim, *buf, *next;
! 116: struct rt_msghdr *rtm;
! 117: struct sockaddr_inarp *sin;
! 118: struct sockaddr_dl *sdl;
! 119:
! 120: /* Get ARP table */
! 121: mib[0] = CTL_NET;
! 122: mib[1] = PF_ROUTE;
! 123: mib[2] = 0;
! 124: mib[3] = AF_INET;
! 125: mib[4] = NET_RT_FLAGS;
! 126: #ifdef RTF_LLINFO
! 127: mib[5] = RTF_LLINFO;
! 128: #else
! 129: mib[5] = 0;
! 130: #endif
! 131: if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
! 132: return (-1);
! 133: needed += 128;
! 134: if ((buf = MALLOC(TYPED_MEM_TEMP, needed)) == NULL)
! 135: return (-1);
! 136: if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
! 137: FREE(TYPED_MEM_TEMP, buf);
! 138: return (-1);
! 139: }
! 140:
! 141: /* Find desired entry */
! 142: lim = buf + needed;
! 143: for (next = buf; next < lim; next += rtm->rtm_msglen) {
! 144: rtm = (struct rt_msghdr *)(void *)next;
! 145: sin = (struct sockaddr_inarp *)(rtm + 1);
! 146: sdl = (struct sockaddr_dl *)(void *)
! 147: ((char *)sin + ROUNDUP(sin->sin_len));
! 148: if (sin->sin_addr.s_addr != ip.s_addr)
! 149: continue;
! 150: if (sdl->sdl_alen == 0)
! 151: break;
! 152: memcpy(ether, LLADDR(sdl), ETHER_ADDR_LEN);
! 153: FREE(TYPED_MEM_TEMP, buf);
! 154: return (0);
! 155: }
! 156:
! 157: /* Not found */
! 158: FREE(TYPED_MEM_TEMP, buf);
! 159: errno = ENOENT;
! 160: return (-1);
! 161: }
! 162:
! 163: /*
! 164: * Set or remove an ARP entry.
! 165: */
! 166: int
! 167: if_set_arp(struct in_addr ip, const u_char *ether, int temp, int publish)
! 168: {
! 169: int ret = -1;
! 170: int sock;
! 171:
! 172: /* Get socket */
! 173: if ((sock = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
! 174: return (-1);
! 175:
! 176: /* Delete any existing entries */
! 177: while ((ret = arp_delete(sock, ip)) != -1);
! 178: if (errno != ENOENT)
! 179: goto done;
! 180:
! 181: /* If not setting a new one, done */
! 182: if (ether == NULL) {
! 183: ret = 0;
! 184: goto done;
! 185: }
! 186:
! 187: /* Set a new one */
! 188: ret = arp_set(sock, ip, ether, temp, publish);
! 189:
! 190: done:
! 191: /* Done */
! 192: (void)close(sock);
! 193: return (ret);
! 194: }
! 195:
! 196: /*
! 197: * Set an individual arp entry
! 198: */
! 199: static int
! 200: arp_set(int sock, struct in_addr ip, const u_char *ether, int temp, int publish)
! 201: {
! 202: struct rt m_rtmsg;
! 203: struct sockaddr_inarp sin_m;
! 204: struct sockaddr_dl sdl_m;
! 205: struct sockaddr_inarp *sin = &sin_m;
! 206: struct rt_msghdr *const rtm = &m_rtmsg.m_rtm;
! 207: struct sockaddr_dl *sdl;
! 208: int doing_proxy;
! 209: int export_only;
! 210: int expiry;
! 211: int flags;
! 212:
! 213: sdl_m = zero_sdl;
! 214: sin_m = zero_sin;
! 215: sin->sin_addr = ip;
! 216: doing_proxy = flags = export_only = expiry = 0;
! 217: if (temp)
! 218: expiry = time(NULL) + TEMP_EXPIRE;
! 219: if (publish) {
! 220: flags |= RTF_ANNOUNCE;
! 221: doing_proxy = SIN_PROXY;
! 222: }
! 223: memcpy(LLADDR(&sdl_m), ether, ETHER_ADDR_LEN);
! 224: sdl_m.sdl_alen = 6;
! 225: tryagain:
! 226: if (arp_rtmsg(sock, &m_rtmsg, &sin_m, &sdl_m,
! 227: RTM_GET, flags, export_only, doing_proxy, expiry) < 0)
! 228: return (-1);
! 229: sin = (struct sockaddr_inarp *)(rtm + 1);
! 230: sdl = (struct sockaddr_dl *)(void *)
! 231: (ROUNDUP(sin->sin_len) + (char *)sin);
! 232: if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
! 233: if (sdl->sdl_family == AF_LINK &&
! 234: #ifdef RTF_LLINFO
! 235: (rtm->rtm_flags & RTF_LLINFO) != 0 &&
! 236: #endif
! 237: (rtm->rtm_flags & RTF_GATEWAY) == 0) {
! 238: switch (sdl->sdl_type) {
! 239: case IFT_ETHER:
! 240: case IFT_FDDI:
! 241: case IFT_ISO88023:
! 242: case IFT_ISO88024:
! 243: case IFT_ISO88025:
! 244: case IFT_L2VLAN:
! 245: goto overwrite;
! 246: default:
! 247: break;
! 248: }
! 249: }
! 250: if (doing_proxy == 0) {
! 251: errno = EINVAL;
! 252: return (-1);
! 253: }
! 254: if (sin_m.sin_other & SIN_PROXY) {
! 255: errno = EINVAL;
! 256: return (-1);
! 257: }
! 258: sin_m.sin_other = SIN_PROXY;
! 259: export_only = 1;
! 260: goto tryagain;
! 261: }
! 262: overwrite:
! 263: if (sdl->sdl_family != AF_LINK) {
! 264: errno = ENOENT;
! 265: return (-1);
! 266: }
! 267: sdl_m.sdl_type = sdl->sdl_type;
! 268: sdl_m.sdl_index = sdl->sdl_index;
! 269: return (arp_rtmsg(sock, &m_rtmsg, &sin_m, &sdl_m,
! 270: RTM_ADD, flags, export_only, doing_proxy, expiry));
! 271: }
! 272:
! 273: /*
! 274: * Delete an arp entry
! 275: */
! 276: static int
! 277: arp_delete(int sock, struct in_addr ip)
! 278: {
! 279: struct rt m_rtmsg;
! 280: struct sockaddr_inarp sin_m;
! 281: struct sockaddr_dl sdl_m;
! 282: struct sockaddr_inarp *sin = &sin_m;
! 283: struct rt_msghdr *const rtm = &m_rtmsg.m_rtm;
! 284: struct sockaddr_dl *sdl;
! 285:
! 286: sdl_m = zero_sdl;
! 287: sin_m = zero_sin;
! 288: sin->sin_addr = ip;
! 289: tryagain:
! 290: if (arp_rtmsg(sock, &m_rtmsg, &sin_m, &sdl_m, RTM_GET, 0, 0, 0, 0) < 0)
! 291: return (-1);
! 292: sin = (struct sockaddr_inarp *)(rtm + 1);
! 293: sdl = (struct sockaddr_dl *)(void *)
! 294: (ROUNDUP(sin->sin_len) + (char *)sin);
! 295: if (sdl->sdl_family == AF_LINK &&
! 296: #ifdef RTF_LLINFO
! 297: (rtm->rtm_flags & RTF_LLINFO) &&
! 298: #endif
! 299: !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
! 300: case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
! 301: case IFT_ISO88024: case IFT_ISO88025:
! 302: sin->sin_addr.s_addr = sin_m.sin_addr.s_addr;
! 303: goto delete;
! 304: }
! 305: if (sin_m.sin_other & SIN_PROXY) {
! 306: errno = ENOENT;
! 307: return (-1);
! 308: }
! 309: sin_m.sin_other = SIN_PROXY;
! 310: goto tryagain;
! 311: delete:
! 312: if (sdl->sdl_family != AF_LINK) {
! 313: errno = ENOENT;
! 314: return (-1);
! 315: }
! 316: if (arp_rtmsg(sock, &m_rtmsg, &sin_m, &sdl_m,
! 317: RTM_DELETE, 0, 0, 0, 0) == -1)
! 318: return (-1);
! 319: return (0);
! 320: }
! 321:
! 322: static int
! 323: arp_rtmsg(int sock, struct rt *rt, struct sockaddr_inarp *sin,
! 324: struct sockaddr_dl *sdl, int cmd, int flags,
! 325: int export_only, int doing_proxy, u_long expiry)
! 326: {
! 327: struct rt_msghdr *const rtm = &rt->m_rtm;
! 328: const pid_t pid = getpid();
! 329: u_char *cp = (u_char *)rt->m_space;
! 330: static int seq;
! 331: int l;
! 332: int rlen;
! 333:
! 334: if (cmd == RTM_DELETE)
! 335: goto doit;
! 336: memset(rtm, 0, sizeof(*rtm));
! 337: rtm->rtm_flags = flags;
! 338: rtm->rtm_version = RTM_VERSION;
! 339:
! 340: switch (cmd) {
! 341: case RTM_ADD:
! 342: rtm->rtm_addrs |= RTA_GATEWAY;
! 343: rtm->rtm_rmx.rmx_expire = expiry;
! 344: rtm->rtm_inits = RTV_EXPIRE;
! 345: rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
! 346: sin->sin_other = 0;
! 347: if (doing_proxy) {
! 348: if (export_only)
! 349: sin->sin_other = SIN_PROXY;
! 350: else {
! 351: rtm->rtm_addrs |= RTA_NETMASK;
! 352: rtm->rtm_flags &= ~RTF_HOST;
! 353: }
! 354: }
! 355: /* FALLTHROUGH */
! 356: case RTM_GET:
! 357: rtm->rtm_addrs |= RTA_DST;
! 358: break;
! 359: default:
! 360: assert(0);
! 361: }
! 362: #define NEXTADDR(w, s) \
! 363: if (rtm->rtm_addrs & (w)) { \
! 364: memcpy(cp, s, sizeof(*s)); cp += ROUNDUP(sizeof(*s));}
! 365:
! 366: NEXTADDR(RTA_DST, sin);
! 367: NEXTADDR(RTA_GATEWAY, sdl);
! 368: NEXTADDR(RTA_NETMASK, &so_mask);
! 369:
! 370: rtm->rtm_msglen = cp - (u_char *)rtm;
! 371: doit:
! 372: l = rtm->rtm_msglen;
! 373: rtm->rtm_seq = ++seq;
! 374: rtm->rtm_type = cmd;
! 375: if ((rlen = write(sock, (char *)rt, l)) < 0) {
! 376: if (errno != ESRCH || cmd != RTM_DELETE)
! 377: return (-1);
! 378: }
! 379: do {
! 380: l = read(sock, (char *)rt, sizeof(*rt));
! 381: } while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
! 382: if (l < 0)
! 383: return (-1);
! 384: return (0);
! 385: }
! 386:
! 387: /*
! 388: * Flush all ARP entries.
! 389: */
! 390: int
! 391: if_flush_arp(void)
! 392: {
! 393: int errno_save = errno;
! 394: int mib[6];
! 395: size_t needed;
! 396: char *lim, *buf, *next;
! 397: struct rt_msghdr *rtm;
! 398: struct sockaddr_inarp *sin;
! 399: struct sockaddr_dl *sdl;
! 400: int sock, rtn = -1;
! 401:
! 402: /* Get socket */
! 403: if ((sock = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
! 404: return (-1);
! 405:
! 406: /* Get ARP table */
! 407: mib[0] = CTL_NET;
! 408: mib[1] = PF_ROUTE;
! 409: mib[2] = 0;
! 410: mib[3] = AF_INET;
! 411: mib[4] = NET_RT_FLAGS;
! 412: #ifdef RTF_LLINFO
! 413: mib[5] = RTF_LLINFO;
! 414: #else
! 415: mib[5] = 0;
! 416: #endif
! 417: if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
! 418: goto done;
! 419: needed += 128;
! 420: if ((buf = MALLOC(TYPED_MEM_TEMP, needed)) == NULL)
! 421: goto done;
! 422: if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
! 423: goto done2;
! 424: }
! 425:
! 426: /* Find desired entry */
! 427: lim = buf + needed;
! 428: for (next = buf; next < lim; next += rtm->rtm_msglen) {
! 429: rtm = (struct rt_msghdr *)(void *)next;
! 430: sin = (struct sockaddr_inarp *)(rtm + 1);
! 431: sdl = (struct sockaddr_dl *)(void *)
! 432: ((char *)sin + ROUNDUP(sin->sin_len));
! 433: if (sdl->sdl_alen == 0)
! 434: break;
! 435: arp_delete(sock, sin->sin_addr);
! 436: }
! 437:
! 438: rtn = 0;
! 439: done2:
! 440: FREE(TYPED_MEM_TEMP, buf);
! 441: done:
! 442: (void)close(sock);
! 443: errno = errno_save;
! 444: return (rtn);
! 445: }
! 446:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>