mirror of
https://github.com/mfontanini/libtins
synced 2026-01-22 18:25:57 +01:00
Fixed invalid parsing of RadioTap ext flag field.
This commit is contained in:
@@ -355,71 +355,74 @@ namespace Tins {
|
||||
*/
|
||||
PDUType pdu_type() const { return PDU::RADIOTAP; }
|
||||
private:
|
||||
TINS_BEGIN_PACK
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
struct flags_type {
|
||||
uint32_t tsft:1,
|
||||
flags:1,
|
||||
rate:1,
|
||||
channel:1,
|
||||
fhss:1,
|
||||
dbm_signal:1,
|
||||
dbm_noise:1,
|
||||
lock_quality:1,
|
||||
tx_attenuation:1,
|
||||
db_tx_attenuation:1,
|
||||
dbm_tx_attenuation:1,
|
||||
antenna:1,
|
||||
db_signal:1,
|
||||
db_noise:1,
|
||||
rx_flags:1,
|
||||
reserved1:3,
|
||||
channel_plus:1,
|
||||
reserved2:12,
|
||||
ext:1;
|
||||
} TINS_END_PACK;
|
||||
#else
|
||||
struct flags_type {
|
||||
uint32_t lock_quality:1,
|
||||
dbm_noise:1,
|
||||
dbm_signal:1,
|
||||
fhss:1,
|
||||
channel:1,
|
||||
rate:1,
|
||||
flags:1,
|
||||
tsft:1,
|
||||
reserved3:1,
|
||||
rx_flags:1,
|
||||
db_tx_attenuation:1,
|
||||
dbm_tx_attenuation:1,
|
||||
antenna:1,
|
||||
db_signal:1,
|
||||
db_noise:1,
|
||||
tx_attenuation:1,
|
||||
reserved2:5,
|
||||
channel_plus:1,
|
||||
reserved1:2,
|
||||
reserved4:7,
|
||||
ext:1;
|
||||
} TINS_END_PACK;
|
||||
#endif
|
||||
|
||||
TINS_BEGIN_PACK
|
||||
struct radiotap_hdr {
|
||||
#if TINS_IS_LITTLE_ENDIAN
|
||||
uint8_t it_version;
|
||||
uint8_t it_pad;
|
||||
uint16_t it_len;
|
||||
union {
|
||||
struct {
|
||||
uint32_t tsft:1,
|
||||
flags:1,
|
||||
rate:1,
|
||||
channel:1,
|
||||
fhss:1,
|
||||
dbm_signal:1,
|
||||
dbm_noise:1,
|
||||
lock_quality:1,
|
||||
tx_attenuation:1,
|
||||
db_tx_attenuation:1,
|
||||
dbm_tx_attenuation:1,
|
||||
antenna:1,
|
||||
db_signal:1,
|
||||
db_noise:1,
|
||||
rx_flags:1,
|
||||
reserved1:3,
|
||||
channel_plus:1,
|
||||
reserved2:12,
|
||||
ext:1;
|
||||
} flags;
|
||||
uint32_t flags_32;
|
||||
};
|
||||
#else
|
||||
uint8_t it_pad;
|
||||
uint8_t it_version;
|
||||
uint8_t it_version;
|
||||
#endif // TINS_IS_LITTLE_ENDIAN
|
||||
uint16_t it_len;
|
||||
union {
|
||||
struct {
|
||||
uint32_t lock_quality:1,
|
||||
dbm_noise:1,
|
||||
dbm_signal:1,
|
||||
fhss:1,
|
||||
channel:1,
|
||||
rate:1,
|
||||
flags:1,
|
||||
tsft:1,
|
||||
reserved3:1,
|
||||
rx_flags:1,
|
||||
db_tx_attenuation:1,
|
||||
dbm_tx_attenuation:1,
|
||||
antenna:1,
|
||||
db_signal:1,
|
||||
db_noise:1,
|
||||
tx_attenuation:1,
|
||||
reserved2:5,
|
||||
channel_plus:1,
|
||||
reserved1:2,
|
||||
reserved4:7,
|
||||
ext:1;
|
||||
} flags;
|
||||
flags_type flags;
|
||||
uint32_t flags_32;
|
||||
};
|
||||
#endif
|
||||
} TINS_END_PACK;
|
||||
|
||||
void init();
|
||||
void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent);
|
||||
uint32_t find_extra_flag_fields_size(const uint8_t* buffer, uint32_t total_sz);
|
||||
|
||||
|
||||
radiotap_hdr _radio;
|
||||
|
||||
128
src/radiotap.cpp
128
src/radiotap.cpp
@@ -77,63 +77,81 @@ RadioTap::RadioTap(const uint8_t *buffer, uint32_t total_sz)
|
||||
std::memcpy(&_radio, buffer, sizeof(_radio));
|
||||
uint32_t radiotap_hdr_size = length();
|
||||
check_size(total_sz, radiotap_hdr_size);
|
||||
// We start on the first flags field, skipping version, pad and length.
|
||||
const flags_type* current_flags = (const flags_type*)(buffer + sizeof(uint32_t));
|
||||
const uint32_t extra_flags_size = find_extra_flag_fields_size(
|
||||
buffer + sizeof(uint32_t), total_sz);
|
||||
// Find and skip the extra flag fields.
|
||||
buffer += extra_flags_size;
|
||||
radiotap_hdr_size -= extra_flags_size;
|
||||
// Also skip the header
|
||||
buffer += sizeof(_radio);
|
||||
radiotap_hdr_size -= sizeof(_radio);
|
||||
|
||||
if(_radio.flags.tsft)
|
||||
read_field(buffer, radiotap_hdr_size, _tsft);
|
||||
while(true) {
|
||||
_radio.flags_32 |= *(const uint32_t*)current_flags;
|
||||
if(current_flags->tsft)
|
||||
read_field(buffer, radiotap_hdr_size, _tsft);
|
||||
|
||||
if(current_flags->flags)
|
||||
read_field(buffer, radiotap_hdr_size, _flags);
|
||||
|
||||
if(current_flags->rate)
|
||||
read_field(buffer, radiotap_hdr_size, _rate);
|
||||
|
||||
if(_radio.flags.flags)
|
||||
read_field(buffer, radiotap_hdr_size, _flags);
|
||||
|
||||
if(_radio.flags.rate)
|
||||
read_field(buffer, radiotap_hdr_size, _rate);
|
||||
|
||||
if(_radio.flags.channel) {
|
||||
if(((buffer - buffer_start) & 1) == 1) {
|
||||
buffer++;
|
||||
radiotap_hdr_size--;
|
||||
if(current_flags->channel) {
|
||||
if(((buffer - buffer_start) & 1) == 1) {
|
||||
buffer++;
|
||||
radiotap_hdr_size--;
|
||||
}
|
||||
read_field(buffer, radiotap_hdr_size, _channel_freq);
|
||||
read_field(buffer, radiotap_hdr_size, _channel_type);
|
||||
}
|
||||
read_field(buffer, radiotap_hdr_size, _channel_freq);
|
||||
read_field(buffer, radiotap_hdr_size, _channel_type);
|
||||
}
|
||||
|
||||
if(_radio.flags.dbm_signal)
|
||||
read_field(buffer, radiotap_hdr_size, _dbm_signal);
|
||||
|
||||
if(_radio.flags.dbm_noise)
|
||||
read_field(buffer, radiotap_hdr_size, _dbm_noise);
|
||||
|
||||
if(_radio.flags.lock_quality)
|
||||
read_field(buffer, radiotap_hdr_size, _signal_quality);
|
||||
|
||||
if(current_flags->dbm_signal)
|
||||
read_field(buffer, radiotap_hdr_size, _dbm_signal);
|
||||
|
||||
if(current_flags->dbm_noise)
|
||||
read_field(buffer, radiotap_hdr_size, _dbm_noise);
|
||||
|
||||
if(current_flags->lock_quality)
|
||||
read_field(buffer, radiotap_hdr_size, _signal_quality);
|
||||
|
||||
if(_radio.flags.antenna)
|
||||
read_field(buffer, radiotap_hdr_size, _antenna);
|
||||
|
||||
if(_radio.flags.db_signal)
|
||||
read_field(buffer, radiotap_hdr_size, _db_signal);
|
||||
if(current_flags->antenna)
|
||||
read_field(buffer, radiotap_hdr_size, _antenna);
|
||||
|
||||
if(current_flags->db_signal)
|
||||
read_field(buffer, radiotap_hdr_size, _db_signal);
|
||||
|
||||
if(_radio.flags.rx_flags) {
|
||||
if(((buffer - buffer_start) & 1) == 1) {
|
||||
buffer++;
|
||||
radiotap_hdr_size--;
|
||||
if(current_flags->rx_flags) {
|
||||
if(((buffer - buffer_start) & 1) == 1) {
|
||||
buffer++;
|
||||
radiotap_hdr_size--;
|
||||
}
|
||||
read_field(buffer, radiotap_hdr_size, _rx_flags);
|
||||
}
|
||||
read_field(buffer, radiotap_hdr_size, _rx_flags);
|
||||
}
|
||||
if(_radio.flags.channel_plus) {
|
||||
uint32_t offset = ((buffer - buffer_start) % 4);
|
||||
if(offset) {
|
||||
offset = 4 - offset;
|
||||
buffer += offset;
|
||||
radiotap_hdr_size -= offset;
|
||||
if(current_flags->channel_plus) {
|
||||
uint32_t offset = ((buffer - buffer_start) % 4);
|
||||
if(offset) {
|
||||
offset = 4 - offset;
|
||||
buffer += offset;
|
||||
radiotap_hdr_size -= offset;
|
||||
}
|
||||
uint32_t dummy;
|
||||
read_field(buffer, radiotap_hdr_size, dummy);
|
||||
// nasty Big Endian fix
|
||||
_channel_type = Endian::le_to_host<uint16_t>(Endian::host_to_le<uint32_t>(dummy));
|
||||
read_field(buffer, radiotap_hdr_size, _channel_freq);
|
||||
read_field(buffer, radiotap_hdr_size, _channel);
|
||||
read_field(buffer, radiotap_hdr_size, _max_power);
|
||||
}
|
||||
// We can do this safely because we checked the size on find_extra_flags...
|
||||
if(current_flags->ext == 1) {
|
||||
current_flags++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
uint32_t dummy;
|
||||
read_field(buffer, radiotap_hdr_size, dummy);
|
||||
// nasty Big Endian fix
|
||||
_channel_type = Endian::le_to_host<uint16_t>(Endian::host_to_le<uint32_t>(dummy));
|
||||
read_field(buffer, radiotap_hdr_size, _channel_freq);
|
||||
read_field(buffer, radiotap_hdr_size, _channel);
|
||||
read_field(buffer, radiotap_hdr_size, _max_power);
|
||||
}
|
||||
|
||||
total_sz -= length();
|
||||
@@ -159,6 +177,20 @@ void RadioTap::init() {
|
||||
antenna(0);
|
||||
}
|
||||
|
||||
// This method finds the extra flags field size, taking into account other
|
||||
// set of flags that may appear if the "ext" bit is on/.
|
||||
uint32_t RadioTap::find_extra_flag_fields_size(const uint8_t* buffer, uint32_t total_sz) {
|
||||
const flags_type* ptr = (const flags_type*)buffer;
|
||||
while (ptr->ext == 1) {
|
||||
if (total_sz < sizeof(flags_type)) {
|
||||
throw malformed_packet();
|
||||
}
|
||||
++ptr;
|
||||
}
|
||||
|
||||
return (const uint8_t*)ptr - buffer;
|
||||
}
|
||||
|
||||
void RadioTap::version(uint8_t new_version) {
|
||||
_radio.it_version = new_version;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <stdint.h>
|
||||
#include "dot11/dot11_data.h"
|
||||
#include "dot11/dot11_beacon.h"
|
||||
#include "arp.h"
|
||||
#include "utils.h"
|
||||
|
||||
using namespace std;
|
||||
@@ -16,7 +17,7 @@ using namespace Tins;
|
||||
class RadioTapTest : public testing::Test {
|
||||
public:
|
||||
static const uint8_t expected_packet[], expected_packet1[],
|
||||
expected_packet2[];
|
||||
expected_packet2[], expected_packet3[];
|
||||
};
|
||||
|
||||
const uint8_t RadioTapTest::expected_packet[] = {
|
||||
@@ -65,6 +66,15 @@ const uint8_t RadioTapTest::expected_packet2[] = {
|
||||
132, 241, 42, 135, 151, 94, 223, 190, 109, 180, 255, 115, 238, 211
|
||||
};
|
||||
|
||||
const uint8_t RadioTapTest::expected_packet3[] = {
|
||||
0, 0, 36, 0, 47, 64, 0, 160, 32, 8, 0, 0, 0, 0, 0, 0, 75, 136, 126,
|
||||
238, 50, 0, 0, 0, 18, 22, 133, 9, 192, 0, 181, 0, 0, 0, 181, 0, 8,
|
||||
2, 0, 0, 255, 255, 255, 255, 255, 255, 116, 37, 138, 78, 207, 112,
|
||||
0, 102, 75, 134, 135, 47, 32, 84, 170, 170, 3, 0, 0, 0, 8, 6, 0, 1,
|
||||
8, 0, 6, 4, 0, 1, 0, 102, 75, 134, 135, 47, 172, 31, 30, 115, 0, 0,
|
||||
0, 0, 0, 0, 172, 31, 31, 105, 106, 113, 120, 145
|
||||
};
|
||||
|
||||
TEST_F(RadioTapTest, DefaultConstructor) {
|
||||
RadioTap radio;
|
||||
EXPECT_TRUE(radio.flags() & RadioTap::FCS);
|
||||
@@ -129,6 +139,20 @@ TEST_F(RadioTapTest, ConstructorFromBuffer2) {
|
||||
EXPECT_TRUE(radio.find_pdu<Dot11QoSData>());
|
||||
}
|
||||
|
||||
TEST_F(RadioTapTest, ConstructorFromBuffer3) {
|
||||
RadioTap radio(expected_packet3, sizeof(expected_packet3));
|
||||
EXPECT_TRUE(radio.present() & RadioTap::RATE);
|
||||
EXPECT_TRUE(radio.present() & RadioTap::CHANNEL);
|
||||
EXPECT_TRUE(radio.present() & RadioTap::DBM_SIGNAL);
|
||||
EXPECT_TRUE(radio.present() & RadioTap::ANTENNA);
|
||||
EXPECT_TRUE(radio.present() & RadioTap::RX_FLAGS);
|
||||
|
||||
EXPECT_EQ(0, radio.antenna());
|
||||
EXPECT_EQ(0xb5, radio.dbm_signal());
|
||||
|
||||
EXPECT_TRUE(radio.find_pdu<ARP>());
|
||||
}
|
||||
|
||||
TEST_F(RadioTapTest, Serialize) {
|
||||
RadioTap radio(expected_packet, sizeof(expected_packet));
|
||||
RadioTap::serialization_type buffer = radio.serialize();
|
||||
|
||||
Reference in New Issue
Block a user