Annotation of embedaddon/libpdel/net/if_arp.c, revision 1.1.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>