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>