class PortIngressRuleClauseMatchLength06(Packet): """ Variable Descriptor: Port Ingress Rule Clause """ name = "Variable Descriptor: Port Ingress Rule Clause" fields_desc = [ XByteField("branch", 0xD7), XShortField("leaf", 0x0501), ByteField("length", 13), XByteField("clause", 2), XByteField("fieldcode", 0), XByteField("fieldinstance", 0), XByteField("msbmask", 0), XByteField("lsbmask", 0), XByteField("operator", 0), XByteField("matchlength", 6), XByteField("match0", 0x01), XByteField("match1", 0x80), XByteField("match2", 0xc2), XByteField("match3", 0x00), XByteField("match4", 0x00), XByteField("match5", 0x00), ]
class GMLAN_RMBAPR(Packet): name = 'ReadMemoryByAddressPositiveResponse' fields_desc = [ MultipleTypeField([ (XShortField('memoryAddress', 0), lambda pkt: GMLAN.determine_len(2)), (X3BytesField('memoryAddress', 0), lambda pkt: GMLAN.determine_len(3)), (XIntField('memoryAddress', 0), lambda pkt: GMLAN.determine_len(4)) ], XIntField('memoryAddress', 0)), StrField('dataRecord', None, fmt="B") ] def answers(self, other): return other.__class__ == GMLAN_RMBA and \ other.memoryAddress == self.memoryAddress @staticmethod def get_log(pkt): return pkt.sprintf("%GMLAN.service%"), \ (pkt.sprintf("%GMLAN_RMBAPR.memoryAddress%"), pkt.dataRecord)
class OFPPacketQueue(Packet): name = "OFP_PACKET_QUEUE" fields_desc = [ IntField("queue_id", 0), ShortField("len", None), XShortField("pad", 0), PacketListField("properties", [], OFPQT, length_from=lambda pkt: pkt.len - 8) ] def extract_padding(self, s): return b"", s def post_build(self, p, pay): if self.properties == []: p += raw(OFPQTNone()) if self.len is None: tmp_len = len(p) + len(pay) p = p[:4] + struct.pack("!H", tmp_len) + p[6:] return p + pay
class EIGRPSeq(EIGRPGeneric): name = "EIGRP Sequence" fields_desc = [ XShortField("type", 0x0003), ShortField("len", None), ByteField("addrlen", 4), ConditionalField(IPField("ipaddr", "192.168.0.1"), lambda pkt: pkt.addrlen == 4), ConditionalField(IP6Field("ip6addr", "2001::"), lambda pkt: pkt.addrlen == 16) ] def post_build(self, p, pay): p += pay if self.len is None: tmp_len = len(p) tmp_p = p[:2] + chb((tmp_len >> 8) & 0xff) p = tmp_p + chb(tmp_len & 0xff) + p[4:] return p
class PPTPStartControlConnectionReply(PPTP): name = "PPTP Start Control Connection Reply" fields_desc = [LenField("len", 156), ShortEnumField("type", 1, _PPTP_msg_type), XIntField("magic_cookie", _PPTP_MAGIC_COOKIE), ShortEnumField("ctrl_msg_type", 2, _PPTP_ctrl_msg_type), XShortField("reserved_0", 0x0000), ShortField("protocol_version", 0x0100), ByteEnumField("result_code", 1, _PPTP_start_control_connection_result), ByteEnumField("error_code", 0, _PPTP_general_error_code), FlagsField("framing_capabilities", 0, 32, _PPTP_FRAMING_CAPABILITIES_FLAGS), FlagsField("bearer_capabilities", 0, 32, _PPTP_BEARER_CAPABILITIES_FLAGS), ShortField("maximum_channels", 65535), ShortField("firmware_revision", 256), StrFixedLenField("host_name", "linux", 64), StrFixedLenField("vendor_string", "", 64)] def answers(self, other): return isinstance(other, PPTPStartControlConnectionRequest)
class PPTP(Packet): name = "PPTP" fields_desc = [FieldLenField("len", None, fmt="H", length_of="data", adjust=lambda p, x: x + 12), ShortEnumField("type", 1, _PPTP_msg_type), XIntField("magic_cookie", _PPTP_MAGIC_COOKIE), ShortEnumField("ctrl_msg_type", 1, _PPTP_ctrl_msg_type), XShortField("reserved_0", 0x0000), StrLenField("data", "", length_from=lambda p: p.len - 12)] registered_options = {} @classmethod def register_variant(cls): cls.registered_options[cls.ctrl_msg_type.default] = cls @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt: o = orb(_pkt[9]) return cls.registered_options.get(o, cls) return cls
class GMLAN_SA(Packet): subfunctions = { 0: 'ReservedByDocument', 1: 'SPSrequestSeed', 2: 'SPSsendKey', 3: 'DevCtrlrequestSeed', 4: 'DevCtrlsendKey', 255: 'ReservedByDocument'} for i in range(0x05, 0x0a + 1): subfunctions[i] = 'ReservedByDocument' for i in range(0x0b, 0xfa + 1): subfunctions[i] = 'Reserved for vehicle manufacturer specific needs' for i in range(0xfb, 0xfe + 1): subfunctions[i] = 'Reserved for ECU or ' \ 'system supplier manufacturing needs' name = 'SecurityAccess' fields_desc = [ ByteEnumField('subfunction', 0, subfunctions), ConditionalField(XShortField('securityKey', B""), lambda pkt: pkt.subfunction % 2 == 0) ]
class PPPoED(PPPoE): name = "PPP over Ethernet Discovery" code_list = { 0x00: "PPP Session Stage", 0x09: "PPPoE Active Discovery Initiation (PADI)", 0x07: "PPPoE Active Discovery Offer (PADO)", 0x0a: "PPPoE Active Discovery Session-Grant (PADG)", 0x0b: "PPPoE Active Discovery Session-Credit Response (PADC)", 0x0c: "PPPoE Active Discovery Quality (PADQ)", 0x19: "PPPoE Active Discovery Request (PADR)", 0x65: "PPPoE Active Discovery Session-confirmation (PADS)", 0xa7: "PPPoE Active Discovery Terminate (PADT)" } fields_desc = [ BitField("version", 1, 4), BitField("type", 1, 4), ByteEnumField("code", 0x09, code_list), XShortField("sessionid", 0x0), ShortField("len", None) ]
class RSVP(Packet): name = "RSVP" fields_desc = [ BitField("Version", 1, 4), BitField("Flags", 1, 4), ByteEnumField("Class", 0x01, rsvpmsgtypes), XShortField("chksum", None), ByteField("TTL", 1), XByteField("dataofs", 0), ShortField("Length", None) ] def post_build(self, p, pay): p += pay if self.Length is None: tmp_len = len(p) tmp_p = p[:6] + chb((tmp_len >> 8) & 0xff) + chb(tmp_len & 0xff) p = tmp_p + p[8:] if self.chksum is None: ck = checksum(p) p = p[:2] + chb(ck >> 8) + chb(ck & 0xff) + p[4:] return p
class AOE(Packet): name = "ATA over Ethernet" fields_desc = [ BitField("version", 1, 4), FlagsField("flags", 0, 4, ["Response", "Error", "r1", "r2"]), ByteEnumField( "error", 0, { 1: "Unrecognized command code", 2: "Bad argument parameter", 3: "Device unavailable", 4: "Config string present", 5: "Unsupported exception", 6: "Target is reserved" }), XShortField("major", 0xFFFF), XByteField("minor", 0xFF), ByteEnumField( "cmd", 1, { 0: "Issue ATA Command", 1: "Query Config Information", 2: "Mac Mask List", 3: "Reserve / Release" }), XIntField("tag", 0), ConditionalField( PacketField("i_ata_cmd", IssueATACommand(), IssueATACommand), lambda x: x.cmd == 0), ConditionalField( PacketField("q_conf_info", QueryConfigInformation(), QueryConfigInformation), lambda x: x.cmd == 1), ConditionalField(PacketField("mac_m_list", MacMaskList(), MacMaskList), lambda x: x.cmd == 2), ConditionalField( PacketField("res_rel", ReserveRelease(), ReserveRelease), lambda x: x.cmd == 3) ] def extract_padding(self, s): return "", s
class ExpectedSubmodule(Packet): """Description of a submodule in an API of an expected submodule""" name = "Submodule" fields_desc = [ XShortField("SubslotNumber", 0), XIntField("SubmoduleIdentNumber", 0), # Submodule Properties XByteField("SubmoduleProperties_reserved_2", 0), BitField("SubmoduleProperties_reserved_1", 0, 2), BitField("SubmoduleProperties_DiscardIOXS", 0, 1), BitField("SubmoduleProperties_ReduceOutputSubmoduleDataLength", 0, 1), BitField("SubmoduleProperties_ReduceInputSubmoduleDataLength", 0, 1), BitField("SubmoduleProperties_SharedInput", 0, 1), BitEnumField("SubmoduleProperties_Type", 0, 2, ["NO_IO", "INPUT", "OUTPUT", "INPUT_OUTPUT"]), PacketListField( "DataDescription", [], ExpectedSubmoduleDataDescription, count_from=lambda p: 2 if p.SubmoduleProperties_Type == 3 else 1 ), ] def extract_padding(self, s): return None, s # No extra payload
class OFPTFlowRemoved(_ofp_header): name = "OFPT_FLOW_REMOVED" fields_desc = [ ByteEnumField("version", 0x01, ofp_version), ByteEnumField("type", 11, ofp_type), ShortField("len", None), IntField("xid", 0), PacketField("match", OFPMatch(), OFPMatch), LongField("cookie", 0), ShortField("priority", 0), ByteEnumField("reason", 0, { 0: "OFPRR_IDLE_TIMEOUT", 1: "OFPRR_HARD_TIMEOUT", 2: "OFPRR_DELETE" }), XByteField("pad1", 0), IntField("duration_sec", 0), IntField("duration_nsec", 0), ShortField("idle_timeout", 0), XShortField("pad2", 0), LongField("packet_count", 0), LongField("byte_count", 0) ]
class PPTPOutgoingCallReply(PPTP): name = "PPTP Outgoing Call Reply" fields_desc = [ LenField("len", 32), ShortEnumField("type", 1, _PPTP_msg_type), XIntField("magic_cookie", _PPTP_MAGIC_COOKIE), ShortEnumField("ctrl_msg_type", 8, _PPTP_ctrl_msg_type), XShortField("reserved_0", 0x0000), ShortField("call_id", 1), ShortField("peer_call_id", 1), ByteEnumField("result_code", 1, _PPTP_result_code), ByteEnumField("error_code", 0, _PPTP_general_error_code), ShortField("cause_code", 0), IntField("connect_speed", 100000000), ShortField("pkt_window_size", 16), ShortField("pkt_proc_delay", 0), IntField("channel_id", 0) ] def answers(self, other): return isinstance( other, PPTPOutgoingCallRequest) and other.call_id == self.peer_call_id
class VRRPv3(Packet): fields_desc = [ BitField("version", 3, 4), BitField("type", 1, 4), ByteField("vrid", 1), ByteField("priority", 100), FieldLenField("ipcount", None, count_of="addrlist", fmt="B"), BitField("res", 0, 4), BitField("adv", 100, 12), XShortField("chksum", None), # FIXME: addrlist should also allow IPv6 addresses :/ FieldListField("addrlist", [], IPField("", "0.0.0.0"), count_from=lambda pkt: pkt.ipcount) ] def post_build(self, p, pay): if self.chksum is None: if isinstance(self.underlayer, IP): ck = in4_chksum(112, self.underlayer, p) elif isinstance(self.underlayer, IPv6): ck = in6_chksum(112, self.underlayer, p) else: warning( "No IP(v6) layer to compute checksum on VRRP. Leaving null" ) # noqa: E501 ck = 0 p = p[:6] + chb(ck >> 8) + chb(ck & 0xff) + p[8:] return p @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 16: ver_n_type = orb(_pkt[0]) if ver_n_type < 48 or ver_n_type > 57: # Version != 3 return VRRP return VRRPv3
class APHECaps(IEEE1905_TLV): name = "AP VHT Capabilities TLV" fields_desc = [ XByteField("type", 0x88), XShortField("len", None), MACField("radio_id", None), FieldLenField("he_mcs_len", None, fmt='B', count_of="he_mcs"), FieldListField("he_mcs", None, XByteField("byte", None), count_from=lambda p: p.he_mcs_len), BitField("max_tx_streams", 0, 3), BitField("max_rx_streams", 0, 3), BitField("he_80mhz_plus_flag", 0, 1), BitField("he_160mhz_flag", 0, 1), BitField("su_beamformer_cap_flag", 0, 1), BitField("mu_beamformer_cap_flag", 0, 1), BitField("ul_mu_mmio_cap_flag", 0, 1), BitField("ul_mu_mmio_ofdma_cap_flag", 0, 1), BitField("dl_mu_mmio_ofdma_cap_flag", 0, 1), BitField("ul_ofdma_cap_flag", 0, 1), BitField("dl_ofdma_cap_flag", 0, 1), BitField("reserved", 0, 1) ]
class YOARP(Packet): name = "YOARP" fields_desc = [ XShortField("hwtype", 0x0001), XShortEnumField("ptype", 0x9999, ETHER_TYPES), ByteField("hwlen", 6), ByteField("plen", 2), ShortEnumField("op", 1, {"who-has": 1, "is-at": 2, "RARP-req": 3, "RARP-rep": 4, "Dyn-RARP-req": 5, "Dyn-RAR-rep": 6, "Dyn-RARP-err": 7, "InARP-req": 8, "InARP-rep": 9}), ARPSourceMACField("hwsrc"), YOIPField("psrc", "0.0"), MACField("hwdst", ETHER_ANY), YOIPField("pdst", "0.0") ] who_has = 1 is_at = 2 def extract_padding(self, s): return "", s def answers(self, other): if isinstance(other, YOARP): if ((self.op == self.is_at) and (other.op == self.who_has) and (self.psrc == other.pdst)): return 1 return 0 @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 4 and _pkt[2:4] == "\x08\x00": return ARP return cls
class OSPFv3_Hdr(Packet): name = "OSPFv3 Header" fields_desc = [ByteField("version", 3), ByteEnumField("type", 1, _OSPF_types), ShortField("len", None), IPField("src", "1.1.1.1"), IPField("area", "0.0.0.0"), XShortField("chksum", None), ByteField("instance", 0), ByteField("reserved", 0)] def post_build(self, p, pay): p += pay tmp_len = self.len if tmp_len is None: tmp_len = len(p) p = p[:2] + struct.pack("!H", tmp_len) + p[4:] if self.chksum is None: chksum = in6_chksum(89, self.underlayer, p) p = p[:12] + struct.pack("!H", chksum) + p[14:] return p
class PIMv2Hdr(Packet): name = "Protocol Independent Multicast Version 2 Header" fields_desc = [ BitField("version", 2, 4), BitEnumField("type", 0, 4, PIM_TYPE), ByteField("reserved", 0), XShortField("chksum", None) ] def post_build(self, p, pay): """ Called implicitly before a packet is sent to compute and place PIM checksum. Parameters: self The instantiation of an PIMv2Hdr class p The PIMv2Hdr message in hex in network byte order pay Additional payload for the PIMv2Hdr message """ p += pay if self.chksum is None: ck = checksum(p) p = p[:2] + struct.pack("!H", ck) + p[4:] return p
class CARP(Packet): name = "CARP" fields_desc = [BitField("version", 4, 4), BitField("type", 4, 4), ByteField("vhid", 1), ByteField("advskew", 0), ByteField("authlen", 0), ByteField("demotion", 0), ByteField("advbase", 0), XShortField("chksum", 0), XIntField("counter1", 0), XIntField("counter2", 0), XIntField("hmac1", 0), XIntField("hmac2", 0), XIntField("hmac3", 0), XIntField("hmac4", 0), XIntField("hmac5", 0) ] def post_build(self, pkt, pay): if self.chksum == None: pkt = pkt[:6] + struct.pack("!H", checksum(pkt)) + pkt[8:] return pkt
class UDS_IOCBIPR(Packet): name = 'InputOutputControlByIdentifierPositiveResponse' fields_desc = [ XShortField('dataIdentifier', 0), StrField('controlStatusRecord', 0, fmt="B") ]
class IrLMP(Packet): name = "IrDA Link Management Protocol" fields_desc = [XShortField("Service hints", 0), XByteField("Character set", 0), StrField("Device name", "")]
class UDS_RSDBI(Packet): name = 'ReadScalingDataByIdentifier' fields_desc = [XShortField('dataIdentifier', 0)]
class UDS_DDDIPR(Packet): name = 'DynamicallyDefineDataIdentifierPositiveResponse' fields_desc = [ ByteField('definitionMode', 0), XShortField('dynamicallyDefinedDataIdentifier', 0) ]
class DoIP(Packet): payload_types = { 0x0000: "Generic DoIP header NACK", 0x0001: "Vehicle identification request", 0x0002: "Vehicle identification request with EID", 0x0003: "Vehicle identification request with VIN", 0x0004: "Vehicle announcement message/vehicle identification response message", # noqa: E501 0x0005: "Routing activation request", 0x0006: "Routing activation response", 0x0007: "Alive check request", 0x0008: "Alive check response", 0x4001: "DoIP entity status request", 0x4002: "DoIP entity status response", 0x4003: "Diagnostic power mode information request", 0x4004: "Diagnostic power mode information response", 0x8001: "Diagnostic message", 0x8002: "Diagnostic message ACK", 0x8003: "Diagnostic message NACK" } name = 'DoIP' fields_desc = [ XByteField("protocol_version", 0x02), XByteField("inverse_version", 0xFD), XShortEnumField("payload_type", 0, payload_types), IntField("payload_length", None), ConditionalField( ByteEnumField( "nack", 0, { 0: "Incorrect pattern format", 1: "Unknown payload type", 2: "Message too large", 3: "Out of memory", 4: "Invalid payload length" }), lambda p: p.payload_type in [0x0]), ConditionalField(StrFixedLenField("vin", b"", 17), lambda p: p.payload_type in [3, 4]), ConditionalField(XShortField("logical_address", 0), lambda p: p.payload_type in [4]), ConditionalField(StrFixedLenField("eid", b"", 6), lambda p: p.payload_type in [2, 4]), ConditionalField(StrFixedLenField("gid", b"", 6), lambda p: p.payload_type in [4]), ConditionalField( XByteEnumField( "further_action", 0, { 0x00: "No further action required", 0x01: "Reserved by ISO 13400", 0x02: "Reserved by ISO 13400", 0x03: "Reserved by ISO 13400", 0x04: "Reserved by ISO 13400", 0x05: "Reserved by ISO 13400", 0x06: "Reserved by ISO 13400", 0x07: "Reserved by ISO 13400", 0x08: "Reserved by ISO 13400", 0x09: "Reserved by ISO 13400", 0x0a: "Reserved by ISO 13400", 0x0b: "Reserved by ISO 13400", 0x0c: "Reserved by ISO 13400", 0x0d: "Reserved by ISO 13400", 0x0e: "Reserved by ISO 13400", 0x0f: "Reserved by ISO 13400", 0x10: "Routing activation required to initiate central security", }), lambda p: p.payload_type in [4]), ConditionalField( XByteEnumField( "vin_gid_status", 0, { 0x00: "VIN and/or GID are synchronized", 0x01: "Reserved by ISO 13400", 0x02: "Reserved by ISO 13400", 0x03: "Reserved by ISO 13400", 0x04: "Reserved by ISO 13400", 0x05: "Reserved by ISO 13400", 0x06: "Reserved by ISO 13400", 0x07: "Reserved by ISO 13400", 0x08: "Reserved by ISO 13400", 0x09: "Reserved by ISO 13400", 0x0a: "Reserved by ISO 13400", 0x0b: "Reserved by ISO 13400", 0x0c: "Reserved by ISO 13400", 0x0d: "Reserved by ISO 13400", 0x0e: "Reserved by ISO 13400", 0x0f: "Reserved by ISO 13400", 0x10: "Incomplete: VIN and GID are NOT synchronized" }), lambda p: p.payload_type in [4]), ConditionalField( XShortField("source_address", 0), lambda p: p.payload_type in [5, 8, 0x8001, 0x8002, 0x8003]), # noqa: E501 ConditionalField( XByteEnumField("activation_type", 0, { 0: "Default", 1: "WWH-OBD", 0xe0: "Central security" }), lambda p: p.payload_type in [5]), ConditionalField(XShortField("logical_address_tester", 0), lambda p: p.payload_type in [6]), ConditionalField(XShortField("logical_address_doip_entity", 0), lambda p: p.payload_type in [6]), ConditionalField( XByteEnumField( "routing_activation_response", 0, { 0x00: "Routing activation denied due to unknown source address.", 0x01: "Routing activation denied because all concurrently supported TCP_DATA sockets are registered and active.", # noqa: E501 0x02: "Routing activation denied because an SA different from the table connection entry was received on the already activated TCP_DATA socket.", # noqa: E501 0x03: "Routing activation denied because the SA is already registered and active on a different TCP_DATA socket.", # noqa: E501 0x04: "Routing activation denied due to missing authentication.", 0x05: "Routing activation denied due to rejected confirmation.", 0x06: "Routing activation denied due to unsupported routing activation type.", # noqa: E501 0x07: "Reserved by ISO 13400.", 0x08: "Reserved by ISO 13400.", 0x09: "Reserved by ISO 13400.", 0x0a: "Reserved by ISO 13400.", 0x0b: "Reserved by ISO 13400.", 0x0c: "Reserved by ISO 13400.", 0x0d: "Reserved by ISO 13400.", 0x0e: "Reserved by ISO 13400.", 0x0f: "Reserved by ISO 13400.", 0x10: "Routing successfully activated.", 0x11: "Routing will be activated; confirmation required." }), lambda p: p.payload_type in [6]), ConditionalField(XIntField("reserved_iso", 0), lambda p: p.payload_type in [5, 6]), ConditionalField(XIntField("reserved_oem", 0), lambda p: p.payload_type in [5, 6]), ConditionalField( XByteEnumField("diagnostic_power_mode", 0, { 0: "not ready", 1: "ready", 2: "not supported" }), lambda p: p.payload_type in [0x4004]), ConditionalField( ByteEnumField("node_type", 0, { 0: "DoIP gateway", 1: "DoIP node" }), lambda p: p.payload_type in [0x4002]), ConditionalField(XByteField("max_open_sockets", 0), lambda p: p.payload_type in [0x4002]), ConditionalField(XByteField("cur_open_sockets", 0), lambda p: p.payload_type in [0x4002]), ConditionalField(IntField("max_data_size", 0), lambda p: p.payload_type in [0x4002]), ConditionalField(XShortField("target_address", 0), lambda p: p.payload_type in [0x8001, 0x8002, 0x8003 ]), # noqa: E501 ConditionalField(XByteEnumField("ack_code", 0, {0: "ACK"}), lambda p: p.payload_type in [0x8002]), ConditionalField( ByteEnumField( "nack_code", 0, { 0x00: "Reserved by ISO 13400", 0x01: "Reserved by ISO 13400", 0x02: "Invalid source address", 0x03: "Unknown target address", 0x04: "Diagnostic message too large", 0x05: "Out of memory", 0x06: "Target unreachable", 0x07: "Unknown network", 0x08: "Transport protocol error" }), lambda p: p.payload_type in [0x8003]), ] def answers(self, other): # type: (Packet) -> int """DEV: true if self is an answer from other""" if other.__class__ == self.__class__: if self.payload_type == 0: return 1 matches = [(4, 1), (4, 2), (4, 3), (6, 5), (8, 7), (0x4002, 0x4001), (0x4004, 0x4003), (0x8001, 0x8001), (0x8003, 0x8001)] if (self.payload_type, other.payload_type) in matches: if self.payload_type == 0x8001: return self.payload.answers(other.payload) return 1 return 0 def hashret(self): # type: () -> bytes if self.payload_type in [0x8001, 0x8002, 0x8003]: return bytes(self)[:2] + struct.pack( "H", self.target_address ^ self.source_address) return bytes(self)[:2] def post_build(self, pkt, pay): # type: (bytes, bytes) -> bytes """ This will set the Field 'payload_length' to the correct value. """ if self.payload_length is None: pkt = pkt[:4] + struct.pack("!I", len(pay) + len(pkt) - 8) + \ pkt[8:] return pkt + pay def extract_padding(self, s): # type: (bytes) -> Tuple[bytes, Optional[bytes]] if self.payload_type == 0x8001: return s[:self.payload_length - 4], None else: return b"", None
class LoWPAN_IPHC(Packet): """6LoWPAN IPv6 header compressed packets It follows the implementation of draft-ietf-6lowpan-hc-15. """ # the LOWPAN_IPHC encoding utilizes 13 bits, 5 dispatch type name = "LoWPAN IP Header Compression Packet" _address_modes = ["Unspecified", "1", "16-bits inline", "Compressed"] _state_mode = ["Stateless", "Stateful"] fields_desc = [ # dispatch BitField("_reserved", 0x03, 3), BitField("tf", 0x0, 2), BitEnumField("nh", 0x0, 1, ["Inline", "Compressed"]), BitField("hlim", 0x0, 2), BitEnumField("cid", 0x0, 1, [False, True]), BitEnumField("sac", 0x0, 1, _state_mode), BitEnumField("sam", 0x0, 2, _address_modes), BitEnumField("m", 0x0, 1, [False, True]), BitEnumField("dac", 0x0, 1, _state_mode), BitEnumField("dam", 0x0, 2, _address_modes), ConditionalField(ByteField("_contextIdentifierExtension", 0x0), lambda pkt: pkt.cid == 0x1), # TODO: THIS IS WRONG!!!!! BitVarSizeField("tc_ecn", 0, calculate_length=lambda pkt: tf_last_attempt(pkt)[0] ), # noqa: E501 BitVarSizeField("tc_dscp", 0, calculate_length=lambda pkt: tf_last_attempt(pkt)[1] ), # noqa: E501 BitVarSizeField("_padd", 0, calculate_length=lambda pkt: tf_last_attempt(pkt)[2] ), # noqa: E501 BitVarSizeField("flowlabel", 0, calculate_length=lambda pkt: tf_last_attempt(pkt)[3] ), # noqa: E501 # NH ConditionalField(ByteField("_nhField", 0x0), lambda pkt: not pkt.nh), # HLIM: Hop Limit: if it's 0 ConditionalField(ByteField("_hopLimit", 0x0), lambda pkt: pkt.hlim == 0x0), IP6FieldLenField("sourceAddr", "::", 0, length_of=source_addr_mode2), IP6FieldLenField( "destinyAddr", "::", 0, length_of=destiny_addr_mode), # problem when it's 0 # noqa: E501 # LoWPAN_UDP Header Compression ######################################## # noqa: E501 # TODO: IMPROVE!!!!! ConditionalField( FlagsField( "header_compression", 0, 8, ["A", "B", "C", "D", "E", "C", "PS", "PD"]), # noqa: E501 lambda pkt: pkt.nh), ConditionalField( BitFieldLenField( "udpSourcePort", 0x0, 16, length_of=lambda pkt: nhc_port(pkt)[0]), # noqa: E501 # ShortField("udpSourcePort", 0x0), lambda pkt: pkt.nh and pkt.header_compression & 0x2 == 0x0), ConditionalField( BitFieldLenField( "udpDestinyPort", 0x0, 16, length_of=lambda pkt: nhc_port(pkt)[1]), # noqa: E501 lambda pkt: pkt.nh and pkt.header_compression & 0x1 == 0x0), ConditionalField( XShortField("udpChecksum", 0x0), lambda pkt: pkt.nh and pkt.header_compression & 0x4 == 0x0), ] def post_dissect(self, data): """dissect the IPv6 package compressed into this IPHC packet. The packet payload needs to be decompressed and depending on the arguments, several conversions should be done. """ # uncompress payload packet = IPv6() packet.version = IPHC_DEFAULT_VERSION packet.tc, packet.fl = self._getTrafficClassAndFlowLabel() if not self.nh: packet.nh = self._nhField # HLIM: Hop Limit if self.hlim == 0: packet.hlim = self._hopLimit elif self.hlim == 0x1: packet.hlim = 1 elif self.hlim == 0x2: packet.hlim = 64 else: packet.hlim = 255 # TODO: Payload length can be inferred from lower layers from either the # noqa: E501 # 6LoWPAN Fragmentation header or the IEEE802.15.4 header packet.src = self.decompressSourceAddr(packet) packet.dst = self.decompressDestinyAddr(packet) if self.nh == 1: # The Next Header field is compressed and the next header is # encoded using LOWPAN_NHC udp = UDP() if self.header_compression and \ self.header_compression & 0x4 == 0x0: udp.chksum = self.udpChecksum s, d = nhc_port(self) if s == 16: udp.sport = self.udpSourcePort elif s == 8: udp.sport = 0xF000 + s elif s == 4: udp.sport = 0xF0B0 + s if d == 16: udp.dport = self.udpDestinyPort elif d == 8: udp.dport = 0xF000 + d elif d == 4: udp.dport = 0xF0B0 + d packet.payload = udp / data data = raw(packet) # else self.nh == 0 not necessary elif self._nhField & 0xE0 == 0xE0: # IPv6 Extension Header Decompression # noqa: E501 warning('Unimplemented: IPv6 Extension Header decompression' ) # noqa: E501 packet.payload = conf.raw_layer(data) data = raw(packet) else: packet.payload = conf.raw_layer(data) data = raw(packet) return Packet.post_dissect(self, data) def decompressDestinyAddr(self, packet): try: tmp_ip = inet_pton(socket.AF_INET6, self.destinyAddr) except socket.error: tmp_ip = b"\x00" * 16 if self.m == 0 and self.dac == 0: if self.dam == 0: pass elif self.dam == 1: tmp_ip = LINK_LOCAL_PREFIX[0:8] + tmp_ip[-8:] elif self.dam == 2: tmp_ip = LINK_LOCAL_PREFIX[ 0:8] + b"\x00\x00\x00\xff\xfe\x00" + tmp_ip[ -2:] # noqa: E501 """else: #self.dam == 3 raise Exception('Unimplemented')""" elif self.m == 0 and self.dac == 1: if self.dam == 0: raise Exception('Reserved') elif self.dam == 0x3: underlayer = self.underlayer while underlayer is not None and not isinstance( underlayer, Dot15d4Data): # noqa: E501 underlayer = underlayer.underlayer if type(underlayer) == Dot15d4Data: if underlayer.underlayer.fcf_destaddrmode == 3: tmp_ip = LINK_LOCAL_PREFIX[0:8] + struct.pack( ">Q", underlayer.dest_addr) # noqa: E501 # Turn off the bit 7. tmp_ip = tmp_ip[0:8] + struct.pack( "B", (orb(tmp_ip[8]) ^ 0x2)) + tmp_ip[9:16] # noqa: E501 elif underlayer.underlayer.fcf_destaddrmode == 2: tmp_ip = LINK_LOCAL_PREFIX[0:8] + \ b"\x00\x00\x00\xff\xfe\x00" + \ struct.pack(">Q", underlayer.dest_addr)[6:] else: # Most of the times, it's necessary the IEEE 802.15.4 data to extract this address # noqa: E501 raise Exception( 'Unimplemented: IP Header is contained into IEEE 802.15.4 frame, in this case it\'s not available.' ) # noqa: E501 elif self.dam not in [0x1, 0x2]: warning("Unknown destiny address compression mode !") elif self.m == 1 and self.dac == 0: if self.dam == 0: raise Exception("unimplemented") elif self.dam == 1: tmp = b"\xff" + chb(tmp_ip[16 - destiny_addr_mode(self)]) tmp_ip = tmp + b"\x00" * 9 + tmp_ip[-5:] elif self.dam == 2: tmp = b"\xff" + chb(tmp_ip[16 - destiny_addr_mode(self)]) tmp_ip = tmp + b"\x00" * 11 + tmp_ip[-3:] else: # self.dam == 3: tmp_ip = b"\xff\x02" + b"\x00" * 13 + tmp_ip[-1:] elif self.m == 1 and self.dac == 1: if self.dam == 0x0: raise Exception( "Unimplemented: I didn't understand the 6lowpan specification" ) # noqa: E501 else: # all the others values raise Exception("Reserved value by specification.") self.destinyAddr = inet_ntop(socket.AF_INET6, tmp_ip) return self.destinyAddr def compressSourceAddr(self, ipv6): tmp_ip = inet_pton(socket.AF_INET6, ipv6.src) if self.sac == 0: if self.sam == 0x0: tmp_ip = tmp_ip elif self.sam == 0x1: tmp_ip = tmp_ip[8:16] elif self.sam == 0x2: tmp_ip = tmp_ip[14:16] else: # self.sam == 0x3: pass else: # self.sac == 1 if self.sam == 0x0: tmp_ip = b"\x00" * 16 elif self.sam == 0x1: tmp_ip = tmp_ip[8:16] elif self.sam == 0x2: tmp_ip = tmp_ip[14:16] self.sourceAddr = inet_ntop(socket.AF_INET6, b"\x00" * (16 - len(tmp_ip)) + tmp_ip) # noqa: E501 return self.sourceAddr def compressDestinyAddr(self, ipv6): tmp_ip = inet_pton(socket.AF_INET6, ipv6.dst) if self.m == 0 and self.dac == 0: if self.dam == 0x0: tmp_ip = tmp_ip elif self.dam == 0x1: tmp_ip = b"\x00" * 8 + tmp_ip[8:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 14 + tmp_ip[14:16] elif self.m == 0 and self.dac == 1: if self.dam == 0x1: tmp_ip = b"\x00" * 8 + tmp_ip[8:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 14 + tmp_ip[14:16] elif self.m == 1 and self.dac == 0: if self.dam == 0x1: tmp_ip = b"\x00" * 10 + tmp_ip[1:2] + tmp_ip[11:16] elif self.dam == 0x2: tmp_ip = b"\x00" * 12 + tmp_ip[1:2] + tmp_ip[13:16] elif self.dam == 0x3: tmp_ip = b"\x00" * 15 + tmp_ip[15:16] elif self.m == 1 and self.dac == 1: raise Exception('Unimplemented') self.destinyAddr = inet_ntop(socket.AF_INET6, tmp_ip) def decompressSourceAddr(self, packet): try: tmp_ip = inet_pton(socket.AF_INET6, self.sourceAddr) except socket.error: tmp_ip = b"\x00" * 16 if self.sac == 0: if self.sam == 0x0: pass elif self.sam == 0x1: tmp_ip = LINK_LOCAL_PREFIX[0:8] + tmp_ip[ 16 - source_addr_mode2(self):16] # noqa: E501 elif self.sam == 0x2: tmp = LINK_LOCAL_PREFIX[0:8] + b"\x00\x00\x00\xff\xfe\x00" tmp_ip = tmp + tmp_ip[16 - source_addr_mode2(self):16] elif self.sam == 0x3: # EXTRACT ADDRESS FROM Dot15d4 underlayer = self.underlayer if underlayer is not None: while underlayer is not None and not isinstance( underlayer, Dot15d4Data): # noqa: E501 underlayer = underlayer.underlayer assert type(underlayer) == Dot15d4Data if underlayer.underlayer.fcf_srcaddrmode == 3: tmp_ip = LINK_LOCAL_PREFIX[0:8] + struct.pack( ">Q", underlayer.src_addr) # noqa: E501 # Turn off the bit 7. tmp_ip = tmp_ip[0:8] + struct.pack( "B", (orb(tmp_ip[8]) ^ 0x2)) + tmp_ip[9:16] # noqa: E501 elif underlayer.underlayer.fcf_srcaddrmode == 2: tmp_ip = LINK_LOCAL_PREFIX[0:8] + \ b"\x00\x00\x00\xff\xfe\x00" + \ struct.pack(">Q", underlayer.src_addr)[6:] else: # Most of the times, it's necessary the IEEE 802.15.4 data to extract this address # noqa: E501 raise Exception( 'Unimplemented: IP Header is contained into IEEE 802.15.4 frame, in this case it\'s not available.' ) # noqa: E501 else: warning("Unknown source address compression mode !") else: # self.sac == 1: if self.sam == 0x0: pass elif self.sam == 0x2: # TODO: take context IID tmp = LINK_LOCAL_PREFIX[0:8] + b"\x00\x00\x00\xff\xfe\x00" tmp_ip = tmp + tmp_ip[16 - source_addr_mode2(self):16] elif self.sam == 0x3: tmp_ip = LINK_LOCAL_PREFIX[ 0:8] + b"\x00" * 8 # TODO: CONTEXT ID # noqa: E501 else: raise Exception('Unimplemented') self.sourceAddr = inet_ntop(socket.AF_INET6, tmp_ip) return self.sourceAddr def guess_payload_class(self, payload): if self.underlayer and isinstance( self.underlayer, (LoWPANFragmentationFirst, LoWPANFragmentationSubsequent)): # noqa: E501 return Raw return IPv6 def do_build(self): if not isinstance(self.payload, IPv6): return Packet.do_build(self) ipv6 = self.payload self._reserved = 0x03 # NEW COMPRESSION TECHNIQUE! # a ) Compression Techniques # 1. Set Traffic Class if self.tf == 0x0: self.tc_ecn = ipv6.tc >> 6 self.tc_dscp = ipv6.tc & 0x3F self.flowlabel = ipv6.fl elif self.tf == 0x1: self.tc_ecn = ipv6.tc >> 6 self.flowlabel = ipv6.fl elif self.tf == 0x2: self.tc_ecn = ipv6.tc >> 6 self.tc_dscp = ipv6.tc & 0x3F else: # self.tf == 0x3: pass # no field is set # 2. Next Header if self.nh == 0x0: self.nh = 0 # ipv6.nh elif self.nh == 0x1: self.nh = 0 # disable compression # The Next Header field is compressed and the next header is encoded using LOWPAN_NHC, which is discussed in Section 4.1. # noqa: E501 warning( 'Next header compression is not implemented yet ! Will be ignored' ) # noqa: E501 # 3. HLim if self.hlim == 0x0: self._hopLimit = ipv6.hlim else: # if hlim is 1, 2 or 3, there are nothing to do! pass # 4. Context (which context to use...) if self.cid == 0x0: pass else: # TODO: Context Unimplemented yet in my class self._contextIdentifierExtension = 0 # 5. Compress Source Addr self.compressSourceAddr(ipv6) self.compressDestinyAddr(ipv6) return Packet.do_build(self) def do_build_payload(self): if self.header_compression and\ self.header_compression & 240 == 240: # TODO: UDP header IMPROVE return raw(self.payload)[40 + 16:] else: return raw(self.payload)[40:] def _getTrafficClassAndFlowLabel(self): """Page 6, draft feb 2011 """ if self.tf == 0x0: return (self.tc_ecn << 6) + self.tc_dscp, self.flowlabel elif self.tf == 0x1: return (self.tc_ecn << 6), self.flowlabel elif self.tf == 0x2: return (self.tc_ecn << 6) + self.tc_dscp, 0 else: return 0, 0
class LinkADRReq(Packet): name = "LinkADRReq" fields_desc = [DataRate_TXPower, XShortField("ChMask", 0), Redundancy]
class ARP(Packet): name = "ARP" fields_desc = [ XShortField("hwtype", 0x0001), XShortEnumField("ptype", 0x0800, ETHER_TYPES), FieldLenField("hwlen", None, fmt="B", length_of="hwsrc"), FieldLenField("plen", None, fmt="B", length_of="psrc"), ShortEnumField("op", 1, { "who-has": 1, "is-at": 2, "RARP-req": 3, "RARP-rep": 4, "Dyn-RARP-req": 5, "Dyn-RAR-rep": 6, "Dyn-RARP-err": 7, "InARP-req": 8, "InARP-rep": 9 }), MultipleTypeField( [ (SourceMACField("hwsrc"), (lambda pkt: pkt.hwtype == 1 and pkt.hwlen == 6, lambda pkt, val: pkt.hwtype == 1 and ( pkt.hwlen == 6 or (pkt.hwlen is None and (val is None or len(val) == 6 or valid_mac(val))) ))), ], StrFixedLenField("hwsrc", None, length_from=lambda pkt: pkt.hwlen), ), MultipleTypeField( [ (SourceIPField("psrc", "pdst"), (lambda pkt: pkt.ptype == 0x0800 and pkt.plen == 4, lambda pkt, val: pkt.ptype == 0x0800 and ( pkt.plen == 4 or (pkt.plen is None and (val is None or valid_net(val))) ))), (SourceIP6Field("psrc", "pdst"), (lambda pkt: pkt.ptype == 0x86dd and pkt.plen == 16, lambda pkt, val: pkt.ptype == 0x86dd and ( pkt.plen == 16 or (pkt.plen is None and (val is None or valid_net6(val))) ))), ], StrFixedLenField("psrc", None, length_from=lambda pkt: pkt.plen), ), MultipleTypeField( [ (MACField("hwdst", ETHER_ANY), (lambda pkt: pkt.hwtype == 1 and pkt.hwlen == 6, lambda pkt, val: pkt.hwtype == 1 and ( pkt.hwlen == 6 or (pkt.hwlen is None and (val is None or len(val) == 6 or valid_mac(val))) ))), ], StrFixedLenField("hwdst", None, length_from=lambda pkt: pkt.hwlen), ), MultipleTypeField( [ (IPField("pdst", "0.0.0.0"), (lambda pkt: pkt.ptype == 0x0800 and pkt.plen == 4, lambda pkt, val: pkt.ptype == 0x0800 and ( pkt.plen == 4 or (pkt.plen is None and (val is None or valid_net(val))) ))), (IP6Field("pdst", "::"), (lambda pkt: pkt.ptype == 0x86dd and pkt.plen == 16, lambda pkt, val: pkt.ptype == 0x86dd and ( pkt.plen == 16 or (pkt.plen is None and (val is None or valid_net6(val))) ))), ], StrFixedLenField("pdst", None, length_from=lambda pkt: pkt.plen), ), ] def hashret(self): return struct.pack(">HHH", self.hwtype, self.ptype, ((self.op + 1) // 2)) + self.payload.hashret() def answers(self, other): if not isinstance(other, ARP): return False if self.op != other.op + 1: return False # We use a loose comparison on psrc vs pdst to catch answers # with ARP leaks self_psrc = self.get_field('psrc').i2m(self, self.psrc) other_pdst = other.get_field('pdst').i2m(other, other.pdst) return self_psrc[:len(other_pdst)] == other_pdst[:len(self_psrc)] def route(self): fld, dst = self.getfield_and_val("pdst") fld, dst = fld._find_fld_pkt_val(self, dst) if isinstance(dst, Gen): dst = next(iter(dst)) if isinstance(fld, IP6Field): return conf.route6.route(dst) elif isinstance(fld, IPField): return conf.route.route(dst) else: return None, None, None def extract_padding(self, s): return "", s def mysummary(self): if self.op == 1: return self.sprintf("ARP who has %pdst% says %psrc%") if self.op == 2: return self.sprintf("ARP is at %hwsrc% says %psrc%") return self.sprintf("ARP %op% %psrc% > %pdst%")
class IGMPv3(IGMP): """IGMP Message Class for v3. This class is derived from class Packet. The fields defined below are a direct interpretation of the v3 Membership Query Message. Fields 'type' through 'qqic' are directly assignable. For 'numsrc', do not assign a value. Instead add to the 'srcaddrs' list to auto-set 'numsrc'. To assign values to 'srcaddrs', use the following methods:: c = IGMPv3() c.srcaddrs = ['1.2.3.4', '5.6.7.8'] c.srcaddrs += ['192.168.10.24'] At this point, 'c.numsrc' is three (3) 'chksum' is automagically calculated before the packet is sent. 'mrcode' is also the Advertisement Interval field """ name = "IGMPv3" igmpv3types = { 0x11: "Membership Query", 0x22: "Version 3 Membership Report", 0x30: "Multicast Router Advertisement", 0x31: "Multicast Router Solicitation", 0x32: "Multicast Router Termination" } fields_desc = [ ByteEnumField("type", 0x11, igmpv3types), ByteField("mrcode", 20), XShortField("chksum", None) ] def encode_maxrespcode(self): """Encode and replace the mrcode value to its IGMPv3 encoded time value if needed, # noqa: E501 as specified in rfc3376#section-4.1.1. If value < 128, return the value specified. If >= 128, encode as a floating # noqa: E501 point value. Value can be 0 - 31744. """ value = self.mrcode if value < 128: code = value elif value > 31743: code = 255 else: exp = 0 value >>= 3 while (value > 31): exp += 1 value >>= 1 exp <<= 4 code = 0x80 | exp | (value & 0x0F) self.mrcode = code def mysummary(self): """Display a summary of the IGMPv3 object.""" if isinstance(self.underlayer, IP): return self.underlayer.sprintf( "IGMPv3: %IP.src% > %IP.dst% %IGMPv3.type%") # noqa: E501 else: return self.sprintf("IGMPv3 %IGMPv3.type%") @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 4: if orb(_pkt[0]) in [0x12, 0x16, 0x17]: return IGMP elif orb(_pkt[0]) == 0x11 and len(_pkt) < 12: return IGMP return IGMPv3
class CDPv2_HDR(_CDPChecksum, CDPMsgGeneric): name = "Cisco Discovery Protocol version 2" fields_desc = [ByteField("vers", 2), ByteField("ttl", 180), XShortField("cksum", None), PacketListField("msg", [], _CDPGuessPayloadClass)]
class ISIS_ChecksumTlv(ISIS_GenericTlv): name = "ISIS Optional Checksum TLV" fields_desc = [ByteEnumField("type", 12, _isis_tlv_names), ByteField("len", 2), XShortField("checksum", None)]