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

airodump.c

/*
 *  pcap-compatible 802.11 packet sniffer
 *
 *  Copyright (C) 2004,2005  Christophe Devine
 *
 *  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
 */

#include <linux/if_ether.h>
#include <netpacket/packet.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <net/if.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <time.h>

#include "pcap.h"
#include "uniqueiv.c"

#define FORMAT_CAP 1
#define FORMAT_IVS 2

#define ARPHRD_IEEE80211 801
#define ARPHRD_IEEE80211_PRISM 802

#define REFRESH_TIMEOUT 200000

#define BROADCAST_ADDR "\xFF\xFF\xFF\xFF\xFF\xFF"

/* linked list of detected access points */

struct AP_info
{
    struct AP_info *prev;     /* the prev AP in list      */
    struct AP_info *next;     /* the next AP in list      */

    time_t tinit, tlast;      /* first and last time seen */

    int power, chanl;         /* signal power and channel */
    int speed, crypt;         /* maxrate & encryption alg */

    unsigned long nb_bcn;     /* total number of beacons  */
    unsigned long nb_pkt;     /* total number of packets  */
    unsigned long nb_data;    /* number of WEP data pkts  */

    unsigned char bssid[6];   /* the access point's MAC   */
    unsigned char essid[33];  /* ascii network identifier */

    unsigned char lanip[4];   /* last detected ip address */
                              /* if non-encrypted network */

    unsigned char **uiv_root; /* unique iv root structure */
                              /* if wep-encrypted network */
};

/* linked list of detected clients */

struct ST_info
{
    struct ST_info *prev;    /* the prev client in list   */
    struct ST_info *next;    /* the next client in list   */
    struct AP_info *base;    /* AP this client belongs to */
    time_t tinit, tlast;     /* first and last time seen  */
    int power;               /* signal power              */
    unsigned long nb_pkt;    /* total number of packets   */
    unsigned char stmac[6];  /* the client's MAC address  */
};

/* bunch of global stuff */

struct AP_info *ap_1st, *ap_end;
struct AP_info *ap_cur, *ap_prv;

struct ST_info *st_1st, *st_end;
struct ST_info *st_cur, *st_prv;

struct pcap_file_header pfh_out;
struct pcap_file_header pfh_out;

unsigned char prev_bssid[6];

FILE *f_cap_in  = NULL;
FILE *f_csv_out = NULL;
FILE *f_cap_out = NULL;
FILE *f_ivs_out = NULL;

int dump_initialize( char *output_prefix, int ivs_only )
{
    int n;
    char o_filename[1024];

    ap_1st = ap_end = NULL;
    st_1st = st_end = NULL;

    /* create the output csv file */

    if( strlen( output_prefix ) >= sizeof( o_filename ) - 5 )
        output_prefix[sizeof( o_filename ) - 5] = '\0';

    if( strcmp( output_prefix, "-" ) != 0 )
    {
        memset( o_filename, 0, sizeof( o_filename ) );
        snprintf( o_filename,  sizeof( o_filename ) - 1,
                  "%s.txt", output_prefix );

        if( ( f_csv_out = fopen( o_filename, "wb+" ) ) == NULL )
        {
            perror( "fopen failed" );
            fprintf( stderr, "Could not create \"%s\".\n", o_filename );
            return( 1 );
        }
    }

    /* open or create the output packet capture file */

    if( ivs_only == 0 )
    {
        n = sizeof( struct pcap_file_header );

        if( strcmp( output_prefix, "-" ) != 0 )
        {
            memset( o_filename, 0, sizeof( o_filename ) );
            snprintf( o_filename,  sizeof( o_filename ) - 1,
                      "%s.cap", output_prefix );
        }
        else
        {
            f_cap_out = fdopen( 1, "wb" );
            goto write_cap_header;
        }

        if( ( f_cap_out = fopen( o_filename, "rb+" ) ) == NULL )
        {
        create_cap_file:

            if( ( f_cap_out = fopen( o_filename, "wb+" ) ) == NULL )
            {
                perror( "fopen failed" );
                fprintf( stderr, "Could not create \"%s\".\n", o_filename );
                return( 1 );
            }

        write_cap_header:

            pfh_out.magic           = TCPDUMP_MAGIC;
            pfh_out.version_major   = PCAP_VERSION_MAJOR;
            pfh_out.version_minor   = PCAP_VERSION_MINOR;
            pfh_out.thiszone        = 0;
            pfh_out.sigfigs         = 0;
            pfh_out.snaplen         = 65535;
            pfh_out.linktype        = LINKTYPE_IEEE802_11;

            if( fwrite( &pfh_out, 1, n, f_cap_out ) != (size_t) n )
            {
                perror( "fwrite(pcap file header) failed" );
                return( 1 );
            }
        }
        else
        {
            if( fread( &pfh_out, 1, n, f_cap_out ) != (size_t) n )
                goto create_cap_file;

            if( pfh_out.magic != TCPDUMP_MAGIC &&
                pfh_out.magic != TCPDUMP_CIGAM )
            {
                fprintf( stderr, "\"%s\" isn't a pcap file (expected "
                                 "TCPDUMP_MAGIC).\n", o_filename );
                return( 1 );
            }

            if( pfh_out.magic == TCPDUMP_CIGAM )
                SWAP32( pfh_out.linktype );

            if( pfh_out.linktype != LINKTYPE_IEEE802_11 )
            {
                fprintf( stderr, "Wrong linktype from pcap file header "
                                 "(expected LINKTYPE_IEEE802_11) -\n"
                                 "this doesn't look like a regular 802.11 "
                                 "capture.\n" );
                return( 1 );
            }

            if( fseek( f_cap_out, 0, SEEK_END ) != 0 )
            {
                perror( "fseek(SEEK_END) failed" );
                return( 1 );
            }
        }
    }

    if( ivs_only == 1 )
    {
        memset( prev_bssid, 0, 6 );

        if( strcmp( output_prefix, "-" ) != 0 )
        {
            memset( o_filename, 0, sizeof( o_filename ) );
            snprintf( o_filename,  sizeof( o_filename ) - 1,
                      "%s.ivs", output_prefix );
        }
        else
        {
            f_ivs_out = fdopen( 1, "wb" );
            goto write_ivs_header;
        }

        if( ( f_ivs_out = fopen( o_filename, "rb+" ) ) == NULL )
        {
        create_ivs_file:

            if( ( f_ivs_out = fopen( o_filename, "wb+" ) ) == NULL )
            {
                perror( "fopen failed" );
                fprintf( stderr, "Could not create \"%s\".\n", o_filename );
                return( 1 );
            }

        write_ivs_header:

            if( fwrite( IVSONLY_MAGIC, 1, 4, f_ivs_out ) != sizeof( n ) )
            {
                perror( "fwrite(IVs file header) failed" );
                return( 1 );
            }
        }
        else
        {
            unsigned char ivs_hdr[4];

            if( fread( ivs_hdr, 1, 4, f_ivs_out ) != 4 )
                goto create_ivs_file;

            if( memcmp( ivs_hdr, IVSONLY_MAGIC, 4 ) != 0 )
            {
                fprintf( stderr, "\"%s\" isn't a IVs file (expected "
                                 "IVSONLY_MAGIC).\n", o_filename );
                return( 1 );
            }

            if( fseek( f_ivs_out, 0, SEEK_END ) != 0 )
            {
                perror( "fseek(SEEK_END) failed" );
                return( 1 );
            }
        }
    }

    return( 0 );
}

int dump_add_packet( unsigned char *h80211, int caplen, int power,
                     int channel, uint tv_sec, uint tv_usec )

{
    int i, n;

    struct pcap_pkthdr pkh;

    unsigned char *p;
    unsigned char bssid[6];
    unsigned char stmac[6];

    ap_cur = NULL;
    st_cur = NULL;

    pkh.caplen = pkh.len = caplen;

    /* skip packets smaller than a 802.11 header */

    if( pkh.caplen < 24 )
        goto write_packet;

    /* skip (uninteresting) control frames */

    if( ( h80211[0] & 0x0C ) == 0x04 )
        goto write_packet;

    /* locate the access point's MAC address */

    switch( h80211[1] & 3 )
    {
        case  0: memcpy( bssid, h80211 + 16, 6 ); break;
        case  1: memcpy( bssid, h80211 +  4, 6 ); break;
        case  2: memcpy( bssid, h80211 + 10, 6 ); break;
        default: memcpy( bssid, h80211 +  4, 6 ); break;
    }

    /* skip broadcast packets */

    if( memcmp( bssid, BROADCAST_ADDR, 6 ) == 0 )
        goto write_packet;

    /* update our chained list of access points */

    ap_cur = ap_1st;
    ap_prv = NULL;

    while( ap_cur != NULL )
    {
        if( ! memcmp( ap_cur->bssid, bssid, 6 ) )
            break;

        ap_prv = ap_cur;
        ap_cur = ap_cur->next;
    }

    /* if it's a new access point, add it */

    if( ap_cur == NULL )
    {
        if( ! ( ap_cur = (struct AP_info *) malloc(
                         sizeof( struct AP_info ) ) ) )
        {
            perror( "malloc failed" );
            return( 1 );
        }

        memset( ap_cur, 0, sizeof( struct AP_info ) );

        if( ap_1st == NULL )
            ap_1st = ap_cur;
        else
            ap_prv->next  = ap_cur;

        memcpy( ap_cur->bssid, bssid, 6 );

        ap_cur->prev = ap_prv;

        if( tv_sec == 0 )
        {
            ap_cur->tinit = time( NULL );
            ap_cur->tlast = time( NULL );
        }
        else
        {
            ap_cur->tinit = tv_sec;
            ap_cur->tlast = tv_sec;
        }

        ap_cur->power = power;

        ap_cur->chanl = -1;
        ap_cur->speed = -1;
        ap_cur->crypt = -1;

        ap_cur->uiv_root = uniqueiv_init();

        ap_end = ap_cur;
    }

    if( tv_sec == 0 )
        ap_cur->tlast = time( NULL );
    else
        ap_cur->tlast = tv_sec;

    if( ( h80211[1] & 1 ) == 0 )
        ap_cur->power = power;

    if( h80211[0] == 0x80 )
        ap_cur->nb_bcn++;

    ap_cur->nb_pkt++;

    /* locate the station MAC in the 802.11 header */

    switch( h80211[1] & 3 )
    {
        case  0: memcpy( stmac, h80211 + 10, 6 ); break;
        case  1: memcpy( stmac, h80211 + 10, 6 ); break;
        case  2:

            /* reject broadcast MACs */

            if( h80211[4] != 0 ) goto skip_station;
            memcpy( stmac, h80211 +  4, 6 ); break;

        default: goto skip_station; break;
    }

    /* skip non-data packets */

    if( ( h80211[0] & 0x0C ) != 0x08 )
        goto skip_station;

    /* update our chained list of wireless clients */

    st_cur = st_1st;
    st_prv = NULL;

    while( st_cur != NULL )
    {
        if( ! memcmp( st_cur->stmac, stmac, 6 ) )
            break;

        st_prv = st_cur;
        st_cur = st_cur->next;
    }

    /* if it's a new client, add it */

    if( st_cur == NULL )
    {
        if( ! ( st_cur = (struct ST_info *) malloc(
                         sizeof( struct ST_info ) ) ) )
        {
            perror( "malloc failed" );
            return( 1 );
        }

        memset( st_cur, 0, sizeof( struct ST_info ) );

        if( st_1st == NULL )
            st_1st = st_cur;
        else
            st_prv->next  = st_cur;

        memcpy( st_cur->stmac, stmac, 6 );

        st_cur->prev = st_prv;
        st_cur->base = ap_cur;

        if( tv_sec == 0 )
        {
            st_cur->tinit = time( NULL );
            st_cur->tlast = time( NULL );
        }
        else
        {
            st_cur->tinit = tv_sec;
            st_cur->tlast = tv_sec;
        }

        st_cur->power = power;

        st_end = st_cur;
    }

    /* every 1s, update the last time seen & receive power */

    if( tv_sec == 0 )
        st_cur->tlast = time( NULL );
    else
        st_cur->tlast = tv_sec;

    if( ( h80211[1] & 3 ) == 1 )
        st_cur->power = power;

    st_cur->nb_pkt++;

skip_station:

    /* packet parsing: Beacon or Probe Response */

    if( h80211[0] == 0x80 ||
        h80211[0] == 0x50 )
    {
        if( ap_cur->crypt < 0 )
            ap_cur->crypt = ( h80211[34] & 0x10 ) >> 4;

        p = h80211 + 36;

        while( p < h80211 + pkh.caplen )
        {
            if( p + 2 + p[1] > h80211 + pkh.caplen )
                break;

            if( p[0] == 0x00 && p[1] > 0 && p[2] != '\0' &&
                ( p[1] > 1 || p[2] != ' ' ) )
            {
                /* found a non-cloaked ESSID */

                n = ( p[1] > 32 ) ? 32 : p[1];

                memset( ap_cur->essid, 0, 33 );
                memcpy( ap_cur->essid, p + 2, n );

                for( i = 0; i < n; i++ )
                    if( ap_cur->essid[i] < 32 ||
                      ( ap_cur->essid[i] > 126 && ap_cur->essid[i] < 160 ) )
                        ap_cur->essid[i] = '.';
            }

            if( p[0] == 0x01 || p[0] == 0x32 )
                ap_cur->speed = ( p[1 + p[1]] & 0x7F ) / 2;

            if( p[0] == 0x03 )
                ap_cur->chanl = p[2];

            p += 2 + p[1];
        }
    }

    /* packet parsing: Association Request */

    if( h80211[0] == 0x00 )
    {
        p = h80211 + 28;

        while( p < h80211 + pkh.caplen )
        {
            if( p + 2 + p[1] > h80211 + pkh.caplen )
                break;

            if( p[0] == 0x00 && p[1] > 0 && p[2] != '\0' &&
                ( p[1] > 1 || p[2] != ' ' ) )
            {
                /* found a non-cloaked ESSID */

                n = ( p[1] > 32 ) ? 32 : p[1];

                memset( ap_cur->essid, 0, 33 );
                memcpy( ap_cur->essid, p + 2, n );

                for( i = 0; i < n; i++ )
                    if( ap_cur->essid[i] < 32 ||
                      ( ap_cur->essid[i] > 126 && ap_cur->essid[i] < 160 ) )
                        ap_cur->essid[i] = '.';
            }

            p += 2 + p[1];
        }
    }

    /* packet parsing: some data */

    if( ap_cur->chanl == -1 )
        ap_cur->chanl = channel;

    if( ( h80211[0] & 0x0C ) == 0x08 )
    {
        /* check the SNAP header to see if data is encrypted */

        unsigned int z = ( ( h80211[1] & 3 ) != 3 ) ? 24 : 30;

        if( z + 26 > pkh.caplen )
            goto write_packet;

        if( h80211[z] == h80211[z + 1] && h80211[z + 2] == 0x03 )
        {
            if( ap_cur->crypt < 0 )
                ap_cur->crypt = 0;

            /* if ethertype == IPv4, find the LAN address */

            if( h80211[z + 6] == 0x08 && h80211[z + 7] == 0x00 &&
                ( h80211[1] & 3 ) == 0x01 )
                    memcpy( ap_cur->lanip, &h80211[z + 20], 4 );

            if( h80211[z + 6] == 0x08 && h80211[z + 7] == 0x06 )
                memcpy( ap_cur->lanip, &h80211[z + 22], 4 );
        }
        else
            ap_cur->crypt = 2 + ( ( h80211[z + 3] & 0x20 ) >> 5 );

        if( z + 10 > pkh.caplen )
            goto write_packet;

        if( ap_cur->crypt == 2 )
        {
            /* WEP: check if we've already seen this IV */

            if( ! uniqueiv_check( ap_cur->uiv_root, &h80211[z] ) )
            {
                /* first time seen IVs */

                if( f_ivs_out != NULL )
                {
                    unsigned char iv_info[64];

                    if( memcmp( prev_bssid, ap_cur->bssid, 6 ) == 0 )
                    {
                        iv_info[0] = 0xFF;
                        memcpy( iv_info + 1, &h80211[z    ], 3 );
                        memcpy( iv_info + 4, &h80211[z + 4], 2 );
                        n =  6;
                    }
                    else
                    {
                        memcpy( prev_bssid , ap_cur->bssid,  6 );
                        memcpy( iv_info    , ap_cur->bssid,  6 );
                        memcpy( iv_info + 6, &h80211[z    ], 3 );
                        memcpy( iv_info + 9, &h80211[z + 4], 2 );
                        n = 11;
                    }

                    if( fwrite( iv_info, 1, n, f_ivs_out ) != (size_t) n )
                    {
                        perror( "fwrite(IV info) failed" );
                        return( 1 );
                    }
                }

                uniqueiv_mark( ap_cur->uiv_root, &h80211[z] );

                ap_cur->nb_data++;
            }
        }
        else
            ap_cur->nb_data++;
    }

write_packet:

    if( f_cap_out != NULL )
    {
        struct timeval tv;

        gettimeofday( &tv, NULL );

        if( tv_sec == 0 )
        {
            pkh.tv_sec  = tv.tv_sec;
            pkh.tv_usec = ( tv.tv_usec & ~0x1ff ) + power;
        }
        else
        {
            pkh.tv_sec  = tv_sec;
            pkh.tv_usec = tv_usec;
        }

        if( pfh_out.magic == TCPDUMP_CIGAM )
        {
            SWAP32( pkh.tv_sec  );
            SWAP32( pkh.tv_usec );
            SWAP32( pkh.caplen  );
            SWAP32( pkh.len     );
        }

        n = sizeof( pkh );

        if( fwrite( &pkh, 1, n, f_cap_out ) != (size_t) n )
        {
            perror( "fwrite(packet header) failed" );
            return( 1 );
        }

        fflush( stdout );

        n = pkh.caplen;

        if( fwrite( h80211, 1, n, f_cap_out ) != (size_t) n )
        {
            perror( "fwrite(packet data) failed" );
            return( 1 );
        }

        fflush( stdout );
    }

    return( 0 );
}

void dump_print( int ws_row, int ws_col )
{
    int nlines;
    char strbuf[512];

    /* print some informations about each detected AP */

    fprintf( stderr, "\n BSSID              PWR  Beacons"
                     "   # Data  CH  MB  ENC   ESSID\n\n" );

    nlines = 5;

    ap_cur = ap_end;

    while( ap_cur != NULL )
    {
        if( f_cap_in == NULL && ( ap_cur->nb_pkt < 2 ||
              time( NULL ) - ap_cur->tlast > 120 ) )
        {
            ap_cur = ap_cur->prev;
            continue;
        }

        if( ws_row != 0 && nlines > ws_row )
            return;

        nlines++;

        fprintf( stderr, " %02X:%02X:%02X:%02X:%02X:%02X",
                ap_cur->bssid[0], ap_cur->bssid[1],
                ap_cur->bssid[2], ap_cur->bssid[3],
                ap_cur->bssid[4], ap_cur->bssid[5] );

        fprintf( stderr, "  %3d %8ld %8ld",
                 ap_cur->power,
                 ap_cur->nb_bcn,
                 ap_cur->nb_data );

        fprintf( stderr, " %3d %3d  ", ap_cur->chanl, ap_cur->speed );

        switch( ap_cur->crypt )
        {
            case  0: fprintf( stderr, "OPN " ); break;
            case  1: fprintf( stderr, "WEP?" ); break;
            case  2: fprintf( stderr, "WEP " ); break;
            case  3: fprintf( stderr, "WPA " ); break;
            default: fprintf( stderr, "    " ); break;
        }

        memset( strbuf, 0, sizeof( strbuf ) );
        snprintf( strbuf,  sizeof( strbuf ) - 1,
                  "%-32s", ap_cur->essid );
        strbuf[ws_col - 58] = '\0';
        fprintf( stderr, "  %s\n", strbuf );

        ap_cur = ap_cur->prev;
    }

    /* print some informations about each detected station */

    memset( strbuf, 0, ws_col );

    nlines += 3;

    if( ws_row != 0 && nlines > ws_row )
        return;

    memset( strbuf, 0x20, ws_col - 1 );
    fprintf( stderr, "%s\n", strbuf );

    memcpy( strbuf, " BSSID              STATION "
            "           PWR  Packets  ESSID", 58 );
    fprintf( stderr, "%s\n", strbuf );

    memset( strbuf, 0x20, ws_col - 1 );
    fprintf( stderr, "%s\n", strbuf );

    ap_cur = ap_end;

    while( ap_cur != NULL )
    {
        if( f_cap_in == NULL && ( ap_cur->nb_pkt < 2 ||
              time( NULL ) - ap_cur->tlast > 120 ) )
        {
            ap_cur = ap_cur->prev;
            continue;
        }

        if( ws_row != 0 && nlines > ws_row )
            return;

        st_cur = st_end;

        while( st_cur != NULL )
        {
            if( st_cur->base != ap_cur || ( f_cap_in == NULL &&
                  time( NULL ) - ap_cur->tlast > 120 ) )
            {
                st_cur = st_cur->prev;
                continue;
            }

            if( ws_row != 0 && nlines > ws_row )
                return;

            nlines++;

            fprintf( stderr, " %02X:%02X:%02X:%02X:%02X:%02X",
                    ap_cur->bssid[0], ap_cur->bssid[1],
                    ap_cur->bssid[2], ap_cur->bssid[3],
                    ap_cur->bssid[4], ap_cur->bssid[5] );

            fprintf( stderr, "  %02X:%02X:%02X:%02X:%02X:%02X",
                    st_cur->stmac[0], st_cur->stmac[1],
                    st_cur->stmac[2], st_cur->stmac[3],
                    st_cur->stmac[4], st_cur->stmac[5] );

            if( st_cur->power != -1 )
                fprintf( stderr, "  %3d", st_cur->power );
            else
                fprintf( stderr, "     " );

            fprintf( stderr, " %8ld", st_cur->nb_pkt );

            memset( strbuf, 0, sizeof( strbuf ) );
            snprintf( strbuf,  sizeof( strbuf ) - 1,
                      "%-32s", ap_cur->essid );
            strbuf[ws_col - 54] = '\0';
            fprintf( stderr, "  %s\n", strbuf );

            st_cur = st_cur->prev;
        }

        ap_cur = ap_cur->prev;
    }
}

void dump_write_csv( void )
{
    struct tm *ltime;

    if( f_csv_out == NULL )
        return;

    fseek( f_csv_out, 0, SEEK_SET );

    fprintf( f_csv_out,
        "\r\nBSSID, First time seen, Last time seen, Channel, Speed, "
        "Privacy, Power, # beacons, # data, LAN IP, ESSID\r\n" );

    ap_cur = ap_1st;

    while( ap_cur != NULL )
    {
        if( ap_cur->nb_pkt < 2 )
        {
            ap_cur = ap_cur->next;
            continue;
        }

        fprintf( f_csv_out, "%02X:%02X:%02X:%02X:%02X:%02X, ",
                 ap_cur->bssid[0], ap_cur->bssid[1],
                 ap_cur->bssid[2], ap_cur->bssid[3],
                 ap_cur->bssid[4], ap_cur->bssid[5] );

        ltime = localtime( &ap_cur->tinit );

        fprintf( f_csv_out, "%04d-%02d-%02d %02d:%02d:%02d, ",
                 1900 + ltime->tm_year, 1 + ltime->tm_mon,
                 ltime->tm_mday, ltime->tm_hour,
                 ltime->tm_min,  ltime->tm_sec );

        ltime = localtime( &ap_cur->tlast );

        fprintf( f_csv_out, "%04d-%02d-%02d %02d:%02d:%02d, ",
                 1900 + ltime->tm_year, 1 + ltime->tm_mon,
                 ltime->tm_mday, ltime->tm_hour,
                 ltime->tm_min,  ltime->tm_sec );

        fprintf( f_csv_out, "%2d, %3d, ",
                 ap_cur->chanl,
                 ap_cur->speed );

        switch( ap_cur->crypt )
        {
            case  0: fprintf( f_csv_out, "OPN " ); break;
            case  1: fprintf( f_csv_out, "WEP?" ); break;
            case  2: fprintf( f_csv_out, "WEP " ); break;
            case  3: fprintf( f_csv_out, "WPA " ); break;
            default: fprintf( f_csv_out, "    " ); break;
        }

        fprintf( f_csv_out, ", %3d, %8ld, %8ld, ",
                 ap_cur->power,
                 ap_cur->nb_bcn,
                 ap_cur->nb_data );

        fprintf( f_csv_out, "%3d.%3d.%3d.%3d, ",
                 ap_cur->lanip[0], ap_cur->lanip[1],
                 ap_cur->lanip[2], ap_cur->lanip[2] );

        fprintf( f_csv_out, "%-32s\r\n", ap_cur->essid );

        ap_cur = ap_cur->next;
    }

    fprintf( f_csv_out,
        "\r\nStation MAC, First time seen, Last time seen, "
        "Power, # packets, BSSID, ESSID\r\n" );

    st_cur = st_1st;

    while( st_cur != NULL )
    {
        ap_cur = st_cur->base;

        if( ap_cur->nb_pkt < 2 )
        {
            st_cur = st_cur->next;
            continue;
        }

        fprintf( f_csv_out, "%02X:%02X:%02X:%02X:%02X:%02X, ",
                 st_cur->stmac[0], st_cur->stmac[1],
                 st_cur->stmac[2], st_cur->stmac[3],
                 st_cur->stmac[4], st_cur->stmac[5] );

        ltime = localtime( &st_cur->tinit );

        fprintf( f_csv_out, "%04d-%02d-%02d %02d:%02d:%02d, ",
                 1900 + ltime->tm_year, 1 + ltime->tm_mon,
                 ltime->tm_mday, ltime->tm_hour,
                 ltime->tm_min,  ltime->tm_sec );

        ltime = localtime( &st_cur->tlast );

        fprintf( f_csv_out, "%04d-%02d-%02d %02d:%02d:%02d, ",
                 1900 + ltime->tm_year, 1 + ltime->tm_mon,
                 ltime->tm_mday, ltime->tm_hour,
                 ltime->tm_min,  ltime->tm_sec );

        fprintf( f_csv_out, "%3d, %8ld, ",
                 st_cur->power,
                 st_cur->nb_pkt );

        fprintf( f_csv_out, "%02X:%02X:%02X:%02X:%02X:%02X, ",
                 ap_cur->bssid[0], ap_cur->bssid[1],
                 ap_cur->bssid[2], ap_cur->bssid[3],
                 ap_cur->bssid[4], ap_cur->bssid[5] );

        fprintf( f_csv_out, "%-32s\r\n", ap_cur->essid );

        st_cur = st_cur->next;
    }

    fprintf( f_csv_out, "\r\n" );

    fflush( f_csv_out );
    sync();
}

int channel;
int ch_pipe[2];
int do_exit = 0;
struct winsize ws;

void sighandler( int signum )
{
    signal( signum, sighandler );

    if( signum == SIGUSR1 )
        read( ch_pipe[0], &channel, sizeof( int ) );

    if( signum == SIGINT || signum == SIGTERM )
    {
        do_exit = 1;
        alarm( 1 );
        signal( SIGALRM, sighandler );
        printf( "\n" );
    }

    if( signum == SIGALRM )
    {
        if( f_ivs_out != NULL ) fclose( f_ivs_out );
        if( f_cap_out != NULL ) fclose( f_cap_out );
        if( f_csv_out != NULL ) fclose( f_csv_out );
        exit( 1 );
    }

    if( signum == SIGCHLD )
        wait( NULL );

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

        if( ws.ws_col < 54 )
            ws.ws_col = 54;

        if( ws.ws_col > 132 )
            ws.ws_col = 132;

        fprintf( stderr, "\33[2J" );
        fflush( stdout );
    }
}

void set_monitor( char *interface, int channel )
{
    char s[128];

    if( memcmp( interface, "wlan", 4 ) == 0 )
    {
        /* possibly wlan-ng */

        memset( s, 0, sizeof( s ) );
        snprintf( s,  sizeof( s ) - 1, "channel=%d", channel );

        if( ! fork() )
        {
            close( 0 ); close( 1 ); close( 2 ); chdir( "/" );
            execlp( "wlanctl-ng", "wlanctl-ng", interface,
                    "lnxreq_wlansniff", "enable=true",
                    "prismheader=true", "wlanheader=false",
                    "stripfcs=true", "keepwepflags=true", s, NULL );
            exit( 1 );
        }

        wait( NULL );
    }

    memset( s, 0, sizeof( s ) );
    snprintf( s,  sizeof( s ) - 1, "%d", channel );

#if 0
    /* orinoco monitor mode not enabled as ipw2200 *
     * goes dead when calling iwpriv eth1 monitor  */

    if( memcmp( interface, "eth", 3 ) == 0 )
    {
        if( ! fork() )
        {
            close( 0 ); close( 1 ); close( 2 ); chdir( "/" );
            execlp( "iwpriv", "iwpriv", interface,
                    "monitor", "1", s, 0 );
            exit( 1 );
        }

        wait( NULL );
    }
#endif

    if( memcmp( interface, "prism", 5 ) == 0 )
        interface = "eth1";     /* OpenWRT */

    if( ! fork() )
    {
        /* try the generic way */

        close( 0 ); close( 1 ); close( 2 ); chdir( "/" );
        execlp( "iwconfig", "iwconfig", interface, "mode",
                "Monitor", "channel", s, NULL );
        exit( 1 );
    }

    wait( NULL );
}

void set_channel( char *interface, int channel )
{
    char s[128];

    if( memcmp( interface, "wlan", 4 ) == 0 )
    {
        memset( s, 0, sizeof( s ) );
        snprintf( s,  sizeof( s ) - 1, "channel=%d", channel );

        if( ! fork() )
        {
            close( 0 ); close( 1 ); close( 2 ); chdir( "/" );
            execlp( "wlanctl-ng", "wlanctl-ng", interface,
                    "lnxreq_wlansniff", "enable=true",
                    "prismheader=true", "wlanheader=false",
                    "stripfcs=true", "keepwepflags=true", s, NULL );
            exit( 1 );
        }

        wait( NULL );
    }

    memset( s, 0, sizeof( s ) );
    snprintf( s,  sizeof( s ) - 1, "%d", channel );

    if( memcmp( interface, "prism", 5 ) == 0 )
        interface = "eth1";

    if( ! fork() )
    {
        close( 0 ); close( 1 ); close( 2 ); chdir( "/" );
        execlp( "iwconfig", "iwconfig", interface, "channel", s, NULL );
        exit( 1 );
    }

    wait( NULL );
}

int bg_chans[] = { 7, 1, 5, 10, 13, 2, 6, 11, 12, 3, 8, 4, 9, 0 };

char usage[] =

"\n"
"  airodump %d.%d - (C) 2004,2005 Christophe Devine\n"
"\n"
"  usage: airodump <interface name or pcap filename>\n"
"                  <output prefix> <channel> [IVs flag]\n"
"\n"
"  Specify 0 as the channel number to hop between b/g channels;\n"
"  the channel is ignored if the packet source is a pcap file.\n"
"\n"
"  If the optional IVs flag is set to 1, then only the captured\n"
"  unique WEP IVs are saved, so as to save space -- the default\n"
"  behaviour is to write the whole packets in libpcap format.\n"
"\n"
"  Examples:\n"
"  \n"
"    Capture packets on channel 7: airodump ath0 wlan-dump 7\n"
"    Extract IVs from a pcap file: airodump out.cap small 0 1\n"
"\n";

int main( int argc, char *argv[] )
{
    int n;
    int ivs_only;       /* if set, only save the unique WEP IVs */
    int power;          /* strength of signal if Prism2 header  */
    int fd_raw_in;      /* file descriptor of the raw socket    */
    int caplen;         /* length of captured packet            */
    int arptype;        /* hardware linktype (packet header)    */
    long time_slept;    /* counter used to refresh the screen   */
    long nb_pkt_read;   /* total number of packets read         */

    time_t tt;

    unsigned char *buffer;
    unsigned char *h80211;

    struct pcap_file_header pfh_in;
    struct pcap_pkthdr pkh_in;

    struct ifreq ifr;
    struct packet_mreq mr;
    struct sockaddr_ll sll;
    struct timeval tv;

    fd_set rfds;

    /* initialize a bunch of variables */

    ivs_only    =  0;
    channel     =  0;
    power       = -1;
    fd_raw_in   = -1;
    arptype     =  0;
    time_slept  =  0;
    nb_pkt_read =  0;

    /* check the arguments */

    if( argc < 4 || argc > 5 )
    {
        printf( usage, _VER_MAJOR, _VER_MINOR );
        return( 1 );
    }

    channel  = atoi( argv[3] );

    if( argc == 5 )
        ivs_only = atoi( argv[4] );

    /* create the raw socket and drop privileges */

    fd_raw_in = socket( PF_PACKET, SOCK_RAW, htons( ETH_P_ALL ) );

    setuid( getuid() );

    /* reserve the buffer space */

    if( ( buffer = (unsigned char *) malloc( 65536 ) ) == NULL )
    {
        perror( "malloc failed" );
        return( 1 );
    }

    /* try to open the first argument */

    if( ( f_cap_in = fopen( argv[1], "rb" ) ) != NULL )
    {
        close( fd_raw_in );

        n = sizeof( struct pcap_file_header );

        if( fread( &pfh_in, 1, n, f_cap_in ) != (size_t) n )
        {
            perror( "fread(pcap file header) failed" );
            return( 1 );
        }

        if( pfh_in.magic != TCPDUMP_MAGIC &&
            pfh_in.magic != TCPDUMP_CIGAM )
        {
            fprintf( stderr, "\"%s\" isn't a pcap file (expected "
                             "TCPDUMP_MAGIC).\n", argv[1] );
            return( 1 );
        }

        if( pfh_in.magic == TCPDUMP_CIGAM )
            SWAP32( pfh_in.linktype );

        if( pfh_in.linktype != LINKTYPE_IEEE802_11 )
        {
            fprintf( stderr, "Wrong linktype from pcap file header "
                             "(expected LINKTYPE_IEEE802_11) -\n"
                             "this doesn't look like a regular 802.11 "
                             "capture.\n" );
            return( 1 );
        }
    }
    else
    {
        if( fd_raw_in < 0 )
        {
            perror( "socket(PF_PACKET) failed" );
            fprintf( stderr, "This program requires root privileges.\n" );
            return( 1 );
        }

        /* find the interface index */

        memset( &ifr, 0, sizeof( ifr ) );
        strncpy( ifr.ifr_name, argv[1], sizeof( ifr.ifr_name ) - 1 );

        if( ioctl( fd_raw_in, SIOCGIFINDEX, &ifr ) < 0 )
        {
            fprintf( stderr, "\"%s\" is neither a file nor a network "
                             "interface, exiting.\n", argv[1] );
            return( 1 );
        }

        memset( &sll, 0, sizeof( sll ) );
        sll.sll_family   = AF_PACKET;
        sll.sll_ifindex  = ifr.ifr_ifindex;
        sll.sll_protocol = htons( ETH_P_ALL );

        if( memcmp( argv[1], "wlan", 4 ) == 0 )
        {
            if( ! fork() )      /* wlan-ng brain damage */
            {
                close( 0 ); close( 1 ); close( 2 ); chdir( "/" );
                execlp( "wlanctl-ng", "wlanctl-ng", argv[1],
                        "lnxreq_ifstate", "ifstate=enable", NULL );
                exit( 1 );
            }
            wait( NULL );

            if( ! fork() )      /* hostap card reset */
            {
                close( 0 ); close( 1 ); close( 2 ); chdir( "/" );
                execlp( "iwpriv", "iwpriv", argv[1], "reset", "1", NULL );
                exit( 1 );
            }
            wait( NULL );
        }

        /* try to get in Monitor mode */

        set_monitor( argv[1], 10 );

        /* make sure the interface is up */

        ifr.ifr_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING;        

        if( ioctl( fd_raw_in, SIOCSIFFLAGS, &ifr ) < 0 )
        {
            perror( "ioctl(SIOCSIFFLAGS) failed" );
            return( 1 );
        }

        /* bind the raw socket to the interface */

        if( bind( fd_raw_in, (struct sockaddr *) &sll,
                  sizeof( sll ) ) < 0 )
        {
            perror( "bind(ETH_P_ALL) failed" );
            return( 1 );
        }

        if( memcmp( argv[1], "prism", 5 ) == 0 )
            goto skip_iwpriv;   /* OpenWRT */

        /* couple of iwprivs to enable the prism header */

        if( ! fork() )  /* hostap */
        {
            close( 0 ); close( 1 ); close( 2 ); chdir( "/" );
            execlp( "iwpriv", "iwpriv", argv[1], "monitor_type", "1", NULL );
            exit( 1 );
        }
        wait( NULL );

        if( ! fork() )  /* r8180 */
        {
            close( 0 ); close( 1 ); close( 2 ); chdir( "/" );
            execlp( "iwpriv", "iwpriv", argv[1], "prismhdr", "1", NULL );
            exit( 1 );
        }
        wait( NULL );

        if( ! fork() )  /* prism54 */
        {
            close( 0 ); close( 1 ); close( 2 ); chdir( "/" );
            execlp( "iwpriv", "iwpriv", argv[1], "set_prismhdr", "1", NULL );
            exit( 1 );
        }
        wait( NULL );

        /* make sure the WEP key is off */

        if( ! fork() )
        {
            close( 0 ); close( 1 ); close( 2 ); chdir( "/" );
            execlp( "iwconfig", "iwconfig", argv[1], "key", "off", NULL );
            exit( 1 );
        }
        wait( NULL );

skip_iwpriv:

        /* start a child to hop between channels */

        if( channel == 0 )
        {
            pipe( ch_pipe );

            signal( SIGUSR1,  sighandler );

            if( ! fork() )
            {
                int ch_idx = 0;

                while( getppid() != 1 )
                {
                    channel = bg_chans[ch_idx++];

                    if( bg_chans[ch_idx] == 0 ) 
                        ch_idx = 0;

                    set_channel( argv[1], channel );

                    write( ch_pipe[1], &channel, sizeof( int ) );
                    kill( getppid(), SIGUSR1 );

                    usleep( 250000 );
                }

                exit( 0 );
            }

            usleep( 250000 );
        }
        else
            set_channel( argv[1], channel );

        /* lookup the hardware type */

        if( ioctl( fd_raw_in, SIOCGIFHWADDR, &ifr ) < 0 )
        {
            perror( "ioctl(SIOCGIFHWADDR) failed" );
            return( 1 );
        }

        arptype = ifr.ifr_hwaddr.sa_family;

        if( arptype != ARPHRD_IEEE80211 &&
            arptype != ARPHRD_IEEE80211_PRISM )
        {
            if( arptype == 1 )
                fprintf( stderr, "\nARP linktype is set to 1 (Ethernet) " );
            else
                fprintf( stderr, "\nUnsupported hardware link type %4d ",
                         arptype );

            fprintf( stderr, "- expected ARPHRD_IEEE80211\nor ARPHRD_IEEE8021"
                             "1_PRISM instead.  Make sure RFMON is enabled:\n"
                             "run 'ifconfig %s up; iwconfig %s mode Monitor "
                             "channel <#>'\n\n", argv[1], argv[1] );
            return( 1 );
        }

        /* enable promiscuous mode */

        memset( &mr, 0, sizeof( mr ) );
        mr.mr_ifindex = sll.sll_ifindex;
        mr.mr_type    = PACKET_MR_PROMISC;

        if( setsockopt( fd_raw_in, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
                        &mr, sizeof( mr ) ) < 0 )
        {
            perror( "setsockopt(PACKET_MR_PROMISC) failed" );
            return( 1 );
        }
    }

    /* open or create the output files */

    if( dump_initialize( argv[2], ivs_only ) )
        return( 1 );

    signal( SIGINT,   sighandler );
    signal( SIGTERM,  sighandler );
    signal( SIGCHLD,  sighandler );
    signal( SIGWINCH, sighandler );

    sighandler( SIGWINCH );

    if( f_cap_in == NULL )
        fprintf( stderr, "\33[2J\n" );

    tt = time( NULL );

    while( 1 )
    {
        if( do_exit ) break;

        if( f_cap_in == NULL )
        {
            if( time( NULL ) - tt >= 20 )
            {
                /* update the CSV stats file */

                tt = time( NULL );
                dump_write_csv();
            }

            /* capture one packet */

            FD_ZERO( &rfds );
            FD_SET( fd_raw_in, &rfds );

            tv.tv_sec  = 0;
            tv.tv_usec = REFRESH_TIMEOUT;

            if( select( fd_raw_in + 1, &rfds, NULL, NULL, &tv ) < 0 )
            {
                if( errno == EINTR ) continue;
                perror( "select failed" );
                return( 1 );
            }

            time_slept += REFRESH_TIMEOUT - tv.tv_usec;

            if( time_slept > REFRESH_TIMEOUT )
            {
                time_slept = 0;

                /* display the list of access points we have */

                fprintf( stderr, "\33[1;1H" );
                dump_print( ws.ws_row, ws.ws_col );
                fprintf( stderr, "\33[J" );
                fflush( stdout );
                continue;
            }

            if( ! FD_ISSET( fd_raw_in, &rfds ) )
                continue;

            /* one packet available for reading */

            memset( buffer, 0, 4096 );

            if( ( caplen = read( fd_raw_in, buffer, 65535 ) ) < 0 )
            {
                perror( "read failed" );
                return( 1 );
            }

            /* if device is an atheros, remove the FCS */

            if( ! memcmp( argv[1], "ath", 3 ) )
                caplen -= 4;

            /* skip the prism header if present */

            h80211 = buffer;

            if( arptype == ARPHRD_IEEE80211_PRISM )
            {
                if( buffer[7] == 0x40 )
                {
                    n = 0x40;
                    power = buffer[0x33];
                }
                else
                {
                    n = *(int *)( buffer + 4 );

                    if( *(int *)( buffer + 0x44 ) != 0 )
                        power = *(int *)( buffer + 0x44 );
                    else
                        power = *(int *)( buffer + 0x5C );

                    if( n <= 0 || n > 4096 )
                        continue;
                }

                h80211 += n;
                caplen -= n;
            }

            pkh_in.tv_sec  = 0;
            pkh_in.tv_usec = 0;
        }
        else
        {
            /* read one packet */

            if( time( NULL ) - tt >= 1 )
            {
                tt = time( NULL );
                printf( "\rRead %ld packets...\r", nb_pkt_read );
            }

            n = sizeof( pkh_in );

            if( fread( &pkh_in, 1, n, f_cap_in ) != (size_t) n )
                break;

            if( pfh_in.magic == TCPDUMP_CIGAM )
                SWAP32( pkh_in.caplen );

            n = caplen = pkh_in.caplen;

            if( n <= 0 || n > 65535 )
            {
                printf( "Corrupted file? Invalid packet length %d.\n", n );
                break;
            }

            if( fread( buffer, 1, n, f_cap_in ) != (size_t) n )
                break;

            h80211 = buffer;
        }

        nb_pkt_read++;

        dump_add_packet( h80211, caplen, power, channel,
                         pkh_in.tv_sec, pkh_in.tv_usec );

        if( f_ivs_out != NULL ) fflush( f_ivs_out );
        if( f_cap_out != NULL ) fflush( f_cap_out );
    }

    if( f_cap_in != NULL )
    {
        fprintf( stderr, "\33[1;1H" );
        dump_print( 0, ws.ws_col );
        fprintf( stderr, "\33[J\n" );
    }

    dump_write_csv();

    if( f_ivs_out != NULL ) fclose( f_ivs_out );
    if( f_cap_out != NULL ) fclose( f_cap_out );
    if( f_csv_out != NULL ) fclose( f_csv_out );

    return( 0 );
}

Generated by  Doxygen 1.6.0   Back to index