class UDS_RDBI(Packet): dataIdentifiers = ObservableDict() name = 'ReadDataByIdentifier' fields_desc = [ FieldListField("identifiers", [], XShortEnumField('dataIdentifier', 0, dataIdentifiers)) ]
class GENEVE(Packet): name = "GENEVE" fields_desc = [ BitField("version", 0, 2), BitField("optionlen", None, 6), BitField("oam", 0, 1), BitField("critical", 0, 1), BitField("reserved", 0, 6), XShortEnumField("proto", 0x0000, ETHER_TYPES), X3BytesField("vni", 0), XByteField("reserved2", 0x00), PacketListField("options", [], GeneveOptions, length_from=lambda pkt: pkt.optionlen * 4) ] def post_build(self, p, pay): if self.optionlen is None: tmp_len = (len(p) - 8) // 4 p = chb(tmp_len & 0x2f | orb(p[0]) & 0xc0) + p[1:] return p + pay def answers(self, other): if isinstance(other, GENEVE): if ((self.proto == other.proto) and (self.vni == other.vni)): return self.payload.answers(other.payload) else: return self.payload.answers(other) return 0 def mysummary(self): return self.sprintf("GENEVE (vni=%GENEVE.vni%," "optionlen=%GENEVE.optionlen%," "proto=%GENEVE.proto%)")
class CDPMsgCapabilities(CDPMsgGeneric): name = "Capabilities" fields_desc = [ XShortEnumField("type", 0x0004, _cdp_tlv_types), ShortField("len", 8), FlagsField("cap", 0, 32, _cdp_capabilities) ]
class DoIPRawPacket(Packet): """ This class models the a raw/generic Diagnositics over IP (DoIP) packet. The protocol version (inverse protocol version) are fixed to 0x02. The fields 'payload_type', 'payload_length' and 'payload_content' should be set according to the actual payload. Example of a generic acknowledge: >>> from scapy.contrib.doip import * >>> DoIP(payload_type=0x0000, payload_length=1, payload_content=b'\x02') <DoIP payload_type=generic DoIP header negative acknowledge payload_length=1 payload_content='\x02' |> """ name = "DoIPRaw" # field names are abbreviated to facilitate pretty printing etc. fields_desc = [ XByteField("protocol_version", 0x02), XByteField("inverse_version", 0xFD), XShortEnumField("payload_type", 0, payload_types), IntField("payload_length", 0), StrLenField("payload_content", "", length_from=lambda pkt: pkt.payload_length) ] def dissect(self, b): """ Dissect an incoming DoIP packet. :param b: bytes to dissect :type b: bytes :raises: ValueError """ if len(b) < 8: raise ValueError("given packet too short") return super(DoIPRawPacket, self).dissect(b)
class Dot1Q(Packet): name = "802.1Q" aliastypes = [Ether] fields_desc = [BitField("prio", 0, 3), BitField("id", 0, 1), BitField("vlan", 1, 12), XShortEnumField("type", 0x0000, ETHER_TYPES)] def answers(self, other): if isinstance(other, Dot1Q): if ((self.type == other.type) and (self.vlan == other.vlan)): return self.payload.answers(other.payload) else: return self.payload.answers(other) return 0 def default_payload_class(self, pay): if self.type <= 1500: return LLC return conf.raw_layer def extract_padding(self, s): if self.type <= 1500: return s[:self.type], s[self.type:] return s, None def mysummary(self): if isinstance(self.underlayer, Ether): return self.underlayer.sprintf("802.1q %Ether.src% > %Ether.dst% (%Dot1Q.type%) vlan %Dot1Q.vlan%") # noqa: E501 else: return self.sprintf("802.1q (%Dot1Q.type%) vlan %Dot1Q.vlan%")
class CDPMsgDuplex(CDPMsgGeneric): name = "Duplex" fields_desc = [ XShortEnumField("type", 0x000b, _cdp_tlv_types), ShortField("len", 5), ByteEnumField("duplex", 0x00, _cdp_duplex) ]
class CDPMsgPortID(CDPMsgGeneric): name = "Port ID" fields_desc = [ XShortEnumField("type", 0x0003, _cdp_tlv_types), FieldLenField("len", None, "iface", "!H", adjust=lambda pkt, x: x + 4), StrLenField("iface", "Port 1", length_from=lambda x: x.len - 4) ] # noqa: E501
class ModbusPDU08DiagnosticsResponse(_ModbusPDUNoPayload): name = "Diagnostics Response" fields_desc = [ XByteField("funcCode", 0x08), XShortEnumField("subFunc", 0x0000, _diagnostics_sub_function), FieldListField("data", [0x0000], XShortField("", 0x0000)) ]
class CDPMsgNativeVLAN(CDPMsgGeneric): name = "Native VLAN" fields_desc = [ XShortEnumField("type", 0x000a, _cdp_tlv_types), ShortField("len", 6), ShortField("vlan", 1) ]
class GENEVE(Packet): name = "GENEVE" fields_desc = [ BitField("version", 0, 2), BitField("optionlen", None, 6), BitField("oam", 0, 1), BitField("critical", 0, 1), BitField("reserved", 0, 6), XShortEnumField("proto", 0x0000, ETHER_TYPES), X3BytesField("vni", 0), XByteField("reserved2", 0x00), GENEVEOptionsField("options", "") ] def post_build(self, p, pay): p += pay optionlen = self.optionlen if optionlen is None: optionlen = (len(self.options) + 3) // 4 p = chb(optionlen & 0x2f | orb(p[0]) & 0xc0) + p[1:] return p def answers(self, other): if isinstance(other, GENEVE): if ((self.proto == other.proto) and (self.vni == other.vni)): return self.payload.answers(other.payload) else: return self.payload.answers(other) return 0 def mysummary(self): return self.sprintf("GENEVE (vni=%GENEVE.vni%," "optionlen=%GENEVE.optionlen%," "proto=%GENEVE.proto%)")
class CDPMsg(CDPMsgGeneric): name = "CDP " fields_desc = [XShortEnumField("type", None, _cdp_tlv_types), FieldLenField("len", None, "val", fmt="!H", adjust=lambda pkt, x: x + 4), StrLenField("val", "", length_from=lambda x:x.len - 4, max_length=65531)]
class UDS_WDBI(Packet): name = 'WriteDataByIdentifier' fields_desc = [ XShortEnumField('dataIdentifier', 0, UDS_RDBI.dataIdentifiers), StrField('dataRecord', 0, fmt="B") ]
class GRE_PPTP(GRE): """ Enhanced GRE header used with PPTP RFC 2637 """ name = "GRE PPTP" deprecated_fields = { "seqence_number": ("sequence_number", "2.4.4"), } fields_desc = [BitField("chksum_present", 0, 1), BitField("routing_present", 0, 1), BitField("key_present", 1, 1), BitField("seqnum_present", 0, 1), BitField("strict_route_source", 0, 1), BitField("recursion_control", 0, 3), BitField("acknum_present", 0, 1), BitField("flags", 0, 4), BitField("version", 1, 3), XShortEnumField("proto", 0x880b, ETHER_TYPES), ShortField("payload_len", None), ShortField("call_id", None), ConditionalField(XIntField("sequence_number", None), lambda pkt: pkt.seqnum_present == 1), # noqa: E501 ConditionalField(XIntField("ack_number", None), lambda pkt: pkt.acknum_present == 1)] # noqa: E501 def post_build(self, p, pay): p += pay if self.payload_len is None: pay_len = len(pay) p = p[:4] + chb((pay_len >> 8) & 0xff) + chb(pay_len & 0xff) + p[6:] # noqa: E501 return p
class CDPMsgIPPrefix(CDPMsgGeneric): name = "IP Prefix" type = 0x0007 fields_desc = [XShortEnumField("type", 0x0007, _cdp_tlv_types), ShortField("len", 9), IPField("prefix", "192.168.0.1"), ByteField("plen", 24)]
class IODWriteMultipleReq(Block): """IODWriteMultiple request""" fields_desc = [ BlockHeader, ShortField("seqNum", 0), UUIDField("ARUUID", None), XIntField("API", 0xffffffff), XShortField("slotNumber", 0xffff), XShortField("subslotNumber", 0xffff), StrFixedLenField("padding", "", length=2), XShortEnumField("index", 0, IOD_WRITE_REQ_INDEX), FieldLenField("recordDataLength", None, fmt="I", length_of="blocks"), StrFixedLenField("RWPadding", "", length=24), FieldListField("blocks", [], PadFieldWithLen(PacketField("", None, IODWriteReq), 4), length_from=lambda pkt: pkt.recordDataLength) ] # default values block_type = 0x0008 index = 0xe040 API = 0xffffffff slotNumber = 0xffff subslotNumber = 0xffff def post_build(self, p, pay): # patch the update of block_length, as requests field must not be # included. block_length is always 60 if self.block_length is None: p = p[:2] + struct.pack("!H", 60) + p[4:] # Remove the final padding added in requests fld, val = self.getfield_and_val("blocks") if fld.i2count(self, val) > 0: length = len(val[-1]) pad = fld.field.padlen(length) if pad > 0: p = p[:-pad] # also reduce the recordDataLength accordingly if self.recordDataLength is None: val = struct.unpack("!I", p[36:40])[0] val -= pad p = p[:36] + struct.pack("!I", val) + p[40:] return Packet.post_build(self, p, pay) def get_response(self): """Generate the response block of this request. Careful: it only sets the fields which can be set from the request """ res = IODWriteMultipleRes() for field in ["seqNum", "ARUUID", "API", "slotNumber", "subslotNumber", "index"]: res.setfieldval(field, self.getfieldval(field)) # append all block response res_blocks = [] for block in self.getfieldval("blocks"): res_blocks.append(block.get_response()) res.setfieldval("blocks", res_blocks) return res
class IODWriteMultipleRes(Block): """IODWriteMultiple response""" fields_desc = [ BlockHeader, ShortField("seqNum", 0), UUIDField("ARUUID", None), XIntField("API", 0xffffffff), XShortField("slotNumber", 0xffff), XShortField("subslotNumber", 0xffff), StrFixedLenField("padding", "", length=2), XShortEnumField("index", 0, IOD_WRITE_REQ_INDEX), FieldLenField("recordDataLength", None, fmt="I", length_of="blocks"), XShortField("additionalValue1", 0), XShortField("additionalValue2", 0), IntEnumField("status", 0, ["OK"]), StrFixedLenField("RWPadding", "", length=16), FieldListField("blocks", [], PacketField("", None, IODWriteRes), length_from=lambda pkt: pkt.recordDataLength) ] # default values block_type = 0x8008 index = 0xe040 def post_build(self, p, pay): # patch the update of block_length, as requests field must not be # included. block_length is always 60 if self.block_length is None: p = p[:2] + struct.pack("!H", 60) + p[4:] return Packet.post_build(self, p, pay)
class MACsec(Packet): """representation of one MACsec frame""" name = '802.1AE' fields_desc = [ BitField('Ver', 0, 1), BitField('ES', 0, 1), BitField('SC', 0, 1), BitField('SCB', 0, 1), BitField('E', 0, 1), BitField('C', 0, 1), BitField('an', 0, 2), BitField('reserved', 0, 2), BitField('shortlen', 0, 6), IntField("pn", 1), ConditionalField(PacketField("sci", None, MACsecSCI), lambda pkt: pkt.SC), # noqa: E501 ConditionalField(XShortEnumField("type", None, ETHER_TYPES), lambda pkt: pkt.type is not None) ] def mysummary(self): summary = self.sprintf("an=%MACsec.an%, pn=%MACsec.pn%") if self.SC: summary += self.sprintf(", sci=%MACsec.sci%") if self.type is not None: summary += self.sprintf(", %MACsec.type%") return summary
class IODWriteReq(Block): """IODWrite request block""" fields_desc = [ BlockHeader, ShortField("seqNum", 0), UUIDField("ARUUID", None), XIntField("API", 0), XShortField("slotNumber", 0), XShortField("subslotNumber", 0), StrFixedLenField("padding", "", length=2), XShortEnumField("index", 0, IOD_WRITE_REQ_INDEX), LenField("recordDataLength", None, fmt="I"), StrFixedLenField("RWPadding", "", length=24), ] # default block_type value block_type = 0x0008 def payload_length(self): return self.recordDataLength def get_response(self): """Generate the response block of this request. Careful: it only sets the fields which can be set from the request """ res = IODWriteRes() for field in ["seqNum", "ARUUID", "API", "slotNumber", "subslotNumber", "index"]: res.setfieldval(field, self.getfieldval(field)) return res
class Ether(Packet): name = "Ethernet" fields_desc = [DestMACField("dst"), SourceMACField("src"), XShortEnumField("type", 0x9000, ETHER_TYPES)] __slots__ = ["_defrag_pos"] def hashret(self): return struct.pack("H", self.type) + self.payload.hashret() def answers(self, other): if isinstance(other, Ether): if self.type == other.type: return self.payload.answers(other.payload) return 0 def mysummary(self): return self.sprintf("%src% > %dst% (%type%)") @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and len(_pkt) >= 14: if struct.unpack("!H", _pkt[12:14])[0] <= 1500: return Dot3 return cls
class GRE(Packet): name = "GRE" deprecated_fields = { "seqence_number": ("sequence_number", "2.4.4"), } fields_desc = [BitField("chksum_present", 0, 1), BitField("routing_present", 0, 1), BitField("key_present", 0, 1), BitField("seqnum_present", 0, 1), BitField("strict_route_source", 0, 1), BitField("recursion_control", 0, 3), BitField("flags", 0, 5), BitField("version", 0, 3), XShortEnumField("proto", 0x0000, ETHER_TYPES), ConditionalField(XShortField("chksum", None), lambda pkt:pkt.chksum_present == 1 or pkt.routing_present == 1), # noqa: E501 ConditionalField(XShortField("offset", None), lambda pkt:pkt.chksum_present == 1 or pkt.routing_present == 1), # noqa: E501 ConditionalField(XIntField("key", None), lambda pkt:pkt.key_present == 1), # noqa: E501 ConditionalField(XIntField("sequence_number", None), lambda pkt:pkt.seqnum_present == 1), # noqa: E501 ] @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and struct.unpack("!H", _pkt[2:4])[0] == 0x880b: return GRE_PPTP return cls def post_build(self, p, pay): p += pay if self.chksum_present and self.chksum is None: c = checksum(p) p = p[:4] + chb((c >> 8) & 0xff) + chb(c & 0xff) + p[6:] return p
class ProfinetIO(Packet): """ Basic PROFINET IO dispatcher """ fields_desc = [ XShortEnumField("frameID", 0, (i2s_frameid, s2i_frameid)) ] def guess_payload_class(self, payload): # For frameID in the RT_CLASS_* range, use the RTC packet as payload if self.frameID in [0xfefe, 0xfeff, 0xfefd]: from scapy.contrib.pnio_dcp import ProfinetDCP return ProfinetDCP elif self.frameID == 0xFE01: from scapy.contrib.pnio_rpc import Alarm_Low return Alarm_Low elif self.frameID == 0xFC01: from scapy.contrib.pnio_rpc import Alarm_High return Alarm_High elif ( (0x0100 <= self.frameID < 0x1000) or (0x8000 <= self.frameID < 0xFC00) ): return PNIORealTimeCyclicPDU return super(ProfinetIO, self).guess_payload_class(payload)
class CDPMsgUntrustedPortCoS(CDPMsgGeneric): name = "Untrusted Port CoS" fields_desc = [ XShortEnumField("type", 0x0013, _cdp_tlv_types), ShortField("len", 5), XByteField("untrusted_port_cos", 0x0) ]
class CDPMsgTrustBitmap(CDPMsgGeneric): name = "Trust Bitmap" fields_desc = [ XShortEnumField("type", 0x0012, _cdp_tlv_types), ShortField("len", 5), XByteField("trust_bitmap", 0x0) ]
class CDPMsgPower(CDPMsgGeneric): name = "Power" # Check if field length is fixed (2 bytes) fields_desc = [ XShortEnumField("type", 0x0010, _cdp_tlv_types), ShortField("len", 6), _CDPPowerField("power", 1337) ]
class CDPMsgMTU(CDPMsgGeneric): name = "MTU" # Check if field length is fixed (2 bytes) fields_desc = [ XShortEnumField("type", 0x0011, _cdp_tlv_types), ShortField("len", 6), ShortField("mtu", 1500) ]
class CDPMsgIPGateway(CDPMsgGeneric): name = "IP Gateway" type = 0x0007 fields_desc = [ XShortEnumField("type", 0x0007, _cdp_tlv_types), ShortField("len", 8), IPField("defaultgw", "192.168.0.1") ]
class CDPMsgVoIPVLANReply(CDPMsgGeneric): name = "VoIP VLAN Reply" fields_desc = [ XShortEnumField("type", 0x000e, _cdp_tlv_types), ShortField("len", 7), ByteField("status?", 1), ShortField("vlan", 1) ]
class UDS_IOCBI(Packet): name = 'InputOutputControlByIdentifier' dataIdentifiers = ObservableDict() fields_desc = [ XShortEnumField('dataIdentifier', 0, dataIdentifiers), ByteField('controlOptionRecord', 0), StrField('controlEnableMaskRecord', b"", fmt="B") ]
class KWP_CDIPR(Packet): name = 'ClearDiagnosticInformationPositiveResponse' fields_desc = [XShortEnumField('groupOfDTC', 0, KWP_CDI.DTCGroups)] def answers(self, other): # type: (Packet) -> int return isinstance(other, KWP_CDI) and \ self.groupOfDTC == other.groupOfDTC
class AlarmCRBlockRes(Block): fields_desc = [ BlockHeader, XShortEnumField("AlarmCRType", 1, ALARM_CR_TYPE), ShortField("LocalAlarmReference", 0), ShortField("MaxAlarmDataLength", 0) ] # default block_type value block_type = 0x8103