• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1## This file is part of Scapy
2## See http://www.secdev.org/projects/scapy for more informations
3## Copyright (C) Philippe Biondi <phil@secdev.org>
4## This program is published under a GPLv2 license
5
6"""
7Packet class. Binding mechanism. fuzz() method.
8"""
9
10from __future__ import absolute_import
11from __future__ import print_function
12import re
13import time,itertools
14import copy
15import subprocess
16
17from scapy.fields import StrField, ConditionalField, Emph, PacketListField, BitField, \
18    MultiEnumField, EnumField, FlagsField
19from scapy.config import conf
20from scapy.compat import *
21from scapy.base_classes import BasePacket, Gen, SetGen, Packet_metaclass
22from scapy.volatile import VolatileValue
23from scapy.utils import import_hexcap,tex_escape,colgen,get_temp_file, \
24    ContextManagerSubprocess
25from scapy.error import Scapy_Exception, log_runtime
26from scapy.consts import PYX
27import scapy.modules.six as six
28
29try:
30    import pyx
31except ImportError:
32    pass
33
34
35class RawVal:
36    def __init__(self, val=""):
37        self.val = val
38    def __str__(self):
39        return str(self.val)
40    def __bytes__(self):
41        return raw(self.val)
42    def __repr__(self):
43        return "<RawVal [%r]>" % self.val
44
45
46class Packet(six.with_metaclass(Packet_metaclass, BasePacket)):
47    __slots__ = [
48        "time", "sent_time", "name", "default_fields",
49        "overload_fields", "overloaded_fields", "fields", "fieldtype",
50        "packetfields",
51        "original", "explicit", "raw_packet_cache",
52        "raw_packet_cache_fields", "_pkt", "post_transforms",
53        # then payload and underlayer
54        "payload", "underlayer",
55        "name",
56        # used for sr()
57        "_answered",
58        # used when sniffing
59        "direction", "sniffed_on"
60    ]
61    name = None
62    fields_desc = []
63    overload_fields = {}
64    payload_guess = []
65    show_indent = 1
66    show_summary = True
67
68    @classmethod
69    def from_hexcap(cls):
70        return cls(import_hexcap())
71
72    @classmethod
73    def upper_bonds(self):
74        for fval,upper in self.payload_guess:
75            print("%-20s  %s" % (upper.__name__, ", ".join("%-12s" % ("%s=%r"%i) for i in six.iteritems(fval))))
76
77    @classmethod
78    def lower_bonds(self):
79        for lower,fval in six.iteritems(self._overload_fields):
80            print("%-20s  %s" % (lower.__name__, ", ".join("%-12s" % ("%s=%r"%i) for i in six.iteritems(fval))))
81
82    def _unpickle(self, dlist):
83        """Used to unpack pickling"""
84        self.__init__(b"".join(dlist))
85        return self
86
87    def __reduce__(self):
88        """Used by pickling methods"""
89        return (self.__class__, (), (self.build(),))
90
91    def __reduce_ex__(self, proto):
92        """Used by pickling methods"""
93        return self.__reduce__()
94
95    def __getstate__(self):
96        """Mark object as pickable"""
97        return self.__reduce__()[2]
98
99    def __setstate__(self, state):
100        """Rebuild state using pickable methods"""
101        return self._unpickle(state)
102
103    def __deepcopy__(self, memo):
104        """Used by copy.deepcopy"""
105        return self.copy()
106
107    def __init__(self, _pkt=b"", post_transform=None, _internal=0, _underlayer=None, **fields):
108        self.time  = time.time()
109        self.sent_time = None
110        self.name = (self.__class__.__name__
111                     if self._name is None else
112                     self._name)
113        self.default_fields = {}
114        self.overload_fields = self._overload_fields
115        self.overloaded_fields = {}
116        self.fields = {}
117        self.fieldtype = {}
118        self.packetfields = []
119        self.payload = NoPayload()
120        self.init_fields()
121        self.underlayer = _underlayer
122        self.original = _pkt
123        self.explicit = 0
124        self.raw_packet_cache = None
125        self.raw_packet_cache_fields = None
126        if _pkt:
127            self.dissect(_pkt)
128            if not _internal:
129                self.dissection_done(self)
130        for f, v in six.iteritems(fields):
131            self.fields[f] = self.get_field(f).any2i(self, v)
132        if isinstance(post_transform, list):
133            self.post_transforms = post_transform
134        elif post_transform is None:
135            self.post_transforms = []
136        else:
137            self.post_transforms = [post_transform]
138
139    def init_fields(self):
140        """
141        Initialize each fields of the fields_desc dict
142        """
143        self.do_init_fields(self.fields_desc)
144
145    def do_init_fields(self, flist):
146        """
147        Initialize each fields of the fields_desc dict
148        """
149        for f in flist:
150            self.default_fields[f.name] = copy.deepcopy(f.default)
151            self.fieldtype[f.name] = f
152            if f.holds_packets:
153                self.packetfields.append(f)
154
155    def dissection_done(self,pkt):
156        """DEV: will be called after a dissection is completed"""
157        self.post_dissection(pkt)
158        self.payload.dissection_done(pkt)
159
160    def post_dissection(self, pkt):
161        """DEV: is called after the dissection of the whole packet"""
162        pass
163
164    def get_field(self, fld):
165        """DEV: returns the field instance from the name of the field"""
166        return self.fieldtype[fld]
167
168    def add_payload(self, payload):
169        if payload is None:
170            return
171        elif not isinstance(self.payload, NoPayload):
172            self.payload.add_payload(payload)
173        else:
174            if isinstance(payload, Packet):
175                self.payload = payload
176                payload.add_underlayer(self)
177                for t in self.aliastypes:
178                    if t in payload.overload_fields:
179                        self.overloaded_fields = payload.overload_fields[t]
180                        break
181            elif isinstance(payload, bytes):
182                self.payload = conf.raw_layer(load=payload)
183            else:
184                raise TypeError("payload must be either 'Packet' or 'bytes', not [%s]" % repr(payload))
185    def remove_payload(self):
186        self.payload.remove_underlayer(self)
187        self.payload = NoPayload()
188        self.overloaded_fields = {}
189    def add_underlayer(self, underlayer):
190        self.underlayer = underlayer
191    def remove_underlayer(self,other):
192        self.underlayer = None
193    def copy(self):
194        """Returns a deep copy of the instance."""
195        clone = self.__class__()
196        clone.fields = self.copy_fields_dict(self.fields)
197        clone.default_fields = self.copy_fields_dict(self.default_fields)
198        clone.overloaded_fields = self.overloaded_fields.copy()
199        clone.underlayer = self.underlayer
200        clone.explicit = self.explicit
201        clone.raw_packet_cache = self.raw_packet_cache
202        clone.raw_packet_cache_fields = self.copy_fields_dict(
203            self.raw_packet_cache_fields
204        )
205        clone.post_transforms = self.post_transforms[:]
206        clone.payload = self.payload.copy()
207        clone.payload.add_underlayer(clone)
208        clone.time = self.time
209        return clone
210
211    def getfieldval(self, attr):
212        if attr in self.fields:
213            return self.fields[attr]
214        if attr in self.overloaded_fields:
215            return self.overloaded_fields[attr]
216        if attr in self.default_fields:
217            return self.default_fields[attr]
218        return self.payload.getfieldval(attr)
219
220    def getfield_and_val(self, attr):
221        if attr in self.fields:
222            return self.get_field(attr),self.fields[attr]
223        if attr in self.overloaded_fields:
224            return self.get_field(attr),self.overloaded_fields[attr]
225        if attr in self.default_fields:
226            return self.get_field(attr),self.default_fields[attr]
227
228    def __getattr__(self, attr):
229        try:
230            fld, v = self.getfield_and_val(attr)
231        except TypeError:
232            return self.payload.__getattr__(attr)
233        if fld is not None:
234            return fld.i2h(self, v)
235        return v
236
237    def setfieldval(self, attr, val):
238        if attr in self.default_fields:
239            fld = self.get_field(attr)
240            if fld is None:
241                any2i = lambda x,y: y
242            else:
243                any2i = fld.any2i
244            self.fields[attr] = any2i(self, val)
245            self.explicit = 0
246            self.raw_packet_cache = None
247            self.raw_packet_cache_fields = None
248        elif attr == "payload":
249            self.remove_payload()
250            self.add_payload(val)
251        else:
252            self.payload.setfieldval(attr,val)
253
254    def __setattr__(self, attr, val):
255        if attr in self.__all_slots__:
256            return object.__setattr__(self, attr, val)
257        try:
258            return self.setfieldval(attr,val)
259        except AttributeError:
260            pass
261        return object.__setattr__(self, attr, val)
262
263    def delfieldval(self, attr):
264        if attr in self.fields:
265            del(self.fields[attr])
266            self.explicit = 0 # in case a default value must be explicited
267            self.raw_packet_cache = None
268            self.raw_packet_cache_fields = None
269        elif attr in self.default_fields:
270            pass
271        elif attr == "payload":
272            self.remove_payload()
273        else:
274            self.payload.delfieldval(attr)
275
276    def __delattr__(self, attr):
277        if attr == "payload":
278            return self.remove_payload()
279        if attr in self.__all_slots__:
280            return object.__delattr__(self, attr)
281        try:
282            return self.delfieldval(attr)
283        except AttributeError:
284            pass
285        return object.__delattr__(self, attr)
286
287    def _superdir(self):
288        """
289        Return a list of slots and methods, including those from subclasses.
290        """
291        attrs = set()
292        cls = self.__class__
293        if hasattr(cls, '__all_slots__'):
294            attrs.update(cls.__all_slots__)
295        for bcls in cls.__mro__:
296            if hasattr(bcls, '__dict__'):
297                attrs.update(bcls.__dict__)
298        return attrs
299
300    def __dir__(self):
301        """
302        Add fields to tab completion list.
303        """
304        return sorted(itertools.chain(self._superdir(), self.default_fields))
305
306    def __repr__(self):
307        s = ""
308        ct = conf.color_theme
309        for f in self.fields_desc:
310            if isinstance(f, ConditionalField) and not f._evalcond(self):
311                continue
312            if f.name in self.fields:
313                val = f.i2repr(self, self.fields[f.name])
314            elif f.name in self.overloaded_fields:
315                val =  f.i2repr(self, self.overloaded_fields[f.name])
316            else:
317                continue
318            if isinstance(f, Emph) or f in conf.emph:
319                ncol = ct.emph_field_name
320                vcol = ct.emph_field_value
321            else:
322                ncol = ct.field_name
323                vcol = ct.field_value
324
325
326            s += " %s%s%s" % (ncol(f.name),
327                              ct.punct("="),
328                              vcol(val))
329        return "%s%s %s %s%s%s"% (ct.punct("<"),
330                                  ct.layer_name(self.__class__.__name__),
331                                  s,
332                                  ct.punct("|"),
333                                  repr(self.payload),
334                                  ct.punct(">"))
335    def __str__(self):
336        return str(self.build())
337    def __bytes__(self):
338        return self.build()
339    def __div__(self, other):
340        if isinstance(other, Packet):
341            cloneA = self.copy()
342            cloneB = other.copy()
343            cloneA.add_payload(cloneB)
344            return cloneA
345        elif isinstance(other, (bytes, str)):
346            return self/conf.raw_layer(load=other)
347        else:
348            return other.__rdiv__(self)
349    __truediv__ = __div__
350    def __rdiv__(self, other):
351        if isinstance(other, (bytes, str)):
352            return conf.raw_layer(load=other)/self
353        else:
354            raise TypeError
355    __rtruediv__ = __rdiv__
356    def __mul__(self, other):
357        if isinstance(other, int):
358            return  [self]*other
359        else:
360            raise TypeError
361    def __rmul__(self,other):
362        return self.__mul__(other)
363
364    def __nonzero__(self):
365        return True
366    __bool__ = __nonzero__
367    def __len__(self):
368        return len(self.__bytes__())
369    def copy_field_value(self, fieldname, value):
370        return self.get_field(fieldname).do_copy(value)
371    def copy_fields_dict(self, fields):
372        if fields is None:
373            return None
374        return {fname: self.copy_field_value(fname, fval)
375                for fname, fval in six.iteritems(fields)}
376    def self_build(self, field_pos_list=None):
377        """
378        Create the default layer regarding fields_desc dict
379
380        :param field_pos_list:
381        """
382        if self.raw_packet_cache is not None:
383            for fname, fval in six.iteritems(self.raw_packet_cache_fields):
384                if self.getfieldval(fname) != fval:
385                    self.raw_packet_cache = None
386                    self.raw_packet_cache_fields = None
387                    break
388            if self.raw_packet_cache is not None:
389                return self.raw_packet_cache
390        p=b""
391        for f in self.fields_desc:
392            val = self.getfieldval(f.name)
393            if isinstance(val, RawVal):
394                sval = raw(val)
395                p += sval
396                if field_pos_list is not None:
397                    field_pos_list.append( (f.name, sval.encode("string_escape"), len(p), len(sval) ) )
398            else:
399                p = f.addfield(self, p, val)
400        return p
401
402    def do_build_payload(self):
403        """
404        Create the default version of the payload layer
405
406        :return: a string of payload layer
407        """
408        return self.payload.do_build()
409
410    def do_build(self):
411        """
412        Create the default version of the layer
413
414        :return: a string of the packet with the payload
415        """
416        if not self.explicit:
417            self = next(iter(self))
418        pkt = self.self_build()
419        for t in self.post_transforms:
420            pkt = t(pkt)
421        pay = self.do_build_payload()
422        if self.raw_packet_cache is None:
423            return self.post_build(pkt, pay)
424        else:
425            return pkt + pay
426
427    def build_padding(self):
428        return self.payload.build_padding()
429
430    def build(self):
431        """
432        Create the current layer
433
434        :return: string of the packet with the payload
435        """
436        p = self.do_build()
437        p += self.build_padding()
438        p = self.build_done(p)
439        return p
440
441    def post_build(self, pkt, pay):
442        """
443        DEV: called right after the current layer is build.
444
445        :param str pkt: the current packet (build by self_buil function)
446        :param str pay: the packet payload (build by do_build_payload function)
447        :return: a string of the packet with the payload
448        """
449        return pkt+pay
450
451    def build_done(self, p):
452        return self.payload.build_done(p)
453
454    def do_build_ps(self):
455        p = b""
456        pl = []
457        q = b""
458        for f in self.fields_desc:
459            if isinstance(f, ConditionalField) and not f._evalcond(self):
460                continue
461            p = f.addfield(self, p, self.getfieldval(f.name) )
462            if isinstance(p, bytes):
463                r = p[len(q):]
464                q = p
465            else:
466                r = b""
467            pl.append( (f, f.i2repr(self,self.getfieldval(f.name)), r) )
468
469        pkt,lst = self.payload.build_ps(internal=1)
470        p += pkt
471        lst.append( (self, pl) )
472
473        return p,lst
474
475    def build_ps(self,internal=0):
476        p,lst = self.do_build_ps()
477#        if not internal:
478#            pkt = self
479#            while pkt.haslayer(conf.padding_layer):
480#                pkt = pkt.getlayer(conf.padding_layer)
481#                lst.append( (pkt, [ ("loakjkjd", pkt.load, pkt.load) ] ) )
482#                p += pkt.load
483#                pkt = pkt.payload
484        return p,lst
485
486
487    def psdump(self, filename=None, **kargs):
488        """
489        psdump(filename=None, layer_shift=0, rebuild=1)
490
491        Creates an EPS file describing a packet. If filename is not provided a
492        temporary file is created and gs is called.
493
494        :param filename: the file's filename
495        """
496        canvas = self.canvas_dump(**kargs)
497        if filename is None:
498            fname = get_temp_file(autoext=".eps")
499            canvas.writeEPSfile(fname)
500            with ContextManagerSubprocess("psdump()", conf.prog.psreader):
501                subprocess.Popen([conf.prog.psreader, fname])
502        else:
503            canvas.writeEPSfile(filename)
504
505    def pdfdump(self, filename=None, **kargs):
506        """
507        pdfdump(filename=None, layer_shift=0, rebuild=1)
508
509        Creates a PDF file describing a packet. If filename is not provided a
510        temporary file is created and xpdf is called.
511
512        :param filename: the file's filename
513        """
514        canvas = self.canvas_dump(**kargs)
515        if filename is None:
516            fname = get_temp_file(autoext=".pdf")
517            canvas.writePDFfile(fname)
518            with ContextManagerSubprocess("pdfdump()", conf.prog.pdfreader):
519                subprocess.Popen([conf.prog.pdfreader, fname])
520        else:
521            canvas.writePDFfile(filename)
522
523
524    def canvas_dump(self, layer_shift=0, rebuild=1):
525        if PYX == 0:
526            raise ImportError("PyX and its depedencies must be installed")
527        canvas = pyx.canvas.canvas()
528        if rebuild:
529            p,t = self.__class__(raw(self)).build_ps()
530        else:
531            p,t = self.build_ps()
532        YTXT=len(t)
533        for n,l in t:
534            YTXT += len(l)
535        YTXT = float(YTXT)
536        YDUMP=YTXT
537
538        XSTART = 1
539        XDSTART = 10
540        y = 0.0
541        yd = 0.0
542        xd = 0
543        XMUL= 0.55
544        YMUL = 0.4
545
546        backcolor=colgen(0.6, 0.8, 1.0, trans=pyx.color.rgb)
547        forecolor=colgen(0.2, 0.5, 0.8, trans=pyx.color.rgb)
548#        backcolor=makecol(0.376, 0.729, 0.525, 1.0)
549
550
551        def hexstr(x):
552            s = []
553            for c in x:
554                s.append("%02x" % orb(c))
555            return " ".join(s)
556
557
558        def make_dump_txt(x,y,txt):
559            return pyx.text.text(XDSTART+x*XMUL, (YDUMP-y)*YMUL, r"\tt{%s}"%hexstr(txt), [pyx.text.size.Large])
560
561        def make_box(o):
562            return pyx.box.rect(o.left(), o.bottom(), o.width(), o.height(), relcenter=(0.5,0.5))
563
564        def make_frame(lst):
565            if len(lst) == 1:
566                b = lst[0].bbox()
567                b.enlarge(pyx.unit.u_pt)
568                return b.path()
569            else:
570                fb = lst[0].bbox()
571                fb.enlarge(pyx.unit.u_pt)
572                lb = lst[-1].bbox()
573                lb.enlarge(pyx.unit.u_pt)
574                if len(lst) == 2 and fb.left() > lb.right():
575                    return pyx.path.path(pyx.path.moveto(fb.right(), fb.top()),
576                                         pyx.path.lineto(fb.left(), fb.top()),
577                                         pyx.path.lineto(fb.left(), fb.bottom()),
578                                         pyx.path.lineto(fb.right(), fb.bottom()),
579                                         pyx.path.moveto(lb.left(), lb.top()),
580                                         pyx.path.lineto(lb.right(), lb.top()),
581                                         pyx.path.lineto(lb.right(), lb.bottom()),
582                                         pyx.path.lineto(lb.left(), lb.bottom()))
583                else:
584                    # XXX
585                    gb = lst[1].bbox()
586                    if gb != lb:
587                        gb.enlarge(pyx.unit.u_pt)
588                    kb = lst[-2].bbox()
589                    if kb != gb and kb != lb:
590                        kb.enlarge(pyx.unit.u_pt)
591                    return pyx.path.path(pyx.path.moveto(fb.left(), fb.top()),
592                                         pyx.path.lineto(fb.right(), fb.top()),
593                                         pyx.path.lineto(fb.right(), kb.bottom()),
594                                         pyx.path.lineto(lb.right(), kb.bottom()),
595                                         pyx.path.lineto(lb.right(), lb.bottom()),
596                                         pyx.path.lineto(lb.left(), lb.bottom()),
597                                         pyx.path.lineto(lb.left(), gb.top()),
598                                         pyx.path.lineto(fb.left(), gb.top()),
599                                         pyx.path.closepath(),)
600
601
602        def make_dump(s, shift=0, y=0, col=None, bkcol=None, larg=16):
603            c = pyx.canvas.canvas()
604            tlist = []
605            while s:
606                dmp,s = s[:larg-shift],s[larg-shift:]
607                txt = make_dump_txt(shift, y, dmp)
608                tlist.append(txt)
609                shift += len(dmp)
610                if shift >= 16:
611                    shift = 0
612                    y += 1
613            if col is None:
614                col = pyx.color.rgb.red
615            if bkcol is None:
616                col = pyx.color.rgb.white
617            c.stroke(make_frame(tlist),[col,pyx.deco.filled([bkcol]),pyx.style.linewidth.Thick])
618            for txt in tlist:
619                c.insert(txt)
620            return c, tlist[-1].bbox(), shift, y
621
622
623        last_shift,last_y=0,0.0
624        while t:
625            bkcol = next(backcolor)
626            proto,fields = t.pop()
627            y += 0.5
628            pt = pyx.text.text(XSTART, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % proto.name, [ pyx.text.size.Large])
629            y += 1
630            ptbb=pt.bbox()
631            ptbb.enlarge(pyx.unit.u_pt*2)
632            canvas.stroke(ptbb.path(),[pyx.color.rgb.black, pyx.deco.filled([bkcol])])
633            canvas.insert(pt)
634            for fname, fval, fdump in fields:
635                col = next(forecolor)
636                ft = pyx.text.text(XSTART, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % tex_escape(fname.name))
637                if isinstance(fval, str):
638                    if len(fval) > 18:
639                        fval = fval[:18]+"[...]"
640                else:
641                    fval=""
642                vt = pyx.text.text(XSTART+3, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % tex_escape(fval))
643                y += 1.0
644                if fdump:
645                    dt,target,last_shift,last_y = make_dump(fdump, last_shift, last_y, col, bkcol)
646
647                    dtb = dt.bbox()
648                    dtb=target
649                    vtb = vt.bbox()
650                    bxvt = make_box(vtb)
651                    bxdt = make_box(dtb)
652                    dtb.enlarge(pyx.unit.u_pt)
653                    try:
654                        if yd < 0:
655                            cnx = pyx.connector.curve(bxvt,bxdt,absangle1=0, absangle2=-90)
656                        else:
657                            cnx = pyx.connector.curve(bxvt,bxdt,absangle1=0, absangle2=90)
658                    except:
659                        pass
660                    else:
661                        canvas.stroke(cnx,[pyx.style.linewidth.thin,pyx.deco.earrow.small,col])
662
663                    canvas.insert(dt)
664
665                canvas.insert(ft)
666                canvas.insert(vt)
667            last_y += layer_shift
668
669        return canvas
670
671
672
673    def extract_padding(self, s):
674        """
675        DEV: to be overloaded to extract current layer's padding.
676
677        :param str s: the current layer
678        :return: a couple of strings (actual layer, padding)
679        """
680        return s,None
681
682    def post_dissect(self, s):
683        """DEV: is called right after the current layer has been dissected"""
684        return s
685
686    def pre_dissect(self, s):
687        """DEV: is called right before the current layer is dissected"""
688        return s
689
690    def do_dissect(self, s):
691        s = raw(s)
692        _raw = s
693        self.raw_packet_cache_fields = {}
694        for f in self.fields_desc:
695            if not s:
696                break
697            s, fval = f.getfield(self, s)
698            # We need to track fields with mutable values to discard
699            # .raw_packet_cache when needed.
700            if f.islist or f.holds_packets or f.ismutable:
701                self.raw_packet_cache_fields[f.name] = f.do_copy(fval)
702            self.fields[f.name] = fval
703        assert(_raw.endswith(raw(s)))
704        self.raw_packet_cache = _raw[:-len(s)] if s else _raw
705        self.explicit = 1
706        return s
707
708    def do_dissect_payload(self, s):
709        """
710        Perform the dissection of the layer's payload
711
712        :param str s: the raw layer
713        """
714        if s:
715            cls = self.guess_payload_class(s)
716            try:
717                p = cls(s, _internal=1, _underlayer=self)
718            except KeyboardInterrupt:
719                raise
720            except:
721                if conf.debug_dissector:
722                    if isinstance(cls,type) and issubclass(cls,Packet):
723                        log_runtime.error("%s dissector failed" % cls.__name__)
724                    else:
725                        log_runtime.error("%s.guess_payload_class() returned [%s]" % (self.__class__.__name__,repr(cls)))
726                    if cls is not None:
727                        raise
728                p = conf.raw_layer(s, _internal=1, _underlayer=self)
729            self.add_payload(p)
730
731    def dissect(self, s):
732        s = self.pre_dissect(s)
733
734        s = self.do_dissect(s)
735
736        s = self.post_dissect(s)
737
738        payl,pad = self.extract_padding(s)
739        self.do_dissect_payload(payl)
740        if pad and conf.padding:
741            self.add_payload(conf.padding_layer(pad))
742
743
744    def guess_payload_class(self, payload):
745        """
746        DEV: Guesses the next payload class from layer bonds.
747        Can be overloaded to use a different mechanism.
748
749        :param str payload: the layer's payload
750        :return: the payload class
751        """
752        for t in self.aliastypes:
753            for fval, cls in t.payload_guess:
754                ok = 1
755                for k, v in six.iteritems(fval):
756                    if not hasattr(self, k) or v != self.getfieldval(k):
757                        ok = 0
758                        break
759                if ok:
760                    return cls
761        return self.default_payload_class(payload)
762
763    def default_payload_class(self, payload):
764        """
765        DEV: Returns the default payload class if nothing has been found by the
766        guess_payload_class() method.
767
768        :param str payload: the layer's payload
769        :return: the default payload class define inside the configuration file
770        """
771        return conf.raw_layer
772
773    def hide_defaults(self):
774        """Removes fields' values that are the same as default values."""
775        for k, v in list(self.fields.items()):  # use list(): self.fields is modified in the loop
776            v = self.fields[k]
777            if k in self.default_fields:
778                if self.default_fields[k] == v:
779                    del self.fields[k]
780        self.payload.hide_defaults()
781
782    def clone_with(self, payload=None, **kargs):
783        pkt = self.__class__()
784        pkt.explicit = 1
785        pkt.fields = kargs
786        pkt.default_fields = self.copy_fields_dict(self.default_fields)
787        pkt.overloaded_fields = self.overloaded_fields.copy()
788        pkt.time = self.time
789        pkt.underlayer = self.underlayer
790        pkt.post_transforms = self.post_transforms
791        pkt.raw_packet_cache = self.raw_packet_cache
792        pkt.raw_packet_cache_fields = self.copy_fields_dict(
793            self.raw_packet_cache_fields
794        )
795        if payload is not None:
796            pkt.add_payload(payload)
797        return pkt
798
799    def __iter__(self):
800        def loop(todo, done, self=self):
801            if todo:
802                eltname = todo.pop()
803                elt = self.getfieldval(eltname)
804                if not isinstance(elt, Gen):
805                    if self.get_field(eltname).islist:
806                        elt = SetGen([elt])
807                    else:
808                        elt = SetGen(elt)
809                for e in elt:
810                    done[eltname]=e
811                    for x in loop(todo[:], done):
812                        yield x
813            else:
814                if isinstance(self.payload,NoPayload):
815                    payloads = [None]
816                else:
817                    payloads = self.payload
818                for payl in payloads:
819                    done2=done.copy()
820                    for k in done2:
821                        if isinstance(done2[k], VolatileValue):
822                            done2[k] = done2[k]._fix()
823                    pkt = self.clone_with(payload=payl, **done2)
824                    yield pkt
825
826        if self.explicit or self.raw_packet_cache is not None:
827            todo = []
828            done = self.fields
829        else:
830            todo = [k for (k,v) in itertools.chain(six.iteritems(self.default_fields),
831                                                   six.iteritems(self.overloaded_fields))
832                    if isinstance(v, VolatileValue)] + list(self.fields.keys())
833            done = {}
834        return loop(todo, done)
835
836    def __gt__(self, other):
837        """True if other is an answer from self (self ==> other)."""
838        if isinstance(other, Packet):
839            return other < self
840        elif isinstance(other, bytes):
841            return 1
842        else:
843            raise TypeError((self, other))
844    def __lt__(self, other):
845        """True if self is an answer from other (other ==> self)."""
846        if isinstance(other, Packet):
847            return self.answers(other)
848        elif isinstance(other, bytes):
849            return 1
850        else:
851            raise TypeError((self, other))
852
853    def __eq__(self, other):
854        if not isinstance(other, self.__class__):
855            return False
856        for f in self.fields_desc:
857            if f not in other.fields_desc:
858                return False
859            if self.getfieldval(f.name) != other.getfieldval(f.name):
860                return False
861        return self.payload == other.payload
862
863    def __ne__(self, other):
864        return not self.__eq__(other)
865
866    def hashret(self):
867        """DEV: returns a string that has the same value for a request and its answer."""
868        return self.payload.hashret()
869    def answers(self, other):
870        """DEV: true if self is an answer from other"""
871        if other.__class__ == self.__class__:
872            return self.payload.answers(other.payload)
873        return 0
874
875    def haslayer(self, cls):
876        """true if self has a layer that is an instance of cls. Superseded by "cls in self" syntax."""
877        if self.__class__ == cls or self.__class__.__name__ == cls:
878            return 1
879        for f in self.packetfields:
880            fvalue_gen = self.getfieldval(f.name)
881            if fvalue_gen is None:
882                continue
883            if not f.islist:
884                fvalue_gen = SetGen(fvalue_gen,_iterpacket=0)
885            for fvalue in fvalue_gen:
886                if isinstance(fvalue, Packet):
887                    ret = fvalue.haslayer(cls)
888                    if ret:
889                        return ret
890        return self.payload.haslayer(cls)
891
892    def getlayer(self, cls, nb=1, _track=None, _subclass=False, **flt):
893        """Return the nb^th layer that is an instance of cls, matching flt
894values.
895
896        """
897        if _subclass:
898            match = lambda cls1, cls2: issubclass(cls1, cls2)
899        else:
900            match = lambda cls1, cls2: cls1 == cls2
901        if isinstance(cls, int):
902            nb = cls+1
903            cls = None
904        if isinstance(cls, str) and "." in cls:
905            ccls,fld = cls.split(".",1)
906        else:
907            ccls,fld = cls,None
908        if cls is None or match(self.__class__, cls) or self.__class__.__name__ == ccls:
909            if all(self.getfieldval(fldname) == fldvalue
910                   for fldname, fldvalue in six.iteritems(flt)):
911                if nb == 1:
912                    if fld is None:
913                        return self
914                    else:
915                        return self.getfieldval(fld)
916                else:
917                    nb -=1
918        for f in self.packetfields:
919            fvalue_gen = self.getfieldval(f.name)
920            if fvalue_gen is None:
921                continue
922            if not f.islist:
923                fvalue_gen = SetGen(fvalue_gen,_iterpacket=0)
924            for fvalue in fvalue_gen:
925                if isinstance(fvalue, Packet):
926                    track=[]
927                    ret = fvalue.getlayer(cls, nb=nb, _track=track,
928                                          _subclass=_subclass)
929                    if ret is not None:
930                        return ret
931                    nb = track[0]
932        return self.payload.getlayer(cls, nb=nb, _track=_track,
933                                     _subclass=_subclass, **flt)
934
935    def firstlayer(self):
936        q = self
937        while q.underlayer is not None:
938            q = q.underlayer
939        return q
940
941    def __getitem__(self, cls):
942        if isinstance(cls, slice):
943            lname = cls.start
944            if cls.stop:
945                ret = self.getlayer(cls.start, nb=cls.stop, **(cls.step or {}))
946            else:
947                ret = self.getlayer(cls.start, **(cls.step or {}))
948        else:
949            lname = cls
950            ret = self.getlayer(cls)
951        if ret is None:
952            if isinstance(lname, Packet_metaclass):
953                lname = lname.__name__
954            elif not isinstance(lname, bytes):
955                lname = repr(lname)
956            raise IndexError("Layer [%s] not found" % lname)
957        return ret
958
959    def __delitem__(self, cls):
960        del(self[cls].underlayer.payload)
961
962    def __setitem__(self, cls, val):
963        self[cls].underlayer.payload = val
964
965    def __contains__(self, cls):
966        """"cls in self" returns true if self has a layer which is an instance of cls."""
967        return self.haslayer(cls)
968
969    def route(self):
970        return (None,None,None)
971
972    def fragment(self, *args, **kargs):
973        return self.payload.fragment(*args, **kargs)
974
975
976    def display(self,*args,**kargs):  # Deprecated. Use show()
977        """Deprecated. Use show() method."""
978        self.show(*args,**kargs)
979
980    def _show_or_dump(self, dump=False, indent=3, lvl="", label_lvl="", first_call=True):
981        """
982        Internal method that shows or dumps a hierarchical view of a packet.
983        Called by show.
984
985        :param dump: determine if it prints or returns the string value
986        :param int indent: the size of indentation for each layer
987        :param str lvl: additional information about the layer lvl
988        :param str label_lvl: additional information about the layer fields
989        :param first_call: determine if the current function is the first
990        :return: return a hierarchical view if dump, else print it
991        """
992
993        if dump:
994            from scapy.themes import AnsiColorTheme
995            ct = AnsiColorTheme() # No color for dump output
996        else:
997            ct = conf.color_theme
998        s = "%s%s %s %s \n" % (label_lvl,
999                              ct.punct("###["),
1000                              ct.layer_name(self.name),
1001                              ct.punct("]###"))
1002        for f in self.fields_desc:
1003            if isinstance(f, ConditionalField) and not f._evalcond(self):
1004                continue
1005            if isinstance(f, Emph) or f in conf.emph:
1006                ncol = ct.emph_field_name
1007                vcol = ct.emph_field_value
1008            else:
1009                ncol = ct.field_name
1010                vcol = ct.field_value
1011            fvalue = self.getfieldval(f.name)
1012            if isinstance(fvalue, Packet) or (f.islist and f.holds_packets and isinstance(fvalue, list)):
1013                s += "%s  \\%-10s\\\n" % (label_lvl+lvl, ncol(f.name))
1014                fvalue_gen = SetGen(fvalue,_iterpacket=0)
1015                for fvalue in fvalue_gen:
1016                    s += fvalue._show_or_dump(dump=dump, indent=indent, label_lvl=label_lvl+lvl+"   |", first_call=False)
1017            else:
1018                begn = "%s  %-10s%s " % (label_lvl+lvl,
1019                                        ncol(f.name),
1020                                        ct.punct("="),)
1021                reprval = f.i2repr(self,fvalue)
1022                if isinstance(reprval, str):
1023                    reprval = reprval.replace("\n", "\n"+" "*(len(label_lvl)
1024                                                              +len(lvl)
1025                                                              +len(f.name)
1026                                                              +4))
1027                s += "%s%s\n" % (begn,vcol(reprval))
1028        if self.payload:
1029            s += self.payload._show_or_dump(dump=dump, indent=indent, lvl=lvl+(" "*indent*self.show_indent), label_lvl=label_lvl, first_call=False)
1030
1031        if first_call and not dump:
1032            print(s)
1033        else:
1034            return s
1035
1036    def show(self, dump=False, indent=3, lvl="", label_lvl=""):
1037        """
1038        Prints or returns (when "dump" is true) a hierarchical view of the
1039        packet.
1040
1041        :param dump: determine if it prints or returns the string value
1042        :param int indent: the size of indentation for each layer
1043        :param str lvl: additional information about the layer lvl
1044        :param str label_lvl: additional information about the layer fields
1045        :return: return a hierarchical view if dump, else print it
1046        """
1047        return self._show_or_dump(dump, indent, lvl, label_lvl)
1048
1049    def show2(self, dump=False, indent=3, lvl="", label_lvl=""):
1050        """
1051        Prints or returns (when "dump" is true) a hierarchical view of an
1052        assembled version of the packet, so that automatic fields are
1053        calculated (checksums, etc.)
1054
1055        :param dump: determine if it prints or returns the string value
1056        :param int indent: the size of indentation for each layer
1057        :param str lvl: additional information about the layer lvl
1058        :param str label_lvl: additional information about the layer fields
1059        :return: return a hierarchical view if dump, else print it
1060        """
1061        return self.__class__(raw(self)).show(dump, indent, lvl, label_lvl)
1062
1063    def sprintf(self, fmt, relax=1):
1064        """sprintf(format, [relax=1]) -> str
1065where format is a string that can include directives. A directive begins and
1066ends by % and has the following format %[fmt[r],][cls[:nb].]field%.
1067
1068fmt is a classic printf directive, "r" can be appended for raw substitution
1069(ex: IP.flags=0x18 instead of SA), nb is the number of the layer we want
1070(ex: for IP/IP packets, IP:2.src is the src of the upper IP layer).
1071Special case : "%.time%" is the creation time.
1072Ex : p.sprintf("%.time% %-15s,IP.src% -> %-15s,IP.dst% %IP.chksum% "
1073               "%03xr,IP.proto% %r,TCP.flags%")
1074
1075Moreover, the format string can include conditional statements. A conditional
1076statement looks like : {layer:string} where layer is a layer name, and string
1077is the string to insert in place of the condition if it is true, i.e. if layer
1078is present. If layer is preceded by a "!", the result is inverted. Conditions
1079can be imbricated. A valid statement can be :
1080  p.sprintf("This is a{TCP: TCP}{UDP: UDP}{ICMP:n ICMP} packet")
1081  p.sprintf("{IP:%IP.dst% {ICMP:%ICMP.type%}{TCP:%TCP.dport%}}")
1082
1083A side effect is that, to obtain "{" and "}" characters, you must use
1084"%(" and "%)".
1085"""
1086
1087        escape = { "%": "%",
1088                   "(": "{",
1089                   ")": "}" }
1090
1091
1092        # Evaluate conditions
1093        while "{" in fmt:
1094            i = fmt.rindex("{")
1095            j = fmt[i+1:].index("}")
1096            cond = fmt[i+1:i+j+1]
1097            k = cond.find(":")
1098            if k < 0:
1099                raise Scapy_Exception("Bad condition in format string: [%s] (read sprintf doc!)"%cond)
1100            cond,format = cond[:k],cond[k+1:]
1101            res = False
1102            if cond[0] == "!":
1103                res = True
1104                cond = cond[1:]
1105            if self.haslayer(cond):
1106                res = not res
1107            if not res:
1108                format = ""
1109            fmt = fmt[:i]+format+fmt[i+j+2:]
1110
1111        # Evaluate directives
1112        s = ""
1113        while "%" in fmt:
1114            i = fmt.index("%")
1115            s += fmt[:i]
1116            fmt = fmt[i+1:]
1117            if fmt and fmt[0] in escape:
1118                s += escape[fmt[0]]
1119                fmt = fmt[1:]
1120                continue
1121            try:
1122                i = fmt.index("%")
1123                sfclsfld = fmt[:i]
1124                fclsfld = sfclsfld.split(",")
1125                if len(fclsfld) == 1:
1126                    f = "s"
1127                    clsfld = fclsfld[0]
1128                elif len(fclsfld) == 2:
1129                    f,clsfld = fclsfld
1130                else:
1131                    raise Scapy_Exception
1132                if "." in clsfld:
1133                    cls,fld = clsfld.split(".")
1134                else:
1135                    cls = self.__class__.__name__
1136                    fld = clsfld
1137                num = 1
1138                if ":" in cls:
1139                    cls,num = cls.split(":")
1140                    num = int(num)
1141                fmt = fmt[i+1:]
1142            except:
1143                raise Scapy_Exception("Bad format string [%%%s%s]" % (fmt[:25], fmt[25:] and "..."))
1144            else:
1145                if fld == "time":
1146                    val = time.strftime("%H:%M:%S.%%06i", time.localtime(self.time)) % int((self.time-int(self.time))*1000000)
1147                elif cls == self.__class__.__name__ and hasattr(self, fld):
1148                    if num > 1:
1149                        val = self.payload.sprintf("%%%s,%s:%s.%s%%" % (f,cls,num-1,fld), relax)
1150                        f = "s"
1151                    elif f[-1] == "r":  # Raw field value
1152                        val = getattr(self,fld)
1153                        f = f[:-1]
1154                        if not f:
1155                            f = "s"
1156                    else:
1157                        val = getattr(self,fld)
1158                        if fld in self.fieldtype:
1159                            val = self.fieldtype[fld].i2repr(self,val)
1160                else:
1161                    val = self.payload.sprintf("%%%s%%" % sfclsfld, relax)
1162                    f = "s"
1163                s += ("%"+f) % val
1164
1165        s += fmt
1166        return s
1167
1168    def mysummary(self):
1169        """DEV: can be overloaded to return a string that summarizes the layer.
1170           Only one mysummary() is used in a whole packet summary: the one of the upper layer,
1171           except if a mysummary() also returns (as a couple) a list of layers whose
1172           mysummary() must be called if they are present."""
1173        return ""
1174
1175    def _do_summary(self):
1176        found, s, needed = self.payload._do_summary()
1177        ret = ""
1178        if not found or self.__class__ in needed:
1179            ret = self.mysummary()
1180            if isinstance(ret, tuple):
1181                ret,n = ret
1182                needed += n
1183        if ret or needed:
1184            found = 1
1185        if not ret:
1186            ret = self.__class__.__name__ if self.show_summary else ""
1187        if self.__class__ in conf.emph:
1188            impf = []
1189            for f in self.fields_desc:
1190                if f in conf.emph:
1191                    impf.append("%s=%s" % (f.name, f.i2repr(self, self.getfieldval(f.name))))
1192            ret = "%s [%s]" % (ret," ".join(impf))
1193        if ret and s:
1194            ret = "%s / %s" % (ret, s)
1195        else:
1196            ret = "%s%s" % (ret,s)
1197        return found,ret,needed
1198
1199    def summary(self, intern=0):
1200        """Prints a one line summary of a packet."""
1201        found,s,needed = self._do_summary()
1202        return s
1203
1204
1205    def lastlayer(self,layer=None):
1206        """Returns the uppest layer of the packet"""
1207        return self.payload.lastlayer(self)
1208
1209    def decode_payload_as(self,cls):
1210        """Reassembles the payload and decode it using another packet class"""
1211        s = raw(self.payload)
1212        self.payload = cls(s, _internal=1, _underlayer=self)
1213        pp = self
1214        while pp.underlayer is not None:
1215            pp = pp.underlayer
1216        self.payload.dissection_done(pp)
1217
1218    def command(self):
1219        """Returns a string representing the command you have to type to obtain the same packet"""
1220        f = []
1221        for fn,fv in self.fields.items():
1222            fld = self.get_field(fn)
1223            if isinstance(fv, Packet):
1224                fv = fv.command()
1225            elif fld.islist and fld.holds_packets and isinstance(fv, list):
1226                fv = "[%s]" % ",".join( map(Packet.command, fv))
1227            elif isinstance(fld, FlagsField):
1228                fv = int(fv)
1229            else:
1230                fv = repr(fv)
1231            f.append("%s=%s" % (fn, fv))
1232        c = "%s(%s)" % (self.__class__.__name__, ", ".join(f))
1233        pc = self.payload.command()
1234        if pc:
1235            c += "/"+pc
1236        return c
1237
1238class NoPayload(Packet):
1239    def __new__(cls, *args, **kargs):
1240        singl = cls.__dict__.get("__singl__")
1241        if singl is None:
1242            cls.__singl__ = singl = Packet.__new__(cls)
1243            Packet.__init__(singl)
1244        return singl
1245    def __init__(self, *args, **kargs):
1246        pass
1247    def dissection_done(self,pkt):
1248        return
1249    def add_payload(self, payload):
1250        raise Scapy_Exception("Can't add payload to NoPayload instance")
1251    def remove_payload(self):
1252        pass
1253    def add_underlayer(self,underlayer):
1254        pass
1255    def remove_underlayer(self,other):
1256        pass
1257    def copy(self):
1258        return self
1259    def __repr__(self):
1260        return ""
1261    def __str__(self):
1262        return ""
1263    def __bytes__(self):
1264        return b""
1265    def __nonzero__(self):
1266        return False
1267    __bool__ = __nonzero__
1268    def do_build(self):
1269        return b""
1270    def build(self):
1271        return b""
1272    def build_padding(self):
1273        return b""
1274    def build_done(self, p):
1275        return p
1276    def build_ps(self, internal=0):
1277        return b"",[]
1278    def getfieldval(self, attr):
1279        raise AttributeError(attr)
1280    def getfield_and_val(self, attr):
1281        raise AttributeError(attr)
1282    def setfieldval(self, attr, val):
1283        raise AttributeError(attr)
1284    def delfieldval(self, attr):
1285        raise AttributeError(attr)
1286    def hide_defaults(self):
1287        pass
1288    def __iter__(self):
1289        return iter([])
1290    def __eq__(self, other):
1291        if isinstance(other, NoPayload):
1292            return True
1293        return False
1294    def hashret(self):
1295        return b""
1296    def answers(self, other):
1297        return isinstance(other, NoPayload) or isinstance(other, conf.padding_layer)
1298    def haslayer(self, cls):
1299        return 0
1300    def getlayer(self, cls, nb=1, _track=None, **flt):
1301        if _track is not None:
1302            _track.append(nb)
1303        return None
1304    def fragment(self, *args, **kargs):
1305        raise Scapy_Exception("cannot fragment this packet")
1306    def show(self, indent=3, lvl="", label_lvl=""):
1307        pass
1308    def sprintf(self, fmt, relax):
1309        if relax:
1310            return "??"
1311        else:
1312            raise Scapy_Exception("Format not found [%s]"%fmt)
1313    def _do_summary(self):
1314        return 0,"",[]
1315    def lastlayer(self,layer):
1316        return layer
1317    def command(self):
1318        return ""
1319
1320####################
1321## packet classes ##
1322####################
1323
1324
1325class Raw(Packet):
1326    name = "Raw"
1327    fields_desc = [ StrField("load", "") ]
1328    def answers(self, other):
1329        return 1
1330#        s = raw(other)
1331#        t = self.load
1332#        l = min(len(s), len(t))
1333#        return  s[:l] == t[:l]
1334    def mysummary(self):
1335        cs = conf.raw_summary
1336        if cs:
1337            if callable(cs):
1338                return "Raw %s" % cs(self.load)
1339            else:
1340                return "Raw %r" % self.load
1341        return Packet.mysummary(self)
1342
1343class Padding(Raw):
1344    name = "Padding"
1345    def self_build(self):
1346        return b""
1347    def build_padding(self):
1348        return (raw(self.load) if self.raw_packet_cache is None
1349                else self.raw_packet_cache) + self.payload.build_padding()
1350
1351conf.raw_layer = Raw
1352conf.padding_layer = Padding
1353if conf.default_l2 is None:
1354    conf.default_l2 = Raw
1355
1356#################
1357## Bind layers ##
1358#################
1359
1360
1361def bind_bottom_up(lower, upper, __fval=None, **fval):
1362    if __fval is not None:
1363        fval.update(__fval)
1364    lower.payload_guess = lower.payload_guess[:]
1365    lower.payload_guess.append((fval, upper))
1366
1367
1368def bind_top_down(lower, upper, __fval=None, **fval):
1369    if __fval is not None:
1370        fval.update(__fval)
1371    upper._overload_fields = upper._overload_fields.copy()
1372    upper._overload_fields[lower] = fval
1373
1374@conf.commands.register
1375def bind_layers(lower, upper, __fval=None, **fval):
1376    """Bind 2 layers on some specific fields' values"""
1377    if __fval is not None:
1378        fval.update(__fval)
1379    bind_top_down(lower, upper, **fval)
1380    bind_bottom_up(lower, upper, **fval)
1381
1382def split_bottom_up(lower, upper, __fval=None, **fval):
1383    if __fval is not None:
1384        fval.update(__fval)
1385    def do_filter(xxx_todo_changeme,upper=upper,fval=fval):
1386        (f,u) = xxx_todo_changeme
1387        if u != upper:
1388            return True
1389        for k in fval:
1390            if k not in f or f[k] != fval[k]:
1391                return True
1392        return False
1393    lower.payload_guess = [x for x in lower.payload_guess if do_filter(x)]
1394
1395def split_top_down(lower, upper, __fval=None, **fval):
1396    if __fval is not None:
1397        fval.update(__fval)
1398    if lower in upper._overload_fields:
1399        ofval = upper._overload_fields[lower]
1400        for k in fval:
1401            if k not in ofval or ofval[k] != fval[k]:
1402                return
1403        upper._overload_fields = upper._overload_fields.copy()
1404        del(upper._overload_fields[lower])
1405
1406@conf.commands.register
1407def split_layers(lower, upper, __fval=None, **fval):
1408    """Split 2 layers previously bound"""
1409    if __fval is not None:
1410        fval.update(__fval)
1411    split_bottom_up(lower, upper, **fval)
1412    split_top_down(lower, upper, **fval)
1413
1414
1415@conf.commands.register
1416def ls(obj=None, case_sensitive=False, verbose=False):
1417    """List  available layers, or infos on a given layer class or name"""
1418    is_string = isinstance(obj, six.string_types)
1419
1420    if obj is None or is_string:
1421        if obj is None:
1422            all_layers = sorted(conf.layers, key=lambda x: x.__name__)
1423        else:
1424            pattern = re.compile(obj, 0 if case_sensitive else re.I)
1425            all_layers = sorted((layer for layer in conf.layers
1426                                if (pattern.search(layer.__name__ or '')
1427                                    or pattern.search(layer.name or ''))),
1428                                key=lambda x: x.__name__)
1429        for layer in all_layers:
1430            print("%-10s : %s" % (layer.__name__, layer._name))
1431
1432    else:
1433        is_pkt = isinstance(obj, Packet)
1434        if (isinstance(obj, type) and issubclass(obj, Packet)) or is_pkt:
1435            for f in obj.fields_desc:
1436                cur_fld = f
1437                attrs = []
1438                long_attrs = []
1439                while isinstance(cur_fld, (Emph, ConditionalField)):
1440                    if isinstance(cur_fld, ConditionalField):
1441                        attrs.append(cur_fld.__class__.__name__[:4])
1442                    cur_fld = cur_fld.fld
1443                if verbose and isinstance(cur_fld, EnumField) \
1444                   and hasattr(cur_fld, "i2s"):
1445                    if len(cur_fld.i2s) < 50:
1446                        long_attrs.extend(
1447                            "%s: %d" % (strval, numval)
1448                            for numval, strval in
1449                            sorted(six.iteritems(cur_fld.i2s))
1450                        )
1451                elif isinstance(cur_fld, MultiEnumField):
1452                    fld_depend = cur_fld.depends_on(obj.__class__
1453                                                    if is_pkt else obj)
1454                    attrs.append("Depends on %s" % fld_depend.name)
1455                    if verbose:
1456                        cur_i2s = cur_fld.i2s_multi.get(
1457                            cur_fld.depends_on(obj if is_pkt else obj()), {}
1458                        )
1459                        if len(cur_i2s) < 50:
1460                            long_attrs.extend(
1461                                "%s: %d" % (strval, numval)
1462                                for numval, strval in
1463                                sorted(six.iteritems(cur_i2s))
1464                            )
1465                elif verbose and isinstance(cur_fld, FlagsField):
1466                    names = cur_fld.names
1467                    long_attrs.append(", ".join(names))
1468                class_name = "%s (%s)" % (
1469                    cur_fld.__class__.__name__,
1470                    ", ".join(attrs)) if attrs else cur_fld.__class__.__name__
1471                if isinstance(cur_fld, BitField):
1472                    class_name += " (%d bit%s)" % (cur_fld.size,
1473                                                   "s" if cur_fld.size > 1
1474                                                   else "")
1475                print("%-10s : %-35s =" % (f.name, class_name), end=' ')
1476                if is_pkt:
1477                    print("%-15r" % (getattr(obj, f.name),), end=' ')
1478                print("(%r)" % (f.default,))
1479                for attr in long_attrs:
1480                    print("%-15s%s" % ("", attr))
1481            if is_pkt and not isinstance(obj.payload, NoPayload):
1482                print("--")
1483                ls(obj.payload)
1484
1485        else:
1486            print("Not a packet class or name. Type 'ls()' to list packet classes.")
1487
1488
1489
1490#############
1491## Fuzzing ##
1492#############
1493
1494@conf.commands.register
1495def fuzz(p, _inplace=0):
1496    """Transform a layer into a fuzzy layer by replacing some default values by random objects"""
1497    if not _inplace:
1498        p = p.copy()
1499    q = p
1500    while not isinstance(q, NoPayload):
1501        for f in q.fields_desc:
1502            if isinstance(f, PacketListField):
1503                for r in getattr(q, f.name):
1504                    print("fuzzing", repr(r))
1505                    fuzz(r, _inplace=1)
1506            elif f.default is not None:
1507                if not isinstance(f, ConditionalField) or f._evalcond(q):
1508                    rnd = f.randval()
1509                    if rnd is not None:
1510                        q.default_fields[f.name] = rnd
1511        q = q.payload
1512    return p
1513
1514
1515
1516