Annotation of embedaddon/choparp/choparp.c, revision 1.1.1.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/event.h>
                     46: #include <sys/time.h>
                     47: #include <sys/ioctl.h>
                     48: #include <net/bpf.h>
                     49: #include <sys/socket.h>
                     50: #include <net/if.h>
                     51: #include <netinet/in.h>
                     52: /* #include <net/if_arp.h> */
                     53: #if (__FreeBSD__ >= 3)
                     54:  #include <net/if_var.h>
                     55: #endif
                     56: #include <netinet/if_ether.h>
                     57: #include <sys/param.h>
                     58: #include <errno.h>
                     59: #include <ifaddrs.h>
                     60: #include <net/if_dl.h>
                     61: 
                     62: #ifdef DEBUG
                     63: #include <arpa/inet.h>
                     64: #endif
                     65: 
                     66: #define        BPFFILENAME     "/dev/bpf%d"    /* bpf file template */
                     67: #ifndef        NBPFILTER                       /* number of available bpf */
                     68: # define NBPFILTER (16)
                     69: #endif
                     70: 
                     71: struct cidr {
                     72:        struct cidr *next;
                     73:        u_int32_t addr;         /* addr and mask are host order */
                     74:        u_int32_t mask;
                     75: };
                     76: 
                     77: struct cidr *targets = NULL, *excludes = NULL;
                     78: u_char target_mac[ETHER_ADDR_LEN];     /* target MAC address */
                     79: int verbose = 0;
                     80: 
                     81: /*
                     82:    ARP filter program
                     83: */
                     84: struct bpf_insn bpf_filter_arp[] = {
                     85:     /* check Ethernet Encapsulation (RFC894) first */
                     86:     BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 12),        /* load frame type */
                     87:     BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ETHERTYPE_ARP, 0, 3), /* check it */
                     88:     BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 20),        /* load OP code */
                     89:     BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, ARPOP_REQUEST, 0, 1),  /* check it */
                     90:     BPF_STMT(BPF_RET+BPF_K, 14+28),    /* return Ethernet encap ARP req. */
                     91:     /* XXX: IEEE 802.2/802.3 Encap (RFC1042) should be available... */
                     92:     BPF_STMT(BPF_RET+BPF_K, 0),                /* discard */
                     93: };
                     94: 
                     95: /*
                     96:    openbpf:
                     97: 
                     98:    open bpf & set ARP filter program for named interface &
                     99:    allocate enough buffer for BPF.
                    100:    return file descripter or -1 for error
                    101: */
                    102: int
                    103: openbpf(char *ifname, char **bufp, size_t *buflen){
                    104:     char bpffile[sizeof(BPFFILENAME)+5];       /* XXX: */
                    105:     int        fd = -1;
                    106:     int        n;
                    107:     struct bpf_version bpf_version;
                    108:     struct ifreq       bpf_ifreq;
                    109:     u_int      ui;
                    110:     struct bpf_program bpf_program;
                    111: 
                    112:     /* open BPF file */
                    113:     for (n=0; n<NBPFILTER; n++){
                    114:        sprintf(bpffile, BPFFILENAME, n);
                    115:        if ((fd = open(bpffile, O_RDWR, 0)) >= 0)
                    116:            break;
                    117:     }
                    118:     if (fd < 0){
                    119:        fprintf(stderr,"openbpf: Can't open BPF\n");
                    120:        return(-1);             /* error */
                    121:     }
                    122: 
                    123:     /* check version number */
                    124:     if ((ioctl(fd, BIOCVERSION, &bpf_version) == -1) ||
                    125:        bpf_version.bv_major != BPF_MAJOR_VERSION ||
                    126:        bpf_version.bv_minor < BPF_MINOR_VERSION){
                    127:        fprintf(stderr,"openbpf: incorrect BPF version\n");
                    128:        close(fd);
                    129:        return(-1);
                    130:     }
                    131: 
                    132:     /* set interface name */
                    133:     strncpy(bpf_ifreq.ifr_name, ifname, IFNAMSIZ);
                    134:     bpf_ifreq.ifr_name[IFNAMSIZ-1] = '\0';     /* paranoia */
                    135:     if (ioctl(fd, BIOCSETIF, &bpf_ifreq) == -1){
                    136:        fprintf(stderr,"openbpf: BIOCSETIF failed for interface <%s>\n",
                    137:                ifname);
                    138:        close(fd);
                    139:        return(-1);
                    140:     }
                    141: 
                    142:     /* set BPF immediate mode */
                    143:     ui = 1;
                    144:     if (ioctl(fd, BIOCIMMEDIATE, &ui) == -1){
                    145:        fprintf(stderr,"openbpf: BIOCIMMEDIATE failed.\n");
                    146:        close(fd);
                    147:        return(-1);
                    148:     }
                    149: 
                    150:     /* set ARP request filter */
                    151:     bpf_program.bf_len = sizeof(bpf_filter_arp) / sizeof(struct bpf_insn);
                    152:     bpf_program.bf_insns = bpf_filter_arp;
                    153:     if (ioctl(fd, BIOCSETF, &bpf_program) == -1){
                    154:        fprintf(stderr,"openbpf: BIOCSETF failed.\n");
                    155:        close(fd);
                    156:        return(-1);
                    157:     }
                    158: 
                    159:     /* allocate reasonable size & alimented buffer */
                    160:     if (ioctl(fd, BIOCGBLEN, &ui) == -1){
                    161:        fprintf(stderr,"openbpf: BIOCGBLEN failed.\n");
                    162:        close(fd);
                    163:        return(-1);
                    164:     }
                    165:     *buflen = (size_t)ui;
                    166:     if ((*bufp = (char *)malloc((size_t) ui)) == NULL){
                    167:        fprintf(stderr,"openbpf: malloc failed.\n");
                    168:        close(fd);
                    169:        return(-1);
                    170:     }
                    171: 
                    172:     return(fd);
                    173: }
                    174: 
                    175: /*
                    176:    get ARP datalink frame pointer
                    177: 
                    178:    NULL if no more ARP frame
                    179: */
                    180: char *
                    181: getarp(char *bpfframe, ssize_t bpfflen, char **next, ssize_t *nextlen){
                    182:     int        bias;
                    183:     char *p;
                    184: 
                    185:     if (bpfframe == NULL || bpfflen == 0)
                    186:        return(NULL);
                    187: 
                    188:     bias = BPF_WORDALIGN(((struct bpf_hdr *)bpfframe)->bh_hdrlen +
                    189:                         ((struct bpf_hdr *)bpfframe)->bh_caplen);
                    190:     if (bias < bpfflen){
                    191:        /* there is another packet packed into same bpf frame */
                    192:        *next = bpfframe + bias;
                    193:        *nextlen = (size_t) bpfflen - bias;
                    194:     } else {
                    195:        /* no more packet */
                    196:        *next = NULL;
                    197:        *nextlen = 0;
                    198:     }
                    199: 
                    200:     /* cut off BPF header */
                    201:     p = bpfframe + ((struct bpf_hdr *)bpfframe)->bh_hdrlen;
                    202:     return(p);
                    203: }
                    204: 
                    205: /*
                    206:    match
                    207: 
                    208:    match an IP address against a list of address/netmask pairs
                    209: */
                    210: 
                    211: static int
                    212: match (u_int32_t addr, struct cidr *list) {
                    213:     while (list) {
                    214:        if ((addr & list->mask) == list->addr)
                    215:            return 1;
                    216:        list = list->next;
                    217:     }
                    218:     return 0;
                    219: }
                    220: 
                    221: /*
                    222:    checkarp
                    223: 
                    224:    check responsibility of the ARP request
                    225:    return true if responsible
                    226: 
                    227:    arpbuf is pointing top of link-level frame
                    228: */
                    229: 
                    230: static int
                    231: checkarp(char *arpbuf){
                    232:     struct ether_arp   *arp;
                    233:     u_int32_t  target_ip;
                    234: 
                    235:     arp = (struct ether_arp *)(arpbuf + 14);   /* skip ethernet header */
                    236:     if (ntohs(arp->arp_hrd) != ARPHRD_ETHER ||
                    237:        /* XXX: ARPHRD_802 */
                    238:        ntohs(arp->arp_pro) != ETHERTYPE_IP ||
                    239:        (int) (arp->arp_hln) != ETHER_ADDR_LEN || /* length of ethernet addr */
                    240:        (int) (arp->arp_pln) != 4){  /* length of protocol addr */
                    241:        fprintf(stderr,"checkarp: WARNING: received unknown type ARP request.\n");
                    242:        return(0);
                    243:     }
                    244:     if (ntohl(*(u_int32_t *)(arp->arp_tpa)) == ntohl(*(u_int32_t *)(arp->arp_spa))) {
                    245:        if (verbose != 0)
                    246:            fprintf(stderr,"checkarp: WARNING: sender equal dest.\n");
                    247:        return(0);
                    248:     }
                    249:     if (0 == ntohl(*(u_int32_t *)(arp->arp_spa))) {
                    250:        if (verbose != 0)
                    251:            fprintf(stderr,"checkarp: WARNING: zero sender address.\n");
                    252:        return(0);
                    253:     }
                    254:     target_ip = ntohl(*(u_int32_t *)(arp->arp_tpa));
                    255:     return match(target_ip, targets) && !match(target_ip, excludes);
                    256: }
                    257: 
                    258: /*
                    259:    genarpreply
                    260: 
                    261:    generate arp reply link level frame
                    262:    arpbuf is pointing top of link-level frame
                    263:    this routine overwrite arpbuf
                    264: 
                    265:    return reply buffer & its length
                    266: */
                    267: char *
                    268: gen_arpreply(char *arpbuf, size_t *rlen){
                    269:     struct ether_arp   *arp;
                    270:     u_char     ipbuf[4];       /* sender IP */
                    271: 
                    272:     /* set ethernet dst/src address */
                    273:     memcpy(arpbuf, arpbuf+ETHER_ADDR_LEN, ETHER_ADDR_LEN);
                    274:     memcpy(arpbuf+ETHER_ADDR_LEN, target_mac, ETHER_ADDR_LEN);
                    275:     /* set result of ARP request */
                    276:     arp = (struct ether_arp *)(arpbuf + 14);   /* skip ethernet header */
                    277:     memcpy(ipbuf, arp->arp_tpa, 4);            /* save protocol addr */
                    278:     memcpy(arp->arp_tha, arp->arp_sha, 10); /* set target hard/proto addr */
                    279:     memcpy(arp->arp_spa, ipbuf, 4);            /* set source protocol addr */
                    280:     memcpy(arp->arp_sha, target_mac, ETHER_ADDR_LEN); /* set source hard addr */
                    281:     arp->arp_op = htons(ARPOP_REPLY);
                    282: 
                    283:     *rlen = 14 + 28;           /* ethernet header & arp reply */
                    284:     return(arpbuf);
                    285: }
                    286: 
                    287: void
                    288: loop(int fd, char *buf, size_t buflen){
                    289:     ssize_t  rlen;
                    290:     char    *p, *nextp;
                    291:     ssize_t  nextlen;
                    292:     char    *rframe;
                    293:     char    *sframe;
                    294:     size_t  frame_len;
                    295:     int     kq;
                    296:     struct  kevent kev;
                    297: 
                    298:     if ((kq = kqueue()) < 0) {
                    299:         perror("kqueue");
                    300:         return;
                    301:     }
                    302: 
                    303:     EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, NULL);
                    304:     if (kevent(kq, &kev, 1, NULL, 0, NULL) < 0 ) {
                    305:         perror("kevent");
                    306:         return;
                    307:     }
                    308: 
                    309:     for(;;){
                    310:         int r = kevent(kq, NULL, 0, &kev, 1, NULL);
                    311: 
                    312:         if (r < 0) {
                    313:             if (errno == EINTR)
                    314:                 continue;
                    315:             perror("select");
                    316:             return;
                    317:         }
                    318: 
                    319:         rlen = read(kev.ident, buf, buflen);
                    320:         if (rlen < 0) {
                    321:             if (errno == EINTR)
                    322:                 continue;
                    323:             perror("read");
                    324:             return;
                    325:         }
                    326: 
                    327:        p = buf;
                    328:        while((rframe = getarp(p, rlen, &nextp, &nextlen)) != NULL){
                    329:            if (checkarp(rframe)){
                    330:                sframe = gen_arpreply(rframe, &frame_len);
                    331:                write(kev.ident, sframe, frame_len);
                    332:            }
                    333:            p = nextp;
                    334:            rlen = nextlen;
                    335:        }
                    336:     }
                    337:     /* not reach */
                    338: }
                    339: 
                    340: int
                    341: setmac(char *addr, char *ifname){
                    342:     u_int m0, m1, m2, m3, m4, m5;
                    343: 
                    344:     if (!strcmp (addr, "auto")) {
                    345:        struct ifaddrs *ifas, *ifa;
                    346: 
                    347:        getifaddrs (&ifas);
                    348:        for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
                    349: #define SDL ((struct sockaddr_dl *)ifa->ifa_addr)
                    350:            if (strcmp (ifa->ifa_name, ifname)
                    351:              || SDL->sdl_family != AF_LINK
                    352:              || SDL->sdl_alen != 6)
                    353:                continue;
                    354:            memcpy (target_mac, SDL->sdl_data + SDL->sdl_nlen, 6);
                    355:            return 0;
                    356:        }
                    357:        return -1;
                    358:     }
                    359:     if (sscanf(addr, "%x:%x:%x:%x:%x:%x", &m0, &m1, &m2, &m3, &m4, &m5) < 6)
                    360:         return(-1);
                    361:     target_mac[0] = (u_char )m0;
                    362:     target_mac[1] = (u_char )m1;
                    363:     target_mac[2] = (u_char )m2;
                    364:     target_mac[3] = (u_char )m3;
                    365:     target_mac[4] = (u_char )m4;
                    366:     target_mac[5] = (u_char )m5;
                    367:     return(0);
                    368: }
                    369: 
                    370: int
                    371: atoip(char *buf, u_int32_t *ip_addr){
                    372:     u_int      i0, i1, i2, i3;
                    373: 
                    374:     if (sscanf(buf, "%u.%u.%u.%u", &i0, &i1, &i2, &i3) == 4){
                    375:        *ip_addr = (i0 << 24) + (i1 << 16) + (i2 << 8) + i3;
                    376:        return(0);
                    377:     }
                    378:     if (sscanf(buf, "0x%lx", ip_addr) == 1)
                    379:        return(0);
                    380: 
                    381:     return(-1);        
                    382: }
                    383: 
                    384: void
                    385: usage(void){
                    386:     fprintf(stderr,"usage: choparp [-v] if_name mac_addr [-]addr/mask...\n");
                    387:     exit(-1);
                    388: }
                    389: 
                    390: int
                    391: main(int argc, char **argv){
                    392:     int        ch, fd;
                    393:     char *buf, *ifname;
                    394:     struct cidr **targets_tail = &targets, **excludes_tail = &excludes;
                    395: #define APPEND(LIST,ADDR,MASK) \
                    396:     do {                                                       \
                    397:        *(LIST ## _tail) = malloc(sizeof (struct cidr));        \
                    398:        (*(LIST ## _tail))->addr = ADDR;                        \
                    399:        (*(LIST ## _tail))->mask = MASK;                        \
                    400:        (*(LIST ## _tail))->next = NULL;                        \
                    401:        (LIST ## _tail) = &(*(LIST ## _tail))->next;            \
                    402:     } while (0)
                    403:     size_t buflen;
                    404: 
                    405:     while ((ch = getopt(argc, argv, "v")) != -1)
                    406:         switch (ch) {
                    407:         case 'v':
                    408:             verbose++;
                    409:             break;
                    410:         default:
                    411:             usage();
                    412:         }
                    413:     argc -= optind;
                    414:     argv += optind;
                    415: 
                    416:     if (argc < 3)
                    417:        usage();
                    418: 
                    419:     ifname = argv[0];
                    420:     if (setmac(argv[1], ifname))
                    421:        usage();
                    422:     argv += 2; argc -= 2;
                    423: 
                    424:     while (argc > 0) {
                    425:        u_int32_t addr, mask = ~0;
                    426:         char *slash = strchr (*argv, '/');
                    427:        int exclude = 0;
                    428: 
                    429:        if (**argv == '-') {
                    430:            (*argv)++;
                    431:            exclude = 1;
                    432:        }
                    433:        if (slash != NULL)
                    434:            *(slash++) = '\0';
                    435:        if (atoip (*argv, &addr))
                    436:            usage();
                    437:        if (slash != NULL) {
                    438:            char *end;
                    439:            u_int32_t len = strtol (slash, &end, 10);
                    440:            if (*end == '\0')
                    441:                mask <<= (32 - len);
                    442:            else if (atoip (slash, &mask))
                    443:                usage();
                    444:        }
                    445:        if (exclude)
                    446:            APPEND(excludes, addr, mask);
                    447:        else
                    448:            APPEND(targets, addr, mask);
                    449:        argv++, argc--;
                    450:     }
                    451: 
                    452: #ifdef DEBUG
                    453: #define SHOW(LIST) \
                    454:     do {                                                               \
                    455:        struct cidr *t;                                                 \
                    456:        printf (#LIST ":\n");                                           \
                    457:        for (t = LIST; t; t = t->next) {                                \
                    458:            u_int32_t x;                                                        \
                    459:            x = htonl (t->addr);                                        \
                    460:            printf ("  %s", inet_ntoa (*(struct in_addr *)&x));         \
                    461:            x = htonl (t->mask);                                        \
                    462:            printf ("/%s\n", inet_ntoa (*(struct in_addr *)&x));        \
                    463:        }                                                               \
                    464:     } while (0)
                    465: 
                    466:     SHOW(targets);
                    467:     SHOW(excludes);
                    468:     exit (0);
                    469: #endif
                    470:     if ((fd = openbpf(ifname, &buf, &buflen)) < 0)
                    471:        return(-1);
                    472:        #ifndef DEBUG
                    473:                daemon(0, 0);
                    474:        #endif
                    475:     loop(fd, buf, buflen);
                    476:     return(-1);
                    477: }

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