diff --git a/scapy/config.py b/scapy/config.py index a71c025aa66..bd9b4f0fbbd 100755 --- a/scapy/config.py +++ b/scapy/config.py @@ -832,6 +832,7 @@ class Conf(ConfClass): 'llmnr', 'lltd', 'mgcp', + 'mle', 'mobileip', 'netbios', 'netflow', diff --git a/scapy/layers/dot15d4.py b/scapy/layers/dot15d4.py index 9412c9dfea9..842eab37780 100644 --- a/scapy/layers/dot15d4.py +++ b/scapy/layers/dot15d4.py @@ -4,7 +4,7 @@ # Copyright (C) Ryan Speers 2011-2012 # Copyright (C) Roger Meyer : 2012-03-10 Added frames # Copyright (C) Gabriel Potter : 2018 -# Copyright (C) 2020 Dimitrios-Georgios Akestoridis +# Copyright (C) 2020, 2022 Dimitrios-Georgios Akestoridis # This program is published under a GPLv2 license """ @@ -36,6 +36,7 @@ XByteField, XLEIntField, XLEShortField, + XStrField, ) # Fields # @@ -233,9 +234,36 @@ class Dot15d4Data(Packet): lambda pkt:pkt.underlayer.getfieldval("fcf_srcaddrmode") != 0), # noqa: E501 # Security field present if fcf_security == True ConditionalField(PacketField("aux_sec_header", Dot15d4AuxSecurityHeader(), Dot15d4AuxSecurityHeader), # noqa: E501 - lambda pkt:pkt.underlayer.getfieldval("fcf_security") is True), # noqa: E501 + lambda pkt:pkt.underlayer.getfieldval("fcf_security")), # noqa: E501 + # Secured Payload (variable length) + ConditionalField( + XStrField("sec_payload", ""), + lambda pkt:pkt.underlayer.getfieldval("fcf_security"), + ), + # Message Integrity Code (variable length) + ConditionalField( + XStrField("mic", ""), + lambda pkt:pkt.underlayer.getfieldval("fcf_security"), + ), ] + def post_dissect(self, s): + if self.underlayer.getfieldval("fcf_security"): + if self.aux_sec_header.sec_sc_seclevel in {1, 5}: + mic_length = 4 + elif self.aux_sec_header.sec_sc_seclevel in {2, 6}: + mic_length = 8 + elif self.aux_sec_header.sec_sc_seclevel in {3, 7}: + mic_length = 16 + else: + mic_length = 0 + self.sec_payload = bytes(self.aux_sec_header.payload) + self.aux_sec_header.remove_payload() + if mic_length > 0 and mic_length <= len(self.sec_payload): + self.mic = self.sec_payload[-mic_length:] + self.sec_payload = self.sec_payload[:-mic_length] + return s + def guess_payload_class(self, payload): # TODO: See how it's done in wireshark: # https://github.com/wireshark/wireshark/blob/93c60b3b7c801dddd11d8c7f2a0ea4b7d02d700a/epan/dissectors/packet-ieee802154.c#L2061 # noqa: E501 @@ -268,7 +296,7 @@ class Dot15d4Beacon(Packet): dot15d4AddressField("src_addr", None, length_of="fcf_srcaddrmode"), # Security field present if fcf_security == True ConditionalField(PacketField("aux_sec_header", Dot15d4AuxSecurityHeader(), Dot15d4AuxSecurityHeader), # noqa: E501 - lambda pkt:pkt.underlayer.getfieldval("fcf_security") is True), # noqa: E501 + lambda pkt:pkt.underlayer.getfieldval("fcf_security")), # noqa: E501 # Superframe spec field: BitField("sf_sforder", 15, 4), # not used by ZigBee @@ -303,12 +331,137 @@ class Dot15d4Beacon(Packet): FieldListField("pa_long_addresses", [], dot15d4AddressField("", 0, adjust=lambda pkt, x: 8), count_from=lambda pkt: pkt.pa_num_long), - # TODO beacon payload + # Secured Payload (variable length) + ConditionalField( + XStrField("sec_payload", ""), + lambda pkt:pkt.underlayer.getfieldval("fcf_security"), + ), + # Message Integrity Code (variable length) + ConditionalField( + XStrField("mic", ""), + lambda pkt:pkt.underlayer.getfieldval("fcf_security"), + ), ] + def post_dissect(self, s): + if self.underlayer.getfieldval("fcf_security"): + if self.aux_sec_header.sec_sc_seclevel in {1, 5}: + mic_length = 4 + elif self.aux_sec_header.sec_sc_seclevel in {2, 6}: + mic_length = 8 + elif self.aux_sec_header.sec_sc_seclevel in {3, 7}: + mic_length = 16 + else: + mic_length = 0 + self.sec_payload = bytes(self.aux_sec_header.payload) + self.aux_sec_header.remove_payload() + if mic_length > 0 and mic_length <= len(self.sec_payload): + self.mic = self.sec_payload[-mic_length:] + self.sec_payload = self.sec_payload[:-mic_length] + i = 0 + if len(self.sec_payload) > i: + if isinstance(self.sec_payload[i], str): + tmp_val = struct.unpack(">B", self.sec_payload[i])[0] + else: + tmp_val = self.sec_payload[i] + self.sf_sforder = (tmp_val >> 4) & 0b1111 + self.sf_beaconorder = tmp_val & 0b1111 + i += 1 + if len(self.sec_payload) > i: + if isinstance(self.sec_payload[i], str): + tmp_val = struct.unpack(">B", self.sec_payload[i])[0] + else: + tmp_val = self.sec_payload[i] + self.sf_assocpermit = (tmp_val >> 7) & 0b1 + self.sf_pancoord = (tmp_val >> 6) & 0b1 + self.sf_reserved = (tmp_val >> 5) & 0b1 + self.sf_battlifeextend = (tmp_val >> 4) & 0b1 + self.sf_finalcapslot = tmp_val & 0b1111 + i += 1 + if len(self.sec_payload) > i: + if isinstance(self.sec_payload[i], str): + tmp_val = struct.unpack(">B", self.sec_payload[i])[0] + else: + tmp_val = self.sec_payload[i] + self.gts_spec_permit = (tmp_val >> 7) & 0b1 + self.gts_spec_reserved = (tmp_val >> 3) & 0b1111 + self.gts_spec_desccount = tmp_val & 0b111 + i += 1 + if self.gts_spec_desccount != 0 and len(self.sec_payload) > i: + if isinstance(self.sec_payload[i], str): + tmp_val = struct.unpack(">B", self.sec_payload[i])[0] + else: + tmp_val = self.sec_payload[i] + self.gts_dir_reserved = (tmp_val >> 7) & 0b1 + self.gts_dir_mask = tmp_val & 0b1111111 + i += 1 + # TODO: Update the GTS List field + if len(self.sec_payload) > i: + if isinstance(self.sec_payload[i], str): + tmp_val = struct.unpack(">B", self.sec_payload[i])[0] + else: + tmp_val = self.sec_payload[i] + self.pa_reserved_1 = (tmp_val >> 7) & 0b1 + self.pa_num_long = (tmp_val >> 4) & 0b111 + self.pa_reserved_2 = (tmp_val >> 3) & 0b1 + self.pa_num_short = tmp_val & 0b111 + i += 1 + for _ in range(self.pa_num_short): + if len(self.sec_payload) > i + 1: + if isinstance(self.sec_payload[i], str): + tmp_val = ( + struct.unpack(" i + 7: + if isinstance(self.sec_payload[i], str): + tmp_val = ( + struct.unpack(" 0: + if ( + (isinstance(payload[0], int) and payload[0] == 0x03) or + (isinstance(payload[0], bytes) and payload[0] == b'\x03') + ): + # https://gitlab.com/wireshark/wireshark/-/blob/5ecb57cb9026cebf0cfa4918c4a86942620c5ecf/epan/dissectors/packet-thread.c#L2223-2225 # noqa: E501 + return ThreadBeacon + elif ( + (isinstance(payload[0], int) and payload[0] == 0x00) or + (isinstance(payload[0], bytes) and payload[0] == b'\x00') + ): + # https://gitlab.com/wireshark/wireshark/-/blob/5ecb57cb9026cebf0cfa4918c4a86942620c5ecf/epan/dissectors/packet-zbee-nwk.c#L1507-1509 # noqa: E501 + return ZigBeeBeacon + return Packet.guess_payload_class(self, payload) + class Dot15d4Cmd(Packet): name = "802.15.4 Command" @@ -323,7 +476,7 @@ class Dot15d4Cmd(Packet): lambda pkt:pkt.underlayer.getfieldval("fcf_srcaddrmode") != 0), # noqa: E501 # Security field present if fcf_security == True ConditionalField(PacketField("aux_sec_header", Dot15d4AuxSecurityHeader(), Dot15d4AuxSecurityHeader), # noqa: E501 - lambda pkt:pkt.underlayer.getfieldval("fcf_security") is True), # noqa: E501 + lambda pkt:pkt.underlayer.getfieldval("fcf_security")), # noqa: E501 ByteEnumField("cmd_id", 0, { 1: "AssocReq", # Association request 2: "AssocResp", # Association response @@ -336,9 +489,41 @@ class Dot15d4Cmd(Packet): 9: "GTSReq" # GTS request # 0x0a - 0xff reserved }), - # TODO command payload + # Secured Payload (variable length) + ConditionalField( + XStrField("sec_payload", ""), + lambda pkt: pkt.underlayer.getfieldval("fcf_security"), + ), + # Message Integrity Code (variable length) + ConditionalField( + XStrField("mic", ""), + lambda pkt: pkt.underlayer.getfieldval("fcf_security"), + ), ] + def post_dissect(self, s): + if self.underlayer.getfieldval("fcf_security"): + if self.aux_sec_header.sec_sc_seclevel in {1, 5}: + mic_length = 4 + elif self.aux_sec_header.sec_sc_seclevel in {2, 6}: + mic_length = 8 + elif self.aux_sec_header.sec_sc_seclevel in {3, 7}: + mic_length = 16 + else: + mic_length = 0 + self.sec_payload = bytes(self.aux_sec_header.payload) + self.aux_sec_header.remove_payload() + if mic_length > 0 and mic_length <= len(self.sec_payload): + self.mic = self.sec_payload[-mic_length:] + self.sec_payload = self.sec_payload[:-mic_length] + if len(self.sec_payload) > 0: + if isinstance(self.sec_payload[0], str): + self.cmd_id = struct.unpack(">B", self.sec_payload[0])[0] + else: + self.cmd_id = self.sec_payload[0] + self.sec_payload = self.sec_payload[1:] + return s + def mysummary(self): return self.sprintf("802.15.4 Command %Dot15d4Cmd.cmd_id% ( %Dot15dCmd.src_panid%:%Dot15d4Cmd.src_addr% -> %Dot15d4Cmd.dest_panid%:%Dot15d4Cmd.dest_addr% )") # noqa: E501 diff --git a/scapy/layers/mle.py b/scapy/layers/mle.py new file mode 100644 index 00000000000..6ad6946cacf --- /dev/null +++ b/scapy/layers/mle.py @@ -0,0 +1,117 @@ +# This file is part of Scapy +# See http://www.secdev.org/projects/scapy for more information +# Copyright (C) 2022 Dimitrios-Georgios Akestoridis +# This program is published under a GPLv2 license + +""" +MLE (Mesh Link Establishment) +============================= + +For more information, please refer to the following files: + +* https://datatracker.ietf.org/doc/html/draft-ietf-6lo-mesh-link-establishment-00 + +* https://doi.org/10.1109/IEEESTD.2006.232110 + +* https://gitlab.com/wireshark/wireshark/-/blob/5ecb57cb9026cebf0cfa4918c4a86942620c5ecf/epan/dissectors/packet-mle.c + +""" # noqa: E501 + +from scapy.fields import ( + ByteEnumField, + ConditionalField, + PacketField, + XStrField, +) +from scapy.layers.dot15d4 import Dot15d4AuxSecurityHeader +from scapy.layers.inet import UDP +from scapy.packet import ( + Packet, + bind_layers, +) + + +class MLE(Packet): + name = "Mesh Link Establishment" + fields_desc = [ + ByteEnumField( + "sec_suite", + 0, + { + 0: "IEEE 802.15.4 Security (0)", + 255: "No Security (255)", + }, + ), + ConditionalField( + PacketField( + "aux_sec_header", + Dot15d4AuxSecurityHeader(), + Dot15d4AuxSecurityHeader, + ), + lambda pkt: pkt.sec_suite == 0, + ), + ConditionalField( + XStrField("sec_payload", ""), + lambda pkt: pkt.sec_suite == 0, + ), + ConditionalField( + XStrField("mic", ""), + lambda pkt: pkt.sec_suite == 0, + ), + ] + + def post_dissect(self, s): + if self.sec_suite == 0: + if self.aux_sec_header.sec_sc_seclevel in {1, 5}: + mic_length = 4 + elif self.aux_sec_header.sec_sc_seclevel in {2, 6}: + mic_length = 8 + elif self.aux_sec_header.sec_sc_seclevel in {3, 7}: + mic_length = 16 + else: + mic_length = 0 + self.sec_payload = bytes(self.aux_sec_header.payload) + self.aux_sec_header.remove_payload() + if mic_length > 0 and mic_length <= len(self.sec_payload): + self.mic = self.sec_payload[-mic_length:] + self.sec_payload = self.sec_payload[:-mic_length] + return s + + def guess_payload_class(self, payload): + if self.sec_suite == 255: + return MLECmd + return Packet.guess_payload_class(self, payload) + + +class MLECmd(Packet): + name = "Mesh Link Establishment Command" + fields_desc = [ + ByteEnumField( + "cmd_type", + 0, + { + 0: "Link Request (0)", + 1: "Link Accept (1)", + 2: "Link Accept and Request (2)", + 3: "Link Reject (3)", + 4: "Advertisement (4)", + 5: "Update (5)", + 6: "Update Request (6)", + 7: "Data Request (7)", + 8: "Data Response (8)", + 9: "Parent Request (9)", + 10: "Parent Response (10)", + 11: "Child ID Request (11)", + 12: "Child ID Response (12)", + 13: "Child Update Request (13)", + 14: "Child Update Response (14)", + 15: "Announce (15)", + 16: "Discovery Request (16)", + 17: "Discovery Response (17)", + }, + ), + # TODO: Dissect the command payload + ] + + +bind_layers(UDP, MLE, sport=19788, dport=19788) diff --git a/scapy/layers/sixlowpan.py b/scapy/layers/sixlowpan.py index 351139888ef..dfd9c59ac8d 100644 --- a/scapy/layers/sixlowpan.py +++ b/scapy/layers/sixlowpan.py @@ -3,6 +3,7 @@ # Copyright (C) Cesar A. Bernardini # Intern at INRIA Grand Nancy Est # Copyright (C) Gabriel Potter +# Copyright (C) 2022 Dimitrios-Georgios Akestoridis # This program is published under a GPLv2 license """ 6LoWPAN Protocol Stack @@ -73,7 +74,10 @@ XShortField, ) -from scapy.layers.dot15d4 import Dot15d4Data +from scapy.layers.dot15d4 import ( + Dot15d4Data, + dot15d4AddressField, +) from scapy.layers.inet6 import ( IP6Field, IPv6, @@ -156,6 +160,10 @@ class LoWPANMesh(Packet): BitEnumField("v", 0x0, 1, ["EUI-64", "Short"]), BitEnumField("f", 0x0, 1, ["EUI-64", "Short"]), BitField("hopsLeft", 0x0, 4), + ConditionalField( + ByteField("deepHopsLeft", 0x0), + lambda pkt: pkt.hopsLeft == 0b1111, + ), MultipleTypeField( [(XShortField("src", 0x0), lambda pkt: pkt.v == 1)], XLongField("src", 0x0) @@ -520,11 +528,12 @@ def _extract_upperaddress(pkt, source=True): elif type(underlayer) == Dot15d4Data: addr = underlayer.src_addr if source else underlayer.dest_addr addr = struct.pack(">Q", addr) - if underlayer.underlayer.fcf_destaddrmode == 3: # Extended/long + addrmode = underlayer.underlayer.fcf_srcaddrmode if source else underlayer.underlayer.fcf_destaddrmode # noqa: E501 + if addrmode == 3: # Extended/long tmp_ip = LINK_LOCAL_PREFIX[0:8] + addr # Turn off the bit 7. return tmp_ip[0:8] + struct.pack("B", (orb(tmp_ip[8]) ^ 0x2)) + tmp_ip[9:16] # noqa: E501 - elif underlayer.underlayer.fcf_destaddrmode == 2: # Short + elif addrmode == 2: # Short return ( LINK_LOCAL_PREFIX[0:8] + b"\x00\x00\x00\xff\xfe\x00" + @@ -547,33 +556,79 @@ class LoWPAN_IPHC(Packet): __slots__ = ["_ipv6"] # the LOWPAN_IPHC encoding utilizes 13 bits, 5 dispatch type name = "LoWPAN IP Header Compression Packet" - _address_modes = ["Unspecified (0)", "1", "16-bits inline (3)", - "Compressed (3)"] - _state_mode = ["Stateless (0)", "Stateful (1)"] + _compression_modes = ["Stateless (0)", "Stateful (1)"] + _stateless_unicast_address_modes = [ + "128 bits are present (0)", + "64 bits are present (1)", + "16 bits are present (2)", + "0 bits are present (3)", + ] deprecated_fields = { "_nhField": ("nhField", "2.4.4"), "_hopLimit": ("hopLimit", "2.4.4"), "sourceAddr": ("src", "2.4.4"), "destinyAddr": ("dst", "2.4.4"), "udpDestinyPort": ("udpDestPort", "2.4.4"), + "_reserved": ("reserved", "2.5.0"), } fields_desc = [ - # Base Format https://tools.ietf.org/html/rfc6282#section-3.1.2 - BitField("_reserved", 0x03, 3), - BitField("tf", 0x0, 2), - BitEnumField("nh", 0x0, 1, ["Inline", "Compressed"]), - BitEnumField("hlim", 0x0, 2, {0: "Inline", - 1: "Compressed/HL1", - 2: "Compressed/HL64", - 3: "Compressed/HL255"}), - BitEnumField("cid", 0x0, 1, {1: "Present (1)"}), - BitEnumField("sac", 0x0, 1, _state_mode), - BitEnumField("sam", 0x0, 2, _address_modes), - BitEnumField("m", 0x0, 1, {1: "multicast (1)"}), - BitEnumField("dac", 0x0, 1, _state_mode), - BitEnumField("dam", 0x0, 2, _address_modes), - # https://tools.ietf.org/html/rfc6282#section-3.1.2 + # Base Format + # https://tools.ietf.org/html/rfc6282#section-3.1.1 + BitField("reserved", 0x03, 3), + BitEnumField("tf", 0x0, 2, ["In-line ECN, DSCP, and FL (0)", + "In-line ECN and FL; Compressed DSCP (1)", + "In-line ECN and DSCP; Compressed FL (2)", + "Compressed ECN, DSCP, and FL (3)"]), + BitEnumField("nh", 0x0, 1, ["In-line (0)", "Compressed (1)"]), + BitEnumField("hlim", 0x0, 2, ["In-line (0)", + "Compressed; Hop limit is 1 (1)", + "Compressed; Hop limit is 64 (2)", + "Compressed; Hop limit is 255 (3)"]), + BitEnumField("cid", 0x0, 1, ["Absent (0)", "Present (1)"]), + BitEnumField("sac", 0x0, 1, _compression_modes), + MultipleTypeField( + [ + ( + BitEnumField("sam", 0x0, 2, ["Unspecified address (0)", + "64 bits are present (1)", + "16 bits are present (2)", + "0 bits are present (3)"]), + lambda pkt: pkt.sac == 1, + ), + ], + BitEnumField("sam", 0x0, 2, _stateless_unicast_address_modes), + ), + BitEnumField("m", 0x0, 1, ["Not multicasting (0)", + "Multicasting (1)"]), + BitEnumField("dac", 0x0, 1, _compression_modes), + MultipleTypeField( + [ + ( + BitEnumField("dam", 0x0, 2, ["Reserved (0)", + "64 bits are present (1)", + "16 bits are present (2)", + "0 bits are present (3)"]), + lambda pkt: pkt.m == 0 and pkt.dac == 1, + ), + ( + BitEnumField("dam", 0x0, 2, ["128 bits are present (0)", + "48 bits are present (1)", + "32 bits are present (2)", + "8 bits are present (3)"]), + lambda pkt: pkt.m == 1 and pkt.dac == 0, + ), + ( + BitEnumField("dam", 0x0, 2, ["48 bits are present (0)", + "Reserved (1)", + "Reserved (2)", + "Reserved (3)"]), + lambda pkt: pkt.m == 1 and pkt.dac == 1, + ), + ], + BitEnumField("dam", 0x0, 2, _stateless_unicast_address_modes), + ), # Context Identifier Extension + # https://tools.ietf.org/html/rfc6282#section-3.1.2 ConditionalField( BitField("sci", 0, 4), lambda pkt: pkt.cid == 0x1 @@ -582,6 +637,7 @@ class LoWPAN_IPHC(Packet): BitField("dci", 0, 4), lambda pkt: pkt.cid == 0x1 ), + # Traffic Class and Flow Label Compression # https://tools.ietf.org/html/rfc6282#section-3.2.1 ConditionalField( BitField("tc_ecn", 0, 2), @@ -602,7 +658,8 @@ class LoWPAN_IPHC(Packet): BitField("flowlabel", 0, 20), lambda pkt: pkt.tf in [0, 1] ), - # Inline fields https://tools.ietf.org/html/rfc6282#section-3.1.1 + # In-line Fields + # https://tools.ietf.org/html/rfc6282#section-3.1.1 ConditionalField( ByteEnumField("nhField", 0x0, ipv6nh), lambda pkt: pkt.nh == 0x0 @@ -815,7 +872,7 @@ def do_build(self): return Packet.do_build(self) ipv6 = _cur.payload - self._reserved = 0x03 + self.reserved = 0x03 # NEW COMPRESSION TECHNIQUE! # a ) Compression Techniques @@ -1084,6 +1141,7 @@ def guess_payload_class(self, payload): ###################### # https://tools.ietf.org/html/rfc4944#section-5.1 +# https://doi.org/10.17487/rfc6282 class SixLoWPAN_ESC(Packet): name = "SixLoWPAN Dispatcher ESC" @@ -1098,22 +1156,22 @@ def dispatch_hook(cls, _pkt=b"", *args, **kargs): """Depending on the payload content, the frame type we should interpretate""" # noqa: E501 if _pkt and len(_pkt) >= 1: fb = ord(_pkt[:1]) - if fb == 0x41: - return LoWPANUncompressedIPv6 - if fb == 0x42: - return LoWPAN_HC1 + if fb >> 6 == 0x02: + return LoWPANMesh if fb == 0x50: return LoWPANBroadcast - if fb == 0x7f: - return SixLoWPAN_ESC if fb >> 3 == 0x18: return LoWPANFragmentationFirst if fb >> 3 == 0x1C: return LoWPANFragmentationSubsequent - if fb >> 6 == 0x02: - return LoWPANMesh - if fb >> 6 == 0x01: + if fb >> 5 == 0x03: return LoWPAN_IPHC + if fb == 0x40: + return SixLoWPAN_ESC + if fb == 0x41: + return LoWPANUncompressedIPv6 + if fb == 0x42: + return LoWPAN_HC1 return cls @@ -1169,6 +1227,34 @@ def sixlowpan_defragment(packet_list): results[tag] = results.get(tag, b"") + p[cls].payload.load # noqa: E501 return {tag: SixLoWPAN(x) for tag, x in results.items()} + +################## +# Beacon Payload # +################## + + +class ThreadBeacon(Packet): + name = "Thread Beacon Payload" + fields_desc = [ + # https://gitlab.com/wireshark/wireshark/-/blob/5ecb57cb9026cebf0cfa4918c4a86942620c5ecf/epan/dissectors/packet-thread.c#L3293-3315 # noqa: E501 + # https://gitlab.com/wireshark/wireshark/-/blob/5ecb57cb9026cebf0cfa4918c4a86942620c5ecf/epan/dissectors/packet-thread.c#L2147-2169 # noqa: E501 + ByteField("protocol_id", 3), + BitField("version", 2, 4), + BitField("native", 0, 1), + BitField("reserved", 0, 2), + BitField("joining", 0, 1), + StrFixedLenField("network_name", None, 16), + dot15d4AddressField( + "extended_pan_id", + 0, + fmt=">H", + adjust=lambda pkt, x: 8, + ), + # https://gitlab.com/wireshark/wireshark/-/blob/5ecb57cb9026cebf0cfa4918c4a86942620c5ecf/epan/dissectors/packet-thread.c#L2171-2174 # noqa: E501 + # TODO: Check for additional fields + ] + + ############ # Bindings # ############ diff --git a/scapy/layers/zigbee.py b/scapy/layers/zigbee.py index 501da5f96bd..5b2e4d0a434 100644 --- a/scapy/layers/zigbee.py +++ b/scapy/layers/zigbee.py @@ -4,7 +4,7 @@ # Copyright (C) Ryan Speers 2011-2012 # Copyright (C) Roger Meyer : 2012-03-10 Added frames # Copyright (C) Gabriel Potter : 2018 -# Copyright (C) 2020-2021 Dimitrios-Georgios Akestoridis +# Copyright (C) 2020-2022 Dimitrios-Georgios Akestoridis # This program is published under a GPLv2 license """ @@ -20,8 +20,7 @@ IntField, PacketListField, ShortField, StrField, StrFixedLenField, \ StrLenField, XLEShortField, XStrField -from scapy.layers.dot15d4 import dot15d4AddressField, Dot15d4Beacon, Dot15d4, \ - Dot15d4FCS +from scapy.layers.dot15d4 import dot15d4AddressField, Dot15d4, Dot15d4FCS from scapy.layers.inet import UDP from scapy.layers.ntp import TimeStampField @@ -1483,7 +1482,6 @@ class ZEP1(ZEP2): # bind_layers( Dot15d4Data, ZigbeeNWK) bind_layers(ZigbeeAppDataPayload, ZigbeeAppCommandPayload, frametype=1) -bind_layers(Dot15d4Beacon, ZigBeeBeacon) bind_bottom_up(UDP, ZEP2, sport=17754) bind_bottom_up(UDP, ZEP2, sport=17754) diff --git a/test/scapy/layers/dot15d4.uts b/test/scapy/layers/dot15d4.uts index c3a782a93db..53df6e90800 100644 --- a/test/scapy/layers/dot15d4.uts +++ b/test/scapy/layers/dot15d4.uts @@ -29,18 +29,20 @@ assert Dot15d4FCS in pkt.layers() pkt = Ether()/IP()/Dot15d4FCS() assert pkt[Dot15d4] -= Dot15d4FCS - Beacon (without pending addresses) += Dot15d4FCS - Zigbee Beacon (without pending addresses) pkt = Dot15d4FCS(b'\x00\x80\x89\xaa\x99\x00\x00\xff\xcf\x00\x00\x00"\x84\xfe\xca\xef\xbe\xed\xfe\xce\xfa\xff\xff\xff\x00X\xa4') assert Dot15d4FCS in pkt.layers() -assert pkt[Dot15d4FCS].fcf_frametype == 0 +assert pkt[Dot15d4FCS].fcf_frametype == 0b000 assert pkt[Dot15d4FCS].fcf_security == False assert pkt[Dot15d4FCS].fcf_pending == False assert pkt[Dot15d4FCS].fcf_ackreq == False assert pkt[Dot15d4FCS].fcf_panidcompress == False -assert pkt[Dot15d4FCS].fcf_destaddrmode == 0 -assert pkt[Dot15d4FCS].fcf_framever == 0 -assert pkt[Dot15d4FCS].fcf_srcaddrmode == 2 +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b00 +assert pkt[Dot15d4FCS].fcf_framever == 0b00 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b10 assert pkt[Dot15d4FCS].seqnum == 137 assert Dot15d4Beacon in pkt.layers() assert pkt[Dot15d4Beacon].src_panid == 0x99aa @@ -59,20 +61,34 @@ assert pkt[Dot15d4Beacon].pa_num_long == 0 assert pkt[Dot15d4Beacon].pa_short_addresses == [] assert pkt[Dot15d4Beacon].pa_long_addresses == [] assert raw(pkt[Dot15d4Beacon].payload) == b'\x00"\x84\xfe\xca\xef\xbe\xed\xfe\xce\xfa\xff\xff\xff\x00' +assert ZigBeeBeacon in pkt.layers() +assert pkt[ZigBeeBeacon].proto_id == 0x00 +assert pkt[ZigBeeBeacon].stack_profile == 0b0010 +assert pkt[ZigBeeBeacon].nwkc_protocol_version == 0b0010 +assert pkt[ZigBeeBeacon].reserved == 0b00 +assert pkt[ZigBeeBeacon].router_capacity == 0b1 +assert pkt[ZigBeeBeacon].device_depth == 0b0000 +assert pkt[ZigBeeBeacon].end_device_capacity == 0b1 +assert pkt[ZigBeeBeacon].extended_pan_id == 0xfacefeedbeefcafe +assert pkt[ZigBeeBeacon].tx_offset == 16777215 +assert pkt[ZigBeeBeacon].update_id == 0 +assert raw(pkt[ZigBeeBeacon].payload) == b'' assert pkt[Dot15d4FCS].fcs == 0xa458 -= Dot15d4FCS - Beacon (with pending addresses) += Dot15d4FCS - Zigbee Beacon (with pending addresses) pkt = Dot15d4FCS(b'\x00\x80\x89\xaa\x99\x00\x00\xff\xcf\x00\x124\x12xV\x88wfUD3"\x11\x00"\x84\xfe\xca\xef\xbe\xed\xfe\xce\xfa\xff\xff\xff\x00\x96\xd3') assert Dot15d4FCS in pkt.layers() -assert pkt[Dot15d4FCS].fcf_frametype == 0 +assert pkt[Dot15d4FCS].fcf_frametype == 0b000 assert pkt[Dot15d4FCS].fcf_security == False assert pkt[Dot15d4FCS].fcf_pending == False assert pkt[Dot15d4FCS].fcf_ackreq == False assert pkt[Dot15d4FCS].fcf_panidcompress == False -assert pkt[Dot15d4FCS].fcf_destaddrmode == 0 -assert pkt[Dot15d4FCS].fcf_framever == 0 -assert pkt[Dot15d4FCS].fcf_srcaddrmode == 2 +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b00 +assert pkt[Dot15d4FCS].fcf_framever == 0b00 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b10 assert pkt[Dot15d4FCS].seqnum == 137 assert Dot15d4Beacon in pkt.layers() assert pkt[Dot15d4Beacon].src_panid == 0x99aa @@ -91,20 +107,160 @@ assert pkt[Dot15d4Beacon].pa_num_long == 1 assert pkt[Dot15d4Beacon].pa_short_addresses == [0x1234, 0x5678] assert pkt[Dot15d4Beacon].pa_long_addresses == [0x1122334455667788] assert raw(pkt[Dot15d4Beacon].payload) == b'\x00"\x84\xfe\xca\xef\xbe\xed\xfe\xce\xfa\xff\xff\xff\x00' +assert ZigBeeBeacon in pkt.layers() +assert pkt[ZigBeeBeacon].proto_id == 0x00 +assert pkt[ZigBeeBeacon].stack_profile == 0b0010 +assert pkt[ZigBeeBeacon].nwkc_protocol_version == 0b0010 +assert pkt[ZigBeeBeacon].reserved == 0b00 +assert pkt[ZigBeeBeacon].router_capacity == 0b1 +assert pkt[ZigBeeBeacon].device_depth == 0b0000 +assert pkt[ZigBeeBeacon].end_device_capacity == 0b1 +assert pkt[ZigBeeBeacon].extended_pan_id == 0xfacefeedbeefcafe +assert pkt[ZigBeeBeacon].tx_offset == 16777215 +assert pkt[ZigBeeBeacon].update_id == 0 +assert raw(pkt[ZigBeeBeacon].payload) == b'' assert pkt[Dot15d4FCS].fcs == 0xd396 += Dot15d4FCS - Thread Beacon + +pkt = Dot15d4FCS(b'\x00\xc0\xed\xee\xdd\x01\x00\x00\x00\x00\x99\x99\x99\xff\x0f\x00\x00\x03 TestName\x00\x00\x00\x00\x00\x00\x00\x00\xfa\xce\xfe\xed\xbe\xef\xca\xfef\xaa') +assert Dot15d4FCS in pkt.layers() +assert pkt[Dot15d4FCS].fcf_frametype == 0b000 +assert pkt[Dot15d4FCS].fcf_security == False +assert pkt[Dot15d4FCS].fcf_pending == False +assert pkt[Dot15d4FCS].fcf_ackreq == False +assert pkt[Dot15d4FCS].fcf_panidcompress == False +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b00 +assert pkt[Dot15d4FCS].fcf_framever == 0b00 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b11 +assert pkt[Dot15d4FCS].seqnum == 237 +assert Dot15d4Beacon in pkt.layers() +assert pkt[Dot15d4Beacon].src_panid == 0xddee +assert pkt[Dot15d4Beacon].src_addr == 0x9999990000000001 +assert pkt[Dot15d4Beacon].sf_beaconorder == 15 +assert pkt[Dot15d4Beacon].sf_sforder == 15 +assert pkt[Dot15d4Beacon].sf_finalcapslot == 15 +assert pkt[Dot15d4Beacon].sf_battlifeextend == False +assert pkt[Dot15d4Beacon].sf_pancoord == False +assert pkt[Dot15d4Beacon].sf_assocpermit == False +assert pkt[Dot15d4Beacon].gts_spec_permit == False +assert pkt[Dot15d4Beacon].gts_spec_reserved == 0 +assert pkt[Dot15d4Beacon].gts_spec_desccount == 0 +assert pkt[Dot15d4Beacon].pa_num_short == 0 +assert pkt[Dot15d4Beacon].pa_num_long == 0 +assert pkt[Dot15d4Beacon].pa_short_addresses == [] +assert pkt[Dot15d4Beacon].pa_long_addresses == [] +assert ThreadBeacon in pkt.layers() +assert pkt[ThreadBeacon].protocol_id == 0x03 +assert pkt[ThreadBeacon].version == 0b0010 +assert pkt[ThreadBeacon].native == 0b0 +assert pkt[ThreadBeacon].reserved == 0b00 +assert pkt[ThreadBeacon].joining == 0b0 +assert pkt[ThreadBeacon].network_name == b'TestName\x00\x00\x00\x00\x00\x00\x00\x00' +assert pkt[ThreadBeacon].extended_pan_id == 0xfacefeedbeefcafe +assert raw(pkt[ThreadBeacon].payload) == b'' +assert pkt[Dot15d4FCS].fcs == 0xaa66 + += Dot15d4FCS - Secured MAC Beacon (MIC-64) + +pkt = Dot15d4FCS(b'\x08\xd0\xbd\xdd\xcc\x01\x00\x00\x00\x00www\x02Q\x01\x00\x00\xff\xcf\x00\x124\x12xV\x88wfUD3"\x11PAYLOAD\x13\x1ae\x02\xec-\xe9\x1d*\xc4') +assert Dot15d4FCS in pkt.layers() +assert pkt[Dot15d4FCS].fcf_frametype == 0b000 +assert pkt[Dot15d4FCS].fcf_security == True +assert pkt[Dot15d4FCS].fcf_pending == False +assert pkt[Dot15d4FCS].fcf_ackreq == False +assert pkt[Dot15d4FCS].fcf_panidcompress == False +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b00 +assert pkt[Dot15d4FCS].fcf_framever == 0b01 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b11 +assert pkt[Dot15d4FCS].seqnum == 189 +assert Dot15d4Beacon in pkt.layers() +assert pkt[Dot15d4Beacon].src_panid == 0xccdd +assert pkt[Dot15d4Beacon].src_addr == 0x7777770000000001 +assert raw(pkt[Dot15d4Beacon].aux_sec_header) == b'\x02Q\x01\x00\x00' +assert pkt[Dot15d4Beacon].aux_sec_header.sec_sc_seclevel == 0b010 +assert pkt[Dot15d4Beacon].aux_sec_header.sec_sc_keyidmode == 0b00 +assert pkt[Dot15d4Beacon].aux_sec_header.sec_sc_reserved == 0b000 +assert pkt[Dot15d4Beacon].aux_sec_header.sec_framecounter == 337 +assert pkt[Dot15d4Beacon].aux_sec_header.sec_keyid_keysource == b'' +assert pkt[Dot15d4Beacon].sf_beaconorder == 15 +assert pkt[Dot15d4Beacon].sf_sforder == 15 +assert pkt[Dot15d4Beacon].sf_finalcapslot == 15 +assert pkt[Dot15d4Beacon].sf_battlifeextend == False +assert pkt[Dot15d4Beacon].sf_pancoord == True +assert pkt[Dot15d4Beacon].sf_assocpermit == True +assert pkt[Dot15d4Beacon].gts_spec_permit == False +assert pkt[Dot15d4Beacon].gts_spec_reserved == 0 +assert pkt[Dot15d4Beacon].gts_spec_desccount == 0 +assert pkt[Dot15d4Beacon].pa_num_short == 2 +assert pkt[Dot15d4Beacon].pa_num_long == 1 +assert pkt[Dot15d4Beacon].pa_short_addresses == [0x1234, 0x5678] +assert pkt[Dot15d4Beacon].pa_long_addresses == [0x1122334455667788] +assert pkt[Dot15d4Beacon].sec_payload == b'PAYLOAD' +assert pkt[Dot15d4Beacon].mic == b'\x13\x1ae\x02\xec-\xe9\x1d' +assert raw(pkt[Dot15d4Beacon].payload) == b'' +assert pkt[Dot15d4FCS].fcs == 0xc42a + += Dot15d4FCS - Secured MAC Beacon (ENC) + +pkt = Dot15d4FCS(b'\x08\xd0\xbd\xdd\xcc\x01\x00\x00\x00\x00www\x04\xb5\x01\x00\x00\xff\xcf\x00\x00U+\x9bW]\x92\xd3\xebE') +assert Dot15d4FCS in pkt.layers() +assert pkt[Dot15d4FCS].fcf_frametype == 0b000 +assert pkt[Dot15d4FCS].fcf_security == True +assert pkt[Dot15d4FCS].fcf_pending == False +assert pkt[Dot15d4FCS].fcf_ackreq == False +assert pkt[Dot15d4FCS].fcf_panidcompress == False +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b00 +assert pkt[Dot15d4FCS].fcf_framever == 0b01 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b11 +assert pkt[Dot15d4FCS].seqnum == 189 +assert Dot15d4Beacon in pkt.layers() +assert pkt[Dot15d4Beacon].src_panid == 0xccdd +assert pkt[Dot15d4Beacon].src_addr == 0x7777770000000001 +assert raw(pkt[Dot15d4Beacon].aux_sec_header) == b'\x04\xb5\x01\x00\x00' +assert pkt[Dot15d4Beacon].aux_sec_header.sec_sc_seclevel == 0b100 +assert pkt[Dot15d4Beacon].aux_sec_header.sec_sc_keyidmode == 0b00 +assert pkt[Dot15d4Beacon].aux_sec_header.sec_sc_reserved == 0b000 +assert pkt[Dot15d4Beacon].aux_sec_header.sec_framecounter == 437 +assert pkt[Dot15d4Beacon].aux_sec_header.sec_keyid_keysource == b'' +assert pkt[Dot15d4Beacon].sf_beaconorder == 15 +assert pkt[Dot15d4Beacon].sf_sforder == 15 +assert pkt[Dot15d4Beacon].sf_finalcapslot == 15 +assert pkt[Dot15d4Beacon].sf_battlifeextend == False +assert pkt[Dot15d4Beacon].sf_pancoord == True +assert pkt[Dot15d4Beacon].sf_assocpermit == True +assert pkt[Dot15d4Beacon].gts_spec_permit == False +assert pkt[Dot15d4Beacon].gts_spec_reserved == 0 +assert pkt[Dot15d4Beacon].gts_spec_desccount == 0 +assert pkt[Dot15d4Beacon].pa_num_short == 0 +assert pkt[Dot15d4Beacon].pa_num_long == 0 +assert pkt[Dot15d4Beacon].pa_short_addresses == [] +assert pkt[Dot15d4Beacon].pa_long_addresses == [] +assert pkt[Dot15d4Beacon].sec_payload == b'U+\x9bW]\x92\xd3' +assert pkt[Dot15d4Beacon].mic == b'' +assert raw(pkt[Dot15d4Beacon].payload) == b'' +assert pkt[Dot15d4FCS].fcs == 0x45eb + = Dot15d4FCS - Coordinator Realignment (without the channel page) pkt = Dot15d4FCS(b'#\xcc\x89\xff\xff\x88wfUD3"\x11\xaa\x99\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x08\xaa\x99\xde\xc0\x14\xad\xde\\!') assert Dot15d4FCS in pkt.layers() -assert pkt[Dot15d4FCS].fcf_frametype == 3 +assert pkt[Dot15d4FCS].fcf_frametype == 0b011 assert pkt[Dot15d4FCS].fcf_security == False assert pkt[Dot15d4FCS].fcf_pending == False assert pkt[Dot15d4FCS].fcf_ackreq == True assert pkt[Dot15d4FCS].fcf_panidcompress == False -assert pkt[Dot15d4FCS].fcf_destaddrmode == 3 -assert pkt[Dot15d4FCS].fcf_framever == 0 -assert pkt[Dot15d4FCS].fcf_srcaddrmode == 3 +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b11 +assert pkt[Dot15d4FCS].fcf_framever == 0b00 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b11 assert pkt[Dot15d4FCS].seqnum == 137 assert Dot15d4Cmd in pkt.layers() assert pkt[Dot15d4Cmd].dest_panid == 0xffff @@ -124,14 +280,16 @@ assert pkt[Dot15d4FCS].fcs == 0x215c pkt = Dot15d4FCS(b'#\xcc\x89\xff\xff\x88wfUD3"\x11\xaa\x99\xff\xee\xdd\xcc\xbb\xaa\x99\x88\x08\xaa\x99\xde\xc0\x14\xad\xde\x00\xc8\x98') assert Dot15d4FCS in pkt.layers() -assert pkt[Dot15d4FCS].fcf_frametype == 3 +assert pkt[Dot15d4FCS].fcf_frametype == 0b011 assert pkt[Dot15d4FCS].fcf_security == False assert pkt[Dot15d4FCS].fcf_pending == False assert pkt[Dot15d4FCS].fcf_ackreq == True assert pkt[Dot15d4FCS].fcf_panidcompress == False -assert pkt[Dot15d4FCS].fcf_destaddrmode == 3 -assert pkt[Dot15d4FCS].fcf_framever == 0 -assert pkt[Dot15d4FCS].fcf_srcaddrmode == 3 +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b11 +assert pkt[Dot15d4FCS].fcf_framever == 0b00 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b11 assert pkt[Dot15d4FCS].seqnum == 137 assert Dot15d4Cmd in pkt.layers() assert pkt[Dot15d4Cmd].dest_panid == 0xffff @@ -149,6 +307,123 @@ assert pkt[Dot15d4CmdCoordRealignPage].channel_page == 0 assert raw(pkt[Dot15d4CmdCoordRealignPage].payload) == b'' assert pkt[Dot15d4FCS].fcs == 0x98c8 += Dot15d4FCS - Data Request (with MAC-layer security disabled) + +pkt = Dot15d4FCS(b'c\x88d\xcc\xbb\x00\x00z\xfe\x04-\xbb') +assert Dot15d4FCS in pkt.layers() +assert pkt[Dot15d4FCS].fcf_frametype == 0b011 +assert pkt[Dot15d4FCS].fcf_security == False +assert pkt[Dot15d4FCS].fcf_pending == False +assert pkt[Dot15d4FCS].fcf_ackreq == True +assert pkt[Dot15d4FCS].fcf_panidcompress == True +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b10 +assert pkt[Dot15d4FCS].fcf_framever == 0b00 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b10 +assert pkt[Dot15d4FCS].seqnum == 100 +assert Dot15d4Cmd in pkt.layers() +assert pkt[Dot15d4Cmd].dest_panid == 0xbbcc +assert pkt[Dot15d4Cmd].dest_addr == 0x0000 +assert pkt[Dot15d4Cmd].src_addr == 0xfe7a +assert pkt[Dot15d4Cmd].cmd_id == 0x04 +assert raw(pkt[Dot15d4Cmd].payload) == b'' +assert pkt[Dot15d4FCS].fcs == 0xbb2d + += Dot15d4FCS - Data Request (with MAC-layer security enabled) + +pkt = Dot15d4FCS(b'k\x98\x91\xde\xc0\x00\x84\x01\x84\r\x89\x00\x00\x00\x01\x04\x9cP\x8c\x958\xca') +assert Dot15d4FCS in pkt.layers() +assert pkt[Dot15d4FCS].fcf_frametype == 0b011 +assert pkt[Dot15d4FCS].fcf_security == True +assert pkt[Dot15d4FCS].fcf_pending == False +assert pkt[Dot15d4FCS].fcf_ackreq == True +assert pkt[Dot15d4FCS].fcf_panidcompress == True +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b10 +assert pkt[Dot15d4FCS].fcf_framever == 0b01 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b10 +assert pkt[Dot15d4FCS].seqnum == 145 +assert Dot15d4Cmd in pkt.layers() +assert pkt[Dot15d4Cmd].dest_panid == 0xc0de +assert pkt[Dot15d4Cmd].dest_addr == 0x8400 +assert pkt[Dot15d4Cmd].src_addr == 0x8401 +assert raw(pkt[Dot15d4Cmd].aux_sec_header) == b'\r\x89\x00\x00\x00\x01' +assert pkt[Dot15d4Cmd].aux_sec_header.sec_sc_seclevel == 0b101 +assert pkt[Dot15d4Cmd].aux_sec_header.sec_sc_keyidmode == 0b01 +assert pkt[Dot15d4Cmd].aux_sec_header.sec_sc_reserved == 0b000 +assert pkt[Dot15d4Cmd].aux_sec_header.sec_framecounter == 137 +assert pkt[Dot15d4Cmd].aux_sec_header.sec_keyid_keysource == b'' +assert pkt[Dot15d4Cmd].aux_sec_header.sec_keyid_keyindex == 0x01 +assert pkt[Dot15d4Cmd].cmd_id == 0x04 +assert pkt[Dot15d4Cmd].sec_payload == b'' +assert pkt[Dot15d4Cmd].mic == b'\x9cP\x8c\x95' +assert raw(pkt[Dot15d4Cmd].payload) == b'' +assert pkt[Dot15d4FCS].fcs == 0xca38 + += Dot15d4FCS - Secured MAC Data (MIC-32) + +pkt = Dot15d4FCS(b'y\xdc\xf9\xdd\xcc\x03\x00\x00\x00\x00www\x02\x00\x00\x00\x00www\t\xa0%&\x00\x01PAYLOAD\xdf\xdb\\K\xa2\x00') +assert Dot15d4FCS in pkt.layers() +assert pkt[Dot15d4FCS].fcf_frametype == 0b001 +assert pkt[Dot15d4FCS].fcf_security == True +assert pkt[Dot15d4FCS].fcf_pending == True +assert pkt[Dot15d4FCS].fcf_ackreq == True +assert pkt[Dot15d4FCS].fcf_panidcompress == True +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b11 +assert pkt[Dot15d4FCS].fcf_framever == 0b01 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b11 +assert pkt[Dot15d4FCS].seqnum == 249 +assert Dot15d4Data in pkt.layers() +assert pkt[Dot15d4Data].dest_panid == 0xccdd +assert pkt[Dot15d4Data].dest_addr == 0x7777770000000003 +assert pkt[Dot15d4Data].src_addr == 0x7777770000000002 +assert raw(pkt[Dot15d4Data].aux_sec_header) == b'\t\xa0%&\x00\x01' +assert pkt[Dot15d4Data].aux_sec_header.sec_sc_seclevel == 0b001 +assert pkt[Dot15d4Data].aux_sec_header.sec_sc_keyidmode == 0b01 +assert pkt[Dot15d4Data].aux_sec_header.sec_sc_reserved == 0b000 +assert pkt[Dot15d4Data].aux_sec_header.sec_framecounter == 2500000 +assert pkt[Dot15d4Data].aux_sec_header.sec_keyid_keysource == b'' +assert pkt[Dot15d4Data].aux_sec_header.sec_keyid_keyindex == 0x01 +assert pkt[Dot15d4Data].sec_payload == b'PAYLOAD' +assert pkt[Dot15d4Data].mic == b'\xdf\xdb\\K' +assert raw(pkt[Dot15d4Data].payload) == b'' +assert pkt[Dot15d4FCS].fcs == 0x00a2 + += Dot15d4FCS - Secured MAC Data (ENC-MIC-32) + +pkt = Dot15d4FCS(b'y\xdc\xf9\xdd\xcc\x03\x00\x00\x00\x00www\x02\x00\x00\x00\x00www\r@KL\x00\x01\xf4\xf9o\xbf\xf2z;5\x902\xefc<') +assert Dot15d4FCS in pkt.layers() +assert pkt[Dot15d4FCS].fcf_frametype == 0b001 +assert pkt[Dot15d4FCS].fcf_security == True +assert pkt[Dot15d4FCS].fcf_pending == True +assert pkt[Dot15d4FCS].fcf_ackreq == True +assert pkt[Dot15d4FCS].fcf_panidcompress == True +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b11 +assert pkt[Dot15d4FCS].fcf_framever == 0b01 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b11 +assert pkt[Dot15d4FCS].seqnum == 249 +assert Dot15d4Data in pkt.layers() +assert pkt[Dot15d4Data].dest_panid == 0xccdd +assert pkt[Dot15d4Data].dest_addr == 0x7777770000000003 +assert pkt[Dot15d4Data].src_addr == 0x7777770000000002 +assert raw(pkt[Dot15d4Data].aux_sec_header) == b'\r@KL\x00\x01' +assert pkt[Dot15d4Data].aux_sec_header.sec_sc_seclevel == 0b101 +assert pkt[Dot15d4Data].aux_sec_header.sec_sc_keyidmode == 0b01 +assert pkt[Dot15d4Data].aux_sec_header.sec_sc_reserved == 0b000 +assert pkt[Dot15d4Data].aux_sec_header.sec_framecounter == 5000000 +assert pkt[Dot15d4Data].aux_sec_header.sec_keyid_keysource == b'' +assert pkt[Dot15d4Data].aux_sec_header.sec_keyid_keyindex == 0x01 +assert pkt[Dot15d4Data].sec_payload == b'\xf4\xf9o\xbf\xf2z;' +assert pkt[Dot15d4Data].mic == b'5\x902\xef' +assert raw(pkt[Dot15d4Data].payload) == b'' +assert pkt[Dot15d4FCS].fcs == 0x3c63 + ################### #### SixLoWPAN #### ################### @@ -544,6 +819,213 @@ assert packet._nhField == 0x06 assert packet._hopLimit == 128 packet.show2() += SixLoWPAN - First Fragment + +pkt = Dot15d4FCS(b'q\xdc\xd3\xde\xc0\x04\x00\x00\x00\x00\x99\x99\x99\x03\x00\x00\x00\x00\x99\x99\x99\xc2\xc8\xf0\x02\x7f3\xf0MLML\xb0\x01FRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENT`\xc2') +assert Dot15d4FCS in pkt.layers() +assert pkt[Dot15d4FCS].fcf_frametype == 0b001 +assert pkt[Dot15d4FCS].fcf_security == False +assert pkt[Dot15d4FCS].fcf_pending == True +assert pkt[Dot15d4FCS].fcf_ackreq == True +assert pkt[Dot15d4FCS].fcf_panidcompress == True +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b11 +assert pkt[Dot15d4FCS].fcf_framever == 0b01 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b11 +assert pkt[Dot15d4FCS].seqnum == 211 +assert Dot15d4Data in pkt.layers() +assert pkt[Dot15d4Data].dest_panid == 0xc0de +assert pkt[Dot15d4Data].dest_addr == 0x9999990000000004 +assert pkt[Dot15d4Data].src_addr == 0x9999990000000003 +assert LoWPANFragmentationFirst in pkt.layers() +assert pkt[LoWPANFragmentationFirst].reserved == 0b11000 +assert pkt[LoWPANFragmentationFirst].datagramSize == 712 +assert pkt[LoWPANFragmentationFirst].datagramTag == 0xf002 +assert LoWPAN_IPHC in pkt.layers() +assert pkt[LoWPAN_IPHC].reserved == 0b011 +assert pkt[LoWPAN_IPHC].tf == 0b11 +assert pkt[LoWPAN_IPHC].nh == 0b1 +assert pkt[LoWPAN_IPHC].hlim == 0b11 +assert pkt[LoWPAN_IPHC].cid == 0b0 +assert pkt[LoWPAN_IPHC].sac == 0b0 +assert pkt[LoWPAN_IPHC].sam == 0b11 +assert pkt[LoWPAN_IPHC].m == 0b0 +assert pkt[LoWPAN_IPHC].dac == 0b0 +assert pkt[LoWPAN_IPHC].dam == 0b11 +assert pkt[LoWPAN_IPHC].src == "fe80::9b99:9900:0:3" +assert pkt[LoWPAN_IPHC].dst == "fe80::9b99:9900:0:4" +assert LoWPAN_NHC in pkt.layers() +assert len(pkt[LoWPAN_NHC].exts) == 1 +assert pkt[LoWPAN_NHC].exts[0].res == 0b11110 +assert pkt[LoWPAN_NHC].exts[0].C == 0b0 +assert pkt[LoWPAN_NHC].exts[0].P == 0b00 +assert pkt[LoWPAN_NHC].exts[0].udpSourcePort == 19788 +assert pkt[LoWPAN_NHC].exts[0].udpDestPort == 19788 +assert pkt[LoWPAN_NHC].exts[0].udpChecksum == 0xb001 +assert raw(pkt[LoWPAN_NHC].payload) == b'FRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENT' +assert pkt[Dot15d4FCS].fcs == 0xc260 + += SixLoWPAN - Subsequent Fragment + +pkt = Dot15d4FCS(b'q\xdc\xd4\xde\xc0\x04\x00\x00\x00\x00\x99\x99\x99\x03\x00\x00\x00\x00\x99\x99\x99\xe2\xc8\xf0\x02\x11FRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTs\x80') +assert Dot15d4FCS in pkt.layers() +assert pkt[Dot15d4FCS].fcf_frametype == 0b001 +assert pkt[Dot15d4FCS].fcf_security == False +assert pkt[Dot15d4FCS].fcf_pending == True +assert pkt[Dot15d4FCS].fcf_ackreq == True +assert pkt[Dot15d4FCS].fcf_panidcompress == True +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b11 +assert pkt[Dot15d4FCS].fcf_framever == 0b01 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b11 +assert pkt[Dot15d4FCS].seqnum == 212 +assert Dot15d4Data in pkt.layers() +assert pkt[Dot15d4Data].dest_panid == 0xc0de +assert pkt[Dot15d4Data].dest_addr == 0x9999990000000004 +assert pkt[Dot15d4Data].src_addr == 0x9999990000000003 +assert LoWPANFragmentationSubsequent in pkt.layers() +assert pkt[LoWPANFragmentationSubsequent].reserved == 0b11100 +assert pkt[LoWPANFragmentationSubsequent].datagramSize == 712 +assert pkt[LoWPANFragmentationSubsequent].datagramTag == 0xf002 +assert pkt[LoWPANFragmentationSubsequent].datagramOffset == 0x11 +assert raw(pkt[LoWPANFragmentationSubsequent].payload) == b'FRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENTFRAGMENT' +assert pkt[Dot15d4FCS].fcs == 0x8073 + +################### +####### MLE ####### +################### + += MLE - Discovery Request (with MAC-layer and MLE-layer security disabled) + +pkt = Dot15d4FCS(b'\x01\xd8\xe4\xff\xff\xff\xff\xef\xdb\x05\x00\x00\x00\x00\x99\x99\x99\x7f;\x02\xf0MLMLa\xf9\xff\x10\x1a\x04\x80\x028\x00\xba\x8f') +assert Dot15d4FCS in pkt.layers() +assert pkt[Dot15d4FCS].fcf_frametype == 0b001 +assert pkt[Dot15d4FCS].fcf_security == False +assert pkt[Dot15d4FCS].fcf_pending == False +assert pkt[Dot15d4FCS].fcf_ackreq == False +assert pkt[Dot15d4FCS].fcf_panidcompress == False +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b10 +assert pkt[Dot15d4FCS].fcf_framever == 0b01 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b11 +assert pkt[Dot15d4FCS].seqnum == 228 +assert Dot15d4Data in pkt.layers() +assert pkt[Dot15d4Data].dest_panid == 0xffff +assert pkt[Dot15d4Data].dest_addr == 0xffff +assert pkt[Dot15d4Data].src_panid == 0xdbef +assert pkt[Dot15d4Data].src_addr == 0x9999990000000005 +assert LoWPAN_IPHC in pkt.layers() +assert pkt[LoWPAN_IPHC].reserved == 0b011 +assert pkt[LoWPAN_IPHC].tf == 0b11 +assert pkt[LoWPAN_IPHC].nh == 0b1 +assert pkt[LoWPAN_IPHC].hlim == 0b11 +assert pkt[LoWPAN_IPHC].cid == 0b0 +assert pkt[LoWPAN_IPHC].sac == 0b0 +assert pkt[LoWPAN_IPHC].sam == 0b11 +assert pkt[LoWPAN_IPHC].m == 0b1 +assert pkt[LoWPAN_IPHC].dac == 0b0 +assert pkt[LoWPAN_IPHC].dam == 0b11 +assert pkt[LoWPAN_IPHC].src == "fe80::9b99:9900:0:5" +assert pkt[LoWPAN_IPHC].dst == "ff02::2" +assert LoWPAN_NHC in pkt.layers() +assert len(pkt[LoWPAN_NHC].exts) == 1 +assert pkt[LoWPAN_NHC].exts[0].res == 0b11110 +assert pkt[LoWPAN_NHC].exts[0].C == 0b0 +assert pkt[LoWPAN_NHC].exts[0].P == 0b00 +assert pkt[LoWPAN_NHC].exts[0].udpSourcePort == 19788 +assert pkt[LoWPAN_NHC].exts[0].udpDestPort == 19788 +assert pkt[LoWPAN_NHC].exts[0].udpChecksum == 0x61f9 +assert IPv6 in pkt.layers() +assert pkt[IPv6].version == 6 +assert pkt[IPv6].tc == 0 +assert pkt[IPv6].fl == 0 +assert pkt[IPv6].plen == 16 +assert pkt[IPv6].nh == 17 +assert pkt[IPv6].hlim == 255 +assert pkt[IPv6].src == "fe80::9b99:9900:0:5" +assert pkt[IPv6].dst == "ff02::2" +assert UDP in pkt.layers() +assert pkt[UDP].sport == 19788 +assert pkt[UDP].dport == 19788 +assert pkt[UDP].len == 16 +assert pkt[UDP].chksum == 0x61f9 +assert MLE in pkt.layers() +assert pkt[MLE].sec_suite == 0xff +assert MLECmd in pkt.layers() +assert pkt[MLECmd].cmd_type == 0x10 +assert raw(pkt[MLECmd].payload) == b'\x1a\x04\x80\x028\x00' +assert pkt[Dot15d4FCS].fcs == 0x8fba + += MLE - MLE command (with only MLE-layer security enabled) + +pkt = Dot15d4FCS(b'A\xd8\xa5\xde\xc0\xff\xff\x06\x00\x00\x00\x00\x99\x99\x99\x7f;\x02\xf0MLMLD\x14\x00\x15\xed\x00\x00\x00\x00\x00\x00\x00\x01\x8f\x1e\x847\xa6\x98\xa6s\xbb\xae\xc3\xab\x93\xc6\x89\xdff\xf8\x1f\xbb\xac\xd7\xaa\x11\xd39!') +assert Dot15d4FCS in pkt.layers() +assert pkt[Dot15d4FCS].fcf_frametype == 0b001 +assert pkt[Dot15d4FCS].fcf_security == False +assert pkt[Dot15d4FCS].fcf_pending == False +assert pkt[Dot15d4FCS].fcf_ackreq == False +assert pkt[Dot15d4FCS].fcf_panidcompress == True +assert pkt[Dot15d4FCS].fcf_reserved_1 == 0b0 +assert pkt[Dot15d4FCS].fcf_reserved_2 == 0b00 +assert pkt[Dot15d4FCS].fcf_destaddrmode == 0b10 +assert pkt[Dot15d4FCS].fcf_framever == 0b01 +assert pkt[Dot15d4FCS].fcf_srcaddrmode == 0b11 +assert pkt[Dot15d4FCS].seqnum == 165 +assert Dot15d4Data in pkt.layers() +assert pkt[Dot15d4Data].dest_panid == 0xc0de +assert pkt[Dot15d4Data].dest_addr == 0xffff +assert pkt[Dot15d4Data].src_addr == 0x9999990000000006 +assert LoWPAN_IPHC in pkt.layers() +assert pkt[LoWPAN_IPHC].reserved == 0b011 +assert pkt[LoWPAN_IPHC].tf == 0b11 +assert pkt[LoWPAN_IPHC].nh == 0b1 +assert pkt[LoWPAN_IPHC].hlim == 0b11 +assert pkt[LoWPAN_IPHC].cid == 0b0 +assert pkt[LoWPAN_IPHC].sac == 0b0 +assert pkt[LoWPAN_IPHC].sam == 0b11 +assert pkt[LoWPAN_IPHC].m == 0b1 +assert pkt[LoWPAN_IPHC].dac == 0b0 +assert pkt[LoWPAN_IPHC].dam == 0b11 +assert pkt[LoWPAN_IPHC].src == "fe80::9b99:9900:0:6" +assert pkt[LoWPAN_IPHC].dst == "ff02::2" +assert LoWPAN_NHC in pkt.layers() +assert len(pkt[LoWPAN_NHC].exts) == 1 +assert pkt[LoWPAN_NHC].exts[0].res == 0b11110 +assert pkt[LoWPAN_NHC].exts[0].C == 0b0 +assert pkt[LoWPAN_NHC].exts[0].P == 0b00 +assert pkt[LoWPAN_NHC].exts[0].udpSourcePort == 19788 +assert pkt[LoWPAN_NHC].exts[0].udpDestPort == 19788 +assert pkt[LoWPAN_NHC].exts[0].udpChecksum == 0x4414 +assert IPv6 in pkt.layers() +assert pkt[IPv6].version == 6 +assert pkt[IPv6].tc == 0 +assert pkt[IPv6].fl == 0 +assert pkt[IPv6].plen == 44 +assert pkt[IPv6].nh == 17 +assert pkt[IPv6].hlim == 255 +assert pkt[IPv6].src == "fe80::9b99:9900:0:6" +assert pkt[IPv6].dst == "ff02::2" +assert UDP in pkt.layers() +assert pkt[UDP].sport == 19788 +assert pkt[UDP].dport == 19788 +assert pkt[UDP].len == 44 +assert pkt[UDP].chksum == 0x4414 +assert MLE in pkt.layers() +assert pkt[MLE].sec_suite == 0x00 +assert raw(pkt[MLE].aux_sec_header) == b'\x15\xed\x00\x00\x00\x00\x00\x00\x00\x01' +assert pkt[MLE].aux_sec_header.sec_sc_seclevel == 0b101 +assert pkt[MLE].aux_sec_header.sec_sc_keyidmode == 0b10 +assert pkt[MLE].aux_sec_header.sec_sc_reserved == 0b000 +assert pkt[MLE].aux_sec_header.sec_framecounter == 237 +assert pkt[MLE].aux_sec_header.sec_keyid_keysource == 0x00000000 +assert pkt[MLE].aux_sec_header.sec_keyid_keyindex == 0x01 +assert pkt[MLE].sec_payload == b'\x8f\x1e\x847\xa6\x98\xa6s\xbb\xae\xc3\xab\x93\xc6\x89\xdff\xf8\x1f\xbb\xac' +assert pkt[MLE].mic == b'\xd7\xaa\x11\xd3' +assert raw(pkt[MLE].payload) == b'' +assert pkt[Dot15d4FCS].fcs == 0x2139 ################### #### Zigbee ####