【问题标题】:Processing incorrect mac addresses from 802.11 frames with pcap使用 pcap 处理来自 802.11 帧的错误 MAC 地址
【发布时间】:2012-01-02 10:57:25
【问题描述】:

我正在处理一个使用 pcap 和无线的项目。在响应我之前的问题的 oe 中发布的示例之后,我试图从无线帧中提取 MAC 地址。我已经为 radiotap 标头和基本管理框架创建了结构。出于某种原因,在尝试输出 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;
}

【问题讨论】:

  • 我不会为 Mac 编写代码,通常很难找到相关行。但是我最近在这里发布了一个关于 pcap 的问题,得到了一个回复,在 2. 以下,可能有一些适用于你的东西。也许看看。
  • 在打印 fr-&gt;wi_add2fr-&gt;wi_add3 之前将 k 重置为 6 而不是 0 可能会有所帮助,但我不知道这是否是唯一的问题,因为“打印出错误数据”不是很具体。一个示例数据包十六进制转储和相应的“错误”输出将很有用。
  • 你的代码工作了吗?我正在尝试在 libpcap 中以监控模式获取数据包,但似乎无法正确读取标头,因此我可以获取 mac 地址...
  • 嗨,是的,我使用了 Guy 下面包含的 cmets,一旦我考虑了 radiotap 标头长度并删除了 set_snaplen 调用,我就能够修复它,我能够让我的输出与 wireshark 对齐

标签: c macos wireless pcap libpcap


【解决方案1】:

你做错了几件事。

您做错的第一件事是将radiotap 标头声明为具有比it_versionit_padit_lenit_present 更多字段的结构。 绝对不能保证在任意 radiotap 标头中,例如,在 it_present 字段之后会有一个 64 位 MAC_timestamp 字段。您必须查看it_present 字段以查看标题中的哪些字段实际存在。有关如何处理 radiotap 标头的详细信息,请参阅the radiotap Web site

将字段的值与 0(或NULL)进行比较不起作用 - 如果字段不存在,它只是不存在

您的代码可能碰巧与特定操作系统上特定网络适配器的特定驱动程序版本一起工作,但如果驱动程序被更改或如果您在具有不同类型适配器的机器上运行(例如,Atheros vs .Mac 上的 Broadcom 适配器)或者如果您尝试在不同的操作系统(例如 Linux)上运行它。

如果您希望此代码在大端机器上运行,您还需要更仔细地从 radiotap 标头中获取字段,因为它们都是小端。 (您的代码中的#define 对此不够。)

除了字节顺序问题(仅当您在 PowerPC Mac 上运行时才会在 Mac 上显示),您 正确跳过了 radiotap 标头,所以这不是问题.

另外,MAC 时间戳是一个 64 位整数,在 32 位机器上打印时必须使用 %llu 而不是 %u

您还应该检查错误。如果您看到数据包,pcap_create()pcap_activate() 可能不会失败,所以这可能不是直接的问题,但无论如何您都应该检查失败。 pcap_set_ 例程也可能不会失败,至少在 Wi-Fi 设备上不会失败,但无论如何你都应该检查一下。

如果您要假设数据包是 802.11+radiotap 数据包,您可能至少应该检查以确保 pcap_datalink() 的返回值是 DLT_IEEE802_11_RADIO,如果不是则失败。当您使用它时,在为链接层类型打印的消息的末尾添加一个换行符。

但是 main 认为你做错了是捕获不超过 30 个字节的每个数据包!当您执行pcap_set_snaplen(descr,30); 时,您是在说“不要捕获超过 30 个字节”; radiotap 标头可能比这更长,因此您甚至不会获得所有的 radiotap 标头,更不用说获得任何 802.11 标头了。

如果您想捕获整个数据包,只需留下pcap_set_snaplen() 呼叫即可。

哦,如果您想真的小心,请确保在查看 radiotap 和 802.11 标头时,您没有超过 pkthdr-&gt;caplen

这也意味着检查pkthdr-&gt;len 的循环应该检查pkthdr-&gt;caplen AND 应该以packet[0] 开头,或者应该从pkthdr-&gt;caplen 中减去rh-&gt;it_len(因为你应该检查确保rh-&gt;it_len 大于或等于pkthdr-&gt;caplen 在您解析radiotap 标头时或之前,该减法的结果将是正数)。快照长度包括 all 个伪标头,例如 radiotap 标头。

【讨论】:

  • 谢谢。大多数代码真的很糟糕,我应该在发布之前清理它,但感谢所有关于这两个问题的建议。你为我回答了我会清理事情并接受你给出的提示并尝试让事情正常进行。再次感谢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-05-27
  • 2018-04-04
  • 1970-01-01
  • 1970-01-01
  • 2010-09-08
  • 1970-01-01
  • 2021-01-20
相关资源
最近更新 更多