class ENIP_ListIdentity_SocketItem(scapy_all.Packet): name = "Socket_Address" fields_desc = [ scapy_all.ShortField("sin_family", 0), scapy_all.ShortField("sin_port", 0), scapy_all.IPField("sin_address", "0.0.0.0"), scapy_all.StrFixedLenField("name_of_service", "", 8), ] def extract_padding(self, p): # print self.__class__.__name__+": P="+str(p) return "", p
class AVTP(s.Packet): name = "AVTP" fields_desc = [ s.XByteField("controlData", None), s.XByteField("flags", None), s.XByteField("sequence", None), s.XByteField("timestampUncertain", None), s.IntField("streamID0", None), s.IntField("streamID1", None), s.IntField("ptpTimestamp", None), s.IntField("gateway", None), s.ShortField("pktDataLength", None), s.XByteField("pkt1394format", None), s.XByteField("pkt1394tcode", None), s.XByteField("sourceId", None), s.XByteField("dataBlockSize", None), s.XByteField("packing", None), s.XByteField("DBC", None), s.XByteField("formatId", None), s.XByteField("SYT", None), s.IntField("ptpUpper", None), s.IntField("ptpLower", None), ]
class MDCData(scapy.Packet): name = "MulticastDataCenterData " fields_desc = [ scapy.ShortField("addr", 0), scapy.XByteField("mode", 0), scapy.XByteField("label", 0), scapy.ByteEnumField( "code", 5, { 1: "REQUEST", 2: "PTCH_REQ", 3: "DATA_FNSD", 4: "PTCH_DATA", 5: "DATA", 6: "FEEDBACK" }, ), scapy.XByteField("appID", 2), scapy.XByteField("dataID", 0), scapy.XByteField("sn", 0), scapy.XByteField("dataSize", 11), ]
class Modbus_MBAP(scapy_all.Packet): """Modbus TCP base packet layer. This represents the Modbus application protocol header (MBAP)""" name = "Modbus_MBAP" fields_desc = [ scapy_all.ShortField( "transaction_id", 0 ), # A simple implementation of this is to use the tcp sequence number, and increment by 1 for each packet scapy_all.ShortField("protocol_id", 0), # I believe for Modbus TCP this is always 0 scapy_all.ShortField( "length", None ), # Is the length inherited from the child layers? If so, it'll need to be calculated. I'm sure there is a function for this! scapy_all.ByteField("unit_id", None), ] @classmethod def generate_unique_id(self): # should check that this layer is associated with a tcp sequence number, as when it is instantiated it might not be if TCP in self: return self[ TCP].seq # Just being lazy and using tcp sequence num for this else: return 1 # Boring default value @classmethod def is_request(self): """Function to determine if the packet is a request or response There is nothing explicit in the protocol to delineate each, so we must infer it from other things. returns True if 'this' packet is a request, false if a response""" if self[TCP].sport != 502 and self[TCP].dport == 502: return True elif self[TCP].sport == 502 and self[TCP].dport != 502: return False elif self[TCP].sport == self[TCP].dport == 502: return guess_request_response( self) # Define another function to guess else: # None of the ports are 502 return False # Default value #What do we do if both ports are 502? # Can return a default Value # Could return exception? # Could try and use some other method using sequence numbers # Can we use TCP flags? @classmethod def is_response(self): # Added for code readability return (not is_request(self)) def extract_padding( self, p ): # Will there be any padding? This is supposed to return the length return p[:self.length], p[self.length:] def default_payload_class( self ): # In case we want to overload a default payload class with our own return Modbus_PDU # def post_build(self, p, pay): # Post build is used to calculate the length of fields if self.length is None and pay: l = len(pay) p = p[:4] + struct.pack( ">H", l) + p[6:] # This is due to the structure of the frame return p + pay def answers(self, other): # This needs adjusting! # Can base this on whether the packet is a request or response return isinstance(other, Modbus_MBAP)