From 347bcf28cca2bee6229d012eac627caf4f7ae532 Mon Sep 17 00:00:00 2001 From: Hoolean Date: Fri, 7 Feb 2025 20:09:50 +0000 Subject: [PATCH 1/5] Make Dot11EltVendorSpecific packet extensible See #4659 This commit allows the Dot11EltVendorSpecific packet to dispatch to its subclasses based on their OUI, with the same idiom that the parent Dot11Elt uses to select subclasses based on their ID already: https://github.com/secdev/scapy/blob/c15a670926185f6ddb9b3330ed1f947ff6f14b92/scapy/layers/dot11.py#L1057-L1074 This is just a rough sketch, so feedback very welcome to make sure it is heading in the right direction :) --- scapy/layers/dot11.py | 45 +++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/scapy/layers/dot11.py b/scapy/layers/dot11.py index 96cf6619847..b691c69ef7a 100644 --- a/scapy/layers/dot11.py +++ b/scapy/layers/dot11.py @@ -1439,22 +1439,21 @@ class Dot11EltVendorSpecific(Dot11Elt): def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt: oui = struct.unpack("!I", b"\x00" + _pkt[2:5])[0] - if oui == 0x0050f2: # Microsoft - type_ = orb(_pkt[5]) - if type_ == 0x01: - # MS WPA IE - return Dot11EltMicrosoftWPA - elif type_ == 0x02: - # MS WME IE TODO - # return Dot11EltMicrosoftWME - pass - elif type_ == 0x04: - # MS WPS IE TODO - # return Dot11EltWPS - pass - return Dot11EltVendorSpecific + ouicls = cls.registered_ouis.get(oui, cls) + if ouicls.dispatch_hook != cls.dispatch_hook: + # Sub-classes can have their own dispatch_hook + return ouicls.dispatch_hook(_pkt=_pkt, *args, **kargs) + cls = ouicls return cls + registered_ouis = {} + + @classmethod + def register_variant(cls): # XXX: We do not accept id, but our super-class does + oui = cls.oui.default + if oui not in cls.registered_ouis: + cls.registered_ouis[id] = cls + class Dot11EltMicrosoftWPA(Dot11EltVendorSpecific): name = "802.11 Microsoft WPA" @@ -1467,6 +1466,24 @@ class Dot11EltMicrosoftWPA(Dot11EltVendorSpecific): XByteField("type", 0x01) ] + Dot11EltRSN.fields_desc[2:8] + @classmethod + def dispatch_hook(cls, _pkt=None, *args, **kargs): + if _pkt: + type_ = orb(_pkt[5]) + if type_ == 0x01: + # MS WPA IE + return Dot11EltMicrosoftWPA + elif type_ == 0x02: + # MS WME IE TODO + # return Dot11EltMicrosoftWME + pass + elif type_ == 0x04: + # MS WPS IE TODO + # return Dot11EltWPS + pass + return Dot11EltVendorSpecific + return cls + # 802.11-2016 9.4.2.19 From d288a29595f0d4e78e5dd114933536d321de4365 Mon Sep 17 00:00:00 2001 From: Hoolean Date: Fri, 7 Feb 2025 22:45:05 +0000 Subject: [PATCH 2/5] Fix copy-paste typo --- scapy/layers/dot11.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scapy/layers/dot11.py b/scapy/layers/dot11.py index b691c69ef7a..bb73b32dea2 100644 --- a/scapy/layers/dot11.py +++ b/scapy/layers/dot11.py @@ -1452,7 +1452,7 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs): def register_variant(cls): # XXX: We do not accept id, but our super-class does oui = cls.oui.default if oui not in cls.registered_ouis: - cls.registered_ouis[id] = cls + cls.registered_ouis[oui] = cls class Dot11EltMicrosoftWPA(Dot11EltVendorSpecific): From 05b415423225d9542d9056343fcb016c9eaace20 Mon Sep 17 00:00:00 2001 From: Hoolean Date: Fri, 7 Feb 2025 22:50:03 +0000 Subject: [PATCH 3/5] Fix child register_variant swallowing call to parent register_variant --- scapy/layers/dot11.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scapy/layers/dot11.py b/scapy/layers/dot11.py index bb73b32dea2..d029f702b82 100644 --- a/scapy/layers/dot11.py +++ b/scapy/layers/dot11.py @@ -1451,6 +1451,10 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs): @classmethod def register_variant(cls): # XXX: We do not accept id, but our super-class does oui = cls.oui.default + if not oui: + # This is us, register ourselves in the super-class. + # TODO: Is there a better way to check? + super().register_variant() if oui not in cls.registered_ouis: cls.registered_ouis[oui] = cls From 9d8343d688504e2d9d08221da6f785dbc4a1af50 Mon Sep 17 00:00:00 2001 From: gpotter2 <10530980+gpotter2@users.noreply.github.com> Date: Mon, 21 Apr 2025 23:52:11 +0200 Subject: [PATCH 4/5] Fix 'TODO' --- scapy/layers/dot11.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scapy/layers/dot11.py b/scapy/layers/dot11.py index d029f702b82..de5f5d1dc01 100644 --- a/scapy/layers/dot11.py +++ b/scapy/layers/dot11.py @@ -1452,10 +1452,10 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs): def register_variant(cls): # XXX: We do not accept id, but our super-class does oui = cls.oui.default if not oui: - # This is us, register ourselves in the super-class. - # TODO: Is there a better way to check? + # This is Dot11EltVendorSpecific, register it in the super-class. super().register_variant() - if oui not in cls.registered_ouis: + elif oui not in cls.registered_ouis: + # Sub-Vendor (e.g. Dot11EltMicrosoftWPA) cls.registered_ouis[oui] = cls From 37c6521abbab82d6e64f4011e0a1ceb209d50fee Mon Sep 17 00:00:00 2001 From: gpotter2 <10530980+gpotter2@users.noreply.github.com> Date: Wed, 23 Apr 2025 08:45:05 +0200 Subject: [PATCH 5/5] Remove comment --- scapy/layers/dot11.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scapy/layers/dot11.py b/scapy/layers/dot11.py index de5f5d1dc01..862ed6686de 100644 --- a/scapy/layers/dot11.py +++ b/scapy/layers/dot11.py @@ -1449,7 +1449,7 @@ def dispatch_hook(cls, _pkt=None, *args, **kargs): registered_ouis = {} @classmethod - def register_variant(cls): # XXX: We do not accept id, but our super-class does + def register_variant(cls): oui = cls.oui.default if not oui: # This is Dot11EltVendorSpecific, register it in the super-class.