#include <sys/types.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/endian.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <err.h>
#include <assert.h>
#include "w00t.h"
struct client {
char mac[6];
int seq;
struct client *next;
};
struct params {
int tx;
int rx;
int tap;
char mac[6];
char ssid[256];
int chan;
int bint;
struct timeval blast;
int seq;
int wep_len;
char wep_key[13];
int wep_iv;
struct client *clients;
char packet[4096];
int packet_len;
int packet_try;
struct timeval plast;
};
void usage(char *name)
{
printf("Usage: %s <opts>\n"
"-h\thelp\n"
"-i\t<iface>\n"
"-s\t<ssid>\n"
"-m\t<mac>\n"
"-w\t<wep key>\n"
"-c\t<chan>\n"
"-t\t<tap>\n"
, name);
exit(0);
}
void fill_basic(struct ieee80211_frame *wh, struct params *p)
{
short *seq;
wh->i_dur[0] = 0x69;
wh->i_dur[1] = 0x00;
memcpy(wh->i_addr2, p->mac, 6);
seq = (short*)wh->i_seq;
*seq = seqfn(p->seq, 0);
}
void send_frame(struct params *p, void *buf, int len)
{
int rc;
rc = inject(p->tx, buf, len);
if (rc == -1)
err(1, "inject()");
if (rc != len) {
printf("injected %d/%d\n", rc, len);
exit(1);
}
p->seq++;
}
int fill_beacon(struct params *p, struct ieee80211_frame *wh)
{
int len;
char *ptr;
ptr = (char*) (wh+1);
ptr += 8;
ptr += 2;
*ptr |= IEEE80211_CAPINFO_ESS;
ptr += 2;
len = strlen(p->ssid);
*ptr++ = 0;
*ptr++ = len;
memcpy(ptr, p->ssid, len);
ptr += len;
*ptr++ = 1;
*ptr++ = 4;
*ptr++ = 2 | 0x80;
*ptr++ = 4 | 0x80;
*ptr++ = 11;
*ptr++ = 22;
*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);
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);
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;
ptr += 2;
ptr += 2;
*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;
ptr += 2;
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[1] = 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)
{
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;
memcpy(fc, wh->i_fc, 2);
memcpy(seq, wh->i_seq, 2);
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);
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);
if (memcmp(wh->i_addr1, p->mac, 6) != 0)
return;
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_PROTECTED) {
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;
}
ptr += 8 - 2;
ptr -= 6;
memcpy(ptr, wh->i_addr2, 6);
ptr -= 6;
memcpy(ptr, dst, 6);
len -= sizeof(*wh);
len -= 8;
len += 14;
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;
if (memcmp(wh->i_addr2, p->mac, 6) == 0) {
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;
memset(buf, 0, sizeof(buf));
rd = read(p->tap, ptr, len);
if (rd == -1)
err(1, "read()");
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_PROTECTED;
ptr = (char*) (wh+1);
if (p->wep_len)
ptr += 4;
*ptr++ = 0xAA;
*ptr++ = 0xAA;
*ptr++ = 0x03;
*ptr++ = 0x00;
*ptr++ = 0x00;
*ptr++ = 0x00;
rd += offset;
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;
}
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;
if (gettimeofday(&now, NULL) == -1)
err(1, "gettimeofday()");
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;
if (p->packet_try) {
el = elapsed(&p->plast, &now);
if (el >= rtr) {
if (retransmit(p)) {
el = 0;
}
else
el = -1;
}
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;
}
}
}
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 = "wlan0";
char *tap = "tap0";
struct params p;
int ch;
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;
}
}
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);
}