Обработка некорректных mac-адресов из фреймов 802.11 с помощью pcap - PullRequest
2 голосов
/ 20 ноября 2011

Я работаю через проект с pcap и беспроводной связью.Следуя примеру, опубликованному в ответ на мои предыдущие вопросы, я пытаюсь извлечь mac-адреса из беспроводных фреймов.Я создал структуры для заголовка радиоленты и базового фрейма управления.По какой-то причине, когда речь заходит о попытке вывести MAC-адреса, я печатаю неверные данные.Когда я сравниваю их с wireshark, я не понимаю, почему данные радиосигнала распечатываются правильно, а mac-адреса - нет.Я не вижу никаких дополнительных отступов в шестнадцатеричном дампе, который отображается в Wireshark, когда я смотрю на пакеты и сравниваю захваченные пакеты.Я немного знаком с c, но не эксперт, поэтому, может быть, я не правильно использую указатели и структуры, может кто-нибудь помочь показать мне, что я делаю неправильно?

Спасибо, Квентин

//  main.c
//  MacSniffer
//


#include <pcap.h>
#include <string.h>
#include <stdlib.h>

#define MAXBYTES2CAPTURE 65535

#ifdef WORDS_BIGENDIAN
typedef struct frame_control
{
    unsigned int subtype:4; /*frame subtype field*/
    unsigned int protoVer:2; /*frame type field*/
    unsigned int version:2; /*protocol version*/

    unsigned int order:1;  
    unsigned int protected:1;
    unsigned int moreDate:1;
    unsigned int power_management:1;

    unsigned int retry:1; 
    unsigned int moreFrag:1;
    unsigned int fromDS:1;
    unsigned int toDS:1;
}frame_control;

struct ieee80211_radiotap_header{
    u_int8_t it_version;
    u_int8_t it_pad;
    u_int16_t it_len;
    u_int32_t it_present;
    u_int64_t MAC_timestamp;
    u_int8_t flags;
    u_int8_t dataRate;
    u_int16_t channelfrequency;
    u_int16_t channFreq_pad;
    u_int16_t channelType;
    u_int16_t channType_pad;
    u_int8_t ssiSignal;
    u_int8_t ssiNoise;
    u_int8_t antenna;
};

#else
typedef struct frame_control
{
    unsigned int protoVer:2; /* protocol version*/
    unsigned int type:2; /*frame type field (Management,Control,Data)*/
    unsigned int subtype:4; /* frame subtype*/

    unsigned int toDS:1; /* frame coming from Distribution system */
    unsigned int fromDS:1; /*frame coming from Distribution system */
    unsigned int moreFrag:1; /* More fragments?*/
    unsigned int retry:1; /*was this frame retransmitted*/

    unsigned int powMgt:1; /*Power Management*/
    unsigned int moreDate:1; /*More Date*/
    unsigned int protectedData:1; /*Protected Data*/
    unsigned int order:1; /*Order*/
}frame_control;

struct ieee80211_radiotap_header{
    u_int8_t it_version;
    u_int8_t it_pad;
    u_int16_t it_len;
    u_int32_t it_present;
    u_int64_t MAC_timestamp;
    u_int8_t flags;
    u_int8_t dataRate;
    u_int16_t channelfrequency;
    u_int16_t channelType;
    int ssiSignal:8;
    int ssiNoise:8;
};
#endif
struct wi_frame {
    u_int16_t fc;
    u_int16_t wi_duration;
    u_int8_t wi_add1[6];
    u_int8_t wi_add2[6];
    u_int8_t wi_add3[6];
    u_int16_t wi_sequenceControl;
    // u_int8_t wi_add4[6];
    //unsigned int qosControl:2;
    //unsigned int frameBody[23124];
};

void processPacket(u_char *arg, const struct pcap_pkthdr* pkthdr, const u_char* packet)
{
    int i= 0, *counter = (int *) arg;
    struct ieee80211_radiotap_header *rh =(struct ieee80211_radiotap_header *)packet;
    struct wi_frame *fr= (struct wi_frame *)(packet + rh->it_len);
    u_char *ptr;
    //printf("Frame Type: %d",fr->wi_fC->type);
    printf("Packet count: %d\n", ++(*counter));
    printf("Received Packet Size: %d\n", pkthdr->len);
    if(rh->it_version != NULL)
    {
      printf("Radiotap Version: %d\n",rh->it_version);
    }
    if(rh->it_pad!=NULL)
    {
      printf("Radiotap Pad: %d\n",rh->it_pad);
    }
    if(rh->it_len != NULL)
    {
        printf("Radiotap Length: %d\n",rh->it_len);
    }
    if(rh->it_present != NULL)
    {
        printf("Radiotap Present: %c\n",rh->it_present);
    }
    if(rh->MAC_timestamp != NULL)
    {
        printf("Radiotap Timestamp: %u\n",rh->MAC_timestamp);
    }

    if(rh->dataRate != NULL)
    {
        printf("Radiotap Data Rate: %u\n",rh->dataRate);
    }
    if(rh->channelfrequency != NULL)
    {
        printf("Radiotap Channel Freq: %u\n",rh->channelfrequency);
    }
    if(rh->channelType != NULL)
    {
    printf("Radiotap Channel Type: %06x\n",rh->channelType);
    }
    if(rh->ssiSignal != NULL)
    {
        printf("Radiotap SSI signal: %d\n",rh->ssiSignal);
    } 
    if(rh->ssiNoise != NULL)
    {
        printf("Radiotap SSI Noise: %d\n",rh->ssiNoise);
    } 

ptr = fr->wi_add1;
int k= 6;
printf("Destination Address:");
do{
    printf("%s%X",(k==6)?" ":":",*ptr++);
}
while(--k>0);
printf("\n");

ptr = fr->wi_add2;
k=0;
printf("Source Address:");
do{
    printf("%s%X",(k==6)?" ":":",*ptr++);
}while(--k>0);
printf("\n");

ptr = fr->wi_add3;
k=0;
do{
    printf("%s%X",(k==6)?" ":":",*ptr++);
}
while(--k>0);
printf("\n");
/* for(int j = 0; j < 23124;j++)
 {
 if(fr->frameBody[j]!= NULL)
 {
 printf("%x",fr->frameBody[j]);
 }
 }
 */
for (i = 0;i<pkthdr->len;i++)
{

    if(isprint(packet[i +rh->it_len]))
    {
        printf("%c",packet[i + rh->it_len]);    
    }

    else{printf(".");}



    //print newline after each section of the packet
    if((i%16 ==0 && i!=0) ||(i==pkthdr->len-1))
    {
        printf("\n");
    }

}
return;
}
int main(int argc, char** argv)
{

int count = 0;
pcap_t* descr = NULL;
char errbuf[PCAP_ERRBUF_SIZE], *device = NULL;
struct bpf_program fp;
char filter[]="wlan broadcast";
const u_char* packet;
memset(errbuf,0,PCAP_ERRBUF_SIZE);
device = argv[1];

if(device == NULL)
{
    fprintf(stdout,"Supply a device name ");
}

descr = pcap_create(device,errbuf);
pcap_set_rfmon(descr,1);
pcap_set_promisc(descr,1);
pcap_set_snaplen(descr,30);
pcap_set_timeout(descr,10000);

pcap_activate(descr);
int dl =pcap_datalink(descr);
printf("The Data Link type is %s",pcap_datalink_val_to_name(dl));
//pcap_dispatch(descr,MAXBYTES2CAPTURE,1,512,errbuf);
//Open device in promiscuous mode
//descr = pcap_open_live(device,MAXBYTES2CAPTURE,1,512,errbuf);

/* if(pcap_compile(descr,&fp,filter,0,PCAP_NETMASK_UNKNOWN)==-1)
 {
 fprintf(stderr,"Error compiling filter\n");
 exit(1);
 }

 if(pcap_setfilter(descr,&fp)==-1)
 {
 fprintf(stderr,"Error setting filter\n");
 exit(1);
 }
 */
pcap_loop(descr,0, processPacket, (u_char *) &count);

return 0;
}

1 Ответ

8 голосов
/ 21 ноября 2011

Вы делаете несколько вещей неправильно.

первая вещь, которую вы делаете неправильно, объявляет заголовок радиоленты как структуру с большим количеством полей, чем it_version, it_pad, it_len и it_present. абсолютно не гарантирует , что в произвольном заголовке радиоленты будет, например, 64-битное поле MAC_timestamp, следующее за полем it_present. Вы должны посмотреть на поле it_present, чтобы увидеть, какие из полей в заголовке действительно присутствуют. См. веб-сайт радиоленты для получения подробной информации о том, как обрабатывать заголовок радиоленты.

Сравнение значений полей с 0 (или NULL) работает не работает - если поле отсутствует, оно просто не существует .

Ваш код может работать с определенными версиями драйверов для определенных сетевых адаптеров в определенных ОС, но он может не работать, если драйвер был изменен или вы работаете на машине с адаптером другого типа (например, Atheros vs Адаптеры Broadcom на компьютерах Mac) или если вы попытаетесь запустить его в другой операционной системе (например, в Linux).

Если вы ожидаете, что этот код будет выполняться на машине с прямым порядком байтов, вам также нужно будет более осторожно извлекать поля из заголовка радиоленты, поскольку они все с прямым порядком байтов. (#define в вашем коде не достаточно для этого.)

За исключением проблемы порядка байтов, которая будет отображаться на Mac, только если вы работаете на PowerPC Mac, вы правильно пропускают мимо заголовка радиоленты, так что это не проблема.

Кроме того, временная метка MAC-адреса представляет собой 64-разрядное целое число, и на 32-разрядном компьютере она должна быть напечатана с %llu вместо %u.

Вы также должны проверять наличие ошибок. pcap_create() и pcap_activate(), по-видимому, не дают сбоя, если вы видите пакеты, так что это, вероятно, не является непосредственной проблемой, но вам все равно следует проверять наличие ошибок. Процедуры pcap_set_ также, вероятно, не выходят из строя, по крайней мере, не на устройствах Wi-Fi, но вы должны проверить в любом случае.

Если вы предполагаете, что пакеты являются пакетами радиолента 802.11 +, вам, вероятно, следует хотя бы проверить, чтобы возвращаемое значение pcap_datalink() было DLT_IEEE802_11_RADIO, и потерпеть неудачу, если это не так. Пока вы это делаете, добавьте новую строку в конец сообщения, напечатанного для типа канального слоя.

Но main считает, что вы делаете неправильно, захватывает не более 30 байтов каждого пакета! Когда вы делаете pcap_set_snaplen(descr,30);, вы говорите «не захватывайте больше 30 байтов»; заголовок радиоленты, вероятно, длиннее этого, так что вы даже не получите весь заголовок радиоленты, а тем более заголовок 802.11.

Если вы хотите захватить весь пакет , просто оставьте вызов pcap_set_snaplen().

О, и если вы хотите быть действительно осторожным, убедитесь, что, глядя на радиоленту и заголовок 802.11, вы не прошли pkthdr->caplen.

Это также означает, что ваш цикл, который проверяет pkthdr->len, должен проверять pkthdr->caplen И должен либо начинаться с пакета [0], либо вычитать rh->it_len из pkthdr->caplen (как вы должны были проверить убедитесь, что rh->it_len больше или равно pkthdr->caplen во время или до того, как вы проанализировали заголовок радиоленты, результат этого вычитания будет положительным). Длина снимка включает все псевдоголовки, такие как заголовок радиоленты.

...