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