root/scapy/packet.py

Revision 952:e28139770a3a, 40.9 kB (checked in by Phil <phil@secdev.org>, 2 weeks ago)

WARNING: API change. Work on Packet.getitem(), setitem() and delitem()

- Packet.getitem() raises an IndexError? if asked layer is not found
- Added Packet.setitem() to replace a layer by another

ex: del(pkt[Raw])

- Added Packet.delitem() to remove a layer and its sublayers

ex: pkt[Raw] = Raw(load="another payload")

Line 
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 import time,itertools,os
7 from fields import StrField,ConditionalField,Emph,PacketListField
8 from config import conf
9 from base_classes import BasePacket,Gen,SetGen,Packet_metaclass,NewDefaultValues
10 from volatile import VolatileValue
11 from utils import import_hexcap,tex_escape,colgen
12 from error import Scapy_Exception,log_runtime
13
14 try:
15     import pyx
16 except ImportError:
17     pass
18
19
20 class Packet(BasePacket):
21     __metaclass__ = Packet_metaclass
22     name=None
23
24     fields_desc = []
25
26     aliastypes = []
27     overload_fields = {}
28
29     underlayer = None
30
31     payload_guess = []
32     initialized = 0
33     show_indent=1
34     explicit = 0
35
36     @classmethod
37     def from_hexcap(cls):
38         return cls(import_hexcap())
39
40     @classmethod
41     def upper_bonds(self):
42         for fval,upper in self.payload_guess:
43             print "%-20s  %s" % (upper.__name__, ", ".join("%-12s" % ("%s=%r"%i) for i in fval.iteritems()))
44
45     @classmethod
46     def lower_bonds(self):
47         for lower,fval in self.overload_fields.iteritems():
48             print "%-20s  %s" % (lower.__name__, ", ".join("%-12s" % ("%s=%r"%i) for i in fval.iteritems()))
49
50     def __init__(self, _pkt="", post_transform=None, _internal=0, _underlayer=None, **fields):
51         self.time  = time.time()
52         self.sent_time = 0
53         if self.name is None:
54             self.name = self.__class__.__name__
55         self.aliastypes = [ self.__class__ ] + self.aliastypes
56         self.default_fields = {}
57         self.overloaded_fields = {}
58         self.fields={}
59         self.fieldtype={}
60         self.packetfields=[]
61         self.__dict__["payload"] = NoPayload()
62         self.init_fields()
63         self.underlayer = _underlayer
64         self.initialized = 1
65         if _pkt:
66             self.dissect(_pkt)
67             if not _internal:
68                 self.dissection_done(self)
69         for f in fields.keys():
70             self.fields[f] = self.get_field(f).any2i(self,fields[f])
71         if type(post_transform) is list:
72             self.post_transforms = post_transform
73         elif post_transform is None:
74             self.post_transforms = []
75         else:
76             self.post_transforms = [post_transform]
77
78     def init_fields(self):
79         self.do_init_fields(self.fields_desc)
80
81     def do_init_fields(self, flist):
82         for f in flist:
83             self.default_fields[f.name] = f.default
84             self.fieldtype[f.name] = f
85             if f.holds_packets:
86                 self.packetfields.append(f)
87            
88     def dissection_done(self,pkt):
89         """DEV: will be called after a dissection is completed"""
90         self.post_dissection(pkt)
91         self.payload.dissection_done(pkt)
92        
93     def post_dissection(self, pkt):
94         """DEV: is called after the dissection of the whole packet"""
95         pass
96
97     def get_field(self, fld):
98         """DEV: returns the field instance from the name of the field"""
99         return self.fieldtype[fld]
100        
101     def add_payload(self, payload):
102         if payload is None:
103             return
104         elif not isinstance(self.payload, NoPayload):
105             self.payload.add_payload(payload)
106         else:
107             if isinstance(payload, Packet):
108                 self.__dict__["payload"] = payload
109                 payload.add_underlayer(self)
110                 for t in self.aliastypes:
111                     if payload.overload_fields.has_key(t):
112                         self.overloaded_fields = payload.overload_fields[t]
113                         break
114             elif type(payload) is str:
115                 self.__dict__["payload"] = conf.raw_layer(load=payload)
116             else:
117                 raise TypeError("payload must be either 'Packet' or 'str', not [%s]" % repr(payload))
118     def remove_payload(self):
119         self.payload.remove_underlayer(self)
120         self.__dict__["payload"] = NoPayload()
121         self.overloaded_fields = {}
122     def add_underlayer(self, underlayer):
123         self.underlayer = underlayer
124     def remove_underlayer(self,other):
125         self.underlayer = None
126     def copy(self):
127         """Returns a deep copy of the instance."""
128         clone = self.__class__()
129         clone.fields = self.fields.copy()
130         for k in clone.fields:
131             clone.fields[k]=self.get_field(k).do_copy(clone.fields[k])
132         clone.default_fields = self.default_fields.copy()
133         clone.overloaded_fields = self.overloaded_fields.copy()
134         clone.overload_fields = self.overload_fields.copy()
135         clone.underlayer=self.underlayer
136         clone.explicit=self.explicit
137         clone.post_transforms=self.post_transforms[:]
138         clone.__dict__["payload"] = self.payload.copy()
139         clone.payload.add_underlayer(clone)
140         return clone
141
142     def getfieldval(self, attr):
143         if attr in self.fields:
144             return self.fields[attr]
145         if attr in self.overloaded_fields:
146             return self.overloaded_fields[attr]
147         if attr in self.default_fields:
148             return self.default_fields[attr]
149         return self.payload.getfieldval(attr)
150    
151     def getfield_and_val(self, attr):
152         if attr in self.fields:
153             return self.get_field(attr),self.fields[attr]
154         if attr in self.overloaded_fields:
155             return self.get_field(attr),self.overloaded_fields[attr]
156         if attr in self.default_fields:
157             return self.get_field(attr),self.default_fields[attr]
158         return self.payload.getfield_and_val(attr)
159    
160     def __getattr__(self, attr):
161         if self.initialized:
162             fld,v = self.getfield_and_val(attr)
163             if fld is not None:
164                 return fld.i2h(self, v)
165             return v
166         raise AttributeError(attr)
167
168     def setfieldval(self, attr, val):
169         if self.default_fields.has_key(attr):
170             fld = self.get_field(attr)
171             if fld is None:
172                 any2i = lambda x,y: y
173             else:
174                 any2i = fld.any2i
175             self.fields[attr] = any2i(self, val)
176             self.explicit=0
177         elif attr == "payload":
178             self.remove_payload()
179             self.add_payload(val)
180         else:
181             self.payload.setfieldval(attr,val)
182
183     def __setattr__(self, attr, val):
184         if self.initialized:
185             try:
186                 self.setfieldval(attr,val)
187             except AttributeError:
188                 pass
189             else:
190                 return
191         self.__dict__[attr] = val
192
193     def delfieldval(self, attr):
194         if self.fields.has_key(attr):
195             del(self.fields[attr])
196             self.explicit=0 # in case a default value must be explicited
197         elif self.default_fields.has_key(attr):
198             pass
199         elif attr == "payload":
200             self.remove_payload()
201         else:
202             self.payload.delfieldval(attr)
203
204     def __delattr__(self, attr):
205         if self.initialized:
206             try:
207                 self.delfieldval(attr)
208             except AttributeError:
209                 pass
210             else:
211                 return
212         if self.__dict__.has_key(attr):
213             del(self.__dict__[attr])
214         else:
215             raise AttributeError(attr)
216            
217     def __repr__(self):
218         s = ""
219         ct = conf.color_theme
220         for f in self.fields_desc:
221             if isinstance(f, ConditionalField) and not f._evalcond(self):
222                 continue
223             if f.name in self.fields:
224                 val = f.i2repr(self, self.fields[f.name])
225             elif f.name in self.overloaded_fields:
226                 val =  f.i2repr(self, self.overloaded_fields[f.name])
227             else:
228                 continue
229             if isinstance(f, Emph):
230                 ncol = ct.emph_field_name
231                 vcol = ct.emph_field_value
232             else:
233                 ncol = ct.field_name
234                 vcol = ct.field_value
235
236                
237             s += " %s%s%s" % (ncol(f.name),
238                               ct.punct("="),
239                               vcol(val))
240         return "%s%s %s %s%s%s"% (ct.punct("<"),
241                                   ct.layer_name(self.__class__.__name__),
242                                   s,
243                                   ct.punct("|"),
244                                   repr(self.payload),
245                                   ct.punct(">"))
246     def __str__(self):
247         return self.build()
248     def __div__(self, other):
249         if isinstance(other, Packet):
250             cloneA = self.copy()
251             cloneB = other.copy()
252             cloneA.add_payload(cloneB)
253             return cloneA
254         elif type(other) is str:
255             return self/conf.raw_layer(load=other)
256         else:
257             return other.__rdiv__(self)
258     def __rdiv__(self, other):
259         if type(other) is str:
260             return conf.raw_layer(load=other)/self
261         else:
262             raise TypeError
263     def __mul__(self, other):
264         if type(other) is int:
265             return  [self]*other
266         else:
267             raise TypeError
268     def __rmul__(self,other):
269         return self.__mul__(other)
270    
271     def __nonzero__(self):
272         return True
273     def __len__(self):
274         return len(self.__str__())
275     def do_build(self):
276         p=""
277         for f in self.fields_desc:
278             p = f.addfield(self, p, self.getfieldval(f.name))
279         return p
280    
281     def post_build(self, pkt, pay):
282         """DEV: called right after the current layer is build."""
283         return pkt+pay
284
285     def build_payload(self):
286         return self.payload.build(internal=1)
287
288     def build(self,internal=0):
289         if not self.explicit:
290             self = self.__iter__().next()
291         pkt = self.do_build()
292         for t in self.post_transforms:
293             pkt = t(pkt)
294         pay = self.build_payload()
295         p = self.post_build(pkt,pay)
296         if not internal:
297             pad = self.payload.getlayer(Padding)
298             if pad:
299                 p += pad.build()
300             p = self.build_done(p)
301         return p
302
303     def build_done(self, p):
304         return self.payload.build_done(p)
305
306     def do_build_ps(self):
307         p=""
308         pl = []
309         q=""
310         for f in self.fields_desc:
311             p = f.addfield(self, p, self.getfieldval(f.name) )
312             if type(p) is str:
313                 r = p[len(q):]
314                 q = p
315             else:
316                 r = ""
317             pl.append( (f, f.i2repr(self,self.getfieldval(f.name)), r) )
318            
319         pkt,lst = self.payload.build_ps(internal=1)
320         p += pkt
321         lst.append( (self, pl) )
322        
323         return p,lst
324    
325     def build_ps(self,internal=0):
326         p,lst = self.do_build_ps()
327 #        if not internal:
328 #            pkt = self
329 #            while pkt.haslayer(Padding):
330 #                pkt = pkt.getlayer(Padding)
331 #                lst.append( (pkt, [ ("loakjkjd", pkt.load, pkt.load) ] ) )
332 #                p += pkt.load
333 #                pkt = pkt.payload
334         return p,lst
335
336
337     def psdump(self, filename=None, **kargs):
338         """psdump(filename=None, layer_shift=0, rebuild=1)
339 Creates an EPS file describing a packet. If filename is not provided a temporary file is created and gs is called."""
340         canvas = self.canvas_dump(**kargs)
341         if filename is None:
342             fname = "/tmp/scapy.%i"%os.getpid()
343             canvas.writeEPSfile(fname)
344             os.system("%s '%s.eps' &" % (conf.prog.psreader,fname))
345         else:
346             canvas.writeEPSfile(filename)
347
348     def pdfdump(self, filename=None, **kargs):
349         """pdfdump(filename=None, layer_shift=0, rebuild=1)
350         Creates a PDF file describing a packet. If filename is not provided a temporary file is created and xpdf is called."""
351         canvas = self.canvas_dump(**kargs)
352         if filename is None:
353             fname = "/tmp/scapy.%i"%os.getpid()
354             canvas.writePDFfile(fname)
355             os.system("%s '%s.pdf' &" % (conf.prog.pdfreader,fname))
356         else:
357             canvas.writePDFfile(filename)
358
359        
360     def canvas_dump(self, layer_shift=0, rebuild=1):
361         canvas = pyx.canvas.canvas()
362         if rebuild:
363             p,t = self.__class__(str(self)).build_ps()
364         else:
365             p,t = self.build_ps()
366         YTXT=len(t)
367         for n,l in t:
368             YTXT += len(l)
369         YTXT = float(YTXT)
370         YDUMP=YTXT
371
372         XSTART = 1
373         XDSTART = 10
374         y = 0.0
375         yd = 0.0
376         xd = 0
377         XMUL= 0.55
378         YMUL = 0.4
379    
380         backcolor=colgen(0.6, 0.8, 1.0, trans=pyx.color.rgb)
381         forecolor=colgen(0.2, 0.5, 0.8, trans=pyx.color.rgb)
382 #        backcolor=makecol(0.376, 0.729, 0.525, 1.0)
383         
384        
385         def hexstr(x):
386             s = []
387             for c in x:
388                 s.append("%02x" % ord(c))
389             return " ".join(s)
390
391                
392         def make_dump_txt(x,y,txt):
393             return pyx.text.text(XDSTART+x*XMUL, (YDUMP-y)*YMUL, r"\tt{%s}"%hexstr(txt), [pyx.text.size.Large])
394
395         def make_box(o):
396             return pyx.box.rect(o.left(), o.bottom(), o.width(), o.height(), relcenter=(0.5,0.5))
397
398         def make_frame(lst):
399             if len(lst) == 1:
400                 b = lst[0].bbox()
401                 b.enlarge(pyx.unit.u_pt)
402                 return b.path()
403             else:
404                 fb = lst[0].bbox()
405                 fb.enlarge(pyx.unit.u_pt)
406                 lb = lst[-1].bbox()
407                 lb.enlarge(pyx.unit.u_pt)
408                 if len(lst) == 2 and fb.left() > lb.right():
409                     return pyx.path.path(pyx.path.moveto(fb.right(), fb.top()),
410                                          pyx.path.lineto(fb.left(), fb.top()),
411                                          pyx.path.lineto(fb.left(), fb.bottom()),
412                                          pyx.path.lineto(fb.right(), fb.bottom()),
413                                          pyx.path.moveto(lb.left(), lb.top()),
414                                          pyx.path.lineto(lb.right(), lb.top()),
415                                          pyx.path.lineto(lb.right(), lb.bottom()),
416                                          pyx.path.lineto(lb.left(), lb.bottom()))
417                 else:
418                     # XXX
419                     gb = lst[1].bbox()
420                     if gb != lb:
421                         gb.enlarge(pyx.unit.u_pt)
422                     kb = lst[-2].bbox()
423                     if kb != gb and kb != lb:
424                         kb.enlarge(pyx.unit.u_pt)
425                     return pyx.path.path(pyx.path.moveto(fb.left(), fb.top()),
426                                          pyx.path.lineto(fb.right(), fb.top()),
427                                          pyx.path.lineto(fb.right(), kb.bottom()),
428                                          pyx.path.lineto(lb.right(), kb.bottom()),
429                                          pyx.path.lineto(lb.right(), lb.bottom()),
430                                          pyx.path.lineto(lb.left(), lb.bottom()),
431                                          pyx.path.lineto(lb.left(), gb.top()),
432                                          pyx.path.lineto(fb.left(), gb.top()),
433                                          pyx.path.closepath(),)
434                                          
435
436         def make_dump(s, shift=0, y=0, col=None, bkcol=None, larg=16):
437             c = pyx.canvas.canvas()
438             tlist = []
439             while s:
440                 dmp,s = s[:larg-shift],s[larg-shift:]
441                 txt = make_dump_txt(shift, y, dmp)
442                 tlist.append(txt)
443                 shift += len(dmp)
444                 if shift >= 16:
445                     shift = 0
446                     y += 1
447             if col is None:
448                 col = pyx.color.rgb.red
449             if bkcol is None:
450                 col = pyx.color.rgb.white
451             c.stroke(make_frame(tlist),[col,pyx.deco.filled([bkcol]),pyx.style.linewidth.Thick])
452             for txt in tlist:
453                 c.insert(txt)
454             return c, tlist[-1].bbox(), shift, y
455                            
456
457         last_shift,last_y=0,0.0
458         while t:
459             bkcol = backcolor.next()
460             proto,fields = t.pop()
461             y += 0.5
462             pt = pyx.text.text(XSTART, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % proto.name, [ pyx.text.size.Large])
463             y += 1
464             ptbb=pt.bbox()
465             ptbb.enlarge(pyx.unit.u_pt*2)
466             canvas.stroke(ptbb.path(),[pyx.color.rgb.black, pyx.deco.filled([bkcol])])
467             canvas.insert(pt)
468             for fname, fval, fdump in fields:
469                 col = forecolor.next()
470                 ft = pyx.text.text(XSTART, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % tex_escape(fname.name))
471                 if fval is not None:
472                     if len(fval) > 18:
473                         fval = fval[:18]+"[...]"
474                 else:
475                     fval=""
476                 vt = pyx.text.text(XSTART+3, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % tex_escape(fval))
477                 y += 1.0
478                 if fdump:
479                     dt,target,last_shift,last_y = make_dump(fdump, last_shift, last_y, col, bkcol)
480
481                     dtb = dt.bbox()
482                     dtb=target
483                     vtb = vt.bbox()
484                     bxvt = make_box(vtb)
485                     bxdt = make_box(dtb)
486                     dtb.enlarge(pyx.unit.u_pt)
487                     try:
488                         if yd < 0:
489                             cnx = pyx.connector.curve(bxvt,bxdt,absangle1=0, absangle2=-90)
490                         else:
491                             cnx = pyx.connector.curve(bxvt,bxdt,absangle1=0, absangle2=90)
492                     except:
493                         pass
494                     else:
495                         canvas.stroke(cnx,[pyx.style.linewidth.thin,pyx.deco.earrow.small,col])
496                        
497                     canvas.insert(dt)
498                
499                 canvas.insert(ft)
500                 canvas.insert(vt)
501             last_y += layer_shift
502    
503         return canvas
504
505
506
507     def extract_padding(self, s):
508         """DEV: to be overloaded to extract current layer's padding. Return a couple of strings (actual layer, padding)"""
509         return s,None
510
511     def post_dissect(self, s):
512         """DEV: is called right after the current layer has been dissected"""
513         return s
514
515     def pre_dissect(self, s):
516         """DEV: is called right before the current layer is dissected"""
517         return s
518
519     def do_dissect(self, s):
520         flist = self.fields_desc[:]
521         flist.reverse()
522         while s and flist:
523             f = flist.pop()
524             s,fval = f.getfield(self, s)
525             self.fields[f.name] = fval
526            
527         return s
528
529     def do_dissect_payload(self, s):
530         if s:
531             cls = self.guess_payload_class(s)
532             try:
533                 p = cls(s, _internal=1, _underlayer=self)
534             except KeyboardInterrupt:
535                 raise
536             except:
537                 if conf.debug_dissector:
538                     if isinstance(cls,type) and issubclass(cls,Packet):
539                         log_runtime.error("%s dissector failed" % cls.name)
540                     else:
541                         log_runtime.error("%s.guess_payload_class() returned [%s]" % (self.__class__.__name__,repr(cls)))
542                     if cls is not None:
543                         raise
544                 p = conf.raw_layer(s, _internal=1, _underlayer=self)
545             self.add_payload(p)
546
547     def dissect(self, s):
548         s = self.pre_dissect(s)
549
550         s = self.do_dissect(s)
551
552         s = self.post_dissect(s)
553            
554         payl,pad = self.extract_padding(s)
555         self.do_dissect_payload(payl)
556         if pad and conf.padding:
557             self.add_payload(Padding(pad))
558
559
560     def guess_payload_class(self, payload):
561         """DEV: Guesses the next payload class from layer bonds. Can be overloaded to use a different mechanism."""
562         for t in self.aliastypes:
563             for fval, cls in t.payload_guess:
564                 ok = 1
565                 for k in fval.keys():
566                     if not hasattr(self, k) or fval[k] != self.getfieldval(k):
567                         ok = 0
568                         break
569                 if ok:
570                     return cls
571         return self.default_payload_class(payload)
572    
573     def default_payload_class(self, payload):
574         """DEV: Returns the default payload class if nothing has been found by the guess_payload_class() method."""
575         return conf.raw_layer
576
577     def hide_defaults(self):
578         """Removes fields' values that are the same as default values."""
579         for k in self.fields.keys():
580             if self.default_fields.has_key(k):
581                 if self.default_fields[k] == self.fields[k]:
582                     del(self.fields[k])
583         self.payload.hide_defaults()
584            
585     def clone_with(self, payload=None, **kargs):
586         pkt = self.__class__()
587         pkt.explicit = 1
588         pkt.fields = kargs
589         pkt.time = self.time
590         pkt.underlayer = self.underlayer
591         pkt.overload_fields = self.overload_fields.copy()
592         pkt.post_transforms = self.post_transforms
593         if payload is not None:
594             pkt.add_payload(payload)
595         return pkt
596        
597
598     def __iter__(self):
599         def loop(todo, done, self=self):
600             if todo:
601                 eltname = todo.pop()
602                 elt = self.getfieldval(eltname)
603                 if not isinstance(elt, Gen):
604                     if self.get_field(eltname).islist:
605                         elt = SetGen([elt])
606                     else:
607                         elt = SetGen(elt)
608                 for e in elt:
609                     done[eltname]=e
610                     for x in loop(todo[:], done):
611                         yield x
612             else:
613                 if isinstance(self.payload,NoPayload):
614                     payloads = [None]
615                 else:
616                     payloads = self.payload
617                 for payl in payloads:
618                     done2=done.copy()
619                     for k in done2:
620                         if isinstance(done2[k], VolatileValue):
621                             done2[k] = done2[k]._fix()
622                     pkt = self.clone_with(payload=payl, **done2)
623                     yield pkt
624
625         if self.explicit:
626             todo = []
627             done = self.fields
628         else:
629             todo = [ k for (k,v) in itertools.chain(self.default_fields.iteritems(),
630                                                     self.overloaded_fields.iteritems())
631                      if isinstance(v, VolatileValue) ] + self.fields.keys()
632             done = {}
633         return loop(todo, done)
634
635     def __gt__(self, other):
636         """True if other is an answer from self (self ==> other)."""
637         if isinstance(other, Packet):
638             return other < self
639         elif type(other) is str:
640             return 1
641         else:
642             raise TypeError((self, other))
643     def __lt__(self, other):
644         """True if self is an answer from other (other ==> self)."""
645         if isinstance(other, Packet):
646             return self.answers(other)
647         elif type(other) is str:
648             return 1
649         else:
650             raise TypeError((self, other))
651
652     def __eq__(self, other):
653         if not isinstance(other, self.__class__):
654             return False
655         for f in self.fields_desc:
656             if f not in other.fields_desc:
657                 return False
658             if self.getfieldval(f.name) != other.getfieldval(f.name):
659                 return False
660         return self.payload == other.payload
661
662     def __ne__(self, other):
663         return not self.__eq__(other)
664
665     def hashret(self):
666         """DEV: returns a string that has the same value for a request and its answer."""
667         return self.payload.hashret()
668     def answers(self, other):
669         """DEV: true if self is an answer from other"""
670         if other.__class__ == self.__class__:
671             return self.payload.answers(other.payload)
672         return 0
673
674     def haslayer(self, cls):
675         """true if self has a layer that is an instance of cls. Superseded by "cls in self" syntax."""
676         if self.__class__ == cls or self.__class__.__name__ == cls:
677             return 1
678         for f in self.packetfields:
679             fvalue_gen = self.getfieldval(f.name)
680             if fvalue_gen is None:
681                 continue
682             if not f.islist:
683                 fvalue_gen = SetGen(fvalue_gen,_iterpacket=0)
684             for fvalue in fvalue_gen:
685                 if isinstance(fvalue, Packet):
686                     ret = fvalue.haslayer(cls)
687                     if ret:
688                         return ret
689         return self.payload.haslayer(cls)
690     def getlayer(self, cls, nb=1, _track=None):
691         """Return the nb^th layer that is an instance of cls."""
692         if type(cls) is str and "." in cls:
693             ccls,fld = cls.split(".",1)
694         else:
695             ccls,fld = cls,None
696         if self.__class__ == cls or self.__class__.name == ccls:
697             if nb == 1:
698                 if fld is None:
699                     return self
700                 else:
701                     return self.getfieldval(fld)
702             else:
703                 nb -=1
704         for f in self.packetfields:
705             fvalue_gen = self.getfieldval(f.name)
706             if fvalue_gen is None:
707                 continue
708             if not f.islist:
709                 fvalue_gen = SetGen(fvalue_gen,_iterpacket=0)
710             for fvalue in fvalue_gen:
711                 if isinstance(fvalue, Packet):
712                     track=[]
713                     ret = fvalue.getlayer(cls, nb, _track=track)
714                     if ret is not None:
715                         return ret
716                     nb = track[0]
717         return self.payload.getlayer(cls,nb,_track=_track)
718
719     def __getitem__(self, cls):
720         if type(cls) is slice:
721             lname = cls.start
722             if cls.stop:
723                 ret = self.getlayer(cls.start, cls.stop)
724             else:
725                 ret = self.getlayer(cls.start)
726             if ret is None and cls.step is not None:
727                 ret = cls.step
728         else:
729             lname=cls
730             ret = self.getlayer(cls)
731         if ret is None:
732             if type(lname) is Packet_metaclass:
733                 lname = lname.__name__
734             elif type(lname) is not str:
735                 lname = repr(lname)
736             raise IndexError("Layer [%s] not found" % lname)
737         return ret
738
739     def __delitem__(self, cls):
740         del(self[cls].underlayer.payload)
741
742     def __setitem__(self, cls, val):
743         self[cls].underlayer.payload = val
744    
745     def __contains__(self, cls):
746         """"cls in self" returns true if self has a layer which is an instance of cls."""
747         return self.haslayer(cls)
748
749     def route(self):
750         return (None,None,None)
751    
752
753     def display(self,*args,**kargs):  # Deprecated. Use show()
754         """Deprecated. Use show() method."""
755         self.show(*args,**kargs)
756     def show(self, indent=3, lvl="", label_lvl=""):
757         """Prints a hierarchical view of the packet. "indent" gives the size of indentation for each layer."""
758         ct = conf.color_theme
759         print "%s%s %s %s" % (label_lvl,
760                               ct.punct("###["),
761                               ct.layer_name(self.name),
762                               ct.punct("]###"))
763         for f in self.fields_desc:
764             if isinstance(f, ConditionalField) and not f._evalcond(self):
765                 continue
766             if isinstance(f, Emph):
767                 ncol = ct.emph_field_name
768                 vcol = ct.emph_field_value
769             else:
770                 ncol = ct.field_name
771                 vcol = ct.field_value
772             fvalue = self.getfieldval(f.name)
773             if isinstance(fvalue, Packet) or (f.islist and f.holds_packets and type(fvalue) is list):
774                 print "%s  \\%-10s\\" % (label_lvl+lvl, ncol(f.name))
775                 fvalue_gen = SetGen(fvalue,_iterpacket=0)
776                 for fvalue in fvalue_gen:
777                     fvalue.show(indent=indent, label_lvl=label_lvl+lvl+"   |")
778             else:
779                 print "%s  %-10s%s %s" % (label_lvl+lvl,
780                                           ncol(f.name),
781                                           ct.punct("="),
782                                           vcol(f.i2repr(self,fvalue)))
783         self.payload.show(indent=indent, lvl=lvl+(" "*indent*self.show_indent), label_lvl=label_lvl)
784     def show2(self):
785         """Prints a hierarchical view of an assembled version of the packet, so that automatic fields are calculated (checksums, etc.)"""
786         self.__class__(str(self)).show()
787
788     def sprintf(self, fmt, relax=1):
789         """sprintf(format, [relax=1]) -> str
790 where format is a string that can include directives. A directive begins and
791 ends by % and has the following format %[fmt[r],][cls[:nb].]field%.
792
793