class LoWPAN_NHC_UDP(LoWPAN_NHC_Hdr): fields_desc = [ BitField("res", 0x1e, 5), BitField("C", 0, 1), BitField("P", 0, 2), MultipleTypeField( [(BitField("udpSourcePort", 0, 16), lambda pkt: pkt.P in [0, 1]), (BitField("udpSourcePort", 0, 8), lambda pkt: pkt.P == 2), (BitField("udpSourcePort", 0, 4), lambda pkt: pkt.P == 3)], BitField("udpSourcePort", 0x0, 16), ), MultipleTypeField( [(BitField("udpDestPort", 0, 16), lambda pkt: pkt.P in [0, 2]), (BitField("udpDestPort", 0, 8), lambda pkt: pkt.P == 1), (BitField("udpDestPort", 0, 4), lambda pkt: pkt.P == 3)], BitField("udpDestPort", 0x0, 16), ), ConditionalField( XShortField("udpChecksum", 0x0), lambda pkt: pkt.C == 0 ), ]
class NEGOEX_EXCHANGE_MESSAGE(Packet): OFFSET = 64 show_indent = 0 fields_desc = [ NEGOEX_MESSAGE_HEADER, UUIDEnumField("AuthScheme", None, _NEGOEX_AUTH_SCHEMES), LEIntField("ExchangeBufferOffset", 0), LEIntField("ExchangeLen", 0), _NTLMPayloadField( 'Payload', OFFSET, [ # The NEGOEX doc mentions the following blob as as an # "opaque handshake for the client authentication scheme". # NEGOEX_EXCHANGE_NTLM is a reversed interpretation, and is # probably not accurate. MultipleTypeField( [ (PacketField("Exchange", None, NEGOEX_EXCHANGE_NTLM), lambda pkt: pkt.AuthScheme == \ UUID("5c33530d-eaf9-0d4d-b2ec-4ae3786ec308")), ], StrField("Exchange", b"") ) ], length_from=lambda pkt: pkt.cbMessageLength - pkt.cbHeaderLength), ]
class SAPHDBOptionPartRow(PacketNoPadded): """SAP HANA SQL Command Network Protocol Option Part Row This packet represents a row in an Option Part. Each row is comprised of a key, type and value. """ part_kind = None option_keys = None name = "SAP HANA SQL Command Network Protocol Option Part Row" fields_desc = [ MultiEnumField("key", 0, hdb_option_part_key_vals, depends_on=lambda x: x.part_kind, fmt="<b"), EnumField("type", 0, hdb_data_type_vals, fmt="<b"), ConditionalField(FieldLenField("length", None, length_of="value", fmt="<h"), lambda x: x.type in [29, 30, 33]), MultipleTypeField( [ (LESignedByteField("value", 0), lambda x: x.type == 1), (LESignedShortField("value", 0), lambda x: x.type == 2), (LESignedIntField("value", 0), lambda x: x.type == 3), (LESignedLongField("value", 0), lambda x: x.type == 4), (Field("value", 0, fmt="<d"), lambda x: x.type == 7), (YesNoByteField("value", 0), lambda x: x.type == 28), (StrFixedLenField("value", None, length_from=lambda x: x.length), lambda x: x.type in [29, 30, 33]), ], StrField("value", ""), ), ]
class DNSRR(InheritOriginDNSStrPacket): name = "DNS Resource Record" show_indent = 0 fields_desc = [DNSStrField("rrname", ""), ShortEnumField("type", 1, dnstypes), ShortEnumField("rclass", 1, dnsclasses), IntField("ttl", 0), FieldLenField("rdlen", None, length_of="rdata", fmt="H"), MultipleTypeField( [ # A (IPField("rdata", "0.0.0.0"), lambda pkt: pkt.type == 1), # AAAA (IP6Field("rdata", "::"), lambda pkt: pkt.type == 28), # NS, MD, MF, CNAME, PTR (DNSStrField("rdata", "", length_from=lambda pkt: pkt.rdlen), lambda pkt: pkt.type in [2, 3, 4, 5, 12]), # TEXT (DNSTextField("rdata", [], length_from=lambda pkt: pkt.rdlen), lambda pkt: pkt.type == 16), ], StrLenField("rdata", "", length_from=lambda pkt:pkt.rdlen) )]
class FRMPayload(Packet): name = "FRMPayload" fields_desc = [ ConditionalField( MultipleTypeField(datapayload_list, StrField("DataPayload", "", remain=4)), lambda pkt: (dpload_type(pkt) is not None)), ConditionalField( PacketListField("Join_Request_Field", b"", Join_Request, length_from=lambda pkt: 18), lambda pkt: (pkt.MType == 0b000)), ConditionalField( PacketListField("Join_Accept_Field", b"", Join_Accept, count_from=lambda pkt: 1), lambda pkt: (pkt.MType == 0b001 and LoRa.encrypted is False)), ConditionalField( StrField("Join_Accept_Encrypted", 0), lambda pkt: (pkt.MType == 0b001 and LoRa.encrypted is True)), # noqa: E501 ConditionalField( PacketListField( "ReJoin_Request_Field", b"", # noqa: E501 RejoinReq, length_from=lambda pkt: 14), lambda pkt: (pkt.MType == 0b111)) ]
def _NTLMStrField(name, default): return MultipleTypeField( [ (StrFieldUtf16(name, default), lambda pkt: pkt.NegotiateFlags.A) ], StrField(name, default), )
class LoWPANMesh(Packet): name = "6LoWPAN Mesh Packet" deprecated_fields = { "_v": ("v", "2.4.4"), "_f": ("f", "2.4.4"), "_sourceAddr": ("src", "2.4.4"), "_destinyAddr": ("dst", "2.4.4"), } fields_desc = [ BitField("reserved", 0x2, 2), BitEnumField("v", 0x0, 1, ["EUI-64", "Short"]), BitEnumField("f", 0x0, 1, ["EUI-64", "Short"]), BitField("hopsLeft", 0x0, 4), MultipleTypeField([(XShortField("src", 0x0), lambda pkt: pkt.v == 1)], XLongField("src", 0x0)), MultipleTypeField([(XShortField("dst", 0x0), lambda pkt: pkt.v == 1)], XLongField("dst", 0x0)) ]
class GMLAN_RD(Packet): name = 'RequestDownload' fields_desc = [ XByteField('dataFormatIdentifier', 0), MultipleTypeField([ (XShortField('memorySize', 0), lambda pkt: GMLAN.determine_len(2)), (X3BytesField('memorySize', 0), lambda pkt: GMLAN.determine_len(3)), (XIntField('memorySize', 0), lambda pkt: GMLAN.determine_len(4)) ], XIntField('memorySize', 0)) ]
class LLDPDUPortID(LLDPDU): """ ieee 802.1ab-2016 - sec. 8.5.3 / p. 26 """ LLDP_PORT_ID_TLV_SUBTYPES = { 0x00: 'reserved', 0x01: 'interface alias', 0x02: 'port component', 0x03: 'MAC address', 0x04: 'network address', 0x05: 'interface name', 0x06: 'agent circuit ID', 0x07: 'locally assigned', range(0x08, 0xff): 'reserved' } SUBTYPE_RESERVED = 0x00 SUBTYPE_INTERFACE_ALIAS = 0x01 SUBTYPE_PORT_COMPONENT = 0x02 SUBTYPE_MAC_ADDRESS = 0x03 SUBTYPE_NETWORK_ADDRESS = 0x04 SUBTYPE_INTERFACE_NAME = 0x05 SUBTYPE_AGENT_CIRCUIT_ID = 0x06 SUBTYPE_LOCALLY_ASSIGNED = 0x07 fields_desc = [ BitEnumField('_type', 0x02, 7, LLDPDU.TYPES), BitFieldLenField('_length', None, 9, length_of='id', adjust=lambda pkt, x: _ldp_id_adjustlen(pkt, x)), ByteEnumField('subtype', 0x00, LLDP_PORT_ID_TLV_SUBTYPES), ConditionalField( ByteField('family', 0), lambda pkt: pkt.subtype == 0x04 ), MultipleTypeField([ ( MACField('id', None), lambda pkt: pkt.subtype == 0x03 ), ( IPField('id', None), lambda pkt: pkt.subtype == 0x04 ), ], StrLenField('id', '', length_from=lambda pkt: pkt._length - 1) ) ] def _check(self): """ run layer specific checks """ if conf.contribs['LLDP'].strict_mode() and not self.id: raise LLDPInvalidLengthField('id must be >= 1 characters long')
class GMLAN_RMBA(Packet): name = 'ReadMemoryByAddress' 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)), XShortField('memorySize', 0), ]
class GMLAN_DPBA(Packet): name = 'DefinePIDByAddress' fields_desc = [ XShortField('parameterIdentifier', 0), 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)), XByteField('memorySize', 0), ]
class LenStringPacket(Packet): # Among other things, can be (port_any_t - DCE 1.1 RPC - p592) name = "len string packet" fields_desc = [ FieldLenField('length', 0, length_of='data', fmt="H"), MultipleTypeField([(StrFixedLenField( 'data', '', length=2), lambda pkt: not pkt.length)], StrLenField('data', '', length_from=lambda pkt: pkt.length)) ] def extract_padding(self, p): return b"", p
class GMLAN_TD(Packet): subfunctions = {0x00: "download", 0x80: "downloadAndExecuteOrExecute"} name = 'TransferData' fields_desc = [ ByteEnumField('subfunction', 0, subfunctions), MultipleTypeField([(XShortField( 'startingAddress', 0), lambda pkt: GMLAN.determine_len(2)), (X3BytesField('startingAddress', 0), lambda pkt: GMLAN.determine_len(3)), (XIntField('startingAddress', 0), lambda pkt: GMLAN.determine_len(4))], XIntField('startingAddress', 0)), StrField("dataRecord", b"") ]
class Dot15d4AuxSecurityHeader(Packet): name = "802.15.4 Auxiliary Security Header" fields_desc = [ BitField("sec_sc_reserved", 0, 3), # Key Identifier Mode # 0: Key is determined implicitly from the originator and recipient(s) of the frame # noqa: E501 # 1: Key is determined explicitly from the the 1-octet Key Index subfield of the Key Identifier field # noqa: E501 # 2: Key is determined explicitly from the 4-octet Key Source and the 1-octet Key Index # noqa: E501 # 3: Key is determined explicitly from the 8-octet Key Source and the 1-octet Key Index # noqa: E501 BitEnumField( "sec_sc_keyidmode", 0, 2, { 0: "Implicit", 1: "1oKeyIndex", 2: "4o-KeySource-1oKeyIndex", 3: "8o-KeySource-1oKeyIndex" } # noqa: E501 ), BitEnumField( "sec_sc_seclevel", 0, 3, { 0: "None", 1: "MIC-32", 2: "MIC-64", 3: "MIC-128", 4: "ENC", 5: "ENC-MIC-32", 6: "ENC-MIC-64", 7: "ENC-MIC-128" }), # noqa: E501 XLEIntField("sec_framecounter", 0x00000000), # 4 octets # Key Identifier (variable length): identifies the key that is used for cryptographic protection # noqa: E501 # Key Source : length of sec_keyid_keysource varies btwn 0, 4, and 8 bytes depending on sec_sc_keyidmode # noqa: E501 MultipleTypeField( [ # 4 octets when sec_sc_keyidmode == 2 (XLEIntField("sec_keyid_keysource", 0x00000000), lambda pkt: pkt.getfieldval("sec_sc_keyidmode") == 2), # 8 octets when sec_sc_keyidmode == 3 (LELongField("sec_keyid_keysource", 0x0000000000000000), lambda pkt: pkt.getfieldval("sec_sc_keyidmode") == 3), ], StrFixedLenField("sec_keyid_keysource", "", length=0)), # Key Index (1 octet): allows unique identification of different keys with the same originator # noqa: E501 ConditionalField(XByteField("sec_keyid_keyindex", 0xFF), lambda pkt: pkt.getfieldval("sec_sc_keyidmode") != 0), ]
class ENIPTCP(Packet): """Ethernet/IP packet over TCP""" name = "ENIPTCP" fields_desc = [ LEShortEnumField("commandId", None, _commandIdList), LEShortField("length", 0), XLEIntField("session", 0), LEIntEnumField("status", None, _statusList), LELongField("senderContext", 0), LEIntField("options", 0), MultipleTypeField( [ # List Services Reply (PacketField("commandSpecificData", ENIPListServicesReply, ENIPListServicesReply), lambda pkt: pkt.commandId == 0x4), # List Identity Reply (PacketField("commandSpecificData", ENIPListIdentityReply, ENIPListIdentityReply), lambda pkt: pkt.commandId == 0x63), # List Interfaces Reply (PacketField("commandSpecificData", ENIPListInterfacesReply, ENIPListInterfacesReply), lambda pkt: pkt.commandId == 0x64), # Register Session (PacketField("commandSpecificData", ENIPRegisterSession, ENIPRegisterSession), lambda pkt: pkt.commandId == 0x65), # Send RR Data (PacketField("commandSpecificData", ENIPSendRRData, ENIPSendRRData), lambda pkt: pkt.commandId == 0x6f), # Send Unit Data (PacketField("commandSpecificData", ENIPSendUnitData, ENIPSendUnitData), lambda pkt: pkt.commandId == 0x70), ], PacketField( "commandSpecificData", None, CommandSpecificData) # By default ), ] def post_build(self, pkt, pay): if self.length is None and pay: pkt = pkt[:2] + struct.pack("<H", len(pay)) + pkt[4:] return pkt + pay
class GMLAN_RD(Packet): name = 'RequestDownload' fields_desc = [ XByteField('dataFormatIdentifier', 0), MultipleTypeField([ (XShortField('memorySize', 0), lambda pkt: GMLAN.determine_len(2)), (X3BytesField('memorySize', 0), lambda pkt: GMLAN.determine_len(3)), (XIntField('memorySize', 0), lambda pkt: GMLAN.determine_len(4)) ], XIntField('memorySize', 0)) ] @staticmethod def get_log(pkt): return pkt.sprintf("%GMLAN.service%"), \ (pkt.dataFormatIdentifier, pkt.memorySize)
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', b"", fmt="B") ] def answers(self, other): return isinstance(other, GMLAN_RMBA) and \ other.memoryAddress == self.memoryAddress
class GMLAN_RMBA(Packet): name = 'ReadMemoryByAddress' 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)), XShortField('memorySize', 0), ] @staticmethod def get_log(pkt): return pkt.sprintf("%GMLAN.service%"), \ pkt.sprintf("%GMLAN_RMBA.memoryAddress%")
class GMLAN_DPBA(Packet): name = 'DefinePIDByAddress' fields_desc = [ XShortField('parameterIdentifier', 0), 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)), XByteField('memorySize', 0), ] @staticmethod def get_log(pkt): return pkt.sprintf("%GMLAN.service%"), \ (pkt.parameterIdentifier, pkt.memoryAddress, pkt.memorySize)
class SCTPChunkParamAddIPAddr(_SCTPChunkParam, Packet): fields_desc = [ ShortEnumField("type", 0xc001, sctpchunkparamtypes), FieldLenField("len", None, length_of="addr", adjust=lambda pkt, x: x + 12), XIntField("correlation_id", None), ShortEnumField("addr_type", 5, sctpchunkparamtypes), FieldLenField("addr_len", None, length_of="addr", adjust=lambda pkt, x: x + 4), MultipleTypeField([ (IPField("addr", "127.0.0.1"), lambda p: p.addr_type == 5), (IP6Field("addr", "::1"), lambda p: p.addr_type == 6), ], StrFixedLenField("addr", "", length_from=lambda pkt: pkt.addr_len)) ]
class CEMI(Packet): name = "CEMI" fields_desc = [ ByteEnumField("message_code", None, MESSAGE_CODES), MultipleTypeField( [(PacketField("cemi_data", LcEMI(), LcEMI), lambda pkt: pkt.message_code == 0x11), (PacketField("cemi_data", LcEMI(), LcEMI), lambda pkt: pkt.message_code == 0x2e), (PacketField("cemi_data", DPcEMI(), DPcEMI), lambda pkt: pkt.message_code == 0xFC), (PacketField("cemi_data", DPcEMI(), DPcEMI), lambda pkt: pkt.message_code == 0xFB), (PacketField("cemi_data", DPcEMI(), DPcEMI), lambda pkt: pkt.message_code == 0xF6), (PacketField("cemi_data", DPcEMI(), DPcEMI), lambda pkt: pkt.message_code == 0xF5)], PacketField("cemi_data", LcEMI(), LcEMI)) ]
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), MultipleTypeField([ (FieldListField("addrlist", [], IPField("", "0.0.0.0"), count_from=lambda pkt: pkt.ipcount), lambda p: isinstance(p.underlayer, IP)), (FieldListField("addrlist", [], IP6Field("", "::"), count_from=lambda pkt: pkt.ipcount), lambda p: isinstance(p.underlayer, IPv6)), ], StrField("addrlist", "")) ] 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 GMLAN_TD(Packet): subfunctions = {0x00: "download", 0x80: "downloadAndExecuteOrExecute"} name = 'TransferData' fields_desc = [ ByteEnumField('subfunction', 0, subfunctions), MultipleTypeField([(XShortField( 'startingAddress', 0), lambda pkt: GMLAN.determine_len(2)), (X3BytesField('startingAddress', 0), lambda pkt: GMLAN.determine_len(3)), (XIntField('startingAddress', 0), lambda pkt: GMLAN.determine_len(4))], XIntField('startingAddress', 0)), StrField("dataRecord", b"") ] @staticmethod def get_log(pkt): return pkt.sprintf("%GMLAN.service%"), \ (pkt.sprintf("%GMLAN_TD.subfunction%"), pkt.startingAddress, pkt.dataRecord)
class VQPEntry(Packet): name = "VQPEntry" fields_desc = [ IntEnumField( "datatype", 0, { 3073: "clientIPAddress", 3074: "portName", 3075: "VLANName", 3076: "Domain", 3077: "ethernetPacket", 3078: "ReqMACAddress", 3079: "unknown", 3080: "ResMACAddress" }), FieldLenField("len", None, length_of="data", fmt="H"), MultipleTypeField([ (IPField("data", "0.0.0.0"), lambda p: p.datatype == 3073), (MACField("data", "00:00:00:00:00:00"), lambda p: p.datatype in [3078, 3080]), ], StrLenField("data", None, length_from=lambda p: p.len)) ]
class SOCKS5Request(Packet): name = "SOCKS 5 - Request" overload_fields = {SOCKS: {"vn": 0x5}} fields_desc = [ ByteEnumField("cd", 0x0, _socks5_cdtypes), ByteField("res", 0), ByteEnumField("atyp", 0x1, {0x1: "IPv4", 0x3: "DomainName", 0x4: "IPv6"}), MultipleTypeField( [ # IPv4 (IPField("addr", "0.0.0.0"), lambda pkt: pkt.atyp == 0x1), # DNS (DNSStrField("addr", ""), lambda pkt: pkt.atyp == 0x3), # IPv6 (IP6Field("addr", "::"), lambda pkt: pkt.atyp == 0x4), ], StrField("addr", "") ), ShortField("port", 80), ]
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', b"", 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 AV_PAIR(Packet): name = "NTLM AV Pair" fields_desc = [ LEShortEnumField( 'AvId', 0, { 0x0000: "MsvAvEOL", 0x0001: "MsvAvNbComputerName", 0x0002: "MsvAvNbDomainName", 0x0003: "MsvAvDnsComputerName", 0x0004: "MsvAvDnsDomainName", 0x0005: "MsvAvDnsTreeName", 0x0006: "MsvAvFlags", 0x0007: "MsvAvTimestamp", 0x0008: "MsvAvSingleHost", 0x0009: "MsvAvTargetName", 0x000A: "MsvAvChannelBindings", }), FieldLenField('AvLen', None, length_of="Value", fmt="<H"), MultipleTypeField([ (LEIntEnumField( 'Value', 1, { 0x0001: "constrained", 0x0002: "MIC integrity", 0x0004: "SPN from untrusted source" }), lambda pkt: pkt.AvId == 0x0006), (UTCTimeField("Value", None, epoch=[1601, 1, 1, 0, 0, 0], custom_scaling=1e7, fmt="<Q"), lambda pkt: pkt.AvId == 0x0007), (PacketField('Value', Single_Host_Data(), Single_Host_Data), lambda pkt: pkt.AvId == 0x0008), (XStrLenField('Value', b"", length_from=lambda pkt: pkt.AvLen), lambda pkt: pkt.AvId == 0x000A), ], StrLenFieldUtf16('Value', b"", length_from=lambda pkt: pkt.AvLen)) ] def default_payload_class(self, payload): return conf.padding_layer
class IFETlv(Packet): """ Parent Class interhit by all ForCES TLV strucutures """ name = "IFETlv" fields_desc = [ ShortEnumField("type", 0, IFE_META_TYPES), FieldLenField("length", None, length_of="value", adjust=lambda pkt, x: x + 4), MultipleTypeField([ (PadField(ShortField("value", 0), 4, padwith=b'\x00'), lambda pkt: pkt.type in IFE_TYPES_SHORT), (PadField(IntField("value", 0), 4, padwith=b'\x00'), lambda pkt: pkt.type in IFE_TYPES_INT), ], PadField(IntField("value", 0), 4, padwith=b'\x00')), ] def extract_padding(self, s): return "", s
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 LoWPAN_IPHC(Packet): """6LoWPAN IPv6 header compressed packets It follows the implementation of RFC6282 """ __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)"] 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"), } 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 # Context Identifier Extension ConditionalField( BitField("sci", 0, 4), lambda pkt: pkt.cid == 0x1 ), ConditionalField( BitField("dci", 0, 4), lambda pkt: pkt.cid == 0x1 ), # https://tools.ietf.org/html/rfc6282#section-3.2.1 ConditionalField( BitField("tc_ecn", 0, 2), lambda pkt: pkt.tf in [0, 1, 2] ), ConditionalField( BitField("tc_dscp", 0, 6), lambda pkt: pkt.tf in [0, 2], ), ConditionalField( MultipleTypeField( [(BitField("rsv", 0, 4), lambda pkt: pkt.tf == 0)], BitField("rsv", 0, 2), ), lambda pkt: pkt.tf in [0, 1] ), ConditionalField( BitField("flowlabel", 0, 20), lambda pkt: pkt.tf in [0, 1] ), # Inline fields https://tools.ietf.org/html/rfc6282#section-3.1.1 ConditionalField( ByteEnumField("nhField", 0x0, ipv6nh), lambda pkt: pkt.nh == 0x0 ), ConditionalField( ByteField("hopLimit", 0x0), lambda pkt: pkt.hlim == 0x0 ), # The src and dst fields are filled up or removed in the # pre_dissect and post_build, depending on the other options. IP6FieldLenField("src", "::", length_of=source_addr_size), IP6FieldLenField("dst", "::", length_of=dest_addr_size), # problem when it's 0 # noqa: E501 ] 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.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 packet.src = self.decompressSourceAddr(packet) packet.dst = self.decompressDestAddr(packet) pay_cls = self.guess_payload_class(data) if pay_cls == IPv6: packet.add_payload(data) data = raw(packet) elif pay_cls == LoWPAN_NHC: self._ipv6 = packet return Packet.post_dissect(self, data) def decompressDestAddr(self, packet): # https://tools.ietf.org/html/rfc6282#section-3.1.1 try: tmp_ip = inet_pton(socket.AF_INET6, self.dst) except socket.error: tmp_ip = b"\x00" * 16 if self.m == 0 and self.dac == 0: if self.dam == 0: # Address fully carried 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 elif self.dam == 3: tmp_ip = _extract_upperaddress(self, source=False) elif self.m == 0 and self.dac == 1: if self.dam == 0: # reserved pass elif self.dam == 0x3: # should use context IID + encapsulating header tmp_ip = _extract_upperaddress(self, source=False) elif self.dam not in [0x1, 0x2]: # https://tools.ietf.org/html/rfc6282#page-9 # Should use context information: unimplemented pass elif self.m == 1 and self.dac == 0: if self.dam == 0: # Address fully carried pass elif self.dam == 1: tmp = b"\xff" + chb(tmp_ip[16 - dest_addr_size(self)]) tmp_ip = tmp + b"\x00" * 9 + tmp_ip[-5:] elif self.dam == 2: tmp = b"\xff" + chb(tmp_ip[16 - dest_addr_size(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: # https://tools.ietf.org/html/rfc6282#page-10 # https://github.com/wireshark/wireshark/blob/f54611d1104d85a425e52c7318c522ed249916b6/epan/dissectors/packet-6lowpan.c#L2149-L2166 # Format: ffXX:XXLL:PPPP:PPPP:PPPP:PPPP:XXXX:XXXX # P and L should be retrieved from context P = b"\x00" * 16 L = b"\x00" X = tmp_ip[-6:] tmp_ip = b"\xff" + X[:2] + L + P[:8] + X[2:6] else: # all the others values: reserved pass self.dst = inet_ntop(socket.AF_INET6, tmp_ip) return self.dst def compressSourceAddr(self, ipv6): # https://tools.ietf.org/html/rfc6282#section-3.1.1 tmp_ip = inet_pton(socket.AF_INET6, ipv6.src) if self.sac == 0: if self.sam == 0x0: pass 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.src = inet_ntop(socket.AF_INET6, b"\x00" * (16 - len(tmp_ip)) + tmp_ip) # noqa: E501 return self.src def compressDestAddr(self, ipv6): # https://tools.ietf.org/html/rfc6282#section-3.1.1 tmp_ip = inet_pton(socket.AF_INET6, ipv6.dst) if self.m == 0 and self.dac == 0: if self.dam == 0x0: pass 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 == 0x0: pass 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: if self.dam == 0: tmp_ip = b"\x00" * 10 + tmp_ip[1:3] + tmp_ip[12:16] self.dst = inet_ntop(socket.AF_INET6, tmp_ip) def decompressSourceAddr(self, packet): # https://tools.ietf.org/html/rfc6282#section-3.1.1 try: tmp_ip = inet_pton(socket.AF_INET6, self.src) except socket.error: tmp_ip = b"\x00" * 16 if self.sac == 0: if self.sam == 0x0: # Full address is carried in-line pass elif self.sam == 0x1: tmp_ip = LINK_LOCAL_PREFIX[0:8] + tmp_ip[16 - source_addr_size(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_size(self):16] elif self.sam == 0x3: # Taken from encapsulating header tmp_ip = _extract_upperaddress(self, source=True) else: # self.sac == 1: if self.sam == 0x0: # Unspecified address :: pass elif self.sam == 0x1: # should use context IID pass elif self.sam == 0x2: # should use context IID tmp = LINK_LOCAL_PREFIX[0:8] + b"\x00\x00\x00\xff\xfe\x00" tmp_ip = tmp + tmp_ip[16 - source_addr_size(self):16] elif self.sam == 0x3: # should use context IID tmp_ip = LINK_LOCAL_PREFIX[0:8] + b"\x00" * 8 self.src = inet_ntop(socket.AF_INET6, tmp_ip) return self.src def guess_payload_class(self, payload): if self.nh: return LoWPAN_NHC u = self.underlayer if u and isinstance(u, (LoWPANFragmentationFirst, LoWPANFragmentationSubsequent)): return Raw return IPv6 def do_build(self): _cur = self if isinstance(_cur.payload, LoWPAN_NHC): _cur = _cur.payload if not isinstance(_cur.payload, IPv6): return Packet.do_build(self) ipv6 = _cur.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.nhField = ipv6.nh elif self.nh == 1: # This will be handled in LoWPAN_NHC pass # 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 pass # 5. Compress Source Addr self.compressSourceAddr(ipv6) self.compressDestAddr(ipv6) return Packet.do_build(self) def do_build_payload(self): # Elide the IPv6 payload if isinstance(self.payload, IPv6): return raw(self.payload.payload) return Packet.do_build_payload(self) 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