class ENIP_ListIdentity_TargetItem(scapy_all.Packet): name = "ENIP_ListIdentity_TargetItem" fields_desc = [ scapy_all.LEShortField("item_type_code", 0), scapy_all.LEShortField("length", 0), scapy_all.LEShortField("encapsulation_version", 1), scapy_all.PacketField("ListIdentityItems", ENIP_ListIdentity_SocketItem(), ENIP_ListIdentity_SocketItem), #, count_from=1), scapy_all.LEShortField("vendor_ID", 0), scapy_all.LEShortEnumField("device_type", 0x21, DEVICE_PROFILES), scapy_all.LEShortField("product_code", 0), scapy_all.PacketField("ENIP_DeviceRevision", ENIP_DeviceRevision(), ENIP_DeviceRevision), scapy_all.XShortField("status", 0x0000), utils.XLEIntField("serial", 0x00000000), scapy_all.ByteField("product_name_length", 0), scapy_all.StrLenField("product_name", "", length_from=lambda p: p.product_name_length), scapy_all.XByteField("state", 0), ] def extract_padding(self, p): # print self.__class__.__name__ + ": P=" + str(p) return "", p
class CIP_ReqConnectionManager(scapy_all.Packet): fields_desc = [ scapy_all.BitField("reserved", 0, 3), scapy_all.BitField("priority", 0, 1), scapy_all.BitField("ticktime", 5, 4), scapy_all.ByteField("timeout_ticks", 157), utils.LEShortLenField("message_size", None, length_of="message"), scapy_all.PacketLenField("message", None, CIP, length_from=lambda pkt: pkt.message_size), scapy_all.StrLenField("message_padding", None, length_from=lambda pkt: pkt.message_size % 2), scapy_all.ByteField("route_path_size", 1), # TODO: size in words scapy_all.ByteField("reserved2", 0), scapy_all.ByteField("route_path_size_port", 1), scapy_all.ByteField("route_path_size_addr", 0), ] def post_build(self, p, pay): # Autofill the padding if len(p) % 2: p = p[:-4] + b"\0" + p[-4:] return p + pay
class Modbus_ReportSlaveIdResp(scapy_all.Packet): """Layer for report slave ID response""" fields_desc = [ scapy_all.FieldLenField("byte_count", 0, length_of="slave_id"), scapy_all.StrLenField("slave_id", "", length_from=lambda x: x.length), scapy_all.XByteField("run_status", 0x00) ] """
class Modbus_ReadCoilsResp(scapy_all.Packet): """Layer for Read coils response packet""" fields_desc = [ scapy_all.FieldLenField("byte_count", 0, length_of="coil_status"), scapy_all.StrLenField("coil_status", "", length_from=lambda x: x.length) ] def extract_padding(self, p): return p[:self.length], p[self.length:]
class CIP_ResponseStatus(scapy_all.Packet): """The response field of CIP headers""" name = "CIP_ResponseStatus" fields_desc = [ scapy_all.XByteField("reserved", 0), # Reserved byte, always null scapy_all.ByteEnumField("status", 0, {0: "success"}), scapy_all.XByteField("additional_size", 0), scapy_all.StrLenField("additional", "", # additionnal status length_from=lambda p: 2 * p.additional_size), ] ERROR_CODES = { 0x00: "Success", 0x01: "Connection failure", 0x02: "Resource unavailable", 0x03: "Invalid parameter value", 0x04: "Path segment error", 0x05: "Path destination unknown", 0x06: "Partial transfer", 0x07: "Connection lost", 0x08: "Service not supported", 0x09: "Invalid attribute value", 0x0a: "Attribute list error", 0x0b: "Already in requested mode/state", 0x0c: "Object state conflict", 0x0d: "Object already exists", 0x0e: "Attribute not settable", 0x0f: "Privilege violation", 0x10: "Device state conflict", 0x11: "Reply data too large", 0x12: "Fragmentation of a primitive value", 0x13: "Not enough data", 0x14: "Attribute not supported", 0x15: "Too much data", 0x16: "Object does not exist", 0x17: "Service fragmentation sequence not in progress", 0x18: "No stored attribute data", 0x19: "Store operation failure", 0x1a: "Routing failure, request packet too large", 0x1b: "Routing failure, response packet too large", 0x1c: "Missing attribute list entry data", 0x1d: "Invalid attribute value list", 0x1e: "Embedded service error", 0x1f: "Vendor specific error", 0x20: "Invalid parameter", 0x21: "Write-once value or medium already written", 0x22: "Invalid reply received", 0x23: "Buffer overflow", 0x24: "Invalid message format", 0x25: "Key failure in path", 0x26: "Path size invalid", 0x27: "Unexpected attribute in list", 0x28: "Invalid Member ID", 0x29: "Member not settable", 0x2a: "Group 2 only server general failure", 0x2b: "Unknown Modbus error", 0x2c: "Attribute not gettable", } def extract_padding(self, p): return "", p def __repr__(self): if self.reserved != 0: return scapy_all.Packet.__repr__(self) # Known status if self.status in self.ERROR_CODES and self.additional_size == 0: return "<CIP_ResponseStatus status={}>".format(self.ERROR_CODES[self.status]) # Simple status if self.additional_size == 0: return "<CIP_ResponseStatus status=%#x>" % self.status # Forward Open failure if self.status == 1 and self.additional == b"\x00\x01": return "<CIP_ResponseStatus status=Connection failure>" return scapy_all.Packet.__repr__(self)