Annotation of embedaddon/choparp/choparp.c, revision 1.1.1.1.2.1

1.1       misho       1: /*
                      2:    choparp - cheap & omitted proxy arp
                      3: 
                      4:    Copyright (c) 1997 Takamichi Tateoka (tree@mma.club.uec.ac.jp)
                      5:    Copyright (c) 2002 Thomas Quinot (thomas@cuivre.fr.eu.org)
                      6:    
                      7:    Redistribution and use in source and binary forms, with or without
                      8:    modification, are permitted provided that the following conditions
                      9:    are met:
                     10:    1. Redistributions of source code must retain the above copyright
                     11:       notice, this list of conditions and the following disclaimer.
                     12:    2. Redistributions in binary form must reproduce the above copyright
                     13:       notice, this list of conditions and the following disclaimer in the
                     14:       documentation and/or other materials provided with the distribution.
                     15:    3. Neither the name of the authors nor the names of their contributors
                     16:       may be used to endorse or promote products derived from this software
                     17:       without specific prior written permission.
                     18:    
                     19:    THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
                     20:    ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     21:    IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     22:    ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     23:    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     24:    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     25:    OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     26:    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     27:    LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     28:    OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     29:    SUCH DAMAGE.
                     30: 
                     31: 
                     32:    History:
                     33:    17 Jun 1997 Creation (tate)
                     34:    7  Oct 1997 fix some comments (tate)
                     35:    19 Jun 1998  fix read result as ssize_t (tate / pointed by msaitoh)
                     36: 
                     37: */
                     38: 
                     39: #include <stdio.h>
                     40: #include <unistd.h>
                     41: #include <stdlib.h>
                     42: #include <string.h>
                     43: #include <sys/types.h>
                     44: #include <fcntl.h>
                     45: #include <sys/time.h>
                     46: #include <sys/ioctl.h>
                     47: #include <net/bpf.h>
                     48: #include <sys/socket.h>
                     49: #include <net/if.h>
                     50: #include <netinet/in.h>
                     51: /* #include <net/if_arp.h> */
                     52: #if (__FreeBSD__ >= 3)
                     53:  #include <net/if_var.h>
                     54: #endif
                     55: #include <netinet/if_ether.h>
                     56: #include <sys/param.h>
                     57: #include <errno.h>
                     58: #include <ifaddrs.h>
                     59: #include <net/if_dl.h>
                     60: 
                     61: #ifdef DEBUG
                     62: #include <arpa/inet.h>
                     63: #endif
                     64: 
                     65: #define        BPFFILENAME     "/dev/bpf%d"    /* bpf file template */
                     66: #ifndef        NBPFILTER                       /* number of available bpf */
                     67: # define NBPFILTER (16)
                     68: #endif
                     69: 
                     70: struct cidr {
                     71:        struct cidr *next;
                     72:        u_int32_t addr;         /* addr and mask are host order */
                     73:        u_int32_t mask;
                     74: };
                     75: 
                     76: struct cidr *targets = NULL, *excludes = NULL;
                     77: u_char target_mac[ETHER_ADDR_LEN];     /* target MAC address */
                     78: 
                     79: /*
                     80:    ARP filter program
                     81: */
                     82: struct bpf_insn bpf_filter_arp[] = {
                     83:     /* check Ethernet Encapsulation (RFC894) first */
                     84:     BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),        /* load frame type */
                     85:     BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_ARP, 0, 3), /* check it */
                     86:     BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20),        /* load OP code */
                     87:     BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARPOP_REQUEST, 0, 1),  /* check it */
                     88:     BPF_STMT(BPF_RET+BPF_K, 14+28),    /* return Ethernet encap ARP req. */
                     89:     /* XXX: IEEE 802.2/802.3 Encap (RFC1042) should be available... */
                     90:     BPF_STMT(BPF_RET+BPF_K, 0),                /* discard */
                     91: };
                     92: 
                     93: /*
                     94:    openbpf:
                     95: 
                     96:    open bpf & set ARP filter program for named interface &
                     97:    allocate enough buffer for BPF.
                     98:    return file descripter or -1 for error
                     99: */
                    100: int
                    101: openbpf(char *ifname, char **bufp, size_t *buflen){
                    102:     char bpffile[sizeof(BPFFILENAME)+5];       /* XXX: */
                    103:     int        fd = -1;
                    104:     int        n;
                    105:     struct bpf_version bpf_version;
                    106:     struct ifreq       bpf_ifreq;
                    107:     u_int      ui;
                    108:     struct bpf_program bpf_program;
                    109: 
                    110:     /* open BPF file */
                    111:     for (n=0; n<NBPFILTER; n++){
                    112:        sprintf(bpffile, BPFFILENAME, n);
                    113:        if ((fd = open(bpffile, O_RDWR, 0)) >= 0)
                    114:            break;
                    115:     }
                    116:     if (fd < 0){
                    117:        fprintf(stderr,"openbpf: Can't open BPF\n");
                    118:        return(-1);             /* error */
                    119:     }
                    120: 
                    121:     /* check version number */
                    122:     if ((ioctl(fd, BIOCVERSION, &bpf_version) == -1) ||
                    123:        bpf_version.bv_major != BPF_MAJOR_VERSION ||
                    124:        bpf_version.bv_minor < BPF_MINOR_VERSION){
                    125:        fprintf(stderr,"openbpf: incorrect BPF version\n");
                    126:        close(fd);
                    127:        return(-1);
                    128:     }
                    129: 
                    130:     /* set interface name */
                    131:     strncpy(bpf_ifreq.ifr_name, ifname, IFNAMSIZ);
                    132:     bpf_ifreq.ifr_name[IFNAMSIZ-1] = '\0';     /* paranoia */
                    133:     if (ioctl(fd, BIOCSETIF, &bpf_ifreq) == -1){
                    134:        fprintf(stderr,"openbpf: BIOCSETIF failed for interface <%s>\n",
                    135:                ifname);
                    136:        close(fd);
                    137:        return(-1);
                    138:     }
                    139: 
                    140:     /* set BPF immediate mode */
                    141:     ui = 1;
                    142:     if (ioctl(fd, BIOCIMMEDIATE, &ui) == -1){
                    143:        fprintf(stderr,"openbpf: BIOCIMMEDIATE failed.\n");
                    144:        close(fd);
                    145:        return(-1);
                    146:     }
                    147: 
                    148:     /* set ARP request filter */
                    149:     bpf_program.bf_len = sizeof(bpf_filter_arp) / sizeof(struct bpf_insn);
                    150:     bpf_program.bf_insns = bpf_filter_arp;
                    151:     if (ioctl(fd, BIOCSETF, &bpf_program) == -1){
                    152:        fprintf(stderr,"openbpf: BIOCSETF failed.\n");
                    153:        close(fd);
                    154:        return(-1);
                    155:     }
                    156: 
                    157:     /* allocate reasonable size & alimented buffer */
                    158:     if (ioctl(fd, BIOCGBLEN, &ui) == -1){
                    159:        fprintf(stderr,"openbpf: BIOCGBLEN failed.\n");
                    160:        close(fd);
                    161:        return(-1);
                    162:     }
                    163:     *buflen = (size_t)ui;
                    164:     if ((*bufp = (char *)malloc((size_t) ui)) == NULL){
                    165:        fprintf(stderr,"openbpf: malloc failed.\n");
                    166:        close(fd);
                    167:        return(-1);
                    168:     }
                    169: 
                    170:     return(fd);
                    171: }
                    172: 
                    173: /*
                    174:    get ARP datalink frame pointer
                    175: 
                    176:    NULL if no more ARP frame
                    177: */
                    178: char *
                    179: getarp(char *bpfframe, ssize_t bpfflen, char **next, ssize_t *nextlen){
                    180:     int        bias;
                    181:     char *p;
                    182: 
                    183:     if (bpfframe == NULL || bpfflen == 0)
                    184:        return(NULL);
                    185: 
                    186:     bias = BPF_WORDALIGN(((struct bpf_hdr *)bpfframe)->bh_hdrlen +
                    187:                         ((struct bpf_hdr *)bpfframe)->bh_caplen);
                    188:     if (bias < bpfflen){
                    189:        /* there is another packet packed into same bpf frame */
                    190:        *next = bpfframe + bias;
                    191:        *nextlen = (size_t) bpfflen - bias;
                    192:     } else {
                    193:        /* no more packet */
                    194:        *next = NULL;
                    195:        *nextlen = 0;
                    196:     }
                    197: 
                    198:     /* cut off BPF header */
                    199:     p = bpfframe + ((struct bpf_hdr *)bpfframe)->bh_hdrlen;
                    200:     return(p);
                    201: }
                    202: 
                    203: /*
                    204:    match
                    205: 
                    206:    match an IP address against a list of address/netmask pairs
                    207: */
                    208: 
                    209: static int
                    210: match (u_int32_t addr, struct cidr *list) {
                    211:     while (list) {
                    212:        if ((addr & list->mask) == list->addr)
                    213:            return 1;
                    214:        list = list->next;
                    215:     }
                    216:     return 0;
                    217: }
                    218: 
                    219: /*
                    220:    checkarp
                    221: 
                    222:    check responsibility of the ARP request
                    223:    return true if responsible
                    224: 
                    225:    arpbuf is pointing top of link-level frame
                    226: */
                    227: 
                    228: static int
                    229: checkarp(char *arpbuf){
                    230:     struct ether_arp   *arp;
                    231:     u_int32_t  target_ip;
                    232: 
                    233:     arp = (struct ether_arp *)(arpbuf + 14);   /* skip ethernet header */
                    234:     if (ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
                    235:        /* XXX: ARPHRD_802 */
                    236:        ntohs(arp->arp_pro) != ETHERTYPE_IP ||
                    237:        (int) (arp->arp_hln) != ETHER_ADDR_LEN || /* length of ethernet addr */
                    238:        (int) (arp->arp_pln) != 4){  /* length of protocol addr */
                    239:        fprintf(stderr,"checkarp: WARNING: received unknown type ARP request.\n");
                    240:        return(0);
                    241:     }
                    242:     target_ip = ntohl(*(u_int32_t *)(arp->arp_tpa));
                    243:     return match(target_ip, targets) && !match(target_ip, excludes);
                    244: }
                    245: 
                    246: /*
                    247:    genarpreply
                    248: 
                    249:    generate arp reply link level frame
                    250:    arpbuf is pointing top of link-level frame
                    251:    this routine overwrite arpbuf
                    252: 
                    253:    return reply buffer & its length
                    254: */
                    255: char *
                    256: gen_arpreply(char *arpbuf, size_t *rlen){
                    257:     struct ether_arp   *arp;
                    258:     u_char     ipbuf[4];       /* sender IP */
                    259: 
                    260:     /* set ethernet dst/src address */
                    261:     memcpy(arpbuf, arpbuf+ETHER_ADDR_LEN, ETHER_ADDR_LEN);
                    262:     memcpy(arpbuf+ETHER_ADDR_LEN, target_mac, ETHER_ADDR_LEN);
                    263:     /* set result of ARP request */
                    264:     arp = (struct ether_arp *)(arpbuf + 14);   /* skip ethernet header */
                    265:     memcpy(ipbuf, arp->arp_tpa, 4);            /* save protocol addr */
                    266:     memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
                    267:     memcpy(arp->arp_spa, ipbuf, 4);            /* set source protocol addr */
                    268:     memcpy(arp->arp_sha, target_mac, ETHER_ADDR_LEN); /* set source hard addr */
                    269:     arp->arp_op = htons(ARPOP_REPLY);
                    270: 
                    271:     *rlen = 14 + 28;           /* ethernet header & arp reply */
                    272:     return(arpbuf);
                    273: }
                    274: 
                    275: void
                    276: loop(int fd, char *buf, size_t buflen){
                    277:     ssize_t  rlen;
                    278:     char    *p, *nextp;
                    279:     ssize_t  nextlen;
                    280:     char    *rframe;
                    281:     char    *sframe;
                    282:     size_t  frame_len;
1.1.1.1.2.1! misho     283:     fd_set  fdset;
1.1       misho     284: 
1.1.1.1.2.1! misho     285:     FD_ZERO(&fdset);
        !           286:     FD_SET(fd,&fdset);
1.1       misho     287: 
                    288:     for(;;){
1.1.1.1.2.1! misho     289:         int r = select(fd+1,&fdset, 0, 0, 0);
1.1       misho     290: 
                    291:         if (r < 0) {
                    292:             if (errno == EINTR)
                    293:                 continue;
                    294:             perror("select");
                    295:             return;
                    296:         }
                    297: 
1.1.1.1.2.1! misho     298:         rlen = read(fd, buf, buflen);
1.1       misho     299:         if (rlen < 0) {
                    300:             if (errno == EINTR)
                    301:                 continue;
                    302:             perror("read");
                    303:             return;
                    304:         }
                    305: 
                    306:        p = buf;
                    307:        while((rframe = getarp(p, rlen, &nextp, &nextlen)) != NULL){
                    308:            if (checkarp(rframe)){
                    309:                sframe = gen_arpreply(rframe, &frame_len);
1.1.1.1.2.1! misho     310:                write(fd, sframe, frame_len);
1.1       misho     311:            }
                    312:            p = nextp;
                    313:            rlen = nextlen;
                    314:        }
                    315:     }
                    316:     /* not reach */
                    317: }
                    318: 
                    319: int
                    320: setmac(char *addr, char *ifname){
                    321:     u_int m0, m1, m2, m3, m4, m5;
                    322: 
                    323:     if (!strcmp (addr, "auto")) {
                    324:        struct ifaddrs *ifas, *ifa;
                    325: 
                    326:        getifaddrs (&ifas);
                    327:        for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
                    328: #define SDL ((struct sockaddr_dl *)ifa->ifa_addr)
                    329:            if (strcmp (ifa->ifa_name, ifname)
                    330:              || SDL->sdl_family != AF_LINK
                    331:              || SDL->sdl_alen != 6)
                    332:                continue;
                    333:            memcpy (target_mac, SDL->sdl_data + SDL->sdl_nlen, 6);
                    334:            return 0;
                    335:        }
                    336:        return -1;
                    337:     }
                    338:     if (sscanf(addr, "%x:%x:%x:%x:%x:%x", &m0, &m1, &m2, &m3, &m4, &m5) < 6)
                    339:         return(-1);
                    340:     target_mac[0] = (u_char )m0;
                    341:     target_mac[1] = (u_char )m1;
                    342:     target_mac[2] = (u_char )m2;
                    343:     target_mac[3] = (u_char )m3;
                    344:     target_mac[4] = (u_char )m4;
                    345:     target_mac[5] = (u_char )m5;
                    346:     return(0);
                    347: }
                    348: 
                    349: int
                    350: atoip(char *buf, u_int32_t *ip_addr){
                    351:     u_int      i0, i1, i2, i3;
                    352: 
                    353:     if (sscanf(buf, "%u.%u.%u.%u", &i0, &i1, &i2, &i3) == 4){
                    354:        *ip_addr = (i0 << 24) + (i1 << 16) + (i2 << 8) + i3;
                    355:        return(0);
                    356:     }
                    357:     if (sscanf(buf, "0x%lx", ip_addr) == 1)
                    358:        return(0);
                    359: 
                    360:     return(-1);        
                    361: }
                    362: 
                    363: void
                    364: usage(void){
1.1.1.1.2.1! misho     365:     fprintf(stderr,"usage: choparp if_name mac_addr [-]addr/mask...\n");
1.1       misho     366:     exit(-1);
                    367: }
                    368: 
                    369: int
                    370: main(int argc, char **argv){
1.1.1.1.2.1! misho     371:     int        fd;
1.1       misho     372:     char *buf, *ifname;
                    373:     struct cidr **targets_tail = &targets, **excludes_tail = &excludes;
                    374: #define APPEND(LIST,ADDR,MASK) \
                    375:     do {                                                       \
                    376:        *(LIST ## _tail) = malloc(sizeof (struct cidr));        \
                    377:        (*(LIST ## _tail))->addr = ADDR;                        \
                    378:        (*(LIST ## _tail))->mask = MASK;                        \
                    379:        (*(LIST ## _tail))->next = NULL;                        \
                    380:        (LIST ## _tail) = &(*(LIST ## _tail))->next;            \
                    381:     } while (0)
                    382:     size_t buflen;
                    383: 
1.1.1.1.2.1! misho     384:     if (argc < 4)
1.1       misho     385:        usage();
                    386: 
1.1.1.1.2.1! misho     387:     ifname = argv[1];
        !           388:     if (setmac(argv[2], ifname))
1.1       misho     389:        usage();
1.1.1.1.2.1! misho     390:     argv += 3; argc -= 3;
1.1       misho     391: 
                    392:     while (argc > 0) {
                    393:        u_int32_t addr, mask = ~0;
                    394:         char *slash = strchr (*argv, '/');
                    395:        int exclude = 0;
                    396: 
                    397:        if (**argv == '-') {
                    398:            (*argv)++;
                    399:            exclude = 1;
                    400:        }
                    401:        if (slash != NULL)
                    402:            *(slash++) = '\0';
                    403:        if (atoip (*argv, &addr))
                    404:            usage();
                    405:        if (slash != NULL) {
                    406:            char *end;
                    407:            u_int32_t len = strtol (slash, &end, 10);
                    408:            if (*end == '\0')
                    409:                mask <<= (32 - len);
                    410:            else if (atoip (slash, &mask))
                    411:                usage();
                    412:        }
                    413:        if (exclude)
                    414:            APPEND(excludes, addr, mask);
                    415:        else
                    416:            APPEND(targets, addr, mask);
                    417:        argv++, argc--;
                    418:     }
                    419: 
                    420: #ifdef DEBUG
                    421: #define SHOW(LIST) \
                    422:     do {                                                               \
                    423:        struct cidr *t;                                                 \
                    424:        printf (#LIST ":\n");                                           \
                    425:        for (t = LIST; t; t = t->next) {                                \
                    426:            u_int32_t x;                                                        \
                    427:            x = htonl (t->addr);                                        \
                    428:            printf ("  %s", inet_ntoa (*(struct in_addr *)&x));         \
                    429:            x = htonl (t->mask);                                        \
                    430:            printf ("/%s\n", inet_ntoa (*(struct in_addr *)&x));        \
                    431:        }                                                               \
                    432:     } while (0)
                    433: 
                    434:     SHOW(targets);
                    435:     SHOW(excludes);
                    436:     exit (0);
                    437: #endif
                    438:     if ((fd = openbpf(ifname, &buf, &buflen)) < 0)
                    439:        return(-1);
                    440:     loop(fd, buf, buflen);
                    441:     return(-1);
                    442: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>