def _clone(packet: Packet, name: str) -> None: """Replaces the Scapy ``packet`` class by an exact copy. This is a trick used when we need to modify a ``Packet`` class attribute without affecting all instances of an object. For instance, if we change ``fields_desc`` to add a field, all new instances will be changed as this is a class attribute. :param packet: the Scapy Packet to update. :param name: the new class name for packet. """ # Checks if a binding exists between packet and its preceding layer # (bindings are defined as a list of tuples `layer.payload_guess`) in_payload_guess = False if packet.underlayer is not None: in_payload_guess = any(packet.__class__ in binding \ for binding in packet.underlayer.payload_guess) # Duplicates our packet class and replaces it by the clone # first checks that provided name is not already used, otherwise generates a new one while name in [type(o).__name__ for o in gc.get_objects()]: name = name + '_' + str(randint(1000000, 9999999)) class_copy = type(name, (packet.__class__, ), {}) packet.__class__ = class_copy # Bindings with the preceding layer must be done again if in_payload_guess: packet.underlayer.payload_guess.insert(0, ({}, packet.__class__))