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>