From 875fc6be2f9940a40dd8ef0b895b2999a4b4bb1b Mon Sep 17 00:00:00 2001 From: Joel 'Aaron' Cohen Date: Fri, 10 Jul 2020 15:35:43 -0400 Subject: [PATCH 1/6] Improve radiotap situation Correct endianness issues Support multi-byte present flags Handle misaligned flags fields --- dpkt/radiotap.py | 216 ++++++++++++++++++++++++----------------------- 1 file changed, 112 insertions(+), 104 deletions(-) diff --git a/dpkt/radiotap.py b/dpkt/radiotap.py index 7bb9087e..3f58014a 100644 --- a/dpkt/radiotap.py +++ b/dpkt/radiotap.py @@ -12,41 +12,23 @@ # Fields Ref: http://www.radiotap.org/defined-fields/all # Present flags -_TSFT_MASK = 0x1000000 -_FLAGS_MASK = 0x2000000 -_RATE_MASK = 0x4000000 -_CHANNEL_MASK = 0x8000000 -_FHSS_MASK = 0x10000000 -_ANT_SIG_MASK = 0x20000000 -_ANT_NOISE_MASK = 0x40000000 -_LOCK_QUAL_MASK = 0x80000000 -_TX_ATTN_MASK = 0x10000 -_DB_TX_ATTN_MASK = 0x20000 -_DBM_TX_POWER_MASK = 0x40000 -_ANTENNA_MASK = 0x80000 -_DB_ANT_SIG_MASK = 0x100000 -_DB_ANT_NOISE_MASK = 0x200000 -_RX_FLAGS_MASK = 0x400000 -_CHANNELPLUS_MASK = 0x200 -_EXT_MASK = 0x1 - -_TSFT_SHIFT = 24 -_FLAGS_SHIFT = 25 -_RATE_SHIFT = 26 -_CHANNEL_SHIFT = 27 -_FHSS_SHIFT = 28 -_ANT_SIG_SHIFT = 29 -_ANT_NOISE_SHIFT = 30 -_LOCK_QUAL_SHIFT = 31 -_TX_ATTN_SHIFT = 16 -_DB_TX_ATTN_SHIFT = 17 -_DBM_TX_POWER_SHIFT = 18 -_ANTENNA_SHIFT = 19 -_DB_ANT_SIG_SHIFT = 20 -_DB_ANT_NOISE_SHIFT = 21 -_RX_FLAGS_SHIFT = 22 -_CHANNELPLUS_SHIFT = 10 -_EXT_SHIFT = 0 +_TSFT_SHIFT = 0 +_FLAGS_SHIFT = 1 +_RATE_SHIFT = 2 +_CHANNEL_SHIFT = 3 +_FHSS_SHIFT = 4 +_ANT_SIG_SHIFT = 5 +_ANT_NOISE_SHIFT = 6 +_LOCK_QUAL_SHIFT = 7 +_TX_ATTN_SHIFT = 8 +_DB_TX_ATTN_SHIFT = 9 +_DBM_TX_POWER_SHIFT = 10 +_ANTENNA_SHIFT = 11 +_DB_ANT_SIG_SHIFT = 12 +_DB_ANT_NOISE_SHIFT = 13 +_RX_FLAGS_SHIFT = 14 +_CHANNELPLUS_SHIFT = 18 +_EXT_SHIFT = 31 # Flags elements _FLAGS_SIZE = 2 @@ -75,7 +57,7 @@ _QUARTER_RATE_SHIFT = 15 # Flags offsets and masks -_FCS_SHIFT = 4 +_FCS_SHIFT = 1 _FCS_MASK = 0x10 @@ -93,12 +75,18 @@ class Radiotap(dpkt.Packet): ('version', 'B', 0), ('pad', 'B', 0), ('length', 'H', 0), - ('present_flags', 'I', 0) ) + __byte_order__ = '<' + + def is_present(self, bit): + index = bit // 8 + mask = 1 << (bit % 8) + return self.present_flags[index] & mask + @property def tsft_present(self): - return (self.present_flags & _TSFT_MASK) >> _TSFT_SHIFT + return self.is_present(_TSFT_SHIFT) @tsft_present.setter def tsft_present(self, val): @@ -106,7 +94,7 @@ def tsft_present(self, val): @property def flags_present(self): - return (self.present_flags & _FLAGS_MASK) >> _FLAGS_SHIFT + return self.is_present(_FLAGS_SHIFT) @flags_present.setter def flags_present(self, val): @@ -114,7 +102,7 @@ def flags_present(self, val): @property def rate_present(self): - return (self.present_flags & _RATE_MASK) >> _RATE_SHIFT + return self.is_present(_RATE_SHIFT) @rate_present.setter def rate_present(self, val): @@ -122,7 +110,7 @@ def rate_present(self, val): @property def channel_present(self): - return (self.present_flags & _CHANNEL_MASK) >> _CHANNEL_SHIFT + return self.is_present(_CHANNEL_SHIFT) @channel_present.setter def channel_present(self, val): @@ -130,7 +118,7 @@ def channel_present(self, val): @property def fhss_present(self): - return (self.present_flags & _FHSS_MASK) >> _FHSS_SHIFT + return self.is_present(_FHSS_SHIFT) @fhss_present.setter def fhss_present(self, val): @@ -138,7 +126,7 @@ def fhss_present(self, val): @property def ant_sig_present(self): - return (self.present_flags & _ANT_SIG_MASK) >> _ANT_SIG_SHIFT + return self.is_present(_ANT_SIG_SHIFT) @ant_sig_present.setter def ant_sig_present(self, val): @@ -146,7 +134,7 @@ def ant_sig_present(self, val): @property def ant_noise_present(self): - return (self.present_flags & _ANT_NOISE_MASK) >> _ANT_NOISE_SHIFT + return self.is_present(_ANT_NOISE_SHIFT) @ant_noise_present.setter def ant_noise_present(self, val): @@ -154,7 +142,7 @@ def ant_noise_present(self, val): @property def lock_qual_present(self): - return (self.present_flags & _LOCK_QUAL_MASK) >> _LOCK_QUAL_SHIFT + return self.is_present(_LOCK_QUAL_SHIFT) @lock_qual_present.setter def lock_qual_present(self, val): @@ -162,7 +150,7 @@ def lock_qual_present(self, val): @property def tx_attn_present(self): - return (self.present_flags & _TX_ATTN_MASK) >> _TX_ATTN_SHIFT + return self.is_present(_TX_ATTN_SHIFT) @tx_attn_present.setter def tx_attn_present(self, val): @@ -170,7 +158,7 @@ def tx_attn_present(self, val): @property def db_tx_attn_present(self): - return (self.present_flags & _DB_TX_ATTN_MASK) >> _DB_TX_ATTN_SHIFT + return self.is_present(_DB_TX_ATTN_SHIFT) @db_tx_attn_present.setter def db_tx_attn_present(self, val): @@ -178,7 +166,7 @@ def db_tx_attn_present(self, val): @property def dbm_tx_power_present(self): - return (self.present_flags & _DBM_TX_POWER_MASK) >> _DBM_TX_POWER_SHIFT + return self.is_present(_DBM_TX_POWER_SHIFT) @dbm_tx_power_present.setter def dbm_tx_power_present(self, val): @@ -186,7 +174,7 @@ def dbm_tx_power_present(self, val): @property def ant_present(self): - return (self.present_flags & _ANTENNA_MASK) >> _ANTENNA_SHIFT + return self.is_present(_ANTENNA_SHIFT) @ant_present.setter def ant_present(self, val): @@ -194,7 +182,7 @@ def ant_present(self, val): @property def db_ant_sig_present(self): - return (self.present_flags & _DB_ANT_SIG_MASK) >> _DB_ANT_SIG_SHIFT + return self.is_present(_DB_ANT_SIG_SHIFT) @db_ant_sig_present.setter def db_ant_sig_present(self, val): @@ -202,7 +190,7 @@ def db_ant_sig_present(self, val): @property def db_ant_noise_present(self): - return (self.present_flags & _DB_ANT_NOISE_MASK) >> _DB_ANT_NOISE_SHIFT + return self.is_present(_DB_ANT_NOISE_SHIFT) @db_ant_noise_present.setter def db_ant_noise_present(self, val): @@ -210,7 +198,7 @@ def db_ant_noise_present(self, val): @property def rx_flags_present(self): - return (self.present_flags & _RX_FLAGS_MASK) >> _RX_FLAGS_SHIFT + return self.is_present(_RX_FLAGS_SHIFT) @rx_flags_present.setter def rx_flags_present(self, val): @@ -218,27 +206,27 @@ def rx_flags_present(self, val): @property def chanplus_present(self): - return (self.present_flags & _CHANNELPLUS_MASK) >> _CHANNELPLUS_SHIFT + return self.is_present(_CHANNELPLUS_SHIFT) @chanplus_present.setter def chanplus_present(self, val): self.present_flags |= val << _CHANNELPLUS_SHIFT - @property - def ext_present(self): - return (self.present_flags & _EXT_MASK) >> _EXT_SHIFT - - @ext_present.setter - def ext_present(self, val): - self.present_flags |= val << _EXT_SHIFT - def unpack(self, buf): dpkt.Packet.unpack(self, buf) - self.data = buf[socket.ntohs(self.length):] + self.data = buf[self.length:] self.fields = [] buf = buf[self.__hdr_len__:] + self.present_flags = bytearray(buf[:4]) + buf = buf[4:] + ext_bit = _EXT_SHIFT + while self.is_present(ext_bit): + self.present_flags = self.present_flags + bytearray(buf[:4]) + buf = buf[4:] + ext_bit += 32 + # decode each field into self. (eg. self.tsft) as well as append it self.fields list field_decoder = [ ('tsft', self.tsft_present, self.TSFT), @@ -257,8 +245,15 @@ def unpack(self, buf): ('db_ant_noise', self.db_ant_noise_present, self.DbAntennaNoise), ('rx_flags', self.rx_flags_present, self.RxFlags) ] + + offset = self.__hdr_len__ + len(self.present_flags) + for name, present_bit, parser in field_decoder: if present_bit: + if parser.__alignment__ > 1: + padding = offset % parser.__alignment__ + buf = buf[padding:] + offset += padding field = parser(buf) field.data = b'' setattr(self, name, field) @@ -271,34 +266,39 @@ def unpack(self, buf): else: self.data = ieee80211.IEEE80211(self.data) - class Antenna(dpkt.Packet): + class RadiotapField(dpkt.Packet): + __alignment__ = 1 + __byte_order__ = '<' + + class Antenna(RadiotapField): __hdr__ = ( ('index', 'B', 0), ) - class AntennaNoise(dpkt.Packet): + class AntennaNoise(RadiotapField): __hdr__ = ( ('db', 'B', 0), ) - class AntennaSignal(dpkt.Packet): + class AntennaSignal(RadiotapField): __hdr__ = ( ('db', 'B', 0), ) - class Channel(dpkt.Packet): + class Channel(RadiotapField): + __alignment__ = 2 __hdr__ = ( ('freq', 'H', 0), ('flags', 'H', 0), ) - class FHSS(dpkt.Packet): + class FHSS(RadiotapField): __hdr__ = ( ('set', 'B', 0), ('pattern', 'B', 0), ) - class Flags(dpkt.Packet): + class Flags(RadiotapField): __hdr__ = ( ('val', 'B', 0), ) @@ -311,84 +311,92 @@ def fcs(self): return (self.val & _FCS_MASK) >> _FCS_SHIFT def fcs(self, v): (v << _FCS_SHIFT) | (self.val & ~_FCS_MASK) - class LockQuality(dpkt.Packet): + class LockQuality(RadiotapField): + __alignment__ = 2 __hdr__ = ( ('val', 'H', 0), ) - class RxFlags(dpkt.Packet): + class RxFlags(RadiotapField): + __alignment__ = 2 __hdr__ = ( ('val', 'H', 0), ) - class Rate(dpkt.Packet): + class Rate(RadiotapField): __hdr__ = ( ('val', 'B', 0), ) - class TSFT(dpkt.Packet): + class TSFT(RadiotapField): + __alignment__ = 8 __hdr__ = ( ('usecs', 'Q', 0), ) - class TxAttenuation(dpkt.Packet): + class TxAttenuation(RadiotapField): + __alignment__ = 2 __hdr__ = ( ('val', 'H', 0), ) - class DbTxAttenuation(dpkt.Packet): + class DbTxAttenuation(RadiotapField): + __alignment__ = 2 __hdr__ = ( ('db', 'H', 0), ) - class DbAntennaNoise(dpkt.Packet): + class DbAntennaNoise(RadiotapField): __hdr__ = ( ('db', 'B', 0), ) - class DbAntennaSignal(dpkt.Packet): + class DbAntennaSignal(RadiotapField): __hdr__ = ( ('db', 'B', 0), ) - class DbmTxPower(dpkt.Packet): + class DbmTxPower(RadiotapField): __hdr__ = ( ('dbm', 'B', 0), ) + class ChannelPlus(RadiotapField): + __alignment__ = 4 + __hdr__ = ( + ('flags', 'I', 0), + ('freq', 'H', 0), + ('channel', 'B', 0), + ('maxpower', 'B', 0), + ) + def test_Radiotap(): - s = b'\x00\x00\x00\x18\x6e\x48\x00\x00\x00\x02\x6c\x09\xa0\x00\xa8\x81\x02\x00\x00\x00\x00\x00\x00\x00' + s = bytearray.fromhex('000030002f4000a0200800a0200800a020080000000000000884bdac2800000010028509a000a5000000a1009f01a102') rad = Radiotap(s) assert(rad.version == 0) - assert(rad.present_flags == 0x6e480000) - assert(rad.tsft_present == 0) - assert(rad.flags_present == 1) - assert(rad.rate_present == 1) - assert(rad.channel_present == 1) - assert(rad.fhss_present == 0) - assert(rad.ant_sig_present == 1) - assert(rad.ant_noise_present == 1) - assert(rad.lock_qual_present == 0) - assert(rad.db_tx_attn_present == 0) - assert(rad.dbm_tx_power_present == 0) - assert(rad.ant_present == 1) - assert(rad.db_ant_sig_present == 0) - assert(rad.db_ant_noise_present == 0) - assert(rad.rx_flags_present == 1) - assert(rad.channel.freq == 0x6c09) - assert(rad.channel.flags == 0xa000) - assert(len(rad.fields) == 7) - - -def test_fcs(): - s = b'\x00\x00\x1a\x00\x2f\x48\x00\x00\x34\x8f\x71\x09\x00\x00\x00\x00\x10\x0c\x85\x09\xc0\x00\xcc\x01\x00\x00' - rt = Radiotap(s) - assert(rt.flags_present == 1) - assert(rt.flags.fcs == 1) + assert(rad.present_flags == bytearray.fromhex('2f4000a0200800a0200800a020080000')) + assert(rad.tsft_present) + assert(rad.flags_present) + assert(rad.rate_present) + assert(rad.channel_present) + assert(not rad.fhss_present) + assert(rad.ant_sig_present) + assert(not rad.ant_noise_present) + assert(not rad.lock_qual_present) + assert(not rad.db_tx_attn_present) + assert(not rad.dbm_tx_power_present) + assert(not rad.ant_present) + assert(not rad.db_ant_sig_present) + assert(not rad.db_ant_noise_present) + assert(rad.rx_flags_present) + assert(rad.channel.freq == 2437) + assert(rad.channel.flags == 0x00a0) + assert(len(rad.fields) == 6) + assert(rad.flags_present) + assert(rad.flags.fcs) if __name__ == '__main__': test_Radiotap() - test_fcs() print('Tests Successful...') From cb87e77fe80e94b82c71db0535a9da8ad26f13d2 Mon Sep 17 00:00:00 2001 From: obormot Date: Sun, 27 Dec 2020 19:16:17 -0800 Subject: [PATCH 2/6] PR #478 fixes --- dpkt/radiotap.py | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/dpkt/radiotap.py b/dpkt/radiotap.py index 24dd36d5..429b385d 100644 --- a/dpkt/radiotap.py +++ b/dpkt/radiotap.py @@ -5,6 +5,7 @@ from . import dpkt from . import ieee80211 +from .compat import compat_ord # Ref: http://www.radiotap.org # Fields Ref: http://www.radiotap.org/defined-fields/all @@ -55,7 +56,6 @@ _QUARTER_RATE_SHIFT = 15 # Flags offsets and masks -_FCS_SHIFT = 1 _FCS_MASK = 0x10 @@ -80,7 +80,7 @@ class Radiotap(dpkt.Packet): def is_present(self, bit): index = bit // 8 mask = 1 << (bit % 8) - return self.present_flags[index] & mask + return compat_ord(self.present_flags[index]) & mask @property def tsft_present(self): @@ -213,15 +213,15 @@ def chanplus_present(self, val): def unpack(self, buf): dpkt.Packet.unpack(self, buf) self.data = buf[self.length:] - + self.fields = [] buf = buf[self.__hdr_len__:] - self.present_flags = bytearray(buf[:4]) + self.present_flags = buf[:4] buf = buf[4:] ext_bit = _EXT_SHIFT while self.is_present(ext_bit): - self.present_flags = self.present_flags + bytearray(buf[:4]) + self.present_flags += buf[:4] buf = buf[4:] ext_bit += 32 @@ -302,12 +302,13 @@ class Flags(RadiotapField): ) @property - def fcs(self): return (self.val & _FCS_MASK) >> _FCS_SHIFT + def fcs(self): + return (self.val & _FCS_MASK) >> _FCS_SHIFT - # TODO statement seems to have no effect + # TODO: untested @fcs.setter - def fcs(self, v): (v << _FCS_SHIFT) | (self.val & ~_FCS_MASK) - + def fcs(self, v): + self.val = (v << _FCS_SHIFT) | (v & ~_FCS_MASK) class LockQuality(RadiotapField): __alignment__ = 2 @@ -369,11 +370,13 @@ class ChannelPlus(RadiotapField): ) -def test_Radiotap(): - s = bytearray.fromhex('000030002f4000a0200800a0200800a020080000000000000884bdac2800000010028509a000a5000000a1009f01a102') +def test_radiotap(): + s = (b'\x00\x00\x30\x00\x2f\x40\x00\xa0\x20\x08\x00\xa0\x20\x08\x00\xa0\x20\x08\x00\x00\x00\x00' + b'\x00\x00\x08\x84\xbd\xac\x28\x00\x00\x00\x10\x02\x85\x09\xa0\x00\xa5\x00\x00\x00\xa1\x00' + b'\x9f\x01\xa1\x02') rad = Radiotap(s) assert(rad.version == 0) - assert(rad.present_flags == bytearray.fromhex('2f4000a0200800a0200800a020080000')) + assert(rad.present_flags == b'\x2f\x40\x00\xa0\x20\x08\x00\xa0\x20\x08\x00\xa0\x20\x08\x00\x00') assert(rad.tsft_present) assert(rad.flags_present) assert(rad.rate_present) @@ -396,5 +399,5 @@ def test_Radiotap(): if __name__ == '__main__': - test_Radiotap() + test_radiotap() print('Tests Successful...') From 46231d9231ca16b44a6773057b429beecd992c50 Mon Sep 17 00:00:00 2001 From: obormot Date: Sun, 27 Dec 2020 19:19:38 -0800 Subject: [PATCH 3/6] make is_present _private --- dpkt/radiotap.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/dpkt/radiotap.py b/dpkt/radiotap.py index 429b385d..d673fe3f 100644 --- a/dpkt/radiotap.py +++ b/dpkt/radiotap.py @@ -77,14 +77,14 @@ class Radiotap(dpkt.Packet): __byte_order__ = '<' - def is_present(self, bit): + def _is_present(self, bit): index = bit // 8 mask = 1 << (bit % 8) return compat_ord(self.present_flags[index]) & mask @property def tsft_present(self): - return self.is_present(_TSFT_SHIFT) + return self._is_present(_TSFT_SHIFT) @tsft_present.setter def tsft_present(self, val): @@ -92,7 +92,7 @@ def tsft_present(self, val): @property def flags_present(self): - return self.is_present(_FLAGS_SHIFT) + return self._is_present(_FLAGS_SHIFT) @flags_present.setter def flags_present(self, val): @@ -100,7 +100,7 @@ def flags_present(self, val): @property def rate_present(self): - return self.is_present(_RATE_SHIFT) + return self._is_present(_RATE_SHIFT) @rate_present.setter def rate_present(self, val): @@ -108,7 +108,7 @@ def rate_present(self, val): @property def channel_present(self): - return self.is_present(_CHANNEL_SHIFT) + return self._is_present(_CHANNEL_SHIFT) @channel_present.setter def channel_present(self, val): @@ -116,7 +116,7 @@ def channel_present(self, val): @property def fhss_present(self): - return self.is_present(_FHSS_SHIFT) + return self._is_present(_FHSS_SHIFT) @fhss_present.setter def fhss_present(self, val): @@ -124,7 +124,7 @@ def fhss_present(self, val): @property def ant_sig_present(self): - return self.is_present(_ANT_SIG_SHIFT) + return self._is_present(_ANT_SIG_SHIFT) @ant_sig_present.setter def ant_sig_present(self, val): @@ -132,7 +132,7 @@ def ant_sig_present(self, val): @property def ant_noise_present(self): - return self.is_present(_ANT_NOISE_SHIFT) + return self._is_present(_ANT_NOISE_SHIFT) @ant_noise_present.setter def ant_noise_present(self, val): @@ -140,7 +140,7 @@ def ant_noise_present(self, val): @property def lock_qual_present(self): - return self.is_present(_LOCK_QUAL_SHIFT) + return self._is_present(_LOCK_QUAL_SHIFT) @lock_qual_present.setter def lock_qual_present(self, val): @@ -148,7 +148,7 @@ def lock_qual_present(self, val): @property def tx_attn_present(self): - return self.is_present(_TX_ATTN_SHIFT) + return self._is_present(_TX_ATTN_SHIFT) @tx_attn_present.setter def tx_attn_present(self, val): @@ -156,7 +156,7 @@ def tx_attn_present(self, val): @property def db_tx_attn_present(self): - return self.is_present(_DB_TX_ATTN_SHIFT) + return self._is_present(_DB_TX_ATTN_SHIFT) @db_tx_attn_present.setter def db_tx_attn_present(self, val): @@ -164,7 +164,7 @@ def db_tx_attn_present(self, val): @property def dbm_tx_power_present(self): - return self.is_present(_DBM_TX_POWER_SHIFT) + return self._is_present(_DBM_TX_POWER_SHIFT) @dbm_tx_power_present.setter def dbm_tx_power_present(self, val): @@ -172,7 +172,7 @@ def dbm_tx_power_present(self, val): @property def ant_present(self): - return self.is_present(_ANTENNA_SHIFT) + return self._is_present(_ANTENNA_SHIFT) @ant_present.setter def ant_present(self, val): @@ -180,7 +180,7 @@ def ant_present(self, val): @property def db_ant_sig_present(self): - return self.is_present(_DB_ANT_SIG_SHIFT) + return self._is_present(_DB_ANT_SIG_SHIFT) @db_ant_sig_present.setter def db_ant_sig_present(self, val): @@ -188,7 +188,7 @@ def db_ant_sig_present(self, val): @property def db_ant_noise_present(self): - return self.is_present(_DB_ANT_NOISE_SHIFT) + return self._is_present(_DB_ANT_NOISE_SHIFT) @db_ant_noise_present.setter def db_ant_noise_present(self, val): @@ -196,7 +196,7 @@ def db_ant_noise_present(self, val): @property def rx_flags_present(self): - return self.is_present(_RX_FLAGS_SHIFT) + return self._is_present(_RX_FLAGS_SHIFT) @rx_flags_present.setter def rx_flags_present(self, val): @@ -204,7 +204,7 @@ def rx_flags_present(self, val): @property def chanplus_present(self): - return self.is_present(_CHANNELPLUS_SHIFT) + return self._is_present(_CHANNELPLUS_SHIFT) @chanplus_present.setter def chanplus_present(self, val): @@ -220,7 +220,7 @@ def unpack(self, buf): self.present_flags = buf[:4] buf = buf[4:] ext_bit = _EXT_SHIFT - while self.is_present(ext_bit): + while self._is_present(ext_bit): self.present_flags += buf[:4] buf = buf[4:] ext_bit += 32 From 79d329a564e193463d104e4501f933f1521525c5 Mon Sep 17 00:00:00 2001 From: obormot Date: Sun, 27 Dec 2020 19:51:45 -0800 Subject: [PATCH 4/6] get the original unit tests back, and fix em up --- dpkt/radiotap.py | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/dpkt/radiotap.py b/dpkt/radiotap.py index d673fe3f..92787ad5 100644 --- a/dpkt/radiotap.py +++ b/dpkt/radiotap.py @@ -80,7 +80,7 @@ class Radiotap(dpkt.Packet): def _is_present(self, bit): index = bit // 8 mask = 1 << (bit % 8) - return compat_ord(self.present_flags[index]) & mask + return 1 if (compat_ord(self.present_flags[index]) & mask) else 0 @property def tsft_present(self): @@ -370,7 +370,31 @@ class ChannelPlus(RadiotapField): ) -def test_radiotap(): +def test_radiotap_1(): + s = b'\x00\x00\x00\x18\x6e\x48\x00\x00\x00\x02\x6c\x09\xa0\x00\xa8\x81\x02\x00\x00\x00\x00\x00\x00\x00' + rad = Radiotap(s) + assert(rad.version == 0) + assert(rad.present_flags == b'\x6e\x48\x00\x00') + assert(rad.tsft_present == 0) + assert(rad.flags_present == 1) + assert(rad.rate_present == 1) + assert(rad.channel_present == 1) + assert(rad.fhss_present == 0) + assert(rad.ant_sig_present == 1) + assert(rad.ant_noise_present == 1) + assert(rad.lock_qual_present == 0) + assert(rad.db_tx_attn_present == 0) + assert(rad.dbm_tx_power_present == 0) + assert(rad.ant_present == 1) + assert(rad.db_ant_sig_present == 0) + assert(rad.db_ant_noise_present == 0) + assert(rad.rx_flags_present == 1) + assert(rad.channel.freq == 0x096c) + assert(rad.channel.flags == 0xa0) + assert(len(rad.fields) == 7) + + +def test_radiotap_2(): s = (b'\x00\x00\x30\x00\x2f\x40\x00\xa0\x20\x08\x00\xa0\x20\x08\x00\xa0\x20\x08\x00\x00\x00\x00' b'\x00\x00\x08\x84\xbd\xac\x28\x00\x00\x00\x10\x02\x85\x09\xa0\x00\xa5\x00\x00\x00\xa1\x00' b'\x9f\x01\xa1\x02') @@ -398,6 +422,15 @@ def test_radiotap(): assert(rad.flags.fcs) +def test_fcs(): + s = b'\x00\x00\x1a\x00\x2f\x48\x00\x00\x34\x8f\x71\x09\x00\x00\x00\x00\x10\x0c\x85\x09\xc0\x00\xcc\x01\x00\x00' + rt = Radiotap(s) + assert(rt.flags_present) + assert(rt.flags.fcs == 1) + + if __name__ == '__main__': - test_radiotap() + test_radiotap_1() + test_radiotap_2() + test_fcs() print('Tests Successful...') From 465205ace6d3994be290862e4acdd7f332f95475 Mon Sep 17 00:00:00 2001 From: obormot Date: Sun, 27 Dec 2020 19:54:53 -0800 Subject: [PATCH 5/6] minor --- dpkt/radiotap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dpkt/radiotap.py b/dpkt/radiotap.py index 92787ad5..d563cd51 100644 --- a/dpkt/radiotap.py +++ b/dpkt/radiotap.py @@ -425,7 +425,7 @@ def test_radiotap_2(): def test_fcs(): s = b'\x00\x00\x1a\x00\x2f\x48\x00\x00\x34\x8f\x71\x09\x00\x00\x00\x00\x10\x0c\x85\x09\xc0\x00\xcc\x01\x00\x00' rt = Radiotap(s) - assert(rt.flags_present) + assert(rt.flags_present == 1) assert(rt.flags.fcs == 1) From cfa04214f630c34c8f731beb6f4125fdf9676beb Mon Sep 17 00:00:00 2001 From: obormot Date: Tue, 29 Dec 2020 20:07:09 -0800 Subject: [PATCH 6/6] signed byte and padding fixes for field decoding, add unit test --- dpkt/radiotap.py | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/dpkt/radiotap.py b/dpkt/radiotap.py index d563cd51..0512fd44 100644 --- a/dpkt/radiotap.py +++ b/dpkt/radiotap.py @@ -241,15 +241,17 @@ def unpack(self, buf): ('ant', self.ant_present, self.Antenna), ('db_ant_sig', self.db_ant_sig_present, self.DbAntennaSignal), ('db_ant_noise', self.db_ant_noise_present, self.DbAntennaNoise), - ('rx_flags', self.rx_flags_present, self.RxFlags) + ('rx_flags', self.rx_flags_present, self.RxFlags), + ('chanplus', self.chanplus_present, self.ChannelPlus) ] offset = self.__hdr_len__ + len(self.present_flags) for name, present_bit, parser in field_decoder: if present_bit: - if parser.__alignment__ > 1: - padding = offset % parser.__alignment__ + ali = parser.__alignment__ + if ali > 1 and offset % ali: + padding = ali - offset % ali buf = buf[padding:] offset += padding field = parser(buf) @@ -257,6 +259,7 @@ def unpack(self, buf): setattr(self, name, field) self.fields.append(field) buf = buf[len(field):] + offset += len(field) if len(self.data) > 0: if self.flags_present and self.flags.fcs: @@ -275,12 +278,12 @@ class Antenna(RadiotapField): class AntennaNoise(RadiotapField): __hdr__ = ( - ('db', 'B', 0), + ('db', 'b', 0), ) class AntennaSignal(RadiotapField): __hdr__ = ( - ('db', 'B', 0), + ('db', 'b', 0), ) class Channel(RadiotapField): @@ -429,8 +432,29 @@ def test_fcs(): assert(rt.flags.fcs == 1) +def test_radiotap_3(): # xchannel aka channel plus field + s = ( + b'\x00\x00\x20\x00\x67\x08\x04\x00\x84\x84\x66\x25\x00\x00\x00\x00\x22\x0c\xd6\xa0\x01\x00\x00\x00\x40' + b'\x01\x00\x00\x3c\x14\x24\x11\x08\x02\x00\x00\xff\xff\xff\xff\xff\xff\x06\x03\x7f\x07\xa0\x16\x00\x19' + b'\xe3\xd3\x53\x52\x00\x8e\xaa\xaa\x03\x00\x00\x00\x08\x06\x00\x01\x08\x00\x06\x04\x00\x01\x00\x19\xe3' + b'\xd3\x53\x52\xa9\xfe\xf7\x00\x00\x00\x00\x00\x00\x00\x4f\x67\x32\x38' + ) + rt = Radiotap(s) + assert rt.ant_noise.db == -96 + assert rt.ant_sig.db == -42 + assert rt.ant.index == 1 + assert rt.chanplus_present + assert rt.chanplus.flags == 0x140 + assert rt.chanplus.freq == 5180 + assert rt.chanplus.channel == 36 + assert rt.chanplus.maxpower == 17 + assert len(rt.fields) == 7 + assert repr(rt.data).startswith('IEEE80211') + + if __name__ == '__main__': test_radiotap_1() test_radiotap_2() + test_radiotap_3() test_fcs() print('Tests Successful...')