pcap/monitor-mode w/ radiotap:数据包大小似乎永远很小?
pcap/monitor-mode w/ radiotap: packet size seems perpetually small?
出于某种原因,我似乎一直从 c/c++ 中的 pcap 获取 10 字节 802.11 MAC headers 而我没有知道为什么了。
一些介绍细节:
是的,我处于监控模式
是的,我正在使用 wlan1mon
我检查过 pcap_open_live
返回 non-null
我检查过 pcap_datalink
返回了 127(802.11 w/ radiotap header)
我很难找到 802.11 MAC header 的好参考。以太网 header、IPv4 header 等都有 真正 很好的参考资料,其中涉及每个领域的所有必要细节以及您如何知道它是否 is/isn不存在 and/or 有效...但甚至没有人说 addr4 是否在不必要时被完全省略,或者它是否只是 0-filled/unfilled。或者什么安排的header被赋予了不同的types/subtypes(one site暗示,有时候,frame只是control, duration,和MAC for acknowledgements,但是没有 我发现的其他网站也是如此。
下面代码段的快速参考:我制作了一个宏 Assert
(我通常给出符合规范的更长名称,但现在只是这样),它有一个条件作为第一个参数并且,如果失败,它会使用 stringstream
构造一个字符串,如果为假则抛出 runtime_error
。这让我可以制作非常具有描述性的错误消息,必要时包括局部变量值。
好的,这是我现在所在的位置。请注意,这是我使用 pcap 的第一个程序,我完全在 vim 中的 Raspberry Pi 上通过 ssh 从 git-bash 从 Windows 编写它,所以我不完全是在格式化的理想情况下。当我试图让愚蠢的事情不发生时,事情也会变得一团糟
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).
我尝试了几种读取帧控制的组合(一次整个 little-endian uint16_t,或 byte-by-byte、b0-first 或 b0-last 等)因为似乎没有关于如何安排的好规范。我最常将 运行 放入 STA->STA
帧(根据此代码 detected/reported),考虑到我的环境,这似乎不太可能。
我错过了什么?显然我错过了一些东西。
作为参考,此代码报告的 radiotap it_len
总是 18 字节或 21 字节,这看起来也很奇怪。
I have had a really hard time finding a good reference for the 802.11 MAC header.
如果您所说的“好”是指“简单”,不幸的是这是不可能的,因为 header 不像 802.3 以太网那样 header 是。 :-)
总有IEEE Std 802.11-2016;请参阅第 9.2 节“MAC 帧格式”。
(one site suggested that, sometimes, the frame is just the control, duration, and MAC for acknowledgements, but no other site I've found says the same).
帧控制、持续时间、接收器地址和 CRC。就是这样 - 那是 14 个八位字节,CRC 是最后 4 个八位字节,所以如果 CRC 不是 出现在数据包中,那将是 10 个八位字节。
出于某种原因,我似乎一直从 c/c++ 中的 pcap 获取 10 字节 802.11 MAC headers 而我没有知道为什么了。
一些介绍细节:
是的,我处于监控模式
是的,我正在使用
wlan1mon
我检查过
pcap_open_live
返回 non-null我检查过
pcap_datalink
返回了 127(802.11 w/ radiotap header)我很难找到 802.11 MAC header 的好参考。以太网 header、IPv4 header 等都有 真正 很好的参考资料,其中涉及每个领域的所有必要细节以及您如何知道它是否 is/isn不存在 and/or 有效...但甚至没有人说 addr4 是否在不必要时被完全省略,或者它是否只是 0-filled/unfilled。或者什么安排的header被赋予了不同的types/subtypes(one site暗示,有时候,frame只是control, duration,和MAC for acknowledgements,但是没有 我发现的其他网站也是如此。
下面代码段的快速参考:我制作了一个宏 Assert
(我通常给出符合规范的更长名称,但现在只是这样),它有一个条件作为第一个参数并且,如果失败,它会使用 stringstream
构造一个字符串,如果为假则抛出 runtime_error
。这让我可以制作非常具有描述性的错误消息,必要时包括局部变量值。
好的,这是我现在所在的位置。请注意,这是我使用 pcap 的第一个程序,我完全在 vim 中的 Raspberry Pi 上通过 ssh 从 git-bash 从 Windows 编写它,所以我不完全是在格式化的理想情况下。当我试图让愚蠢的事情不发生时,事情也会变得一团糟
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).
我尝试了几种读取帧控制的组合(一次整个 little-endian uint16_t,或 byte-by-byte、b0-first 或 b0-last 等)因为似乎没有关于如何安排的好规范。我最常将 运行 放入 STA->STA
帧(根据此代码 detected/reported),考虑到我的环境,这似乎不太可能。
我错过了什么?显然我错过了一些东西。
作为参考,此代码报告的 radiotap it_len
总是 18 字节或 21 字节,这看起来也很奇怪。
I have had a really hard time finding a good reference for the 802.11 MAC header.
如果您所说的“好”是指“简单”,不幸的是这是不可能的,因为 header 不像 802.3 以太网那样 header 是。 :-)
总有IEEE Std 802.11-2016;请参阅第 9.2 节“MAC 帧格式”。
(one site suggested that, sometimes, the frame is just the control, duration, and MAC for acknowledgements, but no other site I've found says the same).
帧控制、持续时间、接收器地址和 CRC。就是这样 - 那是 14 个八位字节,CRC 是最后 4 个八位字节,所以如果 CRC 不是 出现在数据包中,那将是 10 个八位字节。