def checksum(pkt):
    # type: (bytes) -> int
    if len(pkt) % 2 == 1:
        pkt += b"\0"
    s = sum(array.array("H", pkt))
    s = (s >> 16) + (s & 0xffff)
    s += s >> 16
    s = ~s
    return checksum_endian_transform(s) & 0xffff def do_graph(
    graph,  # type: str
    prog=None,  # type: Optional[str]
    format=None,  # type: Optional[str]
    target=None,  # type: Optional[Union[IO[bytes], str]]
    type=None,  # type: Optional[str]
    string=None,  # type: Optional[bool]
    options=None  # type: Optional[List[str]]
):
    # type: (...) -> Optional[str]
    """Processes graph description using an external software.
    This method is used to convert a graphviz format to an image.

    :param graph: GraphViz graph description
    :param prog: which graphviz program to use
    :param format: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T"
        option
    :param string: if not None, simply return the graph string
    :param target: filename or redirect. Defaults pipe to Imagemagick's
        display program
    :param options: options to be passed to prog
    """

    if format is None:
        format = "svg"
    if string:
        return graph
    if type is not None:
        warnings.warn(
            "type is deprecated, and was renamed format",
            DeprecationWarning
        )
        format = type
    if prog is None:
        prog = conf.prog.dot
    start_viewer = False
    if target is None:
        if WINDOWS:
            target = get_temp_file(autoext="." + format)
            start_viewer = True
        else:
            with ContextManagerSubprocess(conf.prog.display):
                target = subprocess.Popen([conf.prog.display],
                                          stdin=subprocess.PIPE).stdin
    if format is not None:
        format = "-T%s" % format
    if isinstance(target, str):
        if target.startswith('|'):
            target = subprocess.Popen(target[1:].lstrip(), shell=True,
                                      stdin=subprocess.PIPE).stdin
        elif target.startswith('>'):
            target = open(target[1:].lstrip(), "wb")
        else:
            target = open(os.path.abspath(target), "wb")
    target = cast(IO[bytes], target)
    proc = subprocess.Popen(
        "\"%s\" %s %s" % (prog, options or "", format or ""),
        shell=True, stdin=subprocess.PIPE, stdout=target,
        stderr=subprocess.PIPE
    )
    _, stderr = proc.communicate(bytes_encode(graph))
    if proc.returncode != 0:
        raise OSError(
            "GraphViz call failed (is it installed?):\n" +
            plain_str(stderr)
        )
    try:
        target.close()
    except Exception:
        pass
    if start_viewer:
        # Workaround for file not found error: We wait until tempfile is written.  # noqa: E501
        waiting_start = time.time()
        while not os.path.exists(target.name):
            time.sleep(0.1)
            if time.time() - waiting_start > 3:
                warning("Temporary file '%s' could not be written. Graphic will not be displayed.", tempfile)  # noqa: E501
                break
        else:
            if conf.prog.display == conf.prog._default:
                os.startfile(target.name)  # type: ignore
            else:
                with ContextManagerSubprocess(conf.prog.display):
                    subprocess.Popen([conf.prog.display, target.name])
    return None def incremental_label(label="tag%05i", start=0):
    # type: (str, int) -> Iterator[str]
    while True:
        yield label % start
        start += 1 @conf.commands.register
def linehexdump(p, onlyasc=0, onlyhex=0, dump=False):
    # type: (Union[Packet, AnyStr], int, int, bool) -> Optional[str]
    """Build an equivalent view of hexdump() on a single line

    Note that setting both onlyasc and onlyhex to 1 results in a empty output

    :param p: a Packet
    :param onlyasc: 1 to display only the ascii view
    :param onlyhex: 1 to display only the hexadecimal view
    :param dump: print the view if False
    :return: a String only when dump=True
    """
    s = ""
    s = hexstr(p, onlyasc=onlyasc, onlyhex=onlyhex, color=not dump)
    if dump:
        return s
    else:
        print(s)
        return None def strxor(s1, s2):
    # type: (bytes, bytes) -> bytes
    """
    Returns the binary XOR of the 2 provided strings s1 and s2. s1 and s2
    must be of same length.
    """
    return b"".join(map(lambda x, y: chb(orb(x) ^ orb(y)), s1, s2)) def whois(ip_address):
    # type: (str) -> bytes
    """Whois client for Python"""
    whois_ip = str(ip_address)
    try:
        query = socket.gethostbyname(whois_ip)
    except Exception:
        query = whois_ip
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect(("whois.ripe.net", 43))
    s.send(query.encode("utf8") + b"\r\n")
    answer = b""
    while True:
        d = s.recv(4096)
        answer += d
        if not d:
            break
    s.close()
    ignore_tag = b"remarks:"
    # ignore all lines starting with the ignore_tag
    lines = [line for line in answer.split(b"\n") if not line or (line and not line.startswith(ignore_tag))]  # noqa: E501
    # remove empty lines at the bottom
    for i in range(1, len(lines)):
        if not lines[-i].strip():
            del lines[-i]
        else:
            break
    return b"\n".join(lines[3:]) def colgen(*lstcol,  # type: Any
           **kargs  # type: Any
           ):
    # type: (...) -> Iterator[Any]
    """Returns a generator that mixes provided quantities forever
    trans: a function to convert the three arguments into a color. lambda x,y,z:(x,y,z) by default"""  # noqa: E501
    if len(lstcol) < 2:
        lstcol *= 2
    trans = kargs.get("trans", lambda x, y, z: (x, y, z))
    while True:
        for i in range(len(lstcol)):
            for j in range(len(lstcol)):
                for k in range(len(lstcol)):
                    if i != j or j != k or k != i:
                        yield trans(lstcol[(i + j) % len(lstcol)], lstcol[(j + k) % len(lstcol)], lstcol[(k + i) % len(lstcol)])  # noqa: E501 class AnsweringMachine(Generic[_T]):
    function_name = ""
    filter = None  # type: Optional[str]
    sniff_options = {"store": 0}  # type: Dict[str, Any]
    sniff_options_list = ["store", "iface", "count", "promisc", "filter",
                          "type", "prn", "stop_filter", "opened_socket"]
    send_options = {"verbose": 0}  # type: Dict[str, Any]
    send_options_list = ["iface", "inter", "loop", "verbose", "socket"]
    send_function = staticmethod(send)

    def __init__(self, **kargs):
        # type: (Any) -> None
        self.mode = 0
        self.verbose = kargs.get("verbose", conf.verb >= 0)
        if self.filter:
            kargs.setdefault("filter", self.filter)
        kargs.setdefault("prn", self.reply)
        self.optam1 = {}  # type: Dict[str, Any]
        self.optam2 = {}  # type: Dict[str, Any]
        self.optam0 = {}  # type: Dict[str, Any]
        doptsend, doptsniff = self.parse_all_options(1, kargs)
        self.defoptsend = self.send_options.copy()
        self.defoptsend.update(doptsend)
        self.defoptsniff = self.sniff_options.copy()
        self.defoptsniff.update(doptsniff)
        self.optsend = {}   # type: Dict[str, Any]
        self.optsniff = {}   # type: Dict[str, Any]

    def __getattr__(self, attr):
        # type: (str) -> Any
        for dct in [self.optam2, self.optam1]:
            if attr in dct:
                return dct[attr]
        raise AttributeError(attr)

    def __setattr__(self, attr, val):
        # type: (str, Any) -> None
        mode = self.__dict__.get("mode", 0)
        if mode == 0:
            self.__dict__[attr] = val
        else:
            [self.optam1, self.optam2][mode - 1][attr] = val

    def parse_options(self):
        # type: () -> None
        pass

    def parse_all_options(self, mode, kargs):
        # type: (int, Any) -> Tuple[Dict[str, Any], Dict[str, Any]]
        sniffopt = {}  # type: Dict[str, Any]
        sendopt = {}  # type: Dict[str, Any]
        for k in list(kargs):  # use list(): kargs is modified in the loop
            if k in self.sniff_options_list:
                sniffopt[k] = kargs[k]
            if k in self.send_options_list:
                sendopt[k] = kargs[k]
            if k in self.sniff_options_list + self.send_options_list:
                del kargs[k]
        if mode != 2 or kargs:
            if mode == 1:
                self.optam0 = kargs
            elif mode == 2 and kargs:
                k = self.optam0.copy()
                k.update(kargs)
                self.parse_options(**k)
                kargs = k
            omode = self.__dict__.get("mode", 0)
            self.__dict__["mode"] = mode
            self.parse_options(**kargs)
            self.__dict__["mode"] = omode
        return sendopt, sniffopt

    def is_request(self, req):
        # type: (Packet) -> int
        return 1

    def make_reply(self, req):
        # type: (Packet) -> _T
        return req

    def send_reply(self, reply, send_function=None):
        # type: (_T, Optional[Callable[..., None]]) -> None
        if send_function:
            send_function(reply)
        else:
            self.send_function(reply, **self.optsend)

    def print_reply(self, req, reply):
        # type: (Packet, _T) -> None
        if isinstance(reply, PacketList):
            print("%s ==> %s" % (req.summary(),
                                 [res.summary() for res in reply]))
        else:
            print("%s ==> %s" % (req.summary(), reply.summary()))

    def reply(self, pkt, send_function=None, address=None):
        # type: (Packet, Optional[Callable[..., None]], Optional[Any]) -> None
        if not self.is_request(pkt):
            return
        if address:
            # Only on AnsweringMachineTCP
            reply = self.make_reply(pkt, address=address)  # type: ignore
        else:
            reply = self.make_reply(pkt)
        if not reply:
            return
        if send_function:
            self.send_reply(reply, send_function=send_function)
        else:
            # Retro-compability. Remove this if eventually
            self.send_reply(reply)
        if self.verbose:
            self.print_reply(pkt, reply)

    def run(self, *args, **kargs):
        # type: (Any, Any) -> None
        warnings.warn(
            "run() method deprecated. The instance is now callable",
            DeprecationWarning
        )
        self(*args, **kargs)

    def __call__(self, *args, **kargs):
        # type: (Any, Any) -> None
        optsend, optsniff = self.parse_all_options(2, kargs)
        self.optsend = self.defoptsend.copy()
        self.optsend.update(optsend)
        self.optsniff = self.defoptsniff.copy()
        self.optsniff.update(optsniff)

        try:
            self.sniff()
        except KeyboardInterrupt:
            print("Interrupted by user")

    def sniff(self):
        # type: () -> None
        sniff(**self.optsniff) class AnsweringMachineUtils:
    @staticmethod
    def reverse_packet(req):
        # type: (Packet) -> Packet
        from scapy.layers.l2 import Ether
        from scapy.layers.inet import IP, TCP, UDP
        reply = req.copy()
        for layer in [UDP, TCP]:
            if req.haslayer(layer):
                reply[layer].dport, reply[layer].sport = \
                    req[layer].sport, req[layer].dport
                reply[layer].chksum = None
                reply[layer].len = None
        if req.haslayer(IP):
            reply[IP].src, reply[IP].dst = req[IP].dst, req[IP].src
            reply[IP].chksum = None
            reply[IP].len = None
        if req.haslayer(Ether):
            reply[Ether].src, reply[Ether].dst = req[Ether].dst, req[Ether].src
        return reply class Gen(Generic[_T]):
    __slots__ = []  # type: List[str]

    def __iter__(self):
        # type: () -> Iterator[_T]
        return iter([])

    def __iterlen__(self):
        # type: () -> int
        return sum(1 for _ in iter(self)) class Net(Gen[str]):
    """Network object from an IP address or hostname and mask"""
    name = "Net"  # type: str
    family = socket.AF_INET  # type: int
    max_mask = 32  # type: int

    @classmethod
    def name2addr(cls, name):
        # type: (str) -> str
        try:
            return next(
                addr_port[0]
                for family, _, _, _, addr_port in
                socket.getaddrinfo(name, None, cls.family)
                if family == cls.family
            )
        except socket.error:
            if re.search("(^|\\.)[0-9]+-[0-9]+($|\\.)", name) is not None:
                raise Scapy_Exception("Ranges are no longer accepted in %s()" %
                                      cls.__name__)
            raise

    @classmethod
    def ip2int(cls, addr):
        # type: (str) -> int
        return cast(int, struct.unpack(
            "!I", socket.inet_aton(cls.name2addr(addr))
        )[0])

    @staticmethod
    def int2ip(val):
        # type: (int) -> str
        return socket.inet_ntoa(struct.pack('!I', val))

    def __init__(self, net, stop=None):
        # type: (str, Union[None, str]) -> None
        if "*" in net:
            raise Scapy_Exception("Wildcards are no longer accepted in %s()" %
                                  self.__class__.__name__)
        if stop is None:
            try:
                net, mask = net.split("/", 1)
            except ValueError:
                self.mask = self.max_mask  # type: Union[None, int]
            else:
                self.mask = int(mask)
            self.net = net  # type: Union[None, str]
            inv_mask = self.max_mask - self.mask
            self.start = self.ip2int(net) >> inv_mask << inv_mask
            self.count = 1 << inv_mask
            self.stop = self.start + self.count - 1
        else:
            self.start = self.ip2int(net)
            self.stop = self.ip2int(stop)
            self.count = self.stop - self.start + 1
            self.net = self.mask = None

    def __str__(self):
        # type: () -> str
        return next(iter(self), "")

    def __iter__(self):
        # type: () -> Iterator[str]
        # Python 2 won't handle huge (> sys.maxint) values in range()
        for i in range(self.count):
            yield self.int2ip(self.start + i)

    def __len__(self):
        # type: () -> int
        return self.count

    def __iterlen__(self):
        # type: () -> int
        # for compatibility
        return len(self)

    def choice(self):
        # type: () -> str
        return self.int2ip(random.randint(self.start, self.stop))

    def __repr__(self):
        # type: () -> str
        if self.mask is not None:
            return '%s("%s/%d")' % (
                self.__class__.__name__,
                self.net,
                self.mask,
            )
        return '%s("%s", "%s")' % (
            self.__class__.__name__,
            self.int2ip(self.start),
            self.int2ip(self.stop),
        )

    def __eq__(self, other):
        # type: (Any) -> bool
        if isinstance(other, str):
            return self == self.__class__(other)
        if not isinstance(other, Net):
            return False
        if self.family != other.family:
            return False
        return (self.start == other.start) and (self.stop == other.stop)

    def __ne__(self, other):
        # type: (Any) -> bool
        # Python 2.7 compat
        return not self == other

    def __hash__(self):
        # type: () -> int
        return hash(("scapy.Net", self.family, self.start, self.stop))

    def __contains__(self, other):
        # type: (Any) -> bool
        if isinstance(other, int):
            return self.start <= other <= self.stop
        if isinstance(other, str):
            return self.__class__(other) in self
        if type(other) is not self.__class__:
            return False
        return self.start <= other.start <= other.stop <= self.stop class Ether(Packet):
    name = "Ethernet"
    fields_desc = [DestMACField("dst"),
                   SourceMACField("src"),
                   XShortEnumField("type", 0x9000, ETHER_TYPES)]
    __slots__ = ["_defrag_pos"]

    def hashret(self):
        # type: () -> bytes
        return struct.pack("H", self.type) + self.payload.hashret()

    def answers(self, other):
        # type: (Packet) -> int
        if isinstance(other, Ether):
            if self.type == other.type:
                return self.payload.answers(other.payload)
        return 0

    def mysummary(self):
        # type: () -> str
        return self.sprintf("%src% > %dst% (%type%)")

    @classmethod
    def dispatch_hook(cls, _pkt=None, *args, **kargs):
        # type: (Optional[bytes], *Any, **Any) -> Type[Packet]
        if _pkt and len(_pkt) >= 14:
            if struct.unpack("!H", _pkt[12:14])[0] <= 1500:
                return Dot3
        return cls class Dot3(Packet):
    name = "802.3"
    fields_desc = [DestMACField("dst"),
                   SourceMACField("src"),
                   LenField("len", None, "H")]

    def extract_padding(self, s):
        # type: (bytes) -> Tuple[bytes, bytes]
        tmp_len = self.len
        return s[:tmp_len], s[tmp_len:]

    def answers(self, other):
        # type: (Ether) -> int
        if isinstance(other, Dot3):
            return self.payload.answers(other.payload)
        return 0

    def mysummary(self):
        # type: () -> str
        return "802.3 %s > %s" % (self.src, self.dst)

    @classmethod
    def dispatch_hook(cls, _pkt=None, *args, **kargs):
        # type: (Optional[Any], *Any, **Any) -> Type[Packet]
        if _pkt and len(_pkt) >= 14:
            if struct.unpack("!H", _pkt[12:14])[0] > 1500:
                return Ether
        return cls @conf.commands.register
def getmacbyip(ip, chainCC=0):
    # type: (str, int) -> Optional[str]
    """Return MAC address corresponding to a given IP address"""
    if isinstance(ip, Net):
        ip = next(iter(ip))
    ip = inet_ntoa(inet_aton(ip or "0.0.0.0"))
    tmp = [orb(e) for e in inet_aton(ip)]
    if (tmp[0] & 0xf0) == 0xe0:  # mcast @
        return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1] & 0x7f, tmp[2], tmp[3])
    iff, _, gw = conf.route.route(ip)
    if (iff == conf.loopback_name) or (ip in conf.route.get_if_bcast(iff)):
        return "ff:ff:ff:ff:ff:ff"
    if gw != "0.0.0.0":
        ip = gw

    mac = _arp_cache.get(ip)
    if mac:
        return mac

    try:
        res = srp1(Ether(dst=ETHER_BROADCAST) / ARP(op="who-has", pdst=ip),
                   type=ETH_P_ARP,
                   iface=iff,
                   timeout=2,
                   verbose=0,
                   chainCC=chainCC,
                   nofilter=1)
    except Exception as ex:
        warning("getmacbyip failed on %s", ex)
        return None
    if res is not None:
        mac = res.payload.hwsrc
        _arp_cache[ip] = mac
        return mac
    return None class CookedLinux(Packet):
    # Documentation: http://www.tcpdump.org/linktypes/LINKTYPE_LINUX_SLL.html
    name = "cooked linux"
    # from wireshark's database
    fields_desc = [ShortEnumField("pkttype", 0, {0: "unicast",
                                                 1: "broadcast",
                                                 2: "multicast",
                                                 3: "unicast-to-another-host",
                                                 4: "sent-by-us"}),
                   XShortField("lladdrtype", 512),
                   ShortField("lladdrlen", 0),
                   StrFixedLenField("src", b"", 8),
                   XShortEnumField("proto", 0x800, ETHER_TYPES)] 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):
        # type: (Optional[Any], *Any, **Any) -> Type[Packet]
        if _pkt and struct.unpack("!H", _pkt[2:4])[0] == 0x880b:
            return GRE_PPTP
        return cls

    def post_build(self, p, pay):
        # type: (bytes, bytes) -> bytes
        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 SNAP(Packet):
    name = "SNAP"
    fields_desc = [OUIField("OUI", 0x000000),
                   XShortEnumField("code", 0x000, ETHER_TYPES)] class Loopback(Packet):
    r"""\*BSD loopback layer"""

    name = "Loopback"
    if consts.OPENBSD:
        fields_desc = [IntEnumField("type", 0x2, LOOPBACK_TYPES)]
    else:
        fields_desc = [LoIntEnumField("type", 0x2, LOOPBACK_TYPES)]
    __slots__ = ["_defrag_pos"] def raw(x):
    # type: (Union[Packet]) -> bytes
    """
    Builds a packet and returns its bytes representation.
    This function is and will always be cross-version compatible
    """
    if hasattr(x, "__bytes__"):
        return x.__bytes__()
    return bytes(x) def chb(x):
    # type: (int) -> bytes
    if isinstance(x, str):
        return x
    return chr(x) def orb(x):
    # type: (Union[int, str, bytes]) -> int
    """Return ord(x) when not already an int."""
    if isinstance(x, int):
        return x
    return ord(x) def bytes_encode(x):
    # type: (Any) -> bytes
    """Ensure that the given object is bytes.
    If the parameter is a packet, raw() should be preferred.
    """
    if isinstance(x, str):
        return x.encode()
    return bytes(x) class ConfClass(object):
class Interceptor(object):
class ProgPath(ConfClass):
class ConfigFieldList:
class Emphasize(ConfigFieldList):
class Resolve(ConfigFieldList):
class Num2Layer:
class LayersList(List[Type['scapy.packet.Packet']]):
class CommandsList(List[Callable[..., Any]]):
class CacheInstance(Dict[str, Any], object):
class NetCache:
class Conf(ConfClass):
    def configure(self, cnf):
    def __repr__(self):
    def __str__(self):
    def __init__(self,
                 name,  # type: str
                 default,  # type: Any
                 hook,  # type: Callable[..., Any]
                 args=None,  # type: Optional[List[Any]]
                 kargs=None  # type: Optional[Dict[str, Any]]
                 ):
    def __get__(self, obj, typ=None):
    def set_from_hook(obj, name, val):
    def __set__(self, obj, val):
def _readonly(name):
    def __init__(self):
    def _is_field(f):
    def _recalc_layer_list(self):
    def add(self, *flds):
    def remove(self, *flds):
    def __contains__(self, elt):
    def __repr__(self):
    def __init__(self):
    def register(self, num, layer):
    def register_num2layer(self, num, layer):
    def register_layer2num(self, num, layer):
    def __getitem__(self, item):
    def __contains__(self, item):
    def get(self,
            item,  # type: Union[int, Type[Packet]]
            default=None,  # type: Optional[Type[Packet]]
            ):
    def __repr__(self):
    def __init__(self):
    def __repr__(self):
    def register(self, layer):
    def layers(self):
    def filter(self, items):
    def unfilter(self):
    def __repr__(self):
    def register(self, cmd):
def lsc():
    def __init__(self, name="noname", timeout=None):
    def flush(self):
    def __getitem__(self, item):
    def get(self, item, default=None):
    def __setitem__(self, item, v):
    def update(self,  # type: ignore
               other,  # type: Any
               **kwargs  # type: Any
               ):
    def iteritems(self):
    def iterkeys(self):
    def __iter__(self):
    def itervalues(self):
    def items(self):
    def keys(self):
    def values(self):
    def __len__(self):
    def summary(self):
    def __repr__(self):
    def copy(self):
    def __init__(self):
    def add_cache(self, cache):
    def new_cache(self, name, timeout=None):
    def __delattr__(self, attr):
    def update(self, other):
    def flush(self):
    def __repr__(self):
def _version_checker(module, minver):
def isCryptographyValid():
def isCryptographyAdvanced():
def isPyPy():
def _prompt_changer(attr, val, old):
def _set_conf_sockets():
def _socket_changer(attr, val, old):
def _loglevel_changer(attr, val, old):
def _iface_changer(attr, val, old):
    def __getattribute__(self, attr):
def crypto_validator(func):
    def func_in(*args, **kwargs):
def scapy_delete_temp_files():     MATPLOTLIB = 1
        MATPLOTLIB_INLINED = 1
        MATPLOTLIB_INLINED = 0
    MATPLOTLIB_DEFAULT_PLOT_KARGS = {"marker": "+"}
    MATPLOTLIB = 0
    MATPLOTLIB_INLINED = 0
    MATPLOTLIB_DEFAULT_PLOT_KARGS = dict()
        PYX = 1
        PYX = 0
    PYX = 0
def _test_pyx(): class BitEnumField(_BitField[Union[List[int], int]], _EnumField[int]):
    __slots__ = EnumField.__slots__

    def __init__(self, name, default, size, enum, **kwargs):
        # type: (str, Optional[int], int, Dict[int, str], **Any) -> None
        _EnumField.__init__(self, name, default, enum)
        _BitField.__init__(self, name, default, size, **kwargs)

    def any2i(self, pkt, x):
        # type: (Optional[Packet], Any) -> Union[List[int], int]
        return _EnumField.any2i(self, pkt, x)

    def i2repr(self,
               pkt,  # type: Optional[Packet]
               x,  # type: Union[List[int], int]
               ):
        # type: (...) -> Any
        return _EnumField.i2repr(self, pkt, x) class BitField(_BitField[int]):
    __doc__ = _BitField.__doc__ class ByteEnumField(EnumField[int]):
    def __init__(self, name, default, enum):
        # type: (str, Optional[int], Dict[int, str]) -> None
        EnumField.__init__(self, name, default, enum, "B") class ByteField(Field[int, int]):
    def __init__(self, name, default):
        # type: (str, Optional[int]) -> None
        Field.__init__(self, name, default, "B") class ConditionalField(_FieldContainer):
    __slots__ = ["fld", "cond"]

    def __init__(self,
                 fld,  # type: Field[Any, Any]
                 cond  # type: Callable[[Packet], bool]
                 ):
        # type: (...) -> None
        self.fld = fld
        self.cond = cond

    def _evalcond(self, pkt):
        # type: (Packet) -> bool
        return bool(self.cond(pkt))

    def any2i(self, pkt, x):
        # type: (Optional[Packet], Any) -> Any
        # BACKWARD COMPATIBILITY
        # Note: we shouldn't need this function. (it's not correct)
        # However, having i2h implemented (#2364), it changes the default
        # behavior and broke all packets that wrongly use two ConditionalField
        # with the same name. Those packets are the problem: they are wrongly
        # built (they should either be re-using the same conditional field, or
        # using a MultipleTypeField).
        # But I don't want to dive into fixing all of them just yet,
        # so for now, let's keep this this way, even though it's not correct.
        if type(self.fld) is Field:
            return x
        return self.fld.any2i(pkt, x)

    def i2h(self, pkt, val):
        # type: (Optional[Packet], Any) -> Any
        if pkt and not self._evalcond(pkt):
            return None
        return self.fld.i2h(pkt, val)

    def getfield(self, pkt, s):
        # type: (Packet, bytes) -> Tuple[bytes, Any]
        if self._evalcond(pkt):
            return self.fld.getfield(pkt, s)
        else:
            return s, None

    def addfield(self, pkt, s, val):
        # type: (Packet, bytes, Any) -> bytes
        if self._evalcond(pkt):
            return self.fld.addfield(pkt, s, val)
        else:
            return s

    def __getattr__(self, attr):
        # type: (str) -> Any
        return getattr(self.fld, attr) class DestField(Field[str, bytes]):
    __slots__ = ["defaultdst"]
    # Each subclass must have its own bindings attribute
    bindings = {}  # type: Dict[Type[Packet], Tuple[str, Any]]

    def __init__(self, name, default):
        # type: (str, str) -> None
        self.defaultdst = default

    def dst_from_pkt(self, pkt):
        # type: (Packet) -> str
        for addr, condition in self.bindings.get(pkt.payload.__class__, []):
            try:
                if all(pkt.payload.getfieldval(field) == value
                       for field, value in six.iteritems(condition)):
                    return addr  # type: ignore
            except AttributeError:
                pass
        return self.defaultdst

    @classmethod
    def bind_addr(cls, layer, addr, **condition):
        # type: (Type[Packet], str, **Any) -> None
        cls.bindings.setdefault(layer, []).append(  # type: ignore
            (addr, condition)
        ) class Emph(_FieldContainer):
    """Empathize sub-layer for display"""
    __slots__ = ["fld"]

    def __init__(self, fld):
        # type: (Any) -> None
        self.fld = fld

    def __eq__(self, other):
        # type: (Any) -> bool
        return bool(self.fld == other)

    def __ne__(self, other):
        # type: (Any) -> bool
        # Python 2.7 compat
        return not self == other

    # mypy doesn't support __hash__ = None
    __hash__ = None  # type: ignore class FieldLenField(Field[int, int]):
    __slots__ = ["length_of", "count_of", "adjust"]

    def __init__(
            self,
            name,  # type: str
            default,  # type: Optional[Any]
            length_of=None,  # type: Optional[str]
            fmt="H",  # type: str
            count_of=None,  # type: Optional[str]
            adjust=lambda pkt, x: x,  # type: Callable[[Packet, int], int]
    ):
        # type: (...) -> None
        Field.__init__(self, name, default, fmt)
        self.length_of = length_of
        self.count_of = count_of
        self.adjust = adjust

    def i2m(self, pkt, x):
        # type: (Optional[Packet], Optional[int]) -> int
        if x is None and pkt is not None:
            if self.length_of is not None:
                fld, fval = pkt.getfield_and_val(self.length_of)
                f = fld.i2len(pkt, fval)
            elif self.count_of is not None:
                fld, fval = pkt.getfield_and_val(self.count_of)
                f = fld.i2count(pkt, fval)
            else:
                raise ValueError(
                    "Field should have either length_of or count_of"
                )
            x = self.adjust(pkt, f)
        elif x is None:
            x = 0
        return x class FieldListField(Field[List[Any], List[Any]]):
    __slots__ = ["field", "count_from", "length_from"]
    islist = 1

    def __init__(
            self,
            name,  # type: str
            default,  # type: Optional[List[AnyField]]
            field,  # type: AnyField
            length_from=None,  # type: Optional[Callable[[Packet], int]]
            count_from=None,  # type: Optional[Callable[[Packet], int]]
    ):
        # type: (...) -> None
        if default is None:
            default = []  # Create a new list for each instance
        self.field = field
        Field.__init__(self, name, default)
        self.count_from = count_from
        self.length_from = length_from

    def i2count(self, pkt, val):
        # type: (Optional[Packet], List[Any]) -> int
        if isinstance(val, list):
            return len(val)
        return 1

    def i2len(self, pkt, val):
        # type: (Packet, List[Any]) -> int
        return int(sum(self.field.i2len(pkt, v) for v in val))

    def any2i(self, pkt, x):
        # type: (Optional[Packet], List[Any]) -> List[Any]
        if not isinstance(x, list):
            return [self.field.any2i(pkt, x)]
        else:
            return [self.field.any2i(pkt, e) for e in x]

    def i2repr(self,
               pkt,  # type: Optional[Packet]
               x,  # type: List[Any]
               ):
        # type: (...) -> str
        return "[%s]" % ", ".join(self.field.i2repr(pkt, v) for v in x)

    def addfield(self,
                 pkt,  # type: Packet
                 s,  # type: bytes
                 val,  # type: Optional[List[Any]]
                 ):
        # type: (...) -> bytes
        val = self.i2m(pkt, val)
        for v in val:
            s = self.field.addfield(pkt, s, v)
        return s

    def getfield(self,
                 pkt,  # type: Packet
                 s,  # type: bytes
                 ):
        # type: (...) -> Any
        c = len_pkt = None
        if self.length_from is not None:
            len_pkt = self.length_from(pkt)
        elif self.count_from is not None:
            c = self.count_from(pkt)

        val = []
        ret = b""
        if len_pkt is not None:
            s, ret = s[:len_pkt], s[len_pkt:]

        while s:
            if c is not None:
                if c <= 0:
                    break
                c -= 1
            s, v = self.field.getfield(pkt, s)
            val.append(v)
        return s + ret, val class FlagsField(_BitField[Optional[Union[int, FlagValue]]]):
    """ Handle Flag type field

   Make sure all your flags have a label

   Example (list):
       >>> from scapy.packet import Packet
       >>> class FlagsTest(Packet):
               fields_desc = [FlagsField("flags", 0, 8, ["f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7"])]  # noqa: E501
       >>> FlagsTest(flags=9).show2()
       ###[ FlagsTest ]###
         flags     = f0+f3

    Example (str):
       >>> from scapy.packet import Packet
       >>> class TCPTest(Packet):
               fields_desc = [
                   BitField("reserved", 0, 7),
                   FlagsField("flags", 0x2, 9, "FSRPAUECN")
               ]
       >>> TCPTest(flags=3).show2()
       ###[ FlagsTest ]###
         reserved  = 0
         flags     = FS

    Example (dict):
       >>> from scapy.packet import Packet
       >>> class FlagsTest2(Packet):
               fields_desc = [
                   FlagsField("flags", 0x2, 16, {
                       0x0001: "A",
                       0x0008: "B",
                   })
               ]

   :param name: field's name
   :param default: default value for the field
   :param size: number of bits in the field (in bits). if negative, LE
   :param names: (list or str or dict) label for each flag
       If it's a str or a list, the least Significant Bit tag's name
       is written first.
   """
    ismutable = True
    __slots__ = ["names"]

    def __init__(self,
                 name,  # type: str
                 default,  # type: Optional[Union[int, FlagValue]]
                 size,  # type: int
                 names  # type: Union[List[str], str, Dict[int, str]]
                 ):
        # type: (...) -> None
        # Convert the dict to a list
        if isinstance(names, dict):
            tmp = ["bit_%d" % i for i in range(abs(size))]
            for i, v in six.viewitems(names):
                tmp[int(math.floor(math.log(i, 2)))] = v
            names = tmp
        # Store the names as str or list
        self.names = names
        super(FlagsField, self).__init__(name, default, size)

    def _fixup_val(self, x):
        # type: (Any) -> Optional[FlagValue]
        """Returns a FlagValue instance when needed. Internal method, to be
used in *2i() and i2*() methods.

        """
        if isinstance(x, (FlagValue, VolatileValue)):
            return x  # type: ignore
        if x is None:
            return None
        return FlagValue(x, self.names)

    def any2i(self, pkt, x):
        # type: (Optional[Packet], Any) -> Optional[FlagValue]
        return self._fixup_val(super(FlagsField, self).any2i(pkt, x))

    def m2i(self, pkt, x):
        # type: (Optional[Packet], int) -> Optional[FlagValue]
        return self._fixup_val(super(FlagsField, self).m2i(pkt, x))

    def i2h(self, pkt, x):
        # type: (Optional[Packet], Any) -> Optional[FlagValue]
        return self._fixup_val(super(FlagsField, self).i2h(pkt, x))

    def i2repr(self,
               pkt,  # type: Optional[Packet]
               x,  # type: Any
               ):
        # type: (...) -> str
        if isinstance(x, (list, tuple)):
            return repr(type(x)(
                "None" if v is None else str(self._fixup_val(v)) for v in x
            ))
        return "None" if x is None else str(self._fixup_val(x)) class IPField(Field[Union[str, Net], bytes]):
    def __init__(self, name, default):
        # type: (str, Optional[str]) -> None
        Field.__init__(self, name, default, "4s")

    def h2i(self, pkt, x):
        # type: (Optional[Packet], Union[AnyStr, List[AnyStr]]) -> Any
        if isinstance(x, bytes):
            x = plain_str(x)  # type: ignore
        if isinstance(x, str):
            try:
                inet_aton(x)
            except socket.error:
                return Net(x)
        elif isinstance(x, list):
            return [self.h2i(pkt, n) for n in x]
        return x

    def i2h(self, pkt, x):
        # type: (Optional[Packet], Optional[Union[str, Net]]) -> str
        return cast(str, x)

    def resolve(self, x):
        # type: (str) -> str
        if self in conf.resolve:
            try:
                ret = socket.gethostbyaddr(x)[0]
            except Exception:
                pass
            else:
                if ret:
                    return ret
        return x

    def i2m(self, pkt, x):
        # type: (Optional[Packet], Optional[Union[str, Net]]) -> bytes
        if x is None:
            return b'\x00\x00\x00\x00'
        return inet_aton(plain_str(x))

    def m2i(self, pkt, x):
        # type: (Optional[Packet], bytes) -> str
        return inet_ntoa(x)

    def any2i(self, pkt, x):
        # type: (Optional[Packet], Any) -> Any
        return self.h2i(pkt, x)

    def i2repr(self, pkt, x):
        # type: (Optional[Packet], Union[str, Net]) -> str
        r = self.resolve(self.i2h(pkt, x))
        return r if isinstance(r, str) else repr(r)

    def randval(self):
        # type: () -> RandIP
        return RandIP() class IntField(Field[int, int]):
    def __init__(self, name, default):
        # type: (str, Optional[int]) -> None
        Field.__init__(self, name, default, "I") class MultiEnumField(_MultiEnumField[int], EnumField[int]):
    __slots__ = ["depends_on", "i2s_multi", "s2i_multi", "s2i_all"] class MultipleTypeField(_FieldContainer):
    """MultipleTypeField are used for fields that can be implemented by
various Field subclasses, depending on conditions on the packet.

It is initialized with `flds` and `dflt`.

`dflt` is the default field type, to be used when none of the
conditions matched the current packet.

`flds` is a list of tuples (`fld`, `cond`), where `fld` if a field
type, and `cond` a "condition" to determine if `fld` is the field type
that should be used.

`cond` is either:

  - a callable `cond_pkt` that accepts one argument (the packet) and
    returns True if `fld` should be used, False otherwise.

  - a tuple (`cond_pkt`, `cond_pkt_val`), where `cond_pkt` is the same
    as in the previous case and `cond_pkt_val` is a callable that
    accepts two arguments (the packet, and the value to be set) and
    returns True if `fld` should be used, False otherwise.

See scapy.layers.l2.ARP (type "help(ARP)" in Scapy) for an example of
use.

    """

    __slots__ = ["flds", "dflt", "name", "default"]

    def __init__(self,
                 flds,  # type: List[Tuple[Field[Any, Any], Any]]
                 dflt  # type: Field[Any, Any]
                 ):
        # type: (...) -> None
        self.flds = flds
        self.dflt = dflt
        self.default = None  # So that we can detect changes in defaults
        self.name = self.dflt.name
        if any(x[0].name != self.name for x in self.flds):
            warnings.warn(
                "All fields should have the same name in a MultipleTypeField",
                SyntaxWarning
            )

    def _iterate_fields_cond(self, pkt, val, use_val):
        # type: (Optional[Packet], Any, bool) -> Field[Any, Any]
        """Internal function used by _find_fld_pkt & _find_fld_pkt_val"""
        # Iterate through the fields
        for fld, cond in self.flds:
            if isinstance(cond, tuple):
                if use_val:
                    if val is None:
                        val = self.dflt.default
                    if cond[1](pkt, val):
                        return fld
                    continue
                else:
                    cond = cond[0]
            if cond(pkt):
                return fld
        return self.dflt

    def _find_fld_pkt(self, pkt):
        # type: (Optional[Packet]) -> Field[Any, Any]
        """Given a Packet instance `pkt`, returns the Field subclass to be
used. If you know the value to be set (e.g., in .addfield()), use
._find_fld_pkt_val() instead.

        """
        return self._iterate_fields_cond(pkt, None, False)

    def _find_fld_pkt_val(self,
                          pkt,  # type: Optional[Packet]
                          val,  # type: Any
                          ):
        # type: (...) -> Tuple[Field[Any, Any], Any]
        """Given a Packet instance `pkt` and the value `val` to be set,
returns the Field subclass to be used, and the updated `val` if necessary.

        """
        fld = self._iterate_fields_cond(pkt, val, True)
        if val is None:
            val = fld.default
        return fld, val

    def _find_fld(self):
        # type: () -> Field[Any, Any]
        """Returns the Field subclass to be used, depending on the Packet
instance, or the default subclass.

DEV: since the Packet instance is not provided, we have to use a hack
to guess it. It should only be used if you cannot provide the current
Packet instance (for example, because of the current Scapy API).

If you have the current Packet instance, use ._find_fld_pkt_val() (if
the value to set is also known) of ._find_fld_pkt() instead.

        """
        # Hack to preserve current Scapy API
        # See https://stackoverflow.com/a/7272464/3223422
        frame = inspect.currentframe().f_back.f_back  # type: ignore
        while frame is not None:
            try:
                pkt = frame.f_locals['self']
            except KeyError:
                pass
            else:
                if isinstance(pkt, tuple(self.dflt.owners)):
                    if not pkt.default_fields:
                        # Packet not initialized
                        return self.dflt
                    return self._find_fld_pkt(pkt)
            frame = frame.f_back
        return self.dflt

    def getfield(self,
                 pkt,  # type: Packet
                 s,  # type: bytes
                 ):
        # type: (...) -> Tuple[bytes, Any]
        return self._find_fld_pkt(pkt).getfield(pkt, s)

    def addfield(self, pkt, s, val):
        # type: (Packet, bytes, Any) -> bytes
        fld, val = self._find_fld_pkt_val(pkt, val)
        return fld.addfield(pkt, s, val)

    def any2i(self, pkt, val):
        # type: (Optional[Packet], Any) -> Any
        fld, val = self._find_fld_pkt_val(pkt, val)
        return fld.any2i(pkt, val)

    def h2i(self, pkt, val):
        # type: (Optional[Packet], Any) -> Any
        fld, val = self._find_fld_pkt_val(pkt, val)
        return fld.h2i(pkt, val)

    def i2h(self,
            pkt,  # type: Packet
            val,  # type: Any
            ):
        # type: (...) -> Any
        fld, val = self._find_fld_pkt_val(pkt, val)
        return fld.i2h(pkt, val)

    def i2m(self, pkt, val):
        # type: (Optional[Packet], Optional[Any]) -> Any
        fld, val = self._find_fld_pkt_val(pkt, val)
        return fld.i2m(pkt, val)

    def i2len(self, pkt, val):
        # type: (Packet, Any) -> int
        fld, val = self._find_fld_pkt_val(pkt, val)
        return fld.i2len(pkt, val)

    def i2repr(self, pkt, val):
        # type: (Optional[Packet], Any) -> str
        fld, val = self._find_fld_pkt_val(pkt, val)
        return fld.i2repr(pkt, val)

    def register_owner(self, cls):
        # type: (Type[Packet]) -> None
        for fld, _ in self.flds:
            fld.owners.append(cls)
        self.dflt.owners.append(cls)

    @property
    def fld(self):
        # type: () -> Field[Any, Any]
        return self._find_fld() class PacketListField(_PacketField[List[BasePacket]]):
    """PacketListField represents a list containing a series of Packet instances
    that might occur right in the middle of another Packet field.
    This field type may also be used to indicate that a series of Packet
    instances have a sibling semantic instead of a parent/child relationship
    (i.e. a stack of layers).
    """
    __slots__ = ["count_from", "length_from", "next_cls_cb"]
    islist = 1

    def __init__(
            self,
            name,  # type: str
            default,  # type: Optional[List[BasePacket]]
            pkt_cls=None,  # type: Optional[Union[Callable[[bytes], Packet], Type[Packet]]]  # noqa: E501
            count_from=None,  # type: Optional[Callable[[Packet], int]]
            length_from=None,  # type: Optional[Callable[[Packet], int]]
            next_cls_cb=None,  # type: Optional[Callable[[Packet, List[BasePacket], Optional[Packet], bytes], Type[Packet]]]  # noqa: E501
    ):
        # type: (...) -> None
        """
        The number of Packet instances that are dissected by this field can
        be parametrized using one of three different mechanisms/parameters:

            * count_from: a callback that returns the number of Packet
              instances to dissect. The callback prototype is::

                count_from(pkt:Packet) -> int

            * length_from: a callback that returns the number of bytes that
              must be dissected by this field. The callback prototype is::

                length_from(pkt:Packet) -> int

            * next_cls_cb: a callback that enables a Scapy developer to
              dynamically discover if another Packet instance should be
              dissected or not. See below for this callback prototype.

        The bytes that are not consumed during the dissection of this field
        are passed to the next field of the current packet.

        For the serialization of such a field, the list of Packets that are
        contained in a PacketListField can be heterogeneous and is
        unrestricted.

        The type of the Packet instances that are dissected with this field is
        specified or discovered using one of the following mechanism:

            * the pkt_cls parameter may contain a callable that returns an
              instance of the dissected Packet. This may either be a
              reference of a Packet subclass (e.g. DNSRROPT in layers/dns.py)
              to generate an homogeneous PacketListField or a function
              deciding the type of the Packet instance
              (e.g. _CDPGuessAddrRecord in contrib/cdp.py)

            * the pkt_cls parameter may contain a class object with a defined
              ``dispatch_hook`` classmethod. That method must return a Packet
              instance. The ``dispatch_hook`` callmethod must implement the
                following prototype::

                dispatch_hook(cls,
                              _pkt:Optional[Packet],
                              *args, **kargs
                ) -> Type[Packet]

                The _pkt parameter may contain a reference to the packet
                instance containing the PacketListField that is being
                dissected.

            * the ``next_cls_cb`` parameter may contain a callable whose
              prototype is::

                cbk(pkt:Packet,
                    lst:List[Packet],
                    cur:Optional[Packet],
                    remain:str
                ) -> Optional[Type[Packet]]

              The pkt argument contains a reference to the Packet instance
              containing the PacketListField that is being dissected.
              The lst argument is the list of all Packet instances that were
              previously parsed during the current ``PacketListField``
              dissection, saved for the very last Packet instance.
              The cur argument contains a reference to that very last parsed
              ``Packet`` instance. The remain argument contains the bytes
              that may still be consumed by the current PacketListField
              dissection operation.

              This callback returns either the type of the next Packet to
              dissect or None to indicate that no more Packet are to be
              dissected.

              These four arguments allows a variety of dynamic discovery of
              the number of Packet to dissect and of the type of each one of
              these Packets, including: type determination based on current
              Packet instances or its underlayers, continuation based on the
              previously parsed Packet instances within that PacketListField,
              continuation based on a look-ahead on the bytes to be
              dissected...

        The pkt_cls and next_cls_cb parameters are semantically exclusive,
        although one could specify both. If both are specified, pkt_cls is
        silently ignored. The same is true for count_from and next_cls_cb.

        length_from and next_cls_cb are compatible and the dissection will
        end, whichever of the two stop conditions comes first.

        :param name: the name of the field
        :param default: the default value of this field; generally an empty
            Python list
        :param pkt_cls: either a callable returning a Packet instance or a
            class object defining a ``dispatch_hook`` class method
        :param count_from: a callback returning the number of Packet
            instances to dissect.
        :param length_from: a callback returning the number of bytes to dissect
        :param next_cls_cb: a callback returning either None or the type of
            the next Packet to dissect.
        """
        if default is None:
            default = []  # Create a new list for each instance
        super(PacketListField, self).__init__(
            name,
            default,
            pkt_cls  # type: ignore
        )
        self.count_from = count_from
        self.length_from = length_from
        self.next_cls_cb = next_cls_cb

    def any2i(self, pkt, x):
        # type: (Optional[Packet], Any) -> List[BasePacket]
        if not isinstance(x, list):
            return [x]
        else:
            return x

    def i2count(self,
                pkt,  # type: Optional[Packet]
                val,  # type: List[BasePacket]
                ):
        # type: (...) -> int
        if isinstance(val, list):
            return len(val)
        return 1

    def i2len(self,
              pkt,  # type: Optional[Packet]
              val,  # type: List[Packet]
              ):
        # type: (...) -> int
        return sum(len(p) for p in val)

    def getfield(self, pkt, s):
        # type: (Packet, bytes) -> Tuple[bytes, List[BasePacket]]
        c = len_pkt = cls = None
        if self.length_from is not None:
            len_pkt = self.length_from(pkt)
        elif self.count_from is not None:
            c = self.count_from(pkt)
        if self.next_cls_cb is not None:
            cls = self.next_cls_cb(pkt, [], None, s)
            c = 1
            if cls is None:
                c = 0

        lst = []  # type: List[BasePacket]
        ret = b""
        remain = s
        if len_pkt is not None:
            remain, ret = s[:len_pkt], s[len_pkt:]
        while remain:
            if c is not None:
                if c <= 0:
                    break
                c -= 1
            try:
                if cls is not None:
                    p = cls(remain)
                else:
                    p = self.m2i(pkt, remain)
            except Exception:
                if conf.debug_dissector:
                    raise
                p = conf.raw_layer(load=remain)
                remain = b""
            else:
                if conf.padding_layer in p:
                    pad = p[conf.padding_layer]
                    remain = pad.load
                    del(pad.underlayer.payload)
                    if self.next_cls_cb is not None:
                        cls = self.next_cls_cb(pkt, lst, p, remain)
                        if cls is not None:
                            c = 0 if c is None else c
                            c += 1
                else:
                    remain = b""
            lst.append(p)
        return remain + ret, lst

    def addfield(self, pkt, s, val):
        # type: (Packet, bytes, Any) -> bytes
        return s + b"".join(bytes_encode(v) for v in val) class ShortEnumField(EnumField[int]):
    __slots__ = EnumField.__slots__

    def __init__(self,
                 name,  # type: str
                 default,  # type: int
                 enum,  # type: Union[Dict[int, str], Dict[str, int], Tuple[Callable[[int], str], Callable[[str], int]], DADict[int, str]]  # noqa: E501
                 ):
        # type: (...) -> None
        EnumField.__init__(self, name, default, enum, "H") class ShortField(Field[int, int]):
    def __init__(self, name, default):
        # type: (str, Optional[int]) -> None
        Field.__init__(self, name, default, "H") class SourceIPField(IPField):
    __slots__ = ["dstname"]

    def __init__(self, name, dstname):
        # type: (str, Optional[str]) -> None
        IPField.__init__(self, name, None)
        self.dstname = dstname

    def __findaddr(self, pkt):
        # type: (Packet) -> str
        if conf.route is None:
            # unused import, only to initialize conf.route
            import scapy.route  # noqa: F401
        dst = ("0.0.0.0" if self.dstname is None
               else getattr(pkt, self.dstname) or "0.0.0.0")
        if isinstance(dst, (Gen, list)):
            r = {
                conf.route.route(str(daddr))
                for daddr in dst
            }  # type:  Set[Tuple[str, str, str]]
            if len(r) > 1:
                warning("More than one possible route for %r" % (dst,))
            return min(r)[1]
        return conf.route.route(dst)[1]

    def i2m(self, pkt, x):
        # type: (Optional[Packet], Optional[Union[str, Net]]) -> bytes
        if x is None and pkt is not None:
            x = self.__findaddr(pkt)
        return super(SourceIPField, self).i2m(pkt, x)

    def i2h(self, pkt, x):
        # type: (Optional[Packet], Optional[Union[str, Net]]) -> str
        if x is None and pkt is not None:
            x = self.__findaddr(pkt)
        return super(SourceIPField, self).i2h(pkt, x) class StrField(_StrField[bytes]):
    pass class StrFixedLenField(StrField):
    __slots__ = ["length_from"]

    def __init__(
            self,
            name,  # type: str
            default,  # type: Optional[bytes]
            length=None,  # type: Optional[int]
            length_from=None,  # type: Optional[Callable[[Packet], int]]  # noqa: E501
    ):
        # type: (...) -> None
        super(StrFixedLenField, self).__init__(name, default)
        self.length_from = length_from or (lambda x: 0)
        if length is not None:
            self.length_from = lambda x, length=length: length  # type: ignore

    def i2repr(self,
               pkt,  # type: Optional[Packet]
               v,  # type: bytes
               ):
        # type: (...) -> str
        if isinstance(v, bytes):
            v = v.rstrip(b"\0")
        return super(StrFixedLenField, self).i2repr(pkt, v)

    def getfield(self, pkt, s):
        # type: (Packet, bytes) -> Tuple[bytes, bytes]
        len_pkt = self.length_from(pkt)
        return s[len_pkt:], self.m2i(pkt, s[:len_pkt])

    def addfield(self, pkt, s, val):
        # type: (Packet, bytes, Optional[bytes]) -> bytes
        len_pkt = self.length_from(pkt)
        if len_pkt is None:
            return s + self.i2m(pkt, val)
        return s + struct.pack("%is" % len_pkt, self.i2m(pkt, val))

    def randval(self):
        # type: () -> RandBin
        try:
            return RandBin(self.length_from(None))  # type: ignore
        except Exception:
            return RandBin(RandNum(0, 200)) class StrLenField(StrField):
    __slots__ = ["length_from", "max_length"]

    def __init__(
            self,
            name,  # type: str
            default,  # type: bytes
            length_from=None,  # type: Optional[Callable[[Packet], int]]
            max_length=None,  # type: Optional[Any]
    ):
        # type: (...) -> None
        super(StrLenField, self).__init__(name, default)
        self.length_from = length_from
        self.max_length = max_length

    def getfield(self, pkt, s):
        # type: (Any, bytes) -> Tuple[bytes, bytes]
        len_pkt = (self.length_from or (lambda x: 0))(pkt)
        return s[len_pkt:], self.m2i(pkt, s[:len_pkt])

    def randval(self):
        # type: () -> RandBin
        return RandBin(RandNum(0, self.max_length or 1200)) class XByteField(ByteField):
    def i2repr(self, pkt, x):
        # type: (Optional[Packet], int) -> str
        return lhex(self.i2h(pkt, x)) class XShortField(ShortField):
    def i2repr(self, pkt, x):
        # type: (Optional[Packet], int) -> str
        return lhex(self.i2h(pkt, x)) class Packet(six.with_metaclass(Packet_metaclass,  # type: ignore
             BasePacket, _CanvasDumpExtended)):
    __slots__ = [
        "time", "sent_time", "name",
        "default_fields", "fields", "fieldtype",
        "overload_fields", "overloaded_fields",
        "packetfields",
        "original", "explicit", "raw_packet_cache",
        "raw_packet_cache_fields", "_pkt", "post_transforms",
        # then payload and underlayer
        "payload", "underlayer",
        "name",
        # used for sr()
        "_answered",
        # used when sniffing
        "direction", "sniffed_on",
        # handle snaplen Vs real length
        "wirelen",
    ]
    name = None
    fields_desc = []  # type: Sequence[AnyField]
    deprecated_fields = {}  # type: Dict[str, Tuple[str, str]]
    overload_fields = {}  # type: Dict[Type[Packet], Dict[str, Any]]
    payload_guess = []  # type: List[Tuple[Dict[str, Any], Type[Packet]]]
    show_indent = 1
    show_summary = True
    match_subclass = False
    class_dont_cache = {}  # type: Dict[Type[Packet], bool]
    class_packetfields = {}  # type: Dict[Type[Packet], Any]
    class_default_fields = {}  # type: Dict[Type[Packet], Dict[str, Any]]
    class_default_fields_ref = {}  # type: Dict[Type[Packet], List[str]]
    class_fieldtype = {}  # type: Dict[Type[Packet], Dict[str, AnyField]]  # noqa: E501

    @classmethod
    def from_hexcap(cls):
        # type: (Type[Packet]) -> Packet
        return cls(import_hexcap())

    @classmethod
    def upper_bonds(self):
        # type: () -> None
        for fval, upper in self.payload_guess:
            print("%-20s  %s" % (upper.__name__, ", ".join("%-12s" % ("%s=%r" % i) for i in six.iteritems(fval))))  # noqa: E501

    @classmethod
    def lower_bonds(self):
        # type: () -> None
        for lower, fval in six.iteritems(self._overload_fields):
            print("%-20s  %s" % (lower.__name__, ", ".join("%-12s" % ("%s=%r" % i) for i in six.iteritems(fval))))  # noqa: E501

    def __init__(self,
                 _pkt=b"",  # type: bytes
                 post_transform=None,  # type: Any
                 _internal=0,  # type: int
                 _underlayer=None,  # type: Optional[Packet]
                 **fields  # type: Any
                 ):
        # type: (...) -> None
        self.time = time.time()  # type: Union[EDecimal, float]
        self.sent_time = None  # type: Union[EDecimal, float, None]
        self.name = (self.__class__.__name__
                     if self._name is None else
                     self._name)
        self.default_fields = {}  # type: Dict[str, Any]
        self.overload_fields = self._overload_fields
        self.overloaded_fields = {}  # type: Dict[str, Any]
        self.fields = {}  # type: Dict[str, Any]
        self.fieldtype = {}  # type: Dict[str, AnyField]
        self.packetfields = []  # type: List[AnyField]
        self.payload = NoPayload()
        self.init_fields()
        self.underlayer = _underlayer
        self.original = _pkt
        self.explicit = 0
        self.raw_packet_cache = None  # type: Optional[bytes]
        self.raw_packet_cache_fields = None  # type: Optional[Dict[str, Any]]  # noqa: E501
        self.wirelen = None  # type: Optional[int]
        self.direction = None  # type: Optional[int]
        self.sniffed_on = None  # type: Optional[_GlobInterfaceType]
        if _pkt:
            self.dissect(_pkt)
            if not _internal:
                self.dissection_done(self)
        # We use this strange initialization so that the fields
        # are initialized in their declaration order.
        # It is required to always support MultipleTypeField
        for field in self.fields_desc:
            fname = field.name
            try:
                value = fields.pop(fname)
            except KeyError:
                continue
            self.fields[fname] = self.get_field(fname).any2i(self, value)
        # The remaining fields are unknown
        for fname in fields:
            if fname in self.deprecated_fields:
                # Resolve deprecated fields
                value = fields[fname]
                fname = self._resolve_alias(fname)
                self.fields[fname] = self.get_field(fname).any2i(self, value)
                continue
            raise AttributeError(fname)
        if isinstance(post_transform, list):
            self.post_transforms = post_transform
        elif post_transform is None:
            self.post_transforms = []
        else:
            self.post_transforms = [post_transform]

    _PickleType = Tuple[
        Union[EDecimal, float],
        Optional[Union[EDecimal, float, None]],
        Optional[int],
        Optional[_GlobInterfaceType],
        Optional[int]
    ]

    def __reduce__(self):
        # type: () -> Tuple[Type[Packet], Tuple[bytes], Packet._PickleType]
        """Used by pickling methods"""
        return (self.__class__, (self.build(),), (
            self.time,
            self.sent_time,
            self.direction,
            self.sniffed_on,
            self.wirelen,
        ))

    def __setstate__(self, state):
        # type: (Packet._PickleType) -> Packet
        """Rebuild state using pickable methods"""
        self.time = state[0]
        self.sent_time = state[1]
        self.direction = state[2]
        self.sniffed_on = state[3]
        self.wirelen = state[4]
        return self

    def __deepcopy__(self,
                     memo,  # type: Any
                     ):
        # type: (...) -> Packet
        """Used by copy.deepcopy"""
        return self.copy()

    def init_fields(self):
        # type: () -> None
        """
        Initialize each fields of the fields_desc dict
        """

        if self.class_dont_cache.get(self.__class__, False):
            self.do_init_fields(self.fields_desc)
        else:
            self.do_init_cached_fields()

    def do_init_fields(self,
                       flist,  # type: Sequence[AnyField]
                       ):
        # type: (...) -> None
        """
        Initialize each fields of the fields_desc dict
        """
        default_fields = {}
        for f in flist:
            default_fields[f.name] = copy.deepcopy(f.default)
            self.fieldtype[f.name] = f
            if f.holds_packets:
                self.packetfields.append(f)
        # We set default_fields last to avoid race issues
        self.default_fields = default_fields

    def do_init_cached_fields(self):
        # type: () -> None
        """
        Initialize each fields of the fields_desc dict, or use the cached
        fields information
        """

        cls_name = self.__class__

        # Build the fields information
        if Packet.class_default_fields.get(cls_name, None) is None:
            self.prepare_cached_fields(self.fields_desc)

        # Use fields information from cache
        default_fields = Packet.class_default_fields.get(cls_name, None)
        if default_fields:
            self.default_fields = default_fields
            self.fieldtype = Packet.class_fieldtype[cls_name]
            self.packetfields = Packet.class_packetfields[cls_name]

            # Deepcopy default references
            for fname in Packet.class_default_fields_ref[cls_name]:
                value = self.default_fields[fname]
                try:
                    self.fields[fname] = value.copy()
                except AttributeError:
                    # Python 2.7 - list only
                    self.fields[fname] = value[:]

    def prepare_cached_fields(self, flist):
        # type: (Sequence[AnyField]) -> None
        """
        Prepare the cached fields of the fields_desc dict
        """

        cls_name = self.__class__

        # Fields cache initialization
        if not flist:
            return

        class_default_fields = dict()
        class_default_fields_ref = list()
        class_fieldtype = dict()
        class_packetfields = list()

        # Fields initialization
        for f in flist:
            if isinstance(f, MultipleTypeField):
                # Abort
                self.class_dont_cache[cls_name] = True
                self.do_init_fields(self.fields_desc)
                return

            tmp_copy = copy.deepcopy(f.default)
            class_default_fields[f.name] = tmp_copy
            class_fieldtype[f.name] = f
            if f.holds_packets:
                class_packetfields.append(f)

            # Remember references
            if isinstance(f.default, (list, dict, set, RandField, Packet)):
                class_default_fields_ref.append(f.name)

        # Apply
        Packet.class_default_fields_ref[cls_name] = class_default_fields_ref
        Packet.class_fieldtype[cls_name] = class_fieldtype
        Packet.class_packetfields[cls_name] = class_packetfields
        # Last to avoid racing issues
        Packet.class_default_fields[cls_name] = class_default_fields

    def dissection_done(self, pkt):
        # type: (Packet) -> None
        """DEV: will be called after a dissection is completed"""
        self.post_dissection(pkt)
        self.payload.dissection_done(pkt)

    def post_dissection(self, pkt):
        # type: (Packet) -> None
        """DEV: is called after the dissection of the whole packet"""
        pass

    def get_field(self, fld):
        # type: (str) -> AnyField
        """DEV: returns the field instance from the name of the field"""
        return self.fieldtype[fld]

    def add_payload(self, payload):
        # type: (Union[Packet, bytes]) -> None
        if payload is None:
            return
        elif not isinstance(self.payload, NoPayload):
            self.payload.add_payload(payload)
        else:
            if isinstance(payload, Packet):
                self.payload = payload
                payload.add_underlayer(self)
                for t in self.aliastypes:
                    if t in payload.overload_fields:
                        self.overloaded_fields = payload.overload_fields[t]
                        break
            elif isinstance(payload, (bytes, str, bytearray, memoryview)):
                self.payload = conf.raw_layer(load=bytes_encode(payload))
            else:
                raise TypeError("payload must be 'Packet', 'bytes', 'str', 'bytearray', or 'memoryview', not [%s]" % repr(payload))  # noqa: E501

    def remove_payload(self):
        # type: () -> None
        self.payload.remove_underlayer(self)
        self.payload = NoPayload()
        self.overloaded_fields = {}

    def add_underlayer(self, underlayer):
        # type: (Packet) -> None
        self.underlayer = underlayer

    def remove_underlayer(self, other):
        # type: (Packet) -> None
        self.underlayer = None

    def copy(self):
        # type: () -> Packet
        """Returns a deep copy of the instance."""
        clone = self.__class__()
        clone.fields = self.copy_fields_dict(self.fields)
        clone.default_fields = self.copy_fields_dict(self.default_fields)
        clone.overloaded_fields = self.overloaded_fields.copy()
        clone.underlayer = self.underlayer
        clone.explicit = self.explicit
        clone.raw_packet_cache = self.raw_packet_cache
        clone.raw_packet_cache_fields = self.copy_fields_dict(
            self.raw_packet_cache_fields
        )
        clone.wirelen = self.wirelen
        clone.post_transforms = self.post_transforms[:]
        clone.payload = self.payload.copy()
        clone.payload.add_underlayer(clone)
        clone.time = self.time
        return clone

    def _resolve_alias(self, attr):
        # type: (str) -> str
        new_attr, version = self.deprecated_fields[attr]
        warnings.warn(
            "%s has been deprecated in favor of %s since %s !" % (
                attr, new_attr, version
            ), DeprecationWarning
        )
        return new_attr

    def getfieldval(self, attr):
        # type: (str) -> Any
        if self.deprecated_fields and attr in self.deprecated_fields:
            attr = self._resolve_alias(attr)
        if attr in self.fields:
            return self.fields[attr]
        if attr in self.overloaded_fields:
            return self.overloaded_fields[attr]
        if attr in self.default_fields:
            return self.default_fields[attr]
        return self.payload.getfieldval(attr)

    def getfield_and_val(self, attr):
        # type: (str) -> Tuple[AnyField, Any]
        if self.deprecated_fields and attr in self.deprecated_fields:
            attr = self._resolve_alias(attr)
        if attr in self.fields:
            return self.get_field(attr), self.fields[attr]
        if attr in self.overloaded_fields:
            return self.get_field(attr), self.overloaded_fields[attr]
        if attr in self.default_fields:
            return self.get_field(attr), self.default_fields[attr]
        raise ValueError

    def __getattr__(self, attr):
        # type: (str) -> Any
        try:
            fld, v = self.getfield_and_val(attr)
        except ValueError:
            return self.payload.__getattr__(attr)
        if fld is not None:
            return fld.i2h(self, v)
        return v

    def setfieldval(self, attr, val):
        # type: (str, Any) -> None
        if self.deprecated_fields and attr in self.deprecated_fields:
            attr = self._resolve_alias(attr)
        if attr in self.default_fields:
            fld = self.get_field(attr)
            if fld is None:
                any2i = lambda x, y: y  # type: Callable[..., Any]
            else:
                any2i = fld.any2i
            self.fields[attr] = any2i(self, val)
            self.explicit = 0
            self.raw_packet_cache = None
            self.raw_packet_cache_fields = None
            self.wirelen = None
        elif attr == "payload":
            self.remove_payload()
            self.add_payload(val)
        else:
            self.payload.setfieldval(attr, val)

    def __setattr__(self, attr, val):
        # type: (str, Any) -> None
        if attr in self.__all_slots__:
            return object.__setattr__(self, attr, val)
        try:
            return self.setfieldval(attr, val)
        except AttributeError:
            pass
        return object.__setattr__(self, attr, val)

    def delfieldval(self, attr):
        # type: (str) -> None
        if attr in self.fields:
            del(self.fields[attr])
            self.explicit = 0  # in case a default value must be explicit
            self.raw_packet_cache = None
            self.raw_packet_cache_fields = None
            self.wirelen = None
        elif attr in self.default_fields:
            pass
        elif attr == "payload":
            self.remove_payload()
        else:
            self.payload.delfieldval(attr)

    def __delattr__(self, attr):
        # type: (str) -> None
        if attr == "payload":
            return self.remove_payload()
        if attr in self.__all_slots__:
            return object.__delattr__(self, attr)
        try:
            return self.delfieldval(attr)
        except AttributeError:
            pass
        return object.__delattr__(self, attr)

    def _superdir(self):
        # type: () -> Set[str]
        """
        Return a list of slots and methods, including those from subclasses.
        """
        attrs = set()
        cls = self.__class__
        if hasattr(cls, '__all_slots__'):
            attrs.update(cls.__all_slots__)
        for bcls in cls.__mro__:
            if hasattr(bcls, '__dict__'):
                attrs.update(bcls.__dict__)
        return attrs

    def __dir__(self):
        # type: () -> List[str]
        """
        Add fields to tab completion list.
        """
        return sorted(itertools.chain(self._superdir(), self.default_fields))

    def __repr__(self):
        # type: () -> str
        s = ""
        ct = conf.color_theme
        for f in self.fields_desc:
            if isinstance(f, ConditionalField) and not f._evalcond(self):
                continue
            if f.name in self.fields:
                fval = self.fields[f.name]
                if isinstance(fval, (list, dict, set)) and len(fval) == 0:
                    continue
                val = f.i2repr(self, fval)
            elif f.name in self.overloaded_fields:
                fover = self.overloaded_fields[f.name]
                if isinstance(fover, (list, dict, set)) and len(fover) == 0:
                    continue
                val = f.i2repr(self, fover)
            else:
                continue
            if isinstance(f, Emph) or f in conf.emph:
                ncol = ct.emph_field_name
                vcol = ct.emph_field_value
            else:
                ncol = ct.field_name
                vcol = ct.field_value

            s += " %s%s%s" % (ncol(f.name),
                              ct.punct("="),
                              vcol(val))
        return "%s%s %s %s%s%s" % (ct.punct("<"),
                                   ct.layer_name(self.__class__.__name__),
                                   s,
                                   ct.punct("|"),
                                   repr(self.payload),
                                   ct.punct(">"))

    if six.PY2:
        def __str__(self):
            # type: () -> str
            return self.build()
    else:
        def __str__(self):
            # type: () -> str
            warning("Calling str(pkt) on Python 3 makes no sense!")
            return str(self.build())

    def __bytes__(self):
        # type: () -> bytes
        return self.build()

    def __div__(self, other):
        # type: (Any) -> Packet
        if isinstance(other, Packet):
            cloneA = self.copy()
            cloneB = other.copy()
            cloneA.add_payload(cloneB)
            return cloneA
        elif isinstance(other, (bytes, str, bytearray, memoryview)):
            return self / conf.raw_layer(load=bytes_encode(other))
        else:
            return other.__rdiv__(self)  # type: ignore
    __truediv__ = __div__

    def __rdiv__(self, other):
        # type: (Any) -> Packet
        if isinstance(other, (bytes, str, bytearray, memoryview)):
            return conf.raw_layer(load=bytes_encode(other)) / self
        else:
            raise TypeError
    __rtruediv__ = __rdiv__

    def __mul__(self, other):
        # type: (Any) -> List[Packet]
        if isinstance(other, int):
            return [self] * other
        else:
            raise TypeError

    def __rmul__(self, other):
        # type: (Any) -> List[Packet]
        return self.__mul__(other)

    def __nonzero__(self):
        # type: () -> bool
        return True
    __bool__ = __nonzero__

    def __len__(self):
        # type: () -> int
        return len(self.__bytes__())

    def copy_field_value(self, fieldname, value):
        # type: (str, Any) -> Any
        return self.get_field(fieldname).do_copy(value)

    def copy_fields_dict(self, fields):
        # type: (_T) -> _T
        if fields is None:
            return None
        return {fname: self.copy_field_value(fname, fval)
                for fname, fval in six.iteritems(fields)}

    def clear_cache(self):
        # type: () -> None
        """Clear the raw packet cache for the field and all its subfields"""
        self.raw_packet_cache = None
        for fld, fval in six.iteritems(self.fields):
            fld = self.get_field(fld)
            if fld.holds_packets:
                if isinstance(fval, Packet):
                    fval.clear_cache()
                elif isinstance(fval, list):
                    for fsubval in fval:
                        fsubval.clear_cache()
        self.payload.clear_cache()

    def self_build(self):
        # type: () -> bytes
        """
        Create the default layer regarding fields_desc dict

        :param field_pos_list:
        """
        if self.raw_packet_cache is not None:
            for fname, fval in six.iteritems(self.raw_packet_cache_fields):
                if self.getfieldval(fname) != fval:
                    self.raw_packet_cache = None
                    self.raw_packet_cache_fields = None
                    self.wirelen = None
                    break
            if self.raw_packet_cache is not None:
                return self.raw_packet_cache
        p = b""
        for f in self.fields_desc:
            val = self.getfieldval(f.name)
            if isinstance(val, RawVal):
                p += bytes(val)
            else:
                try:
                    p = f.addfield(self, p, val)
                except Exception as ex:
                    try:
                        ex.args = (
                            "While disescting field '%s': " % f.name +
                            ex.args[0],
                        ) + ex.args[1:]
                    except (AttributeError, IndexError):
                        pass
                    raise ex
        return p

    def do_build_payload(self):
        # type: () -> bytes
        """
        Create the default version of the payload layer

        :return: a string of payload layer
        """
        return self.payload.do_build()

    def do_build(self):
        # type: () -> bytes
        """
        Create the default version of the layer

        :return: a string of the packet with the payload
        """
        if not self.explicit:
            self = next(iter(self))
        pkt = self.self_build()
        for t in self.post_transforms:
            pkt = t(pkt)
        pay = self.do_build_payload()
        if self.raw_packet_cache is None:
            return self.post_build(pkt, pay)
        else:
            return pkt + pay

    def build_padding(self):
        # type: () -> bytes
        return self.payload.build_padding()

    def build(self):
        # type: () -> bytes
        """
        Create the current layer

        :return: string of the packet with the payload
        """
        p = self.do_build()
        p += self.build_padding()
        p = self.build_done(p)
        return p

    def post_build(self, pkt, pay):
        # type: (bytes, bytes) -> bytes
        """
        DEV: called right after the current layer is build.

        :param str pkt: the current packet (build by self_build function)
        :param str pay: the packet payload (build by do_build_payload function)
        :return: a string of the packet with the payload
        """
        return pkt + pay

    def build_done(self, p):
        # type: (bytes) -> bytes
        return self.payload.build_done(p)

    def do_build_ps(self):
        # type: () -> Tuple[bytes, List[Tuple[Packet, List[Tuple[Field[Any, Any], str, bytes]]]]]  # noqa: E501
        p = b""
        pl = []
        q = b""
        for f in self.fields_desc:
            if isinstance(f, ConditionalField) and not f._evalcond(self):
                continue
            p = f.addfield(self, p, self.getfieldval(f.name))
            if isinstance(p, bytes):
                r = p[len(q):]
                q = p
            else:
                r = b""
            pl.append((f, f.i2repr(self, self.getfieldval(f.name)), r))

        pkt, lst = self.payload.build_ps(internal=1)
        p += pkt
        lst.append((self, pl))

        return p, lst

    def build_ps(self, internal=0):
        # type: (int) -> Tuple[bytes, List[Tuple[Packet, List[Tuple[Any, Any, bytes]]]]]  # noqa: E501
        p, lst = self.do_build_ps()
#        if not internal:
#            pkt = self
#            while pkt.haslayer(conf.padding_layer):
#                pkt = pkt.getlayer(conf.padding_layer)
#                lst.append( (pkt, [ ("loakjkjd", pkt.load, pkt.load) ] ) )
#                p += pkt.load
#                pkt = pkt.payload
        return p, lst

    def canvas_dump(self, layer_shift=0, rebuild=1):
        # type: (int, int) -> pyx.canvas.canvas
        if PYX == 0:
            raise ImportError("PyX and its dependencies must be installed")
        canvas = pyx.canvas.canvas()
        if rebuild:
            _, t = self.__class__(raw(self)).build_ps()
        else:
            _, t = self.build_ps()
        YTXTI = len(t)
        for _, l in t:
            YTXTI += len(l)
        YTXT = float(YTXTI)
        YDUMP = YTXT

        XSTART = 1
        XDSTART = 10
        y = 0.0
        yd = 0.0
        XMUL = 0.55
        YMUL = 0.4

        backcolor = colgen(0.6, 0.8, 1.0, trans=pyx.color.rgb)
        forecolor = colgen(0.2, 0.5, 0.8, trans=pyx.color.rgb)
#        backcolor=makecol(0.376, 0.729, 0.525, 1.0)

        def hexstr(x):
            # type: (bytes) -> str
            return " ".join("%02x" % orb(c) for c in x)

        def make_dump_txt(x, y, txt):
            # type: (int, float, bytes) -> pyx.text.text
            return pyx.text.text(
                XDSTART + x * XMUL,
                (YDUMP - y) * YMUL,
                r"\tt{%s}" % hexstr(txt),
                [pyx.text.size.Large]
            )

        def make_box(o):
            # type: (pyx.bbox.bbox) -> pyx.bbox.bbox
            return pyx.box.rect(
                o.left(), o.bottom(), o.width(), o.height(),
                relcenter=(0.5, 0.5)
            )

        def make_frame(lst):
            # type: (List[Any]) -> pyx.path.path
            if len(lst) == 1:
                b = lst[0].bbox()
                b.enlarge(pyx.unit.u_pt)
                return b.path()
            else:
                fb = lst[0].bbox()
                fb.enlarge(pyx.unit.u_pt)
                lb = lst[-1].bbox()
                lb.enlarge(pyx.unit.u_pt)
                if len(lst) == 2 and fb.left() > lb.right():
                    return pyx.path.path(pyx.path.moveto(fb.right(), fb.top()),
                                         pyx.path.lineto(fb.left(), fb.top()),
                                         pyx.path.lineto(fb.left(), fb.bottom()),  # noqa: E501
                                         pyx.path.lineto(fb.right(), fb.bottom()),  # noqa: E501
                                         pyx.path.moveto(lb.left(), lb.top()),
                                         pyx.path.lineto(lb.right(), lb.top()),
                                         pyx.path.lineto(lb.right(), lb.bottom()),  # noqa: E501
                                         pyx.path.lineto(lb.left(), lb.bottom()))  # noqa: E501
                else:
                    # XXX
                    gb = lst[1].bbox()
                    if gb != lb:
                        gb.enlarge(pyx.unit.u_pt)
                    kb = lst[-2].bbox()
                    if kb != gb and kb != lb:
                        kb.enlarge(pyx.unit.u_pt)
                    return pyx.path.path(pyx.path.moveto(fb.left(), fb.top()),
                                         pyx.path.lineto(fb.right(), fb.top()),
                                         pyx.path.lineto(fb.right(), kb.bottom()),  # noqa: E501
                                         pyx.path.lineto(lb.right(), kb.bottom()),  # noqa: E501
                                         pyx.path.lineto(lb.right(), lb.bottom()),  # noqa: E501
                                         pyx.path.lineto(lb.left(), lb.bottom()),  # noqa: E501
                                         pyx.path.lineto(lb.left(), gb.top()),
                                         pyx.path.lineto(fb.left(), gb.top()),
                                         pyx.path.closepath(),)

        def make_dump(s,   # type: bytes
                      shift=0,  # type: int
                      y=0.,  # type: float
                      col=None,  # type: pyx.color.color
                      bkcol=None,  # type: pyx.color.color
                      large=16  # type: int
                      ):
            # type: (...) -> Tuple[pyx.canvas.canvas, pyx.bbox.bbox, int, float]  # noqa: E501
            c = pyx.canvas.canvas()
            tlist = []
            while s:
                dmp, s = s[:large - shift], s[large - shift:]
                txt = make_dump_txt(shift, y, dmp)
                tlist.append(txt)
                shift += len(dmp)
                if shift >= 16:
                    shift = 0
                    y += 1
            if col is None:
                col = pyx.color.rgb.red
            if bkcol is None:
                bkcol = pyx.color.rgb.white
            c.stroke(make_frame(tlist), [col, pyx.deco.filled([bkcol]), pyx.style.linewidth.Thick])  # noqa: E501
            for txt in tlist:
                c.insert(txt)
            return c, tlist[-1].bbox(), shift, y

        last_shift, last_y = 0, 0.0
        while t:
            bkcol = next(backcolor)
            proto, fields = t.pop()
            y += 0.5
            pt = pyx.text.text(
                XSTART,
                (YTXT - y) * YMUL,
                r"\font\cmssfont=cmss10\cmssfont{%s}" % tex_escape(
                    str(proto.name)
                ),
                [pyx.text.size.Large]
            )
            y += 1
            ptbb = pt.bbox()
            ptbb.enlarge(pyx.unit.u_pt * 2)
            canvas.stroke(ptbb.path(), [pyx.color.rgb.black, pyx.deco.filled([bkcol])])  # noqa: E501
            canvas.insert(pt)
            for field, fval, fdump in fields:
                col = next(forecolor)
                ft = pyx.text.text(XSTART, (YTXT - y) * YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % tex_escape(field.name))  # noqa: E501
                if isinstance(field, BitField):
                    fsize = '%sb' % field.size
                else:
                    fsize = '%sB' % len(fdump)
                if (hasattr(field, 'field') and
                        'LE' in field.field.__class__.__name__[:3] or
                        'LE' in field.__class__.__name__[:3]):
                    fsize = r'$\scriptstyle\langle$' + fsize
                st = pyx.text.text(XSTART + 3.4, (YTXT - y) * YMUL, r"\font\cmbxfont=cmssbx10 scaled 600\cmbxfont{%s}" % fsize, [pyx.text.halign.boxright])  # noqa: E501
                if isinstance(fval, str):
                    if len(fval) > 18:
                        fval = fval[:18] + "[...]"
                else:
                    fval = ""
                vt = pyx.text.text(XSTART + 3.5, (YTXT - y) * YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % tex_escape(fval))  # noqa: E501
                y += 1.0
                if fdump:
                    dt, target, last_shift, last_y = make_dump(fdump, last_shift, last_y, col, bkcol)  # noqa: E501

                    dtb = target
                    vtb = vt.bbox()
                    bxvt = make_box(vtb)
                    bxdt = make_box(dtb)
                    dtb.enlarge(pyx.unit.u_pt)
                    try:
                        if yd < 0:
                            cnx = pyx.connector.curve(bxvt, bxdt, absangle1=0, absangle2=-90)  # noqa: E501
                        else:
                            cnx = pyx.connector.curve(bxvt, bxdt, absangle1=0, absangle2=90)  # noqa: E501
                    except Exception:
                        pass
                    else:
                        canvas.stroke(cnx, [pyx.style.linewidth.thin, pyx.deco.earrow.small, col])  # noqa: E501

                    canvas.insert(dt)

                canvas.insert(ft)
                canvas.insert(st)
                canvas.insert(vt)
            last_y += layer_shift

        return canvas

    def extract_padding(self, s):
        # type: (bytes) -> Tuple[bytes, Optional[bytes]]
        """
        DEV: to be overloaded to extract current layer's padding.

        :param str s: the current layer
        :return: a couple of strings (actual layer, padding)
        """
        return s, None

    def post_dissect(self, s):
        # type: (bytes) -> bytes
        """DEV: is called right after the current layer has been dissected"""
        return s

    def pre_dissect(self, s):
        # type: (bytes) -> bytes
        """DEV: is called right before the current layer is dissected"""
        return s

    def do_dissect(self, s):
        # type: (bytes) -> bytes
        _raw = s
        self.raw_packet_cache_fields = {}
        for f in self.fields_desc:
            if not s:
                break
            s, fval = f.getfield(self, s)
            # Skip unused ConditionalField
            if isinstance(f, ConditionalField) and fval is None:
                continue
            # We need to track fields with mutable values to discard
            # .raw_packet_cache when needed.
            if f.islist or f.holds_packets or f.ismutable:
                self.raw_packet_cache_fields[f.name] = f.do_copy(fval)
            self.fields[f.name] = fval
        self.raw_packet_cache = _raw[:-len(s)] if s else _raw
        self.explicit = 1
        return s

    def do_dissect_payload(self, s):
        # type: (bytes) -> None
        """
        Perform the dissection of the layer's payload

        :param str s: the raw layer
        """
        if s:
            cls = self.guess_payload_class(s)
            try:
                p = cls(s, _internal=1, _underlayer=self)
            except KeyboardInterrupt:
                raise
            except Exception:
                if conf.debug_dissector:
                    if issubtype(cls, Packet):
                        log_runtime.error("%s dissector failed", cls.__name__)
                    else:
                        log_runtime.error("%s.guess_payload_class() returned "
                                          "[%s]",
                                          self.__class__.__name__, repr(cls))
                    if cls is not None:
                        raise
                p = conf.raw_layer(s, _internal=1, _underlayer=self)
            self.add_payload(p)

    def dissect(self, s):
        # type: (bytes) -> None
        s = self.pre_dissect(s)

        s = self.do_dissect(s)

        s = self.post_dissect(s)

        payl, pad = self.extract_padding(s)
        self.do_dissect_payload(payl)
        if pad and conf.padding:
            self.add_payload(conf.padding_layer(pad))

    def guess_payload_class(self, payload):
        # type: (bytes) -> Type[Packet]
        """
        DEV: Guesses the next payload class from layer bonds.
        Can be overloaded to use a different mechanism.

        :param str payload: the layer's payload
        :return: the payload class
        """
        for t in self.aliastypes:
            for fval, cls in t.payload_guess:
                try:
                    if all(v == self.getfieldval(k)
                           for k, v in six.iteritems(fval)):
                        return cls  # type: ignore
                except AttributeError:
                    pass
        return self.default_payload_class(payload)

    def default_payload_class(self, payload):
        # type: (bytes) -> Type[Packet]
        """
        DEV: Returns the default payload class if nothing has been found by the
        guess_payload_class() method.

        :param str payload: the layer's payload
        :return: the default payload class define inside the configuration file
        """
        return conf.raw_layer

    def hide_defaults(self):
        # type: () -> None
        """Removes fields' values that are the same as default values."""
        # use list(): self.fields is modified in the loop
        for k, v in list(six.iteritems(self.fields)):
            v = self.fields[k]
            if k in self.default_fields:
                if self.default_fields[k] == v:
                    del self.fields[k]
        self.payload.hide_defaults()

    def clone_with(self, payload=None, **kargs):
        # type: (Optional[Any], **Any) -> Any
        pkt = self.__class__()
        pkt.explicit = 1
        pkt.fields = kargs
        pkt.default_fields = self.copy_fields_dict(self.default_fields)
        pkt.overloaded_fields = self.overloaded_fields.copy()
        pkt.time = self.time
        pkt.underlayer = self.underlayer
        pkt.post_transforms = self.post_transforms
        pkt.raw_packet_cache = self.raw_packet_cache
        pkt.raw_packet_cache_fields = self.copy_fields_dict(
            self.raw_packet_cache_fields
        )
        pkt.wirelen = self.wirelen
        if payload is not None:
            pkt.add_payload(payload)
        return pkt

    def __iter__(self):
        # type: () -> Iterator[Packet]
        """Iterates through all sub-packets generated by this Packet."""
        def loop(todo, done, self=self):
            # type: (List[str], Dict[str, Any], Any) -> Iterator[Packet]
            if todo:
                eltname = todo.pop()
                elt = self.getfieldval(eltname)
                if not isinstance(elt, Gen):
                    if self.get_field(eltname).islist:
                        elt = SetGen([elt])
                    else:
                        elt = SetGen(elt)
                for e in elt:
                    done[eltname] = e
                    for x in loop(todo[:], done):
                        yield x
            else:
                if isinstance(self.payload, NoPayload):
                    payloads = SetGen([None])  # type: SetGen[Packet]
                else:
                    payloads = self.payload
                for payl in payloads:
                    # Let's make sure subpackets are consistent
                    done2 = done.copy()
                    for k in done2:
                        if isinstance(done2[k], VolatileValue):
                            done2[k] = done2[k]._fix()
                    pkt = self.clone_with(payload=payl, **done2)
                    yield pkt

        if self.explicit or self.raw_packet_cache is not None:
            todo = []
            done = self.fields
        else:
            todo = [k for (k, v) in itertools.chain(six.iteritems(self.default_fields),  # noqa: E501
                                                    six.iteritems(self.overloaded_fields))  # noqa: E501
                    if isinstance(v, VolatileValue)] + list(self.fields)
            done = {}
        return loop(todo, done)

    def iterpayloads(self):
        # type: () -> Iterator[Packet]
        """Used to iter through the payloads of a Packet.
        Useful for DNS or 802.11 for instance.
        """
        yield self
        current = self
        while current.payload:
            current = current.payload
            yield current

    def __gt__(self, other):
        # type: (Packet) -> int
        """True if other is an answer from self (self ==> other)."""
        if isinstance(other, Packet):
            return other < self
        elif isinstance(other, bytes):
            return 1
        else:
            raise TypeError((self, other))

    def __lt__(self, other):
        # type: (Packet) -> int
        """True if self is an answer from other (other ==> self)."""
        if isinstance(other, Packet):
            return self.answers(other)
        elif isinstance(other, bytes):
            return 1
        else:
            raise TypeError((self, other))

    def __eq__(self, other):
        # type: (Any) -> bool
        if not isinstance(other, self.__class__):
            return False
        for f in self.fields_desc:
            if f not in other.fields_desc:
                return False
            if self.getfieldval(f.name) != other.getfieldval(f.name):
                return False
        return self.payload == other.payload

    def __ne__(self, other):
        # type: (Any) -> bool
        return not self.__eq__(other)

    # Note: setting __hash__ to None is the standard way
    # of making an object un-hashable. mypy doesn't know that
    __hash__ = None  # type: ignore

    def hashret(self):
        # type: () -> bytes
        """DEV: returns a string that has the same value for a request
        and its answer."""
        return self.payload.hashret()

    def answers(self, other):
        # type: (Packet) -> int
        """DEV: true if self is an answer from other"""
        if other.__class__ == self.__class__:
            return self.payload.answers(other.payload)
        return 0

    def layers(self):
        # type: () -> List[Type[Packet]]
        """returns a list of layer classes (including subclasses) in this packet"""  # noqa: E501
        layers = []
        lyr = self  # type: Optional[Packet]
        while lyr:
            layers.append(lyr.__class__)
            lyr = lyr.payload.getlayer(0, _subclass=True)
        return layers

    def haslayer(self, cls, _subclass=None):
        # type: (Union[Type[Packet], str], Optional[bool]) -> int
        """
        true if self has a layer that is an instance of cls.
        Superseded by "cls in self" syntax.
        """
        if _subclass is None:
            _subclass = self.match_subclass or None
        if _subclass:
            match = issubtype
        else:
            match = lambda cls1, cls2: bool(cls1 == cls2)
        if cls is None or match(self.__class__, cls) \
           or cls in [self.__class__.__name__, self._name]:
            return True
        for f in self.packetfields:
            fvalue_gen = self.getfieldval(f.name)
            if fvalue_gen is None:
                continue
            if not f.islist:
                fvalue_gen = SetGen(fvalue_gen, _iterpacket=0)
            for fvalue in fvalue_gen:
                if isinstance(fvalue, Packet):
                    ret = fvalue.haslayer(cls, _subclass=_subclass)
                    if ret:
                        return ret
        return self.payload.haslayer(cls, _subclass=_subclass)

    def getlayer(self,
                 cls,  # type: Union[int, Type[Packet], str]
                 nb=1,  # type: int
                 _track=None,  # type: Optional[List[int]]
                 _subclass=None,  # type: Optional[bool]
                 **flt  # type: Any
                 ):
        # type: (...) -> Optional[Packet]
        """Return the nb^th layer that is an instance of cls, matching flt
values.
        """
        if _subclass is None:
            _subclass = self.match_subclass or None
        if _subclass:
            match = issubtype
        else:
            match = lambda cls1, cls2: bool(cls1 == cls2)
        # Note:
        # cls can be int, packet, str
        # string_class_name can be packet, str (packet or packet+field)
        # class_name can be packet, str (packet only)
        if isinstance(cls, int):
            nb = cls + 1
            string_class_name = ""  # type: Union[Type[Packet], str]
        else:
            string_class_name = cls
        class_name = ""  # type: Union[Type[Packet], str]
        fld = None  # type: Optional[str]
        if isinstance(string_class_name, str) and "." in string_class_name:
            class_name, fld = string_class_name.split(".", 1)
        else:
            class_name, fld = string_class_name, None
        if not class_name or match(self.__class__, class_name) \
           or class_name in [self.__class__.__name__, self._name]:
            if all(self.getfieldval(fldname) == fldvalue
                   for fldname, fldvalue in six.iteritems(flt)):
                if nb == 1:
                    if fld is None:
                        return self
                    else:
                        return self.getfieldval(fld)  # type: ignore
                else:
                    nb -= 1
        for f in self.packetfields:
            fvalue_gen = self.getfieldval(f.name)
            if fvalue_gen is None:
                continue
            if not f.islist:
                fvalue_gen = SetGen(fvalue_gen, _iterpacket=0)
            for fvalue in fvalue_gen:
                if isinstance(fvalue, Packet):
                    track = []  # type: List[int]
                    ret = fvalue.getlayer(class_name, nb=nb, _track=track,
                                          _subclass=_subclass, **flt)
                    if ret is not None:
                        return ret
                    nb = track[0]
        return self.payload.getlayer(class_name, nb=nb, _track=_track,
                                     _subclass=_subclass, **flt)

    def firstlayer(self):
        # type: () -> Packet
        q = self
        while q.underlayer is not None:
            q = q.underlayer
        return q

    def __getitem__(self, cls):
        # type: (Union[Type[Packet], str]) -> Any
        if isinstance(cls, slice):
            lname = cls.start
            if cls.stop:
                ret = self.getlayer(cls.start, nb=cls.stop, **(cls.step or {}))
            else:
                ret = self.getlayer(cls.start, **(cls.step or {}))
        else:
            lname = cls
            ret = self.getlayer(cls)
        if ret is None:
            if isinstance(lname, type):
                name = lname.__name__
            elif not isinstance(lname, bytes):
                name = repr(lname)
            else:
                name = cast(str, lname)
            raise IndexError("Layer [%s] not found" % name)
        return ret

    def __delitem__(self, cls):
        # type: (Type[Packet]) -> None
        del(self[cls].underlayer.payload)

    def __setitem__(self, cls, val):
        # type: (Type[Packet], Packet) -> None
        self[cls].underlayer.payload = val

    def __contains__(self, cls):
        # type: (Union[Type[Packet], str]) -> int
        """
        "cls in self" returns true if self has a layer which is an
        instance of cls.
        """
        return self.haslayer(cls)

    def route(self):
        # type: () -> Tuple[Optional[str], Optional[str], Optional[str]]
        return self.payload.route()

    def fragment(self, *args, **kargs):
        # type: (*Any, **Any) -> List[Packet]
        return self.payload.fragment(*args, **kargs)

    def display(self, *args, **kargs):  # Deprecated. Use show()
        # type: (*Any, **Any) -> None
        """Deprecated. Use show() method."""
        self.show(*args, **kargs)

    def _show_or_dump(self,
                      dump=False,  # type: bool
                      indent=3,  # type: int
                      lvl="",  # type: str
                      label_lvl="",  # type: str
                      first_call=True  # type: bool
                      ):
        # type: (...) -> Optional[str]
        """
        Internal method that shows or dumps a hierarchical view of a packet.
        Called by show.

        :param dump: determine if it prints or returns the string value
        :param int indent: the size of indentation for each layer
        :param str lvl: additional information about the layer lvl
        :param str label_lvl: additional information about the layer fields
        :param first_call: determine if the current function is the first
        :return: return a hierarchical view if dump, else print it
        """

        if dump:
            from scapy.themes import AnsiColorTheme
            ct = AnsiColorTheme()  # No color for dump output
        else:
            ct = conf.color_theme
        s = "%s%s %s %s \n" % (label_lvl,
                               ct.punct("###["),
                               ct.layer_name(self.name),
                               ct.punct("]###"))
        for f in self.fields_desc:
            if isinstance(f, ConditionalField) and not f._evalcond(self):
                continue
            if isinstance(f, Emph) or f in conf.emph:
                ncol = ct.emph_field_name
                vcol = ct.emph_field_value
            else:
                ncol = ct.field_name
                vcol = ct.field_value
            fvalue = self.getfieldval(f.name)
            if isinstance(fvalue, Packet) or (f.islist and f.holds_packets and isinstance(fvalue, list)):  # noqa: E501
                pad = max(0, 10 - len(f.name)) * " "
                s += "%s  \\%s%s\\\n" % (label_lvl + lvl, ncol(f.name), pad)
                fvalue_gen = SetGen(
                    fvalue,
                    _iterpacket=0
                )  # type: SetGen[Packet]
                for fvalue in fvalue_gen:
                    s += fvalue._show_or_dump(dump=dump, indent=indent, label_lvl=label_lvl + lvl + "   |", first_call=False)  # noqa: E501
            else:
                pad = max(0, 10 - len(f.name)) * " "
                begn = "%s  %s%s%s " % (label_lvl + lvl,
                                        ncol(f.name),
                                        pad,
                                        ct.punct("="),)
                reprval = f.i2repr(self, fvalue)
                if isinstance(reprval, str):
                    reprval = reprval.replace("\n", "\n" + " " * (len(label_lvl) +  # noqa: E501
                                                                  len(lvl) +
                                                                  len(f.name) +
                                                                  4))
                s += "%s%s\n" % (begn, vcol(reprval))
        if self.payload:
            s += self.payload._show_or_dump(  # type: ignore
                dump=dump,
                indent=indent,
                lvl=lvl + (" " * indent * self.show_indent),
                label_lvl=label_lvl,
                first_call=False
            )

        if first_call and not dump:
            print(s)
            return None
        else:
            return s

    def show(self, dump=False, indent=3, lvl="", label_lvl=""):
        # type: (bool, int, str, str) -> Optional[Any]
        """
        Prints or returns (when "dump" is true) a hierarchical view of the
        packet.

        :param dump: determine if it prints or returns the string value
        :param int indent: the size of indentation for each layer
        :param str lvl: additional information about the layer lvl
        :param str label_lvl: additional information about the layer fields
        :return: return a hierarchical view if dump, else print it
        """
        return self._show_or_dump(dump, indent, lvl, label_lvl)

    def show2(self, dump=False, indent=3, lvl="", label_lvl=""):
        # type: (bool, int, str, str) -> Optional[Any]
        """
        Prints or returns (when "dump" is true) a hierarchical view of an
        assembled version of the packet, so that automatic fields are
        calculated (checksums, etc.)

        :param dump: determine if it prints or returns the string value
        :param int indent: the size of indentation for each layer
        :param str lvl: additional information about the layer lvl
        :param str label_lvl: additional information about the layer fields
        :return: return a hierarchical view if dump, else print it
        """
        return self.__class__(raw(self)).show(dump, indent, lvl, label_lvl)

    def sprintf(self, fmt, relax=1):
        # type: (str, int) -> str
        """
        sprintf(format, [relax=1]) -> str

        Where format is a string that can include directives. A directive
        begins and ends by % and has the following format:
        ``%[fmt[r],][cls[:nb].]field%``

        :param fmt: is a classic printf directive, "r" can be appended for raw
          substitution:
          (ex: IP.flags=0x18 instead of SA), nb is the number of the layer
          (ex: for IP/IP packets, IP:2.src is the src of the upper IP layer).
          Special case : "%.time%" is the creation time.
          Ex::

            p.sprintf(
              "%.time% %-15s,IP.src% -> %-15s,IP.dst% %IP.chksum% "
              "%03xr,IP.proto% %r,TCP.flags%"
            )

          Moreover, the format string can include conditional statements. A
          conditional statement looks like : {layer:string} where layer is a
          layer name, and string is the string to insert in place of the
          condition if it is true, i.e. if layer is present. If layer is
          preceded by a "!", the result is inverted. Conditions can be
          imbricated. A valid statement can be::

            p.sprintf("This is a{TCP: TCP}{UDP: UDP}{ICMP:n ICMP} packet")
            p.sprintf("{IP:%IP.dst% {ICMP:%ICMP.type%}{TCP:%TCP.dport%}}")

          A side effect is that, to obtain "{" and "}" characters, you must use
          "%(" and "%)".
        """

        escape = {"%": "%",
                  "(": "{",
                  ")": "}"}

        # Evaluate conditions
        while "{" in fmt:
            i = fmt.rindex("{")
            j = fmt[i + 1:].index("}")
            cond = fmt[i + 1:i + j + 1]
            k = cond.find(":")
            if k < 0:
                raise Scapy_Exception("Bad condition in format string: [%s] (read sprintf doc!)" % cond)  # noqa: E501
            cond, format_ = cond[:k], cond[k + 1:]
            res = False
            if cond[0] == "!":
                res = True
                cond = cond[1:]
            if self.haslayer(cond):
                res = not res
            if not res:
                format_ = ""
            fmt = fmt[:i] + format_ + fmt[i + j + 2:]

        # Evaluate directives
        s = ""
        while "%" in fmt:
            i = fmt.index("%")
            s += fmt[:i]
            fmt = fmt[i + 1:]
            if fmt and fmt[0] in escape:
                s += escape[fmt[0]]
                fmt = fmt[1:]
                continue
            try:
                i = fmt.index("%")
                sfclsfld = fmt[:i]
                fclsfld = sfclsfld.split(",")
                if len(fclsfld) == 1:
                    f = "s"
                    clsfld = fclsfld[0]
                elif len(fclsfld) == 2:
                    f, clsfld = fclsfld
                else:
                    raise Scapy_Exception
                if "." in clsfld:
                    cls, fld = clsfld.split(".")
                else:
                    cls = self.__class__.__name__
                    fld = clsfld
                num = 1
                if ":" in cls:
                    cls, snum = cls.split(":")
                    num = int(snum)
                fmt = fmt[i + 1:]
            except Exception:
                raise Scapy_Exception("Bad format string [%%%s%s]" % (fmt[:25], fmt[25:] and "..."))  # noqa: E501
            else:
                if fld == "time":
                    val = time.strftime(
                        "%H:%M:%S.%%06i",
                        time.localtime(float(self.time))
                    ) % int((self.time - int(self.time)) * 1000000)
                elif cls == self.__class__.__name__ and hasattr(self, fld):
                    if num > 1:
                        val = self.payload.sprintf("%%%s,%s:%s.%s%%" % (f, cls, num - 1, fld), relax)  # noqa: E501
                        f = "s"
                    else:
                        try:
                            val = self.getfieldval(fld)
                        except AttributeError:
                            val = getattr(self, fld)
                        if f[-1] == "r":  # Raw field value
                            f = f[:-1]
                            if not f:
                                f = "s"
                        else:
                            if fld in self.fieldtype:
                                val = self.fieldtype[fld].i2repr(self, val)
                else:
                    val = self.payload.sprintf("%%%s%%" % sfclsfld, relax)
                    f = "s"
                s += ("%" + f) % val

        s += fmt
        return s

    def mysummary(self):
        # type: () -> str
        """DEV: can be overloaded to return a string that summarizes the layer.
           Only one mysummary() is used in a whole packet summary: the one of the upper layer,  # noqa: E501
           except if a mysummary() also returns (as a couple) a list of layers whose  # noqa: E501
           mysummary() must be called if they are present."""
        return ""

    def _do_summary(self):
        # type: () -> Tuple[int, str, List[Any]]
        found, s, needed = self.payload._do_summary()
        ret = ""
        if not found or self.__class__ in needed:
            ret = self.mysummary()
            if isinstance(ret, tuple):
                ret, n = ret
                needed += n
        if ret or needed:
            found = 1
        if not ret:
            ret = self.__class__.__name__ if self.show_summary else ""
        if self.__class__ in conf.emph:
            impf = []
            for f in self.fields_desc:
                if f in conf.emph:
                    impf.append("%s=%s" % (f.name, f.i2repr(self, self.getfieldval(f.name))))  # noqa: E501
            ret = "%s [%s]" % (ret, " ".join(impf))
        if ret and s:
            ret = "%s / %s" % (ret, s)
        else:
            ret = "%s%s" % (ret, s)
        return found, ret, needed

    def summary(self, intern=0):
        # type: (int) -> str
        """Prints a one line summary of a packet."""
        return self._do_summary()[1]

    def lastlayer(self, layer=None):
        # type: (Optional[Packet]) -> Packet
        """Returns the uppest layer of the packet"""
        return self.payload.lastlayer(self)

    def decode_payload_as(self, cls):
        # type: (Type[Packet]) -> None
        """Reassembles the payload and decode it using another packet class"""
        s = raw(self.payload)
        self.payload = cls(s, _internal=1, _underlayer=self)
        pp = self
        while pp.underlayer is not None:
            pp = pp.underlayer
        self.payload.dissection_done(pp)

    def command(self):
        # type: () -> str
        """
        Returns a string representing the command you have to type to
        obtain the same packet
        """
        f = []
        for fn, fv in six.iteritems(self.fields):
            fld = self.get_field(fn)
            if isinstance(fv, (list, dict, set)) and len(fv) == 0:
                continue
            if isinstance(fv, Packet):
                fv = fv.command()
            elif fld.islist and fld.holds_packets and isinstance(fv, list):
                fv = "[%s]" % ",".join(map(Packet.command, fv))
            elif isinstance(fld, FlagsField):
                fv = int(fv)
            elif callable(getattr(fv, 'command', None)):
                fv = fv.command()
            else:
                fv = repr(fv)
            f.append("%s=%s" % (fn, fv))
        c = "%s(%s)" % (self.__class__.__name__, ", ".join(f))
        pc = self.payload.command()
        if pc:
            c += "/" + pc
        return c @conf.commands.register
def bind_layers(lower,  # type: Type[Packet]
                upper,  # type: Type[Packet]
                __fval=None,  # type: Optional[Dict[str, int]]
                **fval  # type: Any
                ):
    # type: (...) -> None
    """Bind 2 layers on some specific fields' values.

    It makes the packet being built and dissected when the arguments
    are present.

    This function calls both bind_bottom_up and bind_top_down, with
    all passed arguments.

    Please have a look at their docs:
     - help(bind_bottom_up)
     - help(bind_top_down)
     """
    if __fval is not None:
        fval.update(__fval)
    bind_top_down(lower, upper, **fval)
    bind_bottom_up(lower, upper, **fval) def bind_bottom_up(lower,  # type: Type[Packet]
                   upper,  # type: Type[Packet]
                   __fval=None,  # type: Optional[Any]
                   **fval  # type: Any
                   ):
    # type: (...) -> None
    r"""Bind 2 layers for dissection.
    The upper layer will be chosen for dissection on top of the lower layer, if
    ALL the passed arguments are validated. If multiple calls are made with
    the same layers, the last one will be used as default.

    ex:
        >>> bind_bottom_up(Ether, SNAP, type=0x1234)
        >>> Ether(b'\xff\xff\xff\xff\xff\xff\xd0P\x99V\xdd\xf9\x124\x00\x00\x00\x00\x00')  # noqa: E501
        <Ether  dst=ff:ff:ff:ff:ff:ff src=d0:50:99:56:dd:f9 type=0x1234 |<SNAP  OUI=0x0 code=0x0 |>>  # noqa: E501
    """
    if __fval is not None:
        fval.update(__fval)
    lower.payload_guess = lower.payload_guess[:]
    lower.payload_guess.append((fval, upper)) class NoPayload(Packet):
    def __new__(cls, *args, **kargs):
        # type: (Type[Packet], *Any, **Any) -> Packet
        singl = cls.__dict__.get("__singl__")
        if singl is None:
            cls.__singl__ = singl = Packet.__new__(cls)
            Packet.__init__(singl)
        return singl

    def __init__(self, *args, **kargs):
        # type: (*Any, **Any) -> None
        pass

    def dissection_done(self, pkt):
        # type: (Packet) -> None
        pass

    def add_payload(self, payload):
        # type: (Union[Packet, bytes]) -> NoReturn
        raise Scapy_Exception("Can't add payload to NoPayload instance")

    def remove_payload(self):
        # type: () -> None
        pass

    def add_underlayer(self, underlayer):
        # type: (Any) -> None
        pass

    def remove_underlayer(self, other):
        # type: (Packet) -> None
        pass

    def copy(self):
        # type: () -> NoPayload
        return self

    def clear_cache(self):
        # type: () -> None
        pass

    def __repr__(self):
        # type: () -> str
        return ""

    def __str__(self):
        # type: () -> str
        return ""

    def __bytes__(self):
        # type: () -> bytes
        return b""

    def __nonzero__(self):
        # type: () -> bool
        return False
    __bool__ = __nonzero__

    def do_build(self):
        # type: () -> bytes
        return b""

    def build(self):
        # type: () -> bytes
        return b""

    def build_padding(self):
        # type: () -> bytes
        return b""

    def build_done(self, p):
        # type: (bytes) -> bytes
        return p

    def build_ps(self, internal=0):
        # type: (int) -> Tuple[bytes, List[Any]]
        return b"", []

    def getfieldval(self, attr):
        # type: (str) -> NoReturn
        raise AttributeError(attr)

    def getfield_and_val(self, attr):
        # type: (str) -> NoReturn
        raise AttributeError(attr)

    def setfieldval(self, attr, val):
        # type: (str, Any) -> NoReturn
        raise AttributeError(attr)

    def delfieldval(self, attr):
        # type: (str) -> NoReturn
        raise AttributeError(attr)

    def hide_defaults(self):
        # type: () -> None
        pass

    def __iter__(self):
        # type: () -> Iterator[Packet]
        return iter([])

    def __eq__(self, other):
        # type: (Any) -> bool
        if isinstance(other, NoPayload):
            return True
        return False

    def hashret(self):
        # type: () -> bytes
        return b""

    def answers(self, other):
        # type: (NoPayload) -> bool
        return isinstance(other, (NoPayload, conf.padding_layer))  # noqa: E501

    def haslayer(self, cls, _subclass=None):
        # type: (Union[Type[Packet], str], Optional[bool]) -> int
        return 0

    def getlayer(self,
                 cls,  # type: Union[int, Type[Packet], str]
                 nb=1,  # type: int
                 _track=None,  # type: Optional[List[int]]
                 _subclass=None,  # type: Optional[bool]
                 **flt  # type: Any
                 ):
        # type: (...) -> Optional[Packet]
        if _track is not None:
            _track.append(nb)
        return None

    def fragment(self, *args, **kargs):
        # type: (*Any, **Any) -> List[Packet]
        raise Scapy_Exception("cannot fragment this packet")

    def show(self, dump=False, indent=3, lvl="", label_lvl=""):
        # type: (bool, int, str, str) -> None
        pass

    def sprintf(self, fmt, relax=1):
        # type: (str, int) -> str
        if relax:
            return "??"
        else:
            raise Scapy_Exception("Format not found [%s]" % fmt)

    def _do_summary(self):
        # type: () -> Tuple[int, str, List[Any]]
        return 0, "", []

    def layers(self):
        # type: () -> List[Type[Packet]]
        return []

    def lastlayer(self, layer=None):
        # type: (Optional[Packet]) -> Packet
        return layer or self

    def command(self):
        # type: () -> str
        return ""

    def route(self):
        # type: () -> Tuple[None, None, None]
        return (None, None, None) class RandShort(RandNum):
    def __init__(self):
        # type: () -> None
        RandNum.__init__(self, 0, 2**16 - 1) class RandInt(RandNum):
    def __init__(self):
        # type: () -> None
        RandNum.__init__(self, 0, 2**32 - 1) class RandBin(RandString):
    def __init__(self, size=None):
        # type: (Optional[Union[int, RandNum]]) -> None
        super(RandBin, self).__init__(
            size=size,
            chars=b"".join(chb(c) for c in range(256))
        )

    def _command_args(self):
        # type: () -> str
        if not isinstance(self.size, VolatileValue):
            return "size=%r" % self.size

        if isinstance(self.size, RandNumExpo) and \
                self.size.lambd == 0.01 and self.size.base == 0:
            # Default size for RandString, skip
            return ""
        return "size=%r" % self.size.command() class RandNum(_RandNumeral[int]):
    """Instances evaluate to random integers in selected range"""
    min = 0
    max = 0

    def __init__(self, min, max):
        # type: (int, int) -> None
        self.min = min
        self.max = max

    def _command_args(self):
        # type: () -> str
        if self.__class__.__name__ == 'RandNum':
            return "min=%r, max=%r" % (self.min, self.max)
        return super(RandNum, self)._command_args()

    def _fix(self):
        # type: () -> int
        return random.randrange(self.min, self.max + 1)

    def __lshift__(self, other):
        # type: (int) -> int
        return self._fix() << other

    def __rshift__(self, other):
        # type: (int) -> int
        return self._fix() >> other

    def __and__(self, other):
        # type: (int) -> int
        return self._fix() & other

    def __rand__(self, other):
        # type: (int) -> int
        return other & self._fix()

    def __or__(self, other):
        # type: (int) -> int
        return self._fix() | other

    def __ror__(self, other):
        # type: (int) -> int
        return other | self._fix() class VolatileValue(Generic[_T]):
    def __repr__(self):
        # type: () -> str
        return "<%s>" % self.__class__.__name__

    def _command_args(self):
        # type: () -> str
        return ''

    def command(self):
        # type: () -> str
        return "%s(%s)" % (self.__class__.__name__, self._command_args())

    def __eq__(self, other):
        # type: (Any) -> bool
        x = self._fix()
        y = other._fix() if isinstance(other, VolatileValue) else other
        if not isinstance(x, type(y)):
            return False
        return bool(x == y)

    def __ne__(self, other):
        # type: (Any) -> bool
        # Python 2.7 compat
        return not self == other

    __hash__ = None  # type: ignore

    def __getattr__(self, attr):
        # type: (str) -> Any
        if attr in ["__setstate__", "__getstate__"]:
            raise AttributeError(attr)
        return getattr(self._fix(), attr)

    def __str__(self):
        # type: () -> str
        return str(self._fix())

    def __bytes__(self):
        # type: () -> bytes
        return bytes_encode(self._fix())

    def __len__(self):
        # type: () -> int
        # Does not work for some types (int?)
        return len(self._fix())  # type: ignore

    def copy(self):
        # type: () -> Any
        return copy.copy(self)

    def _fix(self):
        # type: () -> _T
        return cast(_T, None) @conf.commands.register
def sr(x,  # type: _PacketIterable
       promisc=None,  # type: Optional[bool]
       filter=None,  # type: Optional[str]
       iface=None,  # type: Optional[_GlobInterfaceType]
       nofilter=0,  # type: int
       *args,  # type: Any
       **kargs  # type: Any
       ):
    # type: (...) -> Tuple[SndRcvList, PacketList]
    """
    Send and receive packets at layer 3
    """
    s = conf.L3socket(promisc=promisc, filter=filter,
                      iface=iface, nofilter=nofilter)
    result = sndrcv(s, x, *args, **kargs)
    s.close()
    return result @conf.commands.register
def sr1(x,  # type: _PacketIterable
        promisc=None,  # type: Optional[bool]
        filter=None,  # type: Optional[str]
        iface=None,  # type: Optional[_GlobInterfaceType]
        nofilter=0,  # type: int
        *args,  # type: Any
        **kargs  # type: Any
        ):
    # type: (...) -> Optional[Packet]
    """
    Send packets at layer 3 and return only the first answer
    """
    iface = _interface_selection(iface, x)
    s = conf.L3socket(promisc=promisc, filter=filter,
                      nofilter=nofilter, iface=iface)
    ans, _ = sndrcv(s, x, *args, **kargs)
    s.close()
    if len(ans) > 0:
        return cast(Packet, ans[0][1])
    return None class _PacketList(Generic[_Inner]):
    __slots__ = ["stats", "res", "listname"]

    def __init__(self,
                 res=None,  # type: Optional[Union[_PacketList[_Inner], List[_Inner]]]  # noqa: E501
                 name="PacketList",  # type: str
                 stats=None  # type: Optional[List[Type[Packet]]]
                 ):
        # type: (...) -> None
        """create a packet list from a list of packets
           res: the list of packets
           stats: a list of classes that will appear in the stats (defaults to [TCP,UDP,ICMP])"""  # noqa: E501
        if stats is None:
            stats = conf.stats_classic_protocols
        self.stats = stats
        if res is None:
            self.res = []  # type: List[_Inner]
        elif isinstance(res, _PacketList):
            self.res = res.res
        else:
            self.res = res
        self.listname = name

    def __len__(self):
        # type: () -> int
        return len(self.res)

    def _elt2pkt(self, elt):
        # type: (_Inner) -> Packet
        return elt  # type: ignore

    def _elt2sum(self, elt):
        # type: (_Inner) -> str
        return elt.summary()  # type: ignore

    def _elt2show(self, elt):
        # type: (_Inner) -> str
        return self._elt2sum(elt)

    def __repr__(self):
        # type: () -> str
        stats = {x: 0 for x in self.stats}
        other = 0
        for r in self.res:
            f = 0
            for p in stats:
                if self._elt2pkt(r).haslayer(p):
                    stats[p] += 1
                    f = 1
                    break
            if not f:
                other += 1
        s = ""
        ct = conf.color_theme
        for p in self.stats:
            s += " %s%s%s" % (ct.packetlist_proto(p._name),
                              ct.punct(":"),
                              ct.packetlist_value(stats[p]))
        s += " %s%s%s" % (ct.packetlist_proto("Other"),
                          ct.punct(":"),
                          ct.packetlist_value(other))
        return "%s%s%s%s%s" % (ct.punct("<"),
                               ct.packetlist_name(self.listname),
                               ct.punct(":"),
                               s,
                               ct.punct(">"))

    def __getstate__(self):
        # type: () -> Dict[str, Any]
        """
        Creates a basic representation of the instance, used in
        conjunction with __setstate__() e.g. by pickle

        :returns: dict representing this instance
        """
        state = {
            'res': self.res,
            'stats': self.stats,
            'listname': self.listname
        }
        return state

    def __setstate__(self, state):
        # type: (Dict[str, Any]) -> None
        """
        Sets instance attributes to values given by state, used in
        conjunction with __getstate__() e.g. by pickle

        :param state: dict representing this instance
        """
        self.res = state['res']
        self.stats = state['stats']
        self.listname = state['listname']

    def __iter__(self):
        # type: () -> Iterator[_Inner]
        return self.res.__iter__()

    def __getattr__(self, attr):
        # type: (str) -> Any
        return getattr(self.res, attr)

    def __getitem__(self, item):
        # type: (Any) -> Any
        if issubtype(item, BasePacket):
            return self.__class__([x for x in self.res if item in self._elt2pkt(x)],  # noqa: E501
                                  name="%s from %s" % (item.__name__, self.listname))  # noqa: E501
        if isinstance(item, slice):
            return self.__class__(self.res.__getitem__(item),
                                  name="mod %s" % self.listname)
        return self.res.__getitem__(item)

    _T = TypeVar('_T', 'SndRcvList', 'PacketList')

    # Hinting hack: type self
    def __add__(self,  # type: _PacketList._T  # type: ignore
                other  # type: _PacketList._T
                ):
        # type: (...) -> _PacketList._T
        return self.__class__(
            self.res + other.res,
            name="%s+%s" % (
                self.listname,
                other.listname
            )
        )

    def summary(self,
                prn=None,  # type: Optional[Callable[..., Any]]
                lfilter=None  # type: Optional[Callable[..., bool]]
                ):
        # type: (...) -> None
        """prints a summary of each packet

        :param prn: function to apply to each packet instead of
                    lambda x:x.summary()
        :param lfilter: truth function to apply to each packet to decide
                        whether it will be displayed
        """
        # Python 2 backward compatibility
        if prn is not None:
            prn = lambda_tuple_converter(prn)
        if lfilter is not None:
            lfilter = lambda_tuple_converter(lfilter)

        for r in self.res:
            if lfilter is not None:
                if not lfilter(*r):
                    continue
            if prn is None:
                print(self._elt2sum(r))
            else:
                print(prn(*r))

    def nsummary(self,
                 prn=None,  # type: Optional[Callable[..., Any]]
                 lfilter=None  # type: Optional[Callable[..., bool]]
                 ):
        # type: (...) -> None
        """prints a summary of each packet with the packet's number

        :param prn: function to apply to each packet instead of
                    lambda x:x.summary()
        :param lfilter: truth function to apply to each packet to decide
                        whether it will be displayed
        """
        # Python 2 backward compatibility
        if prn is not None:
            prn = lambda_tuple_converter(prn)
        if lfilter is not None:
            lfilter = lambda_tuple_converter(lfilter)

        for i, res in enumerate(self.res):
            if lfilter is not None:
                if not lfilter(*res):
                    continue
            print(conf.color_theme.id(i, fmt="%04i"), end=' ')
            if prn is None:
                print(self._elt2sum(res))
            else:
                print(prn(*res))

    def show(self, *args, **kargs):
        # type: (*Any, **Any) -> None
        """Best way to display the packet list. Defaults to nsummary() method"""  # noqa: E501
        return self.nsummary(*args, **kargs)

    def filter(self, func):
        # type: (Callable[..., bool]) -> _PacketList[_Inner]
        """Returns a packet list filtered by a truth function. This truth
        function has to take a packet as the only argument and return
        a boolean value.
        """
        # Python 2 backward compatibility
        func = lambda_tuple_converter(func)

        return self.__class__([x for x in self.res if func(*x)],
                              name="filtered %s" % self.listname)

    def make_table(self, *args, **kargs):
        # type: (Any, Any) -> Optional[str]
        """Prints a table using a function that returns for each packet its head column value, head row value and displayed value  # noqa: E501
        ex: p.make_table(lambda x:(x[IP].dst, x[TCP].dport, x[TCP].sprintf("%flags%")) """  # noqa: E501
        return make_table(self.res, *args, **kargs)

    def make_lined_table(self, *args, **kargs):
        # type: (Any, Any) -> Optional[str]
        """Same as make_table, but print a table with lines"""
        return make_lined_table(self.res, *args, **kargs)

    def make_tex_table(self, *args, **kargs):
        # type: (Any, Any) -> Optional[str]
        """Same as make_table, but print a table with LaTeX syntax"""
        return make_tex_table(self.res, *args, **kargs)

    def plot(self,
             f,  # type: Callable[..., Any]
             lfilter=None,  # type: Optional[Callable[..., bool]]
             plot_xy=False,  # type: bool
             **kargs  # type: Any
             ):
        # type: (...) -> Line2D
        """Applies a function to each packet to get a value that will be plotted
        with matplotlib. A list of matplotlib.lines.Line2D is returned.

        lfilter: a truth function that decides whether a packet must be plotted
        """

        # Python 2 backward compatibility
        f = lambda_tuple_converter(f)
        if lfilter is not None:
            lfilter = lambda_tuple_converter(lfilter)

        # Get the list of packets
        if lfilter is None:
            lst_pkts = [f(*e) for e in self.res]
        else:
            lst_pkts = [f(*e) for e in self.res if lfilter(*e)]

        # Mimic the default gnuplot output
        if kargs == {}:
            kargs = MATPLOTLIB_DEFAULT_PLOT_KARGS
        if plot_xy:
            lines = plt.plot(*zip(*lst_pkts), **kargs)
        else:
            lines = plt.plot(lst_pkts, **kargs)

        # Call show() if matplotlib is not inlined
        if not MATPLOTLIB_INLINED:
            plt.show()

        return lines

    def diffplot(self,
                 f,  # type: Callable[..., Any]
                 delay=1,  # type: int
                 lfilter=None,  # type: Optional[Callable[..., bool]]
                 **kargs  # type: Any
                 ):
        # type: (...) -> Line2D
        """diffplot(f, delay=1, lfilter=None)
        Applies a function to couples (l[i],l[i+delay])

        A list of matplotlib.lines.Line2D is returned.
        """

        # Get the list of packets
        if lfilter is None:
            lst_pkts = [f(self.res[i], self.res[i + 1])
                        for i in range(len(self.res) - delay)]
        else:
            lst_pkts = [f(self.res[i], self.res[i + 1])
                        for i in range(len(self.res) - delay)
                        if lfilter(self.res[i])]

        # Mimic the default gnuplot output
        if kargs == {}:
            kargs = MATPLOTLIB_DEFAULT_PLOT_KARGS
        lines = plt.plot(lst_pkts, **kargs)

        # Call show() if matplotlib is not inlined
        if not MATPLOTLIB_INLINED:
            plt.show()

        return lines

    def multiplot(self,
                  f,  # type: Callable[..., Any]
                  lfilter=None,  # type: Optional[Callable[..., Any]]
                  plot_xy=False,  # type: bool
                  **kargs  # type: Any
                  ):
        # type: (...) -> Line2D
        """Uses a function that returns a label and a value for this label, then
        plots all the values label by label.

        A list of matplotlib.lines.Line2D is returned.
        """

        # Python 2 backward compatibility
        f = lambda_tuple_converter(f)
        if lfilter is not None:
            lfilter = lambda_tuple_converter(lfilter)

        # Get the list of packets
        if lfilter is None:
            lst_pkts = (f(*e) for e in self.res)
        else:
            lst_pkts = (f(*e) for e in self.res if lfilter(*e))

        # Apply the function f to the packets
        d = {}  # type: Dict[str, List[float]]
        for k, v in lst_pkts:
            d.setdefault(k, []).append(v)

        # Mimic the default gnuplot output
        if not kargs:
            kargs = MATPLOTLIB_DEFAULT_PLOT_KARGS

        if plot_xy:
            lines = [plt.plot(*zip(*pl), **dict(kargs, label=k))
                     for k, pl in six.iteritems(d)]
        else:
            lines = [plt.plot(pl, **dict(kargs, label=k))
                     for k, pl in six.iteritems(d)]
        plt.legend(loc="center right", bbox_to_anchor=(1.5, 0.5))

        # Call show() if matplotlib is not inlined
        if not MATPLOTLIB_INLINED:
            plt.show()

        return lines

    def rawhexdump(self):
        # type: () -> None
        """Prints an hexadecimal dump of each packet in the list"""
        for p in self:
            hexdump(self._elt2pkt(p))

    def hexraw(self, lfilter=None):
        # type: (Optional[Callable[..., bool]]) -> None
        """Same as nsummary(), except that if a packet has a Raw layer, it will be hexdumped  # noqa: E501
        lfilter: a truth function that decides whether a packet must be displayed"""  # noqa: E501
        for i, res in enumerate(self.res):
            p = self._elt2pkt(res)
            if lfilter is not None and not lfilter(p):
                continue
            print("%s %s %s" % (conf.color_theme.id(i, fmt="%04i"),
                                p.sprintf("%.time%"),
                                self._elt2sum(res)))
            if p.haslayer(conf.raw_layer):
                hexdump(p.getlayer(conf.raw_layer).load)  # type: ignore

    def hexdump(self, lfilter=None):
        # type: (Optional[Callable[..., bool]]) -> None
        """Same as nsummary(), except that packets are also hexdumped
        lfilter: a truth function that decides whether a packet must be displayed"""  # noqa: E501
        for i, res in enumerate(self.res):
            p = self._elt2pkt(res)
            if lfilter is not None and not lfilter(p):
                continue
            print("%s %s %s" % (conf.color_theme.id(i, fmt="%04i"),
                                p.sprintf("%.time%"),
                                self._elt2sum(res)))
            hexdump(p)

    def padding(self, lfilter=None):
        # type: (Optional[Callable[..., bool]]) -> None
        """Same as hexraw(), for Padding layer"""
        for i, res in enumerate(self.res):
            p = self._elt2pkt(res)
            if p.haslayer(conf.padding_layer):
                if lfilter is None or lfilter(p):
                    print("%s %s %s" % (conf.color_theme.id(i, fmt="%04i"),
                                        p.sprintf("%.time%"),
                                        self._elt2sum(res)))
                    hexdump(
                        p.getlayer(conf.padding_layer).load  # type: ignore
                    )

    def nzpadding(self, lfilter=None):
        # type: (Optional[Callable[..., bool]]) -> None
        """Same as padding() but only non null padding"""
        for i, res in enumerate(self.res):
            p = self._elt2pkt(res)
            if p.haslayer(conf.padding_layer):
                pad = p.getlayer(conf.padding_layer).load  # type: ignore
                if pad == pad[0] * len(pad):
                    continue
                if lfilter is None or lfilter(p):
                    print("%s %s %s" % (conf.color_theme.id(i, fmt="%04i"),
                                        p.sprintf("%.time%"),
                                        self._elt2sum(res)))
                    hexdump(
                        p.getlayer(conf.padding_layer).load  # type: ignore
                    )

    def conversations(self,
                      getsrcdst=None,  # type: Optional[Callable[[Packet], Tuple[Any, ...]]]  # noqa: E501
                      **kargs  # type: Any
                      ):
        # type: (...) -> Any
        """Graphes a conversations between sources and destinations and display it
        (using graphviz and imagemagick)

        :param getsrcdst: a function that takes an element of the list and
            returns the source, the destination and optionally
            a label. By default, returns the IP source and
            destination from IP and ARP layers
        :param type: output type (svg, ps, gif, jpg, etc.), passed to dot's
            "-T" option
        :param target: filename or redirect. Defaults pipe to Imagemagick's
            display program
        :param prog: which graphviz program to use
        """
        if getsrcdst is None:
            def _getsrcdst(pkt):
                # type: (Packet) -> Tuple[str, str]
                """Extract src and dst addresses"""
                if 'IP' in pkt:
                    return (pkt['IP'].src, pkt['IP'].dst)
                if 'IPv6' in pkt:
                    return (pkt['IPv6'].src, pkt['IPv6'].dst)
                if 'ARP' in pkt:
                    return (pkt['ARP'].psrc, pkt['ARP'].pdst)
                raise TypeError()
            getsrcdst = _getsrcdst
        conv = {}  # type: Dict[Tuple[Any, ...], Any]
        for p in self.res:
            p = self._elt2pkt(p)
            try:
                c = getsrcdst(p)
            except Exception:
                # No warning here: it's OK that getsrcdst() raises an
                # exception, since it might be, for example, a
                # function that expects a specific layer in each
                # packet. The try/except approach is faster and
                # considered more Pythonic than adding tests.
                continue
            if len(c) == 3:
                conv.setdefault(c[:2], set()).add(c[2])
            else:
                conv[c] = conv.get(c, 0) + 1
        gr = 'digraph "conv" {\n'
        for (s, d), l in six.iteritems(conv):
            gr += '\t "%s" -> "%s" [label="%s"]\n' % (
                s, d, ', '.join(str(x) for x in l) if isinstance(l, set) else l
            )
        gr += "}\n"
        return do_graph(gr, **kargs)

    def afterglow(self,
                  src=None,  # type: Optional[Callable[[_Inner], Any]]
                  event=None,  # type: Optional[Callable[[_Inner], Any]]
                  dst=None,  # type: Optional[Callable[[_Inner], Any]]
                  **kargs  # type: Any
                  ):
        # type: (...) -> Any
        """Experimental clone attempt of http://sourceforge.net/projects/afterglow
        each datum is reduced as src -> event -> dst and the data are graphed.
        by default we have IP.src -> IP.dport -> IP.dst"""
        if src is None:
            src = lambda *x: x[0]['IP'].src
        if event is None:
            event = lambda *x: x[0]['IP'].dport
        if dst is None:
            dst = lambda *x: x[0]['IP'].dst
        sl = {}  # type: Dict[Any, Tuple[Union[float, int], List[Any]]]
        el = {}  # type: Dict[Any, Tuple[Union[float, int], List[Any]]]
        dl = {}  # type: Dict[Any, int]
        for i in self.res:
            try:
                s, e, d = src(i), event(i), dst(i)
                if s in sl:
                    n, lst = sl[s]
                    n += 1
                    if e not in lst:
                        lst.append(e)
                    sl[s] = (n, lst)
                else:
                    sl[s] = (1, [e])
                if e in el:
                    n, lst = el[e]
                    n += 1
                    if d not in lst:
                        lst.append(d)
                    el[e] = (n, lst)
                else:
                    el[e] = (1, [d])
                dl[d] = dl.get(d, 0) + 1
            except Exception:
                continue

        def minmax(x):
            # type: (Any) -> Tuple[int, int]
            m, M = reduce(lambda a, b: (min(a[0], b[0]), max(a[1], b[1])),
                          ((a, a) for a in x))
            if m == M:
                m = 0
            if M == 0:
                M = 1
            return m, M

        mins, maxs = minmax(x for x, _ in six.itervalues(sl))
        mine, maxe = minmax(x for x, _ in six.itervalues(el))
        mind, maxd = minmax(six.itervalues(dl))

        gr = 'digraph "afterglow" {\n\tedge [len=2.5];\n'

        gr += "# src nodes\n"
        for s in sl:
            n, _ = sl[s]
            n = 1 + float(n - mins) / (maxs - mins)
            gr += '"src.%s" [label = "%s", shape=box, fillcolor="#FF0000", style=filled, fixedsize=1, height=%.2f,width=%.2f];\n' % (repr(s), repr(s), n, n)  # noqa: E501
        gr += "# event nodes\n"
        for e in el:
            n, _ = el[e]
            n = 1 + float(n - mine) / (maxe - mine)
            gr += '"evt.%s" [label = "%s", shape=circle, fillcolor="#00FFFF", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (repr(e), repr(e), n, n)  # noqa: E501
        for d in dl:
            n = dl[d]
            n = 1 + float(n - mind) / (maxd - mind)
            gr += '"dst.%s" [label = "%s", shape=triangle, fillcolor="#0000ff", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (repr(d), repr(d), n, n)  # noqa: E501

        gr += "###\n"
        for s in sl:
            n, lst1 = sl[s]
            for e in lst1:
                gr += ' "src.%s" -> "evt.%s";\n' % (repr(s), repr(e))
        for e in el:
            n, lst2 = el[e]
            for d in lst2:
                gr += ' "evt.%s" -> "dst.%s";\n' % (repr(e), repr(d))

        gr += "}"
        return do_graph(gr, **kargs)

    def canvas_dump(self, **kargs):
        # type: (Any) -> Any  # Using Any since pyx is imported later
        import pyx
        d = pyx.document.document()
        len_res = len(self.res)
        for i, res in enumerate(self.res):
            c = self._elt2pkt(res).canvas_dump(**kargs)
            cbb = c.bbox()
            c.text(cbb.left(), cbb.top() + 1, r"\font\cmssfont=cmss12\cmssfont{Frame %i/%i}" % (i, len_res), [pyx.text.size.LARGE])  # noqa: E501
            if conf.verb >= 2:
                os.write(1, b".")
            d.append(pyx.document.page(c, paperformat=pyx.document.paperformat.A4,  # noqa: E501
                                       margin=1 * pyx.unit.t_cm,
                                       fittosize=1))
        return d

    def sessions(
            self,
            session_extractor=None  # type: Optional[Callable[[Packet], str]]
    ):
        # type: (...) -> Dict[str, _PacketList[_Inner]]
        if session_extractor is None:
            def _session_extractor(p):
                # type: (Packet) -> str
                """Extract sessions from packets"""
                if 'Ether' in p:
                    if 'IP' in p or 'IPv6' in p:
                        ip_src_fmt = "{IP:%IP.src%}{IPv6:%IPv6.src%}"
                        ip_dst_fmt = "{IP:%IP.dst%}{IPv6:%IPv6.dst%}"
                        addr_fmt = (ip_src_fmt, ip_dst_fmt)
                        if 'TCP' in p:
                            fmt = "TCP {}:%r,TCP.sport% > {}:%r,TCP.dport%"
                        elif 'UDP' in p:
                            fmt = "UDP {}:%r,UDP.sport% > {}:%r,UDP.dport%"
                        elif 'ICMP' in p:
                            fmt = "ICMP {} > {} type=%r,ICMP.type% code=%r," \
                                  "ICMP.code% id=%ICMP.id%"
                        elif 'ICMPv6' in p:
                            fmt = "ICMPv6 {} > {} type=%r,ICMPv6.type% " \
                                  "code=%r,ICMPv6.code%"
                        elif 'IPv6' in p:
                            fmt = "IPv6 {} > {} nh=%IPv6.nh%"
                        else:
                            fmt = "IP {} > {} proto=%IP.proto%"
                        return p.sprintf(fmt.format(*addr_fmt))
                    elif 'ARP' in p:
                        return p.sprintf("ARP %ARP.psrc% > %ARP.pdst%")
                    else:
                        return p.sprintf("Ethernet type=%04xr,Ether.type%")
                return "Other"
            session_extractor = _session_extractor
        sessions = defaultdict(self.__class__)  # type: DefaultDict[str, _PacketList[_Inner]]  # noqa: E501
        for p in self.res:
            sess = session_extractor(
                self._elt2pkt(p)
            )
            sessions[sess].append(p)
        return dict(sessions)

    def replace(self, *args, **kargs):
        # type: (Any, Any) -> PacketList
        """
        lst.replace(<field>,[<oldvalue>,]<newvalue>)
        lst.replace( (fld,[ov],nv),(fld,[ov,]nv),...)
          if ov is None, all values are replaced
        ex:
          lst.replace( IP.src, "192.168.1.1", "10.0.0.1" )
          lst.replace( IP.ttl, 64 )
          lst.replace( (IP.ttl, 64), (TCP.sport, 666, 777), )
        """
        delete_checksums = kargs.get("delete_checksums", False)
        x = PacketList(name="Replaced %s" % self.listname)
        if not isinstance(args[0], tuple):
            args = (args,)
        for _p in self.res:
            p = self._elt2pkt(_p)
            copied = False
            for scheme in args:
                fld = scheme[0]
                old = scheme[1]  # not used if len(scheme) == 2
                new = scheme[-1]
                for o in fld.owners:
                    if o in p:
                        if len(scheme) == 2 or p[o].getfieldval(fld.name) == old:  # noqa: E501
                            if not copied:
                                p = p.copy()
                                if delete_checksums:
                                    p.delete_checksums()
                                copied = True
                            setattr(p[o], fld.name, new)
            x.append(p)
        return x

    def getlayer(self, cls,  # type: Packet
                 nb=None,  # type: Optional[int]
                 flt=None,  # type: Optional[Dict[str, Any]]
                 name=None,  # type: Optional[str]
                 stats=None  # type: Optional[List[Type[Packet]]]
                 ):
        # type: (...) -> PacketList
        """Returns the packet list from a given layer.

        See ``Packet.getlayer`` for more info.

        :param cls: search for a layer that is an instance of ``cls``
        :type cls: Type[scapy.packet.Packet]

        :param nb: return the nb^th layer that is an instance of ``cls``
        :type nb: Optional[int]

        :param flt: filter parameters for ``Packet.getlayer``
        :type flt: Optional[Dict[str, Any]]

        :param name: optional name for the new PacketList
        :type name: Optional[str]

        :param stats: optional list of protocols to give stats on; if not
                      specified, inherits from this PacketList.
        :type stats: Optional[List[Type[scapy.packet.Packet]]]
        :rtype: scapy.plist.PacketList
        """
        if name is None:
            name = "{} layer {}".format(self.listname, cls.__name__)
        if stats is None:
            stats = self.stats

        getlayer_arg = {}  # type: Dict[str, Any]
        if flt is not None:
            getlayer_arg.update(flt)
        getlayer_arg['cls'] = cls
        if nb is not None:
            getlayer_arg['nb'] = nb

        # Only return non-None getlayer results
        return PacketList([
            pc for pc in (
                self._elt2pkt(p).getlayer(**getlayer_arg) for p in self.res
            ) if pc is not None],
            name, stats
        ) class PacketList(_PacketList[Packet],
                 BasePacketList[Packet],
                 _CanvasDumpExtended):
    def sr(self, multi=False, lookahead=None):
        # type: (bool, Optional[int]) -> Tuple[SndRcvList, PacketList]
        """
        Matches packets in the list

        :param multi: True if a packet can have multiple answers
        :param lookahead: Maximum number of packets between packet and answer.
                          If 0 or None, full remaining list is
                          scanned for answers
        :return: ( (matched couples), (unmatched packets) )
        """
        remain = self.res[:]
        sr = []  # type: List[QueryAnswer]
        i = 0
        if lookahead is None or lookahead == 0:
            lookahead = len(remain)
        while i < len(remain):
            s = remain[i]
            j = i
            while j < min(lookahead + i, len(remain) - 1):
                j += 1
                r = remain[j]
                if r.answers(s):
                    sr.append(QueryAnswer(s, r))
                    if multi:
                        remain[i]._answered = 1
                        remain[j]._answered = 2
                        continue
                    del(remain[j])
                    del(remain[i])
                    i -= 1
                    break
            i += 1
        if multi:
            remain = [x for x in remain if not hasattr(x, "_answered")]
        return SndRcvList(sr), PacketList(remain) class SndRcvList(_PacketList[QueryAnswer],
                 BasePacketList[QueryAnswer],
                 _CanvasDumpExtended):
    __slots__ = []  # type: List[str]

    def __init__(self,
                 res=None,  # type: Optional[Union[_PacketList[QueryAnswer], List[QueryAnswer]]]  # noqa: E501
                 name="Results",  # type: str
                 stats=None  # type: Optional[List[Type[Packet]]]
                 ):
        # type: (...) -> None
        super(SndRcvList, self).__init__(res, name, stats)

    def _elt2pkt(self, elt):
        # type: (QueryAnswer) -> Packet
        return elt[1]

    def _elt2sum(self, elt):
        # type: (QueryAnswer) -> str
        return "%s ==> %s" % (elt[0].summary(), elt[1].summary()) class Automaton:
    states = {}             # type: Dict[str, _StateWrapper]
    state = None            # type: ATMT.NewStateRequested
    recv_conditions = {}    # type: Dict[str, List[_StateWrapper]]
    conditions = {}         # type: Dict[str, List[_StateWrapper]]
    ioevents = {}           # type: Dict[str, List[_StateWrapper]]
    timeout = {}            # type: Dict[str, List[Tuple[int, _StateWrapper]]] # noqa: E501
    actions = {}            # type: Dict[str, List[_StateWrapper]]
    initial_states = []     # type: List[_StateWrapper]
    stop_states = []        # type: List[_StateWrapper]
    ionames = []            # type: List[str]
    iosupersockets = []     # type: List[SuperSocket]

    # Internals
    def __init__(self, *args, **kargs):
        # type: (Any, Any) -> None
        external_fd = kargs.pop("external_fd", {})
        self.send_sock_class = kargs.pop("ll", conf.L3socket)
        self.recv_sock_class = kargs.pop("recvsock", conf.L2listen)
        self.is_atmt_socket = kargs.pop("is_atmt_socket", False)
        self.started = threading.Lock()
        self.threadid = None                # type: Optional[int]
        self.breakpointed = None
        self.breakpoints = set()            # type: Set[_StateWrapper]
        self.interception_points = set()    # type: Set[_StateWrapper]
        self.intercepted_packet = None      # type: Union[None, Packet]
        self.debug_level = 0
        self.init_args = args
        self.init_kargs = kargs
        self.io = type.__new__(type, "IOnamespace", (), {})
        self.oi = type.__new__(type, "IOnamespace", (), {})
        self.cmdin = ObjectPipe[Message]("cmdin")
        self.cmdout = ObjectPipe[Message]("cmdout")
        self.ioin = {}
        self.ioout = {}
        self.packets = PacketList()                 # type: PacketList
        for n in self.__class__.ionames:
            extfd = external_fd.get(n)
            if not isinstance(extfd, tuple):
                extfd = (extfd, extfd)
            ioin, ioout = extfd
            if ioin is None:
                ioin = ObjectPipe("ioin")
            else:
                ioin = self._IO_fdwrapper(ioin, None)
            if ioout is None:
                ioout = ObjectPipe("ioout")
            else:
                ioout = self._IO_fdwrapper(None, ioout)

            self.ioin[n] = ioin
            self.ioout[n] = ioout
            ioin.ioname = n
            ioout.ioname = n
            setattr(self.io, n, self._IO_mixer(ioout, ioin))
            setattr(self.oi, n, self._IO_mixer(ioin, ioout))

        for stname in self.states:
            setattr(self, stname,
                    _instance_state(getattr(self, stname)))

        self.start()

    def parse_args(self, debug=0, store=1, **kargs):
        # type: (int, int, Any) -> None
        self.debug_level = debug
        if debug:
            conf.logLevel = logging.DEBUG
        self.socket_kargs = kargs
        self.store_packets = store

    def master_filter(self, pkt):
        # type: (Packet) -> bool
        return True

    def my_send(self, pkt):
        # type: (Packet) -> None
        self.send_sock.send(pkt)

    # Utility classes and exceptions
    class _IO_fdwrapper:
        def __init__(self,
                     rd,  # type: Union[int, ObjectPipe[bytes], None]
                     wr  # type: Union[int, ObjectPipe[bytes], None]
                     ):
            # type: (...) -> None
            if rd is not None and not isinstance(rd, (int, ObjectPipe)):
                rd = rd.fileno()  # type: ignore
            if wr is not None and not isinstance(wr, (int, ObjectPipe)):
                wr = wr.fileno()  # type: ignore
            self.rd = rd
            self.wr = wr

        def fileno(self):
            # type: () -> int
            if isinstance(self.rd, ObjectPipe):
                return self.rd.fileno()
            elif isinstance(self.rd, int):
                return self.rd
            return 0

        def read(self, n=65535):
            # type: (int) -> Optional[bytes]
            if isinstance(self.rd, ObjectPipe):
                return self.rd.recv(n)
            elif isinstance(self.rd, int):
                return os.read(self.rd, n)
            return None

        def write(self, msg):
            # type: (bytes) -> int
            if isinstance(self.wr, ObjectPipe):
                return self.wr.send(msg)
            elif isinstance(self.wr, int):
                return os.write(self.wr, msg)
            return 0

        def recv(self, n=65535):
            # type: (int) -> Optional[bytes]
            return self.read(n)

        def send(self, msg):
            # type: (bytes) -> int
            return self.write(msg)

    class _IO_mixer:
        def __init__(self,
                     rd,  # type: ObjectPipe[Any]
                     wr,  # type: ObjectPipe[Any]
                     ):
            # type: (...) -> None
            self.rd = rd
            self.wr = wr

        def fileno(self):
            # type: () -> Any
            if isinstance(self.rd, ObjectPipe):
                return self.rd.fileno()
            return self.rd

        def recv(self, n=None):
            # type: (Optional[int]) -> Any
            return self.rd.recv(n)

        def read(self, n=None):
            # type: (Optional[int]) -> Any
            return self.recv(n)

        def send(self, msg):
            # type: (str) -> int
            return self.wr.send(msg)

        def write(self, msg):
            # type: (str) -> int
            return self.send(msg)

    class AutomatonException(Exception):
        def __init__(self, msg, state=None, result=None):
            # type: (str, Optional[Message], Optional[str]) -> None
            Exception.__init__(self, msg)
            self.state = state
            self.result = result

    class AutomatonError(AutomatonException):
        pass

    class ErrorState(AutomatonException):
        pass

    class Stuck(AutomatonException):
        pass

    class AutomatonStopped(AutomatonException):
        pass

    class Breakpoint(AutomatonStopped):
        pass

    class Singlestep(AutomatonStopped):
        pass

    class InterceptionPoint(AutomatonStopped):
        def __init__(self, msg, state=None, result=None, packet=None):
            # type: (str, Optional[Message], Optional[str], Optional[str]) -> None  # noqa: E501
            Automaton.AutomatonStopped.__init__(self, msg, state=state, result=result)  # noqa: E501
            self.packet = packet

    class CommandMessage(AutomatonException):
        pass

    # Services
    def debug(self, lvl, msg):
        # type: (int, str) -> None
        if self.debug_level >= lvl:
            log_runtime.debug(msg)

    def send(self, pkt):
        # type: (Packet) -> None
        if self.state.state in self.interception_points:
            self.debug(3, "INTERCEPT: packet intercepted: %s" % pkt.summary())
            self.intercepted_packet = pkt
            self.cmdout.send(
                Message(type=_ATMT_Command.INTERCEPT,
                        state=self.state, pkt=pkt)
            )
            cmd = self.cmdin.recv()
            if not cmd:
                self.debug(3, "CANCELLED")
                return
            self.intercepted_packet = None
            if cmd.type == _ATMT_Command.REJECT:
                self.debug(3, "INTERCEPT: packet rejected")
                return
            elif cmd.type == _ATMT_Command.REPLACE:
                pkt = cmd.pkt
                self.debug(3, "INTERCEPT: packet replaced by: %s" % pkt.summary())  # noqa: E501
            elif cmd.type == _ATMT_Command.ACCEPT:
                self.debug(3, "INTERCEPT: packet accepted")
            else:
                raise self.AutomatonError("INTERCEPT: unknown verdict: %r" % cmd.type)  # noqa: E501
        self.my_send(pkt)
        self.debug(3, "SENT : %s" % pkt.summary())

        if self.store_packets:
            self.packets.append(pkt.copy())

    def __iter__(self):
        # type: () -> Automaton
        return self

    def __del__(self):
        # type: () -> None
        self.stop()

    def _run_condition(self, cond, *args, **kargs):
        # type: (_StateWrapper, Any, Any) -> None
        try:
            self.debug(5, "Trying %s [%s]" % (cond.atmt_type, cond.atmt_condname))  # noqa: E501
            cond(self, *args, **kargs)
        except ATMT.NewStateRequested as state_req:
            self.debug(2, "%s [%s] taken to state [%s]" % (cond.atmt_type, cond.atmt_condname, state_req.state))  # noqa: E501
            if cond.atmt_type == ATMT.RECV:
                if self.store_packets:
                    self.packets.append(args[0])
            for action in self.actions[cond.atmt_condname]:
                self.debug(2, "   + Running action [%s]" % action.__name__)
                action(self, *state_req.action_args, **state_req.action_kargs)
            raise
        except Exception as e:
            self.debug(2, "%s [%s] raised exception [%s]" % (cond.atmt_type, cond.atmt_condname, e))  # noqa: E501
            raise
        else:
            self.debug(2, "%s [%s] not taken" % (cond.atmt_type, cond.atmt_condname))  # noqa: E501

    def _do_start(self, *args, **kargs):
        # type: (Any, Any) -> None
        ready = threading.Event()
        _t = threading.Thread(
            target=self._do_control,
            args=(ready,) + (args),
            kwargs=kargs,
            name="scapy.automaton _do_start"
        )
        _t.daemon = True
        _t.start()
        ready.wait()

    def _do_control(self, ready, *args, **kargs):
        # type: (threading.Event, Any, Any) -> None
        with self.started:
            self.threadid = threading.current_thread().ident
            if self.threadid is None:
                self.threadid = 0

            # Update default parameters
            a = args + self.init_args[len(args):]
            k = self.init_kargs.copy()
            k.update(kargs)
            self.parse_args(*a, **k)

            # Start the automaton
            self.state = self.initial_states[0](self)
            self.send_sock = self.send_sock_class(**self.socket_kargs)
            self.listen_sock = self.recv_sock_class(**self.socket_kargs)
            self.packets = PacketList(name="session[%s]" % self.__class__.__name__)  # noqa: E501

            singlestep = True
            iterator = self._do_iter()
            self.debug(3, "Starting control thread [tid=%i]" % self.threadid)
            # Sync threads
            ready.set()
            try:
                while True:
                    c = self.cmdin.recv()
                    if c is None:
                        return None
                    self.debug(5, "Received command %s" % c.type)
                    if c.type == _ATMT_Command.RUN:
                        singlestep = False
                    elif c.type == _ATMT_Command.NEXT:
                        singlestep = True
                    elif c.type == _ATMT_Command.FREEZE:
                        continue
                    elif c.type == _ATMT_Command.STOP:
                        if self.stop_states:
                            # There is a stop state
                            self.state = self.stop_states[0](self)
                            iterator = self._do_iter()
                        else:
                            # Act as FORCESTOP
                            break
                    elif c.type == _ATMT_Command.FORCESTOP:
                        break
                    while True:
                        state = next(iterator)
                        if isinstance(state, self.CommandMessage):
                            break
                        elif isinstance(state, self.Breakpoint):
                            c = Message(type=_ATMT_Command.BREAKPOINT, state=state)  # noqa: E501
                            self.cmdout.send(c)
                            break
                        if singlestep:
                            c = Message(type=_ATMT_Command.SINGLESTEP, state=state)  # noqa: E501
                            self.cmdout.send(c)
                            break
            except (StopIteration, RuntimeError):
                c = Message(type=_ATMT_Command.END,
                            result=self.final_state_output)
                self.cmdout.send(c)
            except Exception as e:
                exc_info = sys.exc_info()
                self.debug(3, "Transferring exception from tid=%i:\n%s" % (self.threadid, "".join(traceback.format_exception(*exc_info))))  # noqa: E501
                m = Message(type=_ATMT_Command.EXCEPTION, exception=e, exc_info=exc_info)  # noqa: E501
                self.cmdout.send(m)
            self.debug(3, "Stopping control thread (tid=%i)" % self.threadid)
            self.threadid = None

    def _do_iter(self):
        # type: () -> Iterator[Union[Automaton.AutomatonException, Automaton.AutomatonStopped, ATMT.NewStateRequested, None]] # noqa: E501
        while True:
            try:
                self.debug(1, "## state=[%s]" % self.state.state)

                # Entering a new state. First, call new state function
                if self.state.state in self.breakpoints and self.state.state != self.breakpointed:  # noqa: E501
                    self.breakpointed = self.state.state
                    yield self.Breakpoint("breakpoint triggered on state %s" % self.state.state,  # noqa: E501
                                          state=self.state.state)
                self.breakpointed = None
                state_output = self.state.run()
                if self.state.error:
                    raise self.ErrorState("Reached %s: [%r]" % (self.state.state, state_output),  # noqa: E501
                                          result=state_output, state=self.state.state)  # noqa: E501
                if self.state.final:
                    self.final_state_output = state_output
                    return

                if state_output is None:
                    state_output = ()
                elif not isinstance(state_output, list):
                    state_output = state_output,

                # If there are commandMessage, we should skip immediate
                # conditions.
                if not select_objects([self.cmdin], 0):
                    # Then check immediate conditions
                    for cond in self.conditions[self.state.state]:
                        self._run_condition(cond, *state_output)

                    # If still there and no conditions left, we are stuck!
                    if (len(self.recv_conditions[self.state.state]) == 0 and
                        len(self.ioevents[self.state.state]) == 0 and
                            len(self.timeout[self.state.state]) == 1):
                        raise self.Stuck("stuck in [%s]" % self.state.state,
                                         state=self.state.state,
                                         result=state_output)

                # Finally listen and pay attention to timeouts
                expirations = iter(self.timeout[self.state.state])
                next_timeout, timeout_func = next(expirations)
                t0 = time.time()

                fds = [self.cmdin]
                if len(self.recv_conditions[self.state.state]) > 0:
                    fds.append(self.listen_sock)
                for ioev in self.ioevents[self.state.state]:
                    fds.append(self.ioin[ioev.atmt_ioname])
                while True:
                    t = time.time() - t0
                    if next_timeout is not None:
                        if next_timeout <= t:
                            self._run_condition(timeout_func, *state_output)
                            next_timeout, timeout_func = next(expirations)
                    if next_timeout is None:
                        remain = 0
                    else:
                        remain = next_timeout - t

                    self.debug(5, "Select on %r" % fds)
                    r = select_objects(fds, remain)
                    self.debug(5, "Selected %r" % r)
                    for fd in r:
                        self.debug(5, "Looking at %r" % fd)
                        if fd == self.cmdin:
                            yield self.CommandMessage("Received command message")  # noqa: E501
                        elif fd == self.listen_sock:
                            pkt = self.listen_sock.recv(MTU)
                            if pkt is not None:
                                if self.master_filter(pkt):
                                    self.debug(3, "RECVD: %s" % pkt.summary())  # noqa: E501
                                    for rcvcond in self.recv_conditions[self.state.state]:  # noqa: E501
                                        self._run_condition(rcvcond, pkt, *state_output)  # noqa: E501
                                else:
                                    self.debug(4, "FILTR: %s" % pkt.summary())  # noqa: E501
                        else:
                            self.debug(3, "IOEVENT on %s" % fd.ioname)
                            for ioevt in self.ioevents[self.state.state]:
                                if ioevt.atmt_ioname == fd.ioname:
                                    self._run_condition(ioevt, fd, *state_output)  # noqa: E501

            except ATMT.NewStateRequested as state_req:
                self.debug(2, "switching from [%s] to [%s]" % (self.state.state, state_req.state))  # noqa: E501
                self.state = state_req
                yield state_req

    def __repr__(self):
        # type: () -> str
        return "<Automaton %s [%s]>" % (
            self.__class__.__name__,
            ["HALTED", "RUNNING"][self.started.locked()]
        )

    # Public API
    def add_interception_points(self, *ipts):
        # type: (Any) -> None
        for ipt in ipts:
            if hasattr(ipt, "atmt_state"):
                ipt = ipt.atmt_state
            self.interception_points.add(ipt)

    def remove_interception_points(self, *ipts):
        # type: (Any) -> None
        for ipt in ipts:
            if hasattr(ipt, "atmt_state"):
                ipt = ipt.atmt_state
            self.interception_points.discard(ipt)

    def add_breakpoints(self, *bps):
        # type: (Any) -> None
        for bp in bps:
            if hasattr(bp, "atmt_state"):
                bp = bp.atmt_state
            self.breakpoints.add(bp)

    def remove_breakpoints(self, *bps):
        # type: (Any) -> None
        for bp in bps:
            if hasattr(bp, "atmt_state"):
                bp = bp.atmt_state
            self.breakpoints.discard(bp)

    def start(self, *args, **kargs):
        # type: (Any, Any) -> None
        if not self.started.locked():
            self._do_start(*args, **kargs)

    def run(self,
            resume=None,    # type: Optional[Message]
            wait=True       # type: Optional[bool]
            ):
        # type: (...) -> Any
        if resume is None:
            resume = Message(type=_ATMT_Command.RUN)
        self.cmdin.send(resume)
        if wait:
            try:
                c = self.cmdout.recv()
                if c is None:
                    return None
            except KeyboardInterrupt:
                self.cmdin.send(Message(type=_ATMT_Command.FREEZE))
                return None
            if c.type == _ATMT_Command.END:
                return c.result
            elif c.type == _ATMT_Command.INTERCEPT:
                raise self.InterceptionPoint("packet intercepted", state=c.state.state, packet=c.pkt)  # noqa: E501
            elif c.type == _ATMT_Command.SINGLESTEP:
                raise self.Singlestep("singlestep state=[%s]" % c.state.state, state=c.state.state)  # noqa: E501
            elif c.type == _ATMT_Command.BREAKPOINT:
                raise self.Breakpoint("breakpoint triggered on state [%s]" % c.state.state, state=c.state.state)  # noqa: E501
            elif c.type == _ATMT_Command.EXCEPTION:
                six.reraise(c.exc_info[0], c.exc_info[1], c.exc_info[2])
        return None

    def runbg(self, resume=None, wait=False):
        # type: (Optional[Message], Optional[bool]) -> None
        self.run(resume, wait)

    def next(self):
        # type: () -> Any
        return self.run(resume=Message(type=_ATMT_Command.NEXT))
    __next__ = next

    def _flush_inout(self):
        # type: () -> None
        with self.started:
            # Flush command pipes
            while True:
                r = select_objects([self.cmdin, self.cmdout], 0)
                if not r:
                    break
                for fd in r:
                    fd.recv()

    def stop(self, wait=True):
        # type: (bool) -> None
        self.cmdin.send(Message(type=_ATMT_Command.STOP))
        if wait:
            self._flush_inout()

    def forcestop(self, wait=True):
        # type: (bool) -> None
        self.cmdin.send(Message(type=_ATMT_Command.FORCESTOP))
        if wait:
            self._flush_inout()

    def restart(self, *args, **kargs):
        # type: (Any, Any) -> None
        self.stop()
        self.start(*args, **kargs)

    def accept_packet(self,
                      pkt=None,     # type: Optional[Packet]
                      wait=False    # type: Optional[bool]
                      ):
        # type: (...) -> Any
        rsm = Message()
        if pkt is None:
            rsm.type = _ATMT_Command.ACCEPT
        else:
            rsm.type = _ATMT_Command.REPLACE
            rsm.pkt = pkt
        return self.run(resume=rsm, wait=wait)

    def reject_packet(self,
                      wait=False    # type: Optional[bool]
                      ):
        # type: (...) -> Any
        rsm = Message(type=_ATMT_Command.REJECT)
        return self.run(resume=rsm, wait=wait) class ATMT:
    STATE = "State"
    ACTION = "Action"
    CONDITION = "Condition"
    RECV = "Receive condition"
    TIMEOUT = "Timeout condition"
    IOEVENT = "I/O event"

    class NewStateRequested(Exception):
        def __init__(self, state_func, automaton, *args, **kargs):
            # type: (Any, ATMT, Any, Any) -> None
            self.func = state_func
            self.state = state_func.atmt_state
            self.initial = state_func.atmt_initial
            self.error = state_func.atmt_error
            self.stop = state_func.atmt_stop
            self.final = state_func.atmt_final
            Exception.__init__(self, "Request state [%s]" % self.state)
            self.automaton = automaton
            self.args = args
            self.kargs = kargs
            self.action_parameters()  # init action parameters

        def action_parameters(self, *args, **kargs):
            # type: (Any, Any) -> ATMT.NewStateRequested
            self.action_args = args
            self.action_kargs = kargs
            return self

        def run(self):
            # type: () -> Any
            return self.func(self.automaton, *self.args, **self.kargs)

        def __repr__(self):
            # type: () -> str
            return "NewStateRequested(%s)" % self.state

    @staticmethod
    def state(initial=0,    # type: int
              final=0,      # type: int
              stop=0,       # type: int
              error=0       # type: int
              ):
        # type: (...) -> Callable[[DecoratorCallable], DecoratorCallable]
        def deco(f, initial=initial, final=final):
            # type: (_StateWrapper, int, int) -> _StateWrapper
            f.atmt_type = ATMT.STATE
            f.atmt_state = f.__name__
            f.atmt_initial = initial
            f.atmt_final = final
            f.atmt_stop = stop
            f.atmt_error = error

            def _state_wrapper(self, *args, **kargs):
                # type: (ATMT, Any, Any) -> ATMT.NewStateRequested
                return ATMT.NewStateRequested(f, self, *args, **kargs)

            state_wrapper = cast(_StateWrapper, _state_wrapper)
            state_wrapper.__name__ = "%s_wrapper" % f.__name__
            state_wrapper.atmt_type = ATMT.STATE
            state_wrapper.atmt_state = f.__name__
            state_wrapper.atmt_initial = initial
            state_wrapper.atmt_final = final
            state_wrapper.atmt_stop = stop
            state_wrapper.atmt_error = error
            state_wrapper.atmt_origfunc = f
            return state_wrapper
        return deco  # type: ignore

    @staticmethod
    def action(cond, prio=0):
        # type: (Any, int) -> Callable[[_StateWrapper, _StateWrapper], _StateWrapper]  # noqa: E501
        def deco(f, cond=cond):
            # type: (_StateWrapper, _StateWrapper) -> _StateWrapper
            if not hasattr(f, "atmt_type"):
                f.atmt_cond = {}
            f.atmt_type = ATMT.ACTION
            f.atmt_cond[cond.atmt_condname] = prio
            return f
        return deco

    @staticmethod
    def condition(state, prio=0):
        # type: (Any, int) -> Callable[[_StateWrapper, _StateWrapper], _StateWrapper]  # noqa: E501
        def deco(f, state=state):
            # type: (_StateWrapper, _StateWrapper) -> Any
            f.atmt_type = ATMT.CONDITION
            f.atmt_state = state.atmt_state
            f.atmt_condname = f.__name__
            f.atmt_prio = prio
            return f
        return deco

    @staticmethod
    def receive_condition(state, prio=0):
        # type: (_StateWrapper, int) -> Callable[[_StateWrapper, _StateWrapper], _StateWrapper]  # noqa: E501
        def deco(f, state=state):
            # type: (_StateWrapper, _StateWrapper) -> _StateWrapper
            f.atmt_type = ATMT.RECV
            f.atmt_state = state.atmt_state
            f.atmt_condname = f.__name__
            f.atmt_prio = prio
            return f
        return deco

    @staticmethod
    def ioevent(state,                  # type: _StateWrapper
                name,                   # type: str
                prio=0,                 # type: int
                as_supersocket=None     # type: Optional[str]
                ):
        # type: (...) -> Callable[[_StateWrapper, _StateWrapper], _StateWrapper]  # noqa: E501
        def deco(f, state=state):
            # type: (_StateWrapper, _StateWrapper) -> _StateWrapper
            f.atmt_type = ATMT.IOEVENT
            f.atmt_state = state.atmt_state
            f.atmt_condname = f.__name__
            f.atmt_ioname = name
            f.atmt_prio = prio
            f.atmt_as_supersocket = as_supersocket
            return f
        return deco

    @staticmethod
    def timeout(state, timeout):
        # type: (_StateWrapper, int) -> Callable[[_StateWrapper, _StateWrapper, int], _StateWrapper]  # noqa: E501
        def deco(f, state=state, timeout=timeout):
            # type: (_StateWrapper, _StateWrapper, int) -> _StateWrapper
            f.atmt_type = ATMT.TIMEOUT
            f.atmt_state = state.atmt_state
            f.atmt_timeout = timeout
            f.atmt_condname = f.__name__
            return f
        return deco
import time
import struct
import re
import random
import select
import socket
import scapy.as_resolvers
import scapy.modules.six as six
            import scapy.route  # noqa: F401
        import multiprocessing
        import vpython
            import geoip2.database
            import geoip2.errors
            import cartopy.crs as ccrs
    import scapy.layers.inet6
from collections import defaultdict
from scapy.utils import checksum, do_graph, incremental_label, \
    linehexdump, strxor, whois, colgen
from scapy.ansmachine import AnsweringMachine, AnsweringMachineUtils
from scapy.base_classes import Gen, Net
from scapy.data import ETH_P_IP, ETH_P_ALL, DLT_RAW, DLT_RAW_ALT, DLT_IPV4, \
    IP_PROTOS, TCP_SERVICES, UDP_SERVICES
from scapy.layers.l2 import Ether, Dot3, getmacbyip, CookedLinux, GRE, SNAP, \
    Loopback
from scapy.compat import raw, chb, orb, bytes_encode
from scapy.config import conf
from scapy.extlib import plt, MATPLOTLIB, MATPLOTLIB_INLINED, \
    MATPLOTLIB_DEFAULT_PLOT_KARGS
from scapy.fields import (
    BitEnumField,
    BitField,
    ByteEnumField,
    ByteField,
    ConditionalField,
    DestField,
    Emph,
    FieldLenField,
    FieldListField,
    FlagsField,
    IPField,
    IntField,
    MultiEnumField,
    MultipleTypeField,
    PacketListField,
    ShortEnumField,
    ShortField,
    SourceIPField,
    StrField,
    StrFixedLenField,
    StrLenField,
    XByteField,
    XShortField,
)
from scapy.packet import Packet, bind_layers, bind_bottom_up, NoPayload
from scapy.volatile import RandShort, RandInt, RandBin, RandNum, VolatileValue
from scapy.sendrecv import sr, sr1
from scapy.plist import _PacketList, PacketList, SndRcvList
from scapy.automaton import Automaton, ATMT
from scapy.error import log_runtime, warning
from scapy.pton_ntop import inet_pton
from scapy.modules.six.moves import range
        from matplotlib.collections import LineCollection
        from matplotlib import colors as mcolors
        from scapy.sessions import TCPSession
# Add timeskew_graph() method to PacketList
def _packetlist_timeskew_graph(self, ip, **kargs):
    """Tries to graph the timeskew between the timestamps and real time for a given ip"""  # noqa: E501

    # Filter TCP segments which source address is 'ip'
    tmp = (self._elt2pkt(x) for x in self.res)
    b = (x for x in tmp if IP in x and x[IP].src == ip and TCP in x)

    # Build a list of tuples (creation_time, replied_timestamp)
    c = []
    tsf = ICMPTimeStampField("", None)
    for p in b:
        opts = p.getlayer(TCP).options
        for o in opts:
            if o[0] == "Timestamp":
                c.append((p.time, tsf.any2i("", o[1][0])))

    # Stop if the list is empty
    if not c:
        warning("No timestamps found in packet list")
        return []

    # Prepare the data that will be plotted
    first_creation_time = c[0][0]
    first_replied_timestamp = c[0][1]

    def _wrap_data(ts_tuple, wrap_seconds=2000):
        """Wrap the list of tuples."""

        ct, rt = ts_tuple  # (creation_time, replied_timestamp)
        X = ct % wrap_seconds
        Y = ((ct - first_creation_time) - ((rt - first_replied_timestamp) / 1000.0))  # noqa: E501

        return X, Y

    data = [_wrap_data(e) for e in c]

    # Mimic the default gnuplot output
    if kargs == {}:
        kargs = MATPLOTLIB_DEFAULT_PLOT_KARGS
    lines = plt.plot(data, **kargs)

    # Call show() if matplotlib is not inlined
    if not MATPLOTLIB_INLINED:
        plt.show()

    return lines


_PacketList.timeskew_graph = _packetlist_timeskew_graph


# Create a new packet list
class TracerouteResult(SndRcvList):
    __slots__ = ["graphdef", "graphpadding", "graphASres", "padding", "hloc",
                 "nloc"]

    def __init__(self, res=None, name="Traceroute", stats=None):
        SndRcvList.__init__(self, res, name, stats)
        self.graphdef = None
        self.graphASres = None
        self.padding = 0
        self.hloc = None
        self.nloc = None

    def show(self):
        return self.make_table(lambda s, r: (s.sprintf("%IP.dst%:{TCP:tcp%ir,TCP.dport%}{UDP:udp%ir,UDP.dport%}{ICMP:ICMP}"),  # noqa: E501
                                             s.ttl,
                                             r.sprintf("%-15s,IP.src% {TCP:%TCP.flags%}{ICMP:%ir,ICMP.type%}")))  # noqa: E501

    def get_trace(self):
        trace = {}
        for s, r in self.res:
            if IP not in s:
                continue
            d = s[IP].dst
            if d not in trace:
                trace[d] = {}
            trace[d][s[IP].ttl] = r[IP].src, ICMP not in r
        for k in six.itervalues(trace):
            try:
                m = min(x for x, y in six.iteritems(k) if y[1])
            except ValueError:
                continue
            for li in list(k):  # use list(): k is modified in the loop
                if li > m:
                    del k[li]
        return trace

    def trace3D(self, join=True):
        """Give a 3D representation of the traceroute.
        right button: rotate the scene
        middle button: zoom
        shift-left button: move the scene
        left button on a ball: toggle IP displaying
        double-click button on a ball: scan ports 21,22,23,25,80 and 443 and display the result"""  # noqa: E501
        # When not ran from a notebook, vpython pooly closes itself
        # using os._exit once finished. We pack it into a Process
        p = multiprocessing.Process(target=self.trace3D_notebook)
        p.start()
        if join:
            p.join()

    def trace3D_notebook(self):
        """Same than trace3D, used when ran from Jupyter notebooks"""
        trace = self.get_trace()

        class IPsphere(vpython.sphere):
            def __init__(self, ip, **kargs):
                vpython.sphere.__init__(self, **kargs)
                self.ip = ip
                self.label = None
                self.setlabel(self.ip)
                self.last_clicked = None
                self.full = False
                self.savcolor = vpython.vec(*self.color.value)

            def fullinfos(self):
                self.full = True
                self.color = vpython.vec(1, 0, 0)

                a, b = sr(IP(dst=self.ip) / TCP(dport=[21, 22, 23, 25, 80, 443], flags="S"), timeout=2, verbose=0)  # noqa: E501