class SecurityExtension(scapy.Packet): name = "SCION Security Extension" fields_desc = [ scapy.BitEnumField('next_hdr', None, 8, scapy.IP_PROTOS), scapy.ByteField('hdr_len', None), scapy.XByteField('extType', 0x2), scapy.ByteEnumField("secMode", 0x0, { 0x0: "AES-CMAC", 0x1: "HMAC_SHA256", 0x2: "Ed25519", 0x3: "GCM_AES128" }), scapy.XBitField('metadata', 0xffffffff, 4 * 8), scapy.MultipleTypeField([ (scapy.XBitField('authenticator', None, 16 * 8), lambda pkt: pkt.secMode == 0x0), (scapy.XBitField('authenticator', None, 32 * 8), lambda pkt: pkt.secMode == 0x1), (scapy.XBitField('authenticator', None, 64 * 8), lambda pkt: pkt.secMode == 0x2), (scapy.XBitField('authenticator', None, 16 * 8), lambda pkt: pkt.secMode == 0x3), ], scapy.StrField("authenticator", None)), ] def extract_padding(self, p): # TODO fix when removing hard-coded v4 return "", p def post_build(self, pkt, pay): if self.hdr_len == None: self.hdr_len = len(pkt) pkt = pkt[:1] + struct.pack('B', int(self.hdr_len / 8)) + pkt[2:] return pkt + pay
class CIP_RespAttributesAll(scapy_all.Packet): """Content of Get_Attribute_All response""" fields_desc = [ scapy_all.StrField("value", None), ]
class CIP_RespAttributesList(scapy_all.Packet): """List of attributes in Get_Attribute_List responses There are "count" attributes in the "content" field, in the following format: * attribute ID (INT, LEShortField) * status (INT, LEShortField, 0 means success) * value, type and length depends on the attribute and thus can not be known here """ fields_desc = [ scapy_all.LEShortField("count", 0), scapy_all.StrField("content", ""), ] def split_guess(self, attr_list, verbose=False): """Split the content of the Get_Attribute_List response with the known attribute list Return a list of (attr, value) tuples, or None if an error occured """ content = self.content offset = 0 idx = 0 result = [] while offset < len(content): attr, status = struct.unpack("<HH", content[offset:offset + 4]) if attr not in attr_list: if verbose: sys.stderr.write("Error: Get_Attribute_List response contains an unknown attribute\n") sys.stderr.write("... all attrs " + ','.join(hex(a) for a in attr_list) + '\n') sys.stderr.write(utils.hexdump(content[offset:], indentlvl="... ") + "\n") return if attr != attr_list[idx]: if verbose: sys.stderr.write("Error: attr {:#x} not in position {} of attr list\n".format(attr, idx)) sys.stderr.write("... all attrs " + ','.join(hex(a) for a in attr_list) + '\n') return offset += 4 attr_len = None if idx == len(attr_list) - 1: # Last attribute attr_len = len(content) - offset else: # Find next attribute header nexthdr = struct.pack('<HH', attr_list[idx + 1], 0) for i in range(offset + 1, len(content) - 4): if content[i:i + 4] == nexthdr: attr_len = i - offset break if attr_len is None: if verbose: sys.stderr.write("Error: length not found. Here is the remaining\n") sys.stderr.write("... all attrs " + ','.join(hex(a) for a in attr_list) + '\n') sys.stderr.write(utils.hexdump(content[offset:], indentlvl="... ") + "\n") return result.append((attr, content[offset:offset + attr_len])) offset += attr_len idx += 1 return result def split_guess_todict(self, attr_list, verbose=False): """Same as split_guess, but return a dict instead of a list of tuples""" result = self.split_guess(attr_list, verbose) if result is None: return # assert unicity of attributes IDs assert len(frozenset(x[0] for x in result)) == len(result) return dict(result)
class CIP_RespSingleAttribute(scapy_all.Packet): """An attribute... not much information about it""" fields_desc = [scapy_all.StrField("value", None)]