pcap/monitor-mode w/ radiotap:数据包大小似乎永远小?



出于某种原因,我似乎一直从c/c++的pcap中获得10字节的802.11 MAC头,我不知道为什么。

一些介绍细节:

  • 是,我在监控模式

  • 是的,我使用的是wlan1mon

  • 我检查了pcap_open_live返回非空

  • 我检查了pcap_datalink返回127 (802.11 w/radiotap头)

  • 我真的很难找到一个好的参考802.11 MAC头。以太网报头、IPv4报头等都有真正的很好的参考,这些参考涉及到每个字段的所有必要细节,以及如何知道它是否存在和/或有效……但是没有人说addr4是否被完全省略,如果没有必要,或者只是0填充/未填充。或者报头的安排给出了不同的类型/子类型(一个站点建议,有时,帧只是控件、持续时间和致谢的MAC,但没有我发现的其他站点也这么说)。

下面代码段的快速参考:我做了一个宏Assert(我通常给出符合规范的更长的名称,但现在只是这样),它有一个条件作为第一个参数,如果它失败了,它使用stringstream来构造一个字符串,并抛出runtime_error,如果它是假的。这让我可以在必要时制作非常描述性的错误消息,其中包括局部变量值。

好,这是我现在的位置。请注意,这是我使用pcap编写的第一个程序,我完全是在Raspberry Pi上使用vim通过ssh从Windows上使用git-bash编写的,所以我并不是在格式化的理想环境中。另外,当我试图让愚蠢的东西不是

时,事情会变得很混乱
namespace
{
struct ieee80211_radiotap_header {
u_int8_t        it_version;     /* set to 0 */
u_int8_t        it_pad;
u_int16_t       it_len;         /* entire length */
u_int32_t       it_present;     /* fields present */
} __attribute__((__packed__));
static_assert ( sizeof(ieee80211_radiotap_header)==8 , "Bad packed structure" ) ;
/* Presence bits */
enum {
RADIOTAP_TSFT                           = 0 ,
RADIOTAP_FLAGS                          = 1 ,
RADIOTAP_RATE                           = 2 ,
RADIOTAP_CHANNEL                = 3 ,
RADIOTAP_FHSS                           = 4 ,
RADIOTAP_ANTENNA_SIGNAL         = 5 ,
RADIOTAP_ANTENNA_NOISE          = 6 ,
RADIOTAP_LOCK_QUALITY           = 7 ,
RADIOTAP_TX_ATTENUATION         = 8 ,
RADIOTAP_DB_TX_ATTENUATION  = 9 ,
RADIOTAP_DBM_TX_POWER           = 10 ,
RADIOTAP_ANTENNA                = 11 ,
RADIOTAP_DB_ANTENNA_SIGNAL  = 12 ,
} ;

typedef array<uint8_t,6>        MAC ;
static_assert ( is_pod<MAC>::value , "MAC is not a POD type" ) ;
static_assert ( sizeof(MAC)==6 , "MAC is not 6-Bytes" ) ;
string MAC2String ( MAC const& m ) {
string rval = "__:__:__:__" ;
for ( auto iByte(0) ; iByte<6 ; ++iByte ) {
static char const * const hex = "0123456789abcdef" ;
rval[3*iByte]   =       hex [ ( m[iByte] & 0xF0 ) >> 4 ] ;
rval[3*iByte+1] =       hex [ m[iByte] & 0x0F ] ;
}
return rval ;
}
void handlePacket ( u_char * args , pcap_pkthdr const * header , u_char const * packet ) {
static_assert ( sizeof(u_char)==1 , "Huh?" ) ;
//cout << "Packet; " << header->caplen << " of " << header->len << " captured" << endl ;
size_t  expectedSize    =       sizeof(ieee80211_radiotap_header) ;
Assert ( header->caplen>=expectedSize , "Capture is not big enough; expecting " << expectedSize << " so far, but only have " << header->caplen ) ;
uint8_t const*  radioHeader             =       packet ;
auto    rx              =       reinterpret_cast<ieee80211_radiotap_header const*> ( radioHeader ) ;
expectedSize += rx->it_len - sizeof(ieee80211_radiotap_header) ; // add the radiotap body length
Assert ( header->caplen>=expectedSize , "Capture is not big enough; expecting " << expectedSize << " so far, but only have " << header->caplen ) ;
// Look at the 802.11 Radiotap Header


if ( header->caplen == expectedSize ) {
cout << "Packet contains ONLY " << expectedSize << "-Byte RadioTap header" << endl ;
return ;
}
// From this point forward, all error messages should subtract rx->it_len so that the error reflects the 802.11 frame onward
// and does not include the radiotap header.

// Look at the 802.11 MAC Header
expectedSize += 2+2+2+4 ; // everything but the four addresses
Assert ( header->caplen>=expectedSize , "Frame is not big enough; expecting " << expectedSize-rx->it_len << " so far, but only have " << header->caplen-rx->it_len ) ;
uint8_t const*  frameHeader             =       radioHeader + rx->it_len ;
uint8_t version         =       frameHeader[0] & 3 ;
Assert ( version==0 , "Bad 802.11 MAC version: " << int(version) ) ;
uint8_t frameType       =       ( frameHeader[0] >> 2 ) & 0x03 ;
uint8_t frameSubtype=   ( frameHeader[0] >> 4 ) & 0x0F ;
bool    toDS            =       frameHeader[1] & 0x01 ;
bool    fromDS          =       frameHeader[1] & 0x02 ;
bool    isWEP           =       frameHeader[1] & (1<<6) ;
MAC const*              addr1   =       reinterpret_cast<MAC const*> ( frameHeader + 4 ) ;
MAC const*              addr2   =       reinterpret_cast<MAC const*> ( frameHeader + 10 ) ;
MAC const*              addr3   =       reinterpret_cast<MAC const*> ( frameHeader + 16 ) ;
MAC const*              addr4   =       reinterpret_cast<MAC const*> ( frameHeader + 24 ) ;
MAC const*      bssid (0) ;
MAC const*      da ;
MAC const*      sa ;
MAC const*      ra ;
MAC const*      ta ;
char const*     desc ;
// Table found here: https://www.rfwireless-world.com/Articles/WLAN-MAC-layer-protocol.html
if ( !toDS && !fromDS ) {
desc = "STA->STA" ;
da      =       addr1 ;
sa      =       addr2 ;
bssid=  addr3 ;
// inferred
ta      =       sa ;
ra      =       da ;
expectedSize += 6+6+6 ;
} else if ( !toDS && fromDS ) {
desc = "Base->STA" ;
da      =       addr1 ;
bssid=  addr2 ;
sa      =       addr3 ;
// inferred
ta      =       bssid ;
ra      =       da ;
expectedSize += 6+6+6 ;
} else if ( toDS && !fromDS ) {
desc = "STA->Base" ;
bssid=  addr1 ;
sa      =       addr2 ;
da      =       addr3 ;
// inferred
ta      =       sa ;
ra      =       bssid ;
expectedSize += 6+6+6 ;
} else if ( toDS && fromDS ) {
desc = "Base->Base" ;
ra      =       addr1 ;
ta      =       addr2 ;
da      =       addr3 ;
sa      =       addr4 ;
expectedSize += 6+6+6+6 ;
}
Assert ( header->caplen>=expectedSize , "Frame is not big enough; expecting " << expectedSize-rx->it_len << " so far, but only have " << header->caplen-rx->it_len << " for a " << desc << " frame of type " << int(frameType) << '/' << int(frameSubtype) ) ;

cout << desc << "t" << MAC2String(*ta) << '/' << MAC2String(*sa) << "  -->  " << MAC2String(*ra) << '/' << MAC2String(*da) << endl ;
//cout << MAC2String(addr1) << " / " << MAC2String(addr2) << "  -->  " << MAC2String(addr3) << " / " << MAC2String(addr4) << endl ;
//cout << "   " << int(frameType) << " / " << int(frameSubtype) << endl ;
}
}


int main ( int , char const* * )
{
cout << "Hello, world" << endl ;
auto    devName                 =       "wlan1mon" ;
char    errBuf[PCAP_ERRBUF_SIZE] ;
auto    maxTime                 =       0 ; // ms
auto    maxPacketCount  =       0 ;
auto    dev                     =       pcap_open_live ( devName , BUFSIZ , maxPacketCount , maxTime , errBuf ) ;
Assert ( dev!=0 , "Failed to open pcap: " << errBuf ) ;
auto    linkType                =       pcap_datalink ( dev ) ;
// IEEE 802.11 link type is 105, from tcpdump.org/linktypes.html
// 127 is the 802.11 radiotap which is even better
Assert ( linkType==127 , "Link type was " << linkType << ", but expected " << 127 ) ;
pcap_loop ( dev , maxPacketCount , handlePacket , /*user*/0 ) ;
cout << "Exiting" << endl ;
return 0 ;
}

但是我很快得到的是一个错误,即802.11帧(在radiotap之后)是10字节长(这是来自代码中的最后一个Assert,在to/from DS之后)。

我尝试了一些读取帧控制的组合(整个小端uint16_t一次,或字节逐字节,b0-first或b0-last等),因为似乎没有很好的规范它是如何安排的。我确实经常遇到STA->STA帧(由这段代码检测/报告),这在我的环境中似乎不太可能。

我错过了什么?很明显我错过了什么。

作为参考,该代码报告的radiotapit_len总是18字节或21字节,这看起来也很奇怪。

我真的很难找到一个好的参考802.11 MAC头。

如果by "good"你的意思是"简单",不幸的是这是不可能的,因为报头不像802.3以太网报头那样简单。: -)

总是有IEEE标准802.11-2016;参见9.2节"MAC帧格式"。

(一个网站建议,有时,帧只是控件、持续时间和MAC的确认,但我发现没有其他网站说同样的)。

帧控制、持续时间、接收地址和CRC。就是这样——这是14个字节,CRC是最后4个字节,所以如果CRC不在数据包中,那将是10个字节。

最新更新