使用pcap从802.11帧处理不正确的mac地址

我正在通过pcap和无线工作。 根据我之前的问题回复发布的示例,我试图从无线帧中提取mac地址。 我已经为radiotap头和基本管理框架创建了结构。 出于某种原因,当涉及到尝试输出mac地址时,我打印出错误的数据。 当我与wireshark比较时,我不明白为什么无线电分接数据正确打印出来但mac地址却没有。 当我查看数据包并比较我捕获的数据包时,我看不到wireshark显示的hex转储中的任何额外填充。 我有点熟悉c而不是专家所以也许我没有正确使用指针和结构有人可以帮助告诉我我做错了什么?

谢谢,昆汀

// main.c // MacSniffer // #include  #include  #include  #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 frameBody[j]!= NULL) { printf("%x",fr->frameBody[j]); } } */ for (i = 0;ilen;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; } 

你做错了几件事。

你做错的第一件事是将radiotap标头声明为一个结构,其中包含的字段多于it_versionit_padit_lenit_present绝对不能保证在任意的radiotap头中,例如,在MAC_timestamp字段之后将是64位it_present字段。 您必须查看it_present字段以查看标头中的哪些字段实际存在。 有关如何处理radiotap接头的详细信息,请访问radiotap网站 。

将字段的值与0(或NULL )进行比较不起作用 – 如果字段不存在,则根本不存在

您的代码可能适用于特定操作系统上特定网络适配器的特定驱动程序版本,但如果更改驱动程序或在具有不同类型适配器的计算机上运行,​​则可能会失败(例如,Atheros与Broadcom适配器)在Macs上)或者如果你尝试在不同的操作系统(例如Linux)上运行它。

如果你希望这个代码在big-endian机器上运行,你还需要更仔细地从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 ,如果不是则失败。 在您使用它时,在为链接层类型打印的消息末尾添加换行符。

主要认为你做错了就是捕获每个数据包不超过30个字节! 当你做pcap_set_snaplen(descr,30); ,你说“不要捕获超过30个字节”; radiotap头可能比那个更长,所以你甚至不会得到所有的radiotap头,更不用说获得任何802.11头了。

如果要捕获整个数据包,只需将pcap_set_snaplen()调用保留。

哦,如果你想要非常小心,请确保,当你看到radiotap和802.11标题时,你还没有超过pkthdr->caplen

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