| changeset 806: | 87949e07281c |
| parent: | c919e540a57b |
| child: | 19df3f1cd92b |
| author: | Phil <phil@secdev.org> |
| date: | Wed Apr 23 19:35:18 2008 +0200 (21 months ago) |
| permissions: | -rwxr-xr-x |
| description: | Improved mib parsing a bit It will never be perfect until I implement a real parser instead of using regexp |
1#! /usr/bin/env python3#############################################################################4## ##5## scapy.py --- Interactive packet manipulation tool ##6## see http://www.secdev.org/projects/scapy/ ##7## for more informations ##8## ##9## Copyright (C) 2003 Philippe Biondi <phil@secdev.org> ##10## ##11## This program is free software; you can redistribute it and/or modify it ##12## under the terms of the GNU General Public License version 2 as ##13## published by the Free Software Foundation; version 2. ##14## ##15## This program is distributed in the hope that it will be useful, but ##16## WITHOUT ANY WARRANTY; without even the implied warranty of ##17## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ##18## General Public License for more details. ##19## ##20#############################################################################23from __future__ import generators24import os26VERSION = "1.2.0.2"28DEFAULT_CONFIG_FILE = os.path.join(os.environ["HOME"], ".scapy_startup.py")30try:31 os.stat(DEFAULT_CONFIG_FILE)32except OSError:33 DEFAULT_CONFIG_FILE = None35def usage():36 print """Usage: scapy.py [-s sessionfile] [-c new_startup_file] [-C]37 -C: do not read startup file"""38 sys.exit(0)41#############################42##### Logging subsystem #####43#############################45class Scapy_Exception(Exception):46 pass48import logging,traceback,time50class ScapyFreqFilter(logging.Filter):51 def __init__(self):52 logging.Filter.__init__(self)53 self.warning_table = {}54 def filter(self, record):55 wt = conf.warning_threshold56 if wt > 0:57 stk = traceback.extract_stack()58 caller=None59 for f,l,n,c in stk:60 if n == 'warning':61 break62 caller = l63 tm,nb = self.warning_table.get(caller, (0,0))64 ltm = time.time()65 if ltm-tm > wt:66 tm = ltm67 nb = 068 else:69 if nb < 2:70 nb += 171 if nb == 2:72 record.msg = "more "+record.msg73 else:74 return 075 self.warning_table[caller] = (tm,nb)76 return 178log_scapy = logging.getLogger("scapy")79console_handler = logging.StreamHandler()80console_handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))81log_scapy.addHandler(console_handler)82log_runtime = logging.getLogger("scapy.runtime") # logs at runtime83log_runtime.addFilter(ScapyFreqFilter())84log_interactive = logging.getLogger("scapy.interactive") # logs in interactive functions85log_loading = logging.getLogger("scapy.loading") # logs when loading scapy87if __name__ == "__main__":88 log_scapy.setLevel(1)91##################92##### Module #####93##################95import socket, sys, getopt, string, struct, random, code96import cPickle, copy, types, gzip, base64, re, zlib, array97from sets import Set98from select import select99from glob import glob100from fcntl import ioctl101import itertools102import fcntl103import warnings104warnings.filterwarnings("ignore","tempnam",RuntimeWarning, __name__)107try:108 import Gnuplot109 GNUPLOT=1110except ImportError:111 log_loading.info("did not find python gnuplot wrapper . Won't be able to plot")112 GNUPLOT=0114try:115 import pyx116 PYX=1117except ImportError:118 log_loading.info("Can't import PyX. Won't be able to use psdump() or pdfdump()")119 PYX=0122LINUX=sys.platform.startswith("linux")123OPENBSD=sys.platform.startswith("openbsd")124FREEBSD=sys.platform.startswith("freebsd")125DARWIN=sys.platform.startswith("darwin")126BIG_ENDIAN= struct.pack("H",1) == "\x00\x01"127X86_64 = (os.uname()[4] == 'x86_64')128SOLARIS=sys.platform.startswith("sunos")131if LINUX:132 DNET=PCAP=0133else:134 DNET=PCAP=1137if PCAP:138 try:139 import pcap140 PCAP = 1141 except ImportError:142 if LINUX:143 log_loading.warning("did not find pcap module. Fallback to linux primitives")144 PCAP = 0145 else:146 if __name__ == "__main__":147 log_loading.error("did not find pcap module")148 raise SystemExit149 else:150 raise152if DNET:153 try:154 import dnet155 DNET = 1156 except ImportError:157 if LINUX:158 log_loading.warning("did not find dnet module. Fallback to linux primitives")159 DNET = 0160 else:161 if __name__ == "__main__":162 log_loading.error("did not find dnet module")163 raise SystemExit164 else:165 raise167if not PCAP:168 f = os.popen("tcpdump -V 2> /dev/null")169 if f.close() >> 8 == 0x7f:170 log_loading.warning("Failed to execute tcpdump. Check it is installed and in the PATH")171 TCPDUMP=0172 else:173 TCPDUMP=1174 del(f)178try:179 from Crypto.Cipher import ARC4180except ImportError:181 log_loading.info("Can't find Crypto python lib. Won't be able to decrypt WEP")184# Workarround bug 643005 : https://sourceforge.net/tracker/?func=detail&atid=105470&aid=643005&group_id=5470185try:186 socket.inet_aton("255.255.255.255")187except socket.error:188 def inet_aton(x):189 if x == "255.255.255.255":190 return "\xff"*4191 else:192 return socket.inet_aton(x)193else:194 inet_aton = socket.inet_aton196inet_ntoa = socket.inet_ntoa197try:198 inet_ntop = socket.inet_ntop199 inet_pton = socket.inet_pton200except AttributeError:201 log_loading.info("inet_ntop/pton functions not found. Python IPv6 support not present")204if SOLARIS:205 # GRE is missing on Solaris206 socket.IPPROTO_GRE = 47208###############################209## Direct Access dictionnary ##210###############################212def fixname(x):213 if x and x[0] in "0123456789":214 x = "n_"+x215 return x.translate("________________________________________________0123456789_______ABCDEFGHIJKLMNOPQRSTUVWXYZ______abcdefghijklmnopqrstuvwxyz_____________________________________________________________________________________________________________________________________")218class DADict_Exception(Scapy_Exception):219 pass221class DADict:222 def __init__(self, _name="DADict", **kargs):223 self._name=_name224 self.__dict__.update(kargs)225 def fixname(self,val):226 return fixname(val)227 def __contains__(self, val):228 return val in self.__dict__229 def __getitem__(self, attr):230 return getattr(self, attr)231 def __setitem__(self, attr, val):232 return setattr(self, self.fixname(attr), val)233 def __iter__(self):234 return iter(map(lambda (x,y):y,filter(lambda (x,y):x and x[0]!="_", self.__dict__.items())))235 def _show(self):236 for k in self.__dict__.keys():237 if k and k[0] != "_":238 print "%10s = %r" % (k,getattr(self,k))239 def __repr__(self):240 return "<%s/ %s>" % (self._name," ".join(filter(lambda x:x and x[0]!="_",self.__dict__.keys())))242 def _branch(self, br, uniq=0):243 if uniq and br._name in self:244 raise DADict_Exception("DADict: [%s] already branched in [%s]" % (br._name, self._name))245 self[br._name] = br247 def _my_find(self, *args, **kargs):248 if args and self._name not in args:249 return False250 for k in kargs:251 if k not in self or self[k] != kargs[k]:252 return False253 return True255 def _find(self, *args, **kargs):256 return self._recurs_find((), *args, **kargs)257 def _recurs_find(self, path, *args, **kargs):258 if self in path:259 return None260 if self._my_find(*args, **kargs):261 return self262 for o in self:263 if isinstance(o, DADict):264 p = o._recurs_find(path+(self,), *args, **kargs)265 if p is not None:266 return p267 return None268 def _find_all(self, *args, **kargs):269 return self._recurs_find_all((), *args, **kargs)270 def _recurs_find_all(self, path, *args, **kargs):271 r = []272 if self in path:273 return r274 if self._my_find(*args, **kargs):275 r.append(self)276 for o in self:277 if isinstance(o, DADict):278 p = o._recurs_find_all(path+(self,), *args, **kargs)279 r += p280 return r281 def keys(self):282 return filter(lambda x:x and x[0]!="_", self.__dict__.keys())286############287## Consts ##288############290ETHER_ANY = "\x00"*6291ETHER_BROADCAST = "\xff"*6293ETH_P_ALL = 3294ETH_P_IP = 0x800295ETH_P_ARP = 0x806297# From net/if_arp.h298ARPHDR_ETHER = 1299ARPHDR_METRICOM = 23300ARPHDR_PPP = 512301ARPHDR_LOOPBACK = 772302ARPHDR_TUN = 65534304# From bits/ioctls.h305SIOCGIFHWADDR = 0x8927 # Get hardware address306SIOCGIFADDR = 0x8915 # get PA address307SIOCGIFNETMASK = 0x891b # get network PA mask308SIOCGIFNAME = 0x8910 # get iface name309SIOCSIFLINK = 0x8911 # set iface channel310SIOCGIFCONF = 0x8912 # get iface list311SIOCGIFFLAGS = 0x8913 # get flags312SIOCSIFFLAGS = 0x8914 # set flags313SIOCGIFINDEX = 0x8933 # name -> if_index mapping314SIOCGIFCOUNT = 0x8938 # get number of devices315SIOCGSTAMP = 0x8906 # get packet timestamp (as a timeval)318# From if.h319IFF_UP = 0x1 # Interface is up.320IFF_BROADCAST = 0x2 # Broadcast address valid.321IFF_DEBUG = 0x4 # Turn on debugging.322IFF_LOOPBACK = 0x8 # Is a loopback net.323IFF_POINTOPOINT = 0x10 # Interface is point-to-point link.324IFF_NOTRAILERS = 0x20 # Avoid use of trailers.325IFF_RUNNING = 0x40 # Resources allocated.326IFF_NOARP = 0x80 # No address resolution protocol.327IFF_PROMISC = 0x100 # Receive all packets.331# From netpacket/packet.h332PACKET_ADD_MEMBERSHIP = 1333PACKET_DROP_MEMBERSHIP = 2334PACKET_RECV_OUTPUT = 3335PACKET_RX_RING = 5336PACKET_STATISTICS = 6337PACKET_MR_MULTICAST = 0338PACKET_MR_PROMISC = 1339PACKET_MR_ALLMULTI = 2342# From bits/socket.h343SOL_PACKET = 263344# From asm/socket.h345SO_ATTACH_FILTER = 26346SOL_SOCKET = 1348# From net/route.h349RTF_UP = 0x0001 # Route usable350RTF_REJECT = 0x0200352# From BSD net/bpf.h353#BIOCIMMEDIATE=0x80044270354BIOCIMMEDIATE=-2147204496356MTU = 1600359# file parsing to get some values :361def load_protocols(filename):362 spaces = re.compile("[ \t]+|\n")363 dct = DADict(_name=filename)364 try:365 for l in open(filename):366 try:367 shrp = l.find("#")368 if shrp >= 0:369 l = l[:shrp]370 l = l.strip()371 if not l:372 continue373 lt = tuple(re.split(spaces, l))374 if len(lt) < 2 or not lt[0]:375 continue376 dct[lt[0]] = int(lt[1])377 except Exception,e:378 log_loading.info("Couldn't parse file [%s]: line [%r] (%s)" % (filename,l,e))379 except IOError:380 log_loading.info("Can't open /etc/protocols file")381 return dct383IP_PROTOS=load_protocols("/etc/protocols")385def load_ethertypes(filename):386 spaces = re.compile("[ \t]+|\n")387 dct = DADict(_name=filename)388 try:389 f=open(filename)390 for l in f:391 try:392 shrp = l.find("#")393 if shrp >= 0:394 l = l[:shrp]395 l = l.strip()396 if not l:397 continue398 lt = tuple(re.split(spaces, l))399 if len(lt) < 2 or not lt[0]:400 continue401 dct[lt[0]] = int(lt[1], 16)402 except Exception,e:403 log_loading.info("Couldn't parse file [%s]: line [%r] (%s)" % (filename,l,e))404 f.close()405 except IOError,msg:406 pass407 return dct409ETHER_TYPES=load_ethertypes("/etc/ethertypes")411def load_services(filename):412 spaces = re.compile("[ \t]+|\n")413 tdct=DADict(_name="%s-tcp"%filename)414 udct=DADict(_name="%s-udp"%filename)415 try:416 f=open(filename)417 for l in f:418 try:419 shrp = l.find("#")420 if shrp >= 0:421 l = l[:shrp]422 l = l.strip()423 if not l:424 continue425 lt = tuple(re.split(spaces, l))426 if len(lt) < 2 or not lt[0]:427 continue428 if lt[1].endswith("/tcp"):429 tdct[lt[0]] = int(lt[1].split('/')[0])430 elif lt[1].endswith("/udp"):431 udct[lt[0]] = int(lt[1].split('/')[0])432 except Exception,e:433 log_loading.warning("Couldn't file [%s]: line [%r] (%s)" % (filename,l,e))434 f.close()435 except IOError:436 log_loading.info("Can't open /etc/services file")437 return tdct,udct439TCP_SERVICES,UDP_SERVICES=load_services("/etc/services")441class ManufDA(DADict):442 def fixname(self, val):443 return val444 def _get_manuf_couple(self, mac):445 oui = ":".join(mac.split(":")[:3]).upper()446 return self.__dict__.get(oui,(mac,mac))447 def _get_manuf(self, mac):448 return self._get_manuf_couple(mac)[1]449 def _get_short_manuf(self, mac):450 return self._get_manuf_couple(mac)[0]451 def _resolve_MAC(self, mac):452 oui = ":".join(mac.split(":")[:3]).upper()453 if oui in self:454 return ":".join([self[oui][0]]+ mac.split(":")[3:])455 return mac460def load_manuf(filename):461 try:462 manufdb=ManufDA(_name=filename)463 for l in open(filename):464 try:465 l = l.strip()466 if not l or l.startswith("#"):467 continue468 oui,shrt=l.split()[:2]469 i = l.find("#")470 if i < 0:471 lng=shrt472 else:473 lng = l[i+2:]474 manufdb[oui] = shrt,lng475 except Exception,e:476 log_loading.warning("Couldn't parse one line from [%s] [%r] (%s)" % (filename, l, e))477 except IOError:478 #log_loading.warning("Couldn't open [%s] file" % filename)479 pass480 return manufdb482MANUFDB = load_manuf("/usr/share/wireshark/wireshark/manuf")487###########488## Tools ##489###########491def sane_color(x):492 r=""493 for i in x:494 j = ord(i)495 if (j < 32) or (j >= 127):496 r=r+conf.color_theme.not_printable(".")497 else:498 r=r+i499 return r501def sane(x):502 r=""503 for i in x:504 j = ord(i)505 if (j < 32) or (j >= 127):506 r=r+"."507 else:508 r=r+i509 return r511def lhex(x):512 if type(x) in (int,long):513 return hex(x)514 elif type(x) is tuple:515 return "(%s)" % ", ".join(map(lhex, x))516 elif type(x) is list:517 return "[%s]" % ", ".join(map(lhex, x))518 else:519 return x521def hexdump(x):522 x=str(x)523 l = len(x)524 i = 0525 while i < l:526 print "%04x " % i,527 for j in range(16):528 if i+j < l:529 print "%02X" % ord(x[i+j]),530 else:531 print " ",532 if j%16 == 7:533 print "",534 print " ",535 print sane_color(x[i:i+16])536 i += 16538def linehexdump(x, onlyasc=0, onlyhex=0):539 x = str(x)540 l = len(x)541 if not onlyasc:542 for i in range(l):543 print "%02X" % ord(x[i]),544 print "",545 if not onlyhex:546 print sane_color(x)548def chexdump(x):549 x=str(x)550 print ", ".join(map(lambda x: "%#04x"%ord(x), x))552def hexstr(x, onlyasc=0, onlyhex=0):553 s = []554 if not onlyasc:555 s.append(" ".join(map(lambda x:"%02x"%ord(x), x)))556 if not onlyhex:557 s.append(sane(x))558 return " ".join(s)561def hexdiff(x,y):562 x=str(x)[::-1]563 y=str(y)[::-1]564 SUBST=1565 INSERT=1566 d={}567 d[-1,-1] = 0,(-1,-1)568 for j in range(len(y)):569 d[-1,j] = d[-1,j-1][0]+INSERT, (-1,j-1)570 for i in range(len(x)):571 d[i,-1] = d[i-1,-1][0]+INSERT, (i-1,-1)573 for j in range(len(y)):574 for i in range(len(x)):575 d[i,j] = min( ( d[i-1,j-1][0]+SUBST*(x[i] != y[j]), (i-1,j-1) ),576 ( d[i-1,j][0]+INSERT, (i-1,j) ),577 ( d[i,j-1][0]+INSERT, (i,j-1) ) )580 backtrackx = []581 backtracky = []582 i=len(x)-1583 j=len(y)-1584 while not (i == j == -1):585 i2,j2 = d[i,j][1]586 backtrackx.append(x[i2+1:i+1])587 backtracky.append(y[j2+1:j+1])588 i,j = i2,j2592 x = y = i = 0593 colorize = { 0: lambda x:x,594 -1: conf.color_theme.left,595 1: conf.color_theme.right }597 dox=1598 doy=0599 l = len(backtrackx)600 while i < l:601 separate=0602 linex = backtrackx[i:i+16]603 liney = backtracky[i:i+16]604 xx = sum(len(k) for k in linex)605 yy = sum(len(k) for k in liney)606 if dox and not xx:607 dox = 0608 doy = 1609 if dox and linex == liney:610 doy=1612 if dox:613 xd = y614 j = 0615 while not linex[j]:616 j += 1617 xd -= 1618 print colorize[doy-dox]("%04x" % xd),619 x += xx620 line=linex621 else:622 print " ",623 if doy:624 yd = y625 j = 0626 while not liney[j]:627 j += 1628 yd -= 1629 print colorize[doy-dox]("%04x" % yd),630 y += yy631 line=liney632 else:633 print " ",635 print " ",637 cl = ""638 for j in range(16):639 if i+j < l:640 if line[j]:641 col = colorize[(linex[j]!=liney[j])*(doy-dox)]642 print col("%02X" % ord(line[j])),643 if linex[j]==liney[j]:644 cl += sane_color(line[j])645 else:646 cl += col(sane(line[j]))647 else:648 print " ",649 cl += " "650 else:651 print " ",652 if j == 7:653 print "",656 print " ",cl658 if doy or not yy:659 doy=0660 dox=1661 i += 16662 else:663 if yy:664 dox=0665 doy=1666 else:667 i += 16670crc32 = zlib.crc32672if BIG_ENDIAN:673 def checksum(pkt):674 if len(pkt) % 2 == 1:675 pkt += "\0"676 s = sum(array.array("H", pkt))677 s = (s >> 16) + (s & 0xffff)678 s += s >> 16679 s = ~s680 return s & 0xffff681else:682 def checksum(pkt):683 if len(pkt) % 2 == 1:684 pkt += "\0"685 s = sum(array.array("H", pkt))686 s = (s >> 16) + (s & 0xffff)687 s += s >> 16688 s = ~s689 return (((s>>8)&0xff)|s<<8) & 0xffff691def warning(x):692 log_runtime.warning(x)694def mac2str(mac):695 return "".join(map(lambda x: chr(int(x,16)), mac.split(":")))697def str2mac(s):698 return ("%02x:"*6)[:-1] % tuple(map(ord, s))700def strxor(x,y):701 return "".join(map(lambda x,y:chr(ord(x)^ord(y)),x,y))703def atol(x):704 try:705 ip = inet_aton(x)706 except socket.error:707 ip = inet_aton(socket.gethostbyname(x))708 return struct.unpack("!I", ip)[0]709def ltoa(x):710 return inet_ntoa(struct.pack("!I", x))712def itom(x):713 return (0xffffffff00000000L>>x)&0xffffffffL715def do_graph(graph,prog=None,format="svg",target=None, type=None,string=None,options=None):716 """do_graph(graph, prog=conf.prog.dot, format="svg",717 target="| conf.prog.display", options=None, [string=1]):718 string: if not None, simply return the graph string719 graph: GraphViz graph description720 format: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option721 target: filename or redirect. Defaults pipe to Imagemagick's display program722 prog: which graphviz program to use723 options: options to be passed to prog"""726 if string:727 return graph728 if type is not None:729 format=type730 if prog is None:731 prog = conf.prog.dot732 if target is None:733 target = "| %s" % conf.prog.display734 if format is not None:735 format = "-T %s" % format736 w,r = os.popen2("%s %s %s %s" % (prog,options or "", format or "", target))737 w.write(graph)738 w.close()740_TEX_TR = {741 "{":"{\\tt\\char123}",742 "}":"{\\tt\\char125}",743 "\\":"{\\tt\\char92}",744 "^":"\\^{}",745 "$":"\\$",746 "#":"\\#",747 "~":"\\~",748 "_":"\\_",749 "&":"\\&",750 "%":"\\%",751 "|":"{\\tt\\char124}",752 "~":"{\\tt\\char126}",753 "<":"{\\tt\\char60}",754 ">":"{\\tt\\char62}",755 }757def tex_escape(x):758 s = ""759 for c in x:760 s += _TEX_TR.get(c,c)761 return s763def colgen(*lstcol,**kargs):764 """Returns a generator that mixes provided quantities forever765 trans: a function to convert the three arguments into a color. lambda x,y,z:(x,y,z) by default"""766 if len(lstcol) < 2:767 lstcol *= 2768 trans = kargs.get("trans", lambda x,y,z: (x,y,z))769 while 1:770 for i in range(len(lstcol)):771 for j in range(len(lstcol)):772 for k in range(len(lstcol)):773 if i != j or j != k or k != i:774 yield trans(lstcol[(i+j)%len(lstcol)],lstcol[(j+k)%len(lstcol)],lstcol[(k+i)%len(lstcol)])776def incremental_label(label="tag%05i", start=0):777 while True:778 yield label % start779 start += 1781#########################782#### Enum management ####783#########################785class EnumElement:786 _value=None787 def __init__(self, key, value):788 self._key = key789 self._value = value790 def __repr__(self):791 return "<%s %s[%r]>" % (self.__dict__.get("_name", self.__class__.__name__), self._key, self._value)792 def __getattr__(self, attr):793 return getattr(self._value, attr)794 def __str__(self):795 return self._key796 def __eq__(self, other):797 return self._value == int(other)800class Enum_metaclass(type):801 element_class = EnumElement802 def __new__(cls, name, bases, dct):803 rdict={}804 for k,v in dct.iteritems():805 if type(v) is int:806 v = cls.element_class(k,v)807 dct[k] = v808 rdict[v] = k809 dct["__rdict__"] = rdict810 return super(Enum_metaclass, cls).__new__(cls, name, bases, dct)811 def __getitem__(self, attr):812 return self.__rdict__[attr]813 def __contains__(self, val):814 return val in self.__rdict__815 def get(self, attr, val=None):816 return self._rdict__.get(attr, val)817 def __repr__(self):818 return "<%s>" % self.__dict__.get("name", self.__name__)823##############################824## Session saving/restoring ##825##############################828def save_session(fname, session=None, pickleProto=-1):829 if session is None:830 session = scapy_session832 to_be_saved = session.copy()834 if to_be_saved.has_key("__builtins__"):835 del(to_be_saved["__builtins__"])837 for k in to_be_saved.keys():838 if type(to_be_saved[k]) in [types.TypeType, types.ClassType, types.ModuleType]:839 log_interactive.error("[%s] (%s) can't be saved." % (k, type(to_be_saved[k])))840 del(to_be_saved[k])842 try:843 os.rename(fname, fname+".bak")844 except OSError:845 pass846 f=gzip.open(fname,"wb")847 cPickle.dump(to_be_saved, f, pickleProto)848 f.close()850def load_session(fname):851 try:852 s = cPickle.load(gzip.open(fname,"rb"))853 except IOError:854 s = cPickle.load(open(fname,"rb"))855 scapy_session.clear()856 scapy_session.update(s)858def update_session(fname):859 try:860 s = cPickle.load(gzip.open(fname,"rb"))861 except IOError:862 s = cPickle.load(open(fname,"rb"))863 scapy_session.update(s)866def export_object(obj):867 print base64.encodestring(gzip.zlib.compress(cPickle.dumps(obj,2),9))869def import_object(obj=None):870 if obj is None:871 obj = sys.stdin.read()872 return cPickle.loads(gzip.zlib.decompress(base64.decodestring(obj.strip())))875def save_object(fname, obj):876 cPickle.dump(obj,gzip.open(fname,"wb"))878def load_object(fname):879 return cPickle.load(gzip.open(fname,"rb"))882######################883## Extension system ##884######################887def load_extension(filename):888 import imp889 paths = conf.extensions_paths890 if type(paths) is not list:891 paths = [paths]893 name = os.path.realpath(os.path.expanduser(filename))894 thepath = os.path.dirname(name)895 thename = os.path.basename(name)896 if thename.endswith(".py"):897 thename = thename[:-3]899 paths.insert(0, thepath)900 cwd=syspath=None901 try:902 cwd = os.getcwd()903 os.chdir(thepath)904 syspath = sys.path[:]905 sys.path += paths906 try:907 extf = imp.find_module(thename, paths)908 except ImportError:909 log_runtime.error("Module [%s] not found. Check conf.extensions_paths ?" % filename)910 else:911 ext = imp.load_module(thename, *extf)912 import __builtin__913 __builtin__.__dict__.update(ext.__dict__)914 finally:915 if syspath:916 sys.path=syspath917 if cwd:918 os.chdir(cwd)922#################923## Debug class ##924#################926class debug:927 recv=[]928 sent=[]929 match=[]932####################933## IP Tools class ##934####################936class IPTools:937 """Add more powers to a class that have a "src" attribute."""938 def whois(self):939 os.system("whois %s" % self.src)940 def ottl(self):941 t = [32,64,128,255]+[self.ttl]942 t.sort()943 return t[t.index(self.ttl)+1]944 def hops(self):945 return self.ottl()-self.ttl-1948##############################949## Routing/Interfaces stuff ##950##############################952class Route:953 def __init__(self):954 self.resync()955 self.s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)956 self.cache = {}958 def invalidate_cache(self):959 self.cache = {}961 def resync(self):962 self.invalidate_cache()963 self.routes = read_routes()965 def __repr__(self):966 rt = "Network Netmask Gateway Iface Output IP\n"967 for net,msk,gw,iface,addr in self.routes:968 rt += "%-15s %-15s %-15s %-15s %-15s\n" % (ltoa(net),969 ltoa(msk),970 gw,971 iface,972 addr)973 return rt975 def make_route(self, host=None, net=None, gw=None, dev=None):976 if host is not None:977 thenet,msk = host,32978 elif net is not None:979 thenet,msk = net.split("/")980 msk = int(msk)981 else:982 raise Scapy_Exception("make_route: Incorrect parameters. You should specify a host or a net")983 if gw is None:984 gw="0.0.0.0"985 if dev is None:986 if gw:987 nhop = gw988 else:989 nhop = thenet990 dev,ifaddr,x = self.route(nhop)991 else:992 ifaddr = get_if_addr(dev)993 return (atol(thenet), itom(msk), gw, dev, ifaddr)995 def add(self, *args, **kargs):996 """Ex:997 add(net="192.168.1.0/24",gw="1.2.3.4")998 """999 self.invalidate_cache()1000 self.routes.append(self.make_route(*args,**kargs))1003 def delt(self, *args, **kargs):1004 """delt(host|net, gw|dev)"""1005 self.invalidate_cache()1006 route = self.make_route(*args,**kargs)1007 try:1008 i=self.routes.index(route)1009 del(self.routes[i])1010 except ValueError:1011 warning("no matching route found")1013 def ifchange(self, iff, addr):1014 self.invalidate_cache()1015 the_addr,the_msk = (addr.split("/")+["32"])[:2]1016 the_msk = itom(int(the_msk))1017 the_rawaddr = atol(the_addr)1018 the_net = the_rawaddr & the_msk1021 for i in range(len(self.routes)):1022 net,msk,gw,iface,addr = self.routes[i]1023 if iface != iff:1024 continue1025 if gw == '0.0.0.0':1026 self.routes[i] = (the_net,the_msk,gw,iface,the_addr)1027 else:1028 self.routes[i] = (net,msk,gw,iface,the_addr)1029 for i in arp_cache.keys():1030 del(arp_cache[i])1034 def ifdel(self, iff):1035 self.invalidate_cache()1036 new_routes=[]1037 for rt in self.routes:1038 if rt[3] != iff:1039 new_routes.append(rt)1040 self.routes=new_routes1042 def ifadd(self, iff, addr):1043 self.invalidate_cache()1044 the_addr,the_msk = (addr.split("/")+["32"])[:2]1045 the_msk = itom(int(the_msk))1046 the_rawaddr = atol(the_addr)1047 the_net = the_rawaddr & the_msk1048 self.routes.append((the_net,the_msk,'0.0.0.0',iff,the_addr))1051 def route(self,dest,verbose=None):1052 if dest in self.cache:1053 return self.cache[dest]1054 if verbose is None:1055 verbose=conf.verb1056 # Transform "192.168.*.1-5" to one IP of the set1057 dst = dest.split("/")[0]1058 dst = dst.replace("*","0")1059 while 1:1060 l = dst.find("-")1061 if l < 0:1062 break1063 m = (dst[l:]+".").find(".")1064 dst = dst[:l]+dst[l+m:]1067 dst = atol(dst)1068 pathes=[]1069 for d,m,gw,i,a in self.routes:1070 aa = atol(a)1071 if aa == dst:1072 pathes.append((0xffffffffL,("lo",a,"0.0.0.0")))1073 if (dst & m) == (d & m):1074 pathes.append((m,(i,a,gw)))1075 if not pathes:1076 if verbose:1077 warning("No route found (no default route?)")1078 return "lo","0.0.0.0","0.0.0.0" #XXX linux specific!1079 # Choose the more specific route (greatest netmask).1080 # XXX: we don't care about metrics1081 pathes.sort()1082 ret = pathes[-1][1]1083 self.cache[dest] = ret1084 return ret1086 def get_if_bcast(self, iff):1087 for net, msk, gw, iface, addr in self.routes:1088 if (iff == iface and net != 0L):1089 bcast = atol(addr)|(~msk&0xffffffffL); # FIXME: check error in atol()1090 return ltoa(bcast);1091 warning("No broadcast address found for iface %s\n" % iff);1093if DNET:1094 def get_if_raw_hwaddr(iff):1095 if iff[:2] == "lo":1096 return (772, '\x00'*6)1097 try:1098 l = dnet.intf().get(iff)1099 l = l["link_addr"]1100 except:1101 raise Scapy_Exception("Error in attempting to get hw address for interface [%s]" % iff)1102 return l.type,l.data1103 def get_if_raw_addr(ifname):1104 i = dnet.intf()1105 return i.get(ifname)["addr"].data1106else:1107 def get_if_raw_hwaddr(iff):1108 return struct.unpack("16xh6s8x",get_if(iff,SIOCGIFHWADDR))1110 def get_if_raw_addr(iff):1111 try:1112 return get_if(iff, SIOCGIFADDR)[20:24]1113 except IOError:1114 return "\0\0\0\0"1117if PCAP:1118 def get_if_list():1119 # remove 'any' interface1120 return map(lambda x:x[0],filter(lambda x:x[1] is None,pcap.findalldevs()))1121 def get_working_if():1122 try:1123 return pcap.lookupdev()1124 except Exception:1125 return 'lo'1127 def attach_filter(s, filter):1128 warning("attach_filter() should not be called in PCAP mode")1129 def set_promisc(s,iff,val=1):1130 warning("set_promisc() should not be called in DNET/PCAP mode")1132else:1133 def get_if_list():1134 f=open("/proc/net/dev","r")1135 lst = []1136 f.readline()1137 f.readline()1138 for l in f:1139 lst.append(l.split(":")[0].strip())1140 return lst1141 def get_working_if():1142 for i in get_if_list():1143 if i == 'lo':1144 continue1145 ifflags = struct.unpack("16xH14x",get_if(i,SIOCGIFFLAGS))[0]1146 if ifflags & IFF_UP:1147 return i1148 return "lo"1149 def attach_filter(s, filter):1150 # XXX We generate the filter on the interface conf.iface1151 # because tcpdump open the "any" interface and ppp interfaces1152 # in cooked mode. As we use them in raw mode, the filter will not1153 # work... one solution could be to use "any" interface and translate1154 # the filter from cooked mode to raw mode1155 # mode1156 if not TCPDUMP:1157 return1158 try:1159 f = os.popen("%s -i %s -ddd -s 1600 '%s'" % (conf.prog.tcpdump,conf.iface,filter))1160 except OSError,msg:1161 log_interactive.warning("Failed to execute tcpdump: (%s)")1162 return1163 lines = f.readlines()1164 if f.close():1165 raise Scapy_Exception("Filter parse error")1166 nb = int(lines[0])1167 bpf = ""1168 for l in lines[1:]:1169 bpf += struct.pack("HBBI",*map(long,l.split()))1171 # XXX. Argl! We need to give the kernel a pointer on the BPF,1172 # python object header seems to be 20 bytes. 36 bytes for x86 64bits arch.1173 if X86_64:1174 bpfh = struct.pack("HL", nb, id(bpf)+36)1175 else:1176 bpfh = struct.pack("HI", nb, id(bpf)+20)1177 s.setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, bpfh)1179 def set_promisc(s,iff,val=1):1180 mreq = struct.pack("IHH8s", get_if_index(iff), PACKET_MR_PROMISC, 0, "")1181 if val:1182 cmd = PACKET_ADD_MEMBERSHIP1183 else:1184 cmd = PACKET_DROP_MEMBERSHIP1185 s.setsockopt(SOL_PACKET, cmd, mreq)1188if not LINUX:1190 def new_read_routes():1192 rtlst = []1193 def addrt(rt,lst):1194 dst,gw = rt1195 lst.append(rt)1197 r = dnet.route()1198 print r.loop(addrt, rtlst)1199 return rtlst1201 def read_routes():1202 if SOLARIS:1203 f=os.popen("netstat -rvn") # -f inet1204 elif FREEBSD:1205 f=os.popen("netstat -rnW") # -W to handle long interface names1206 else:1207 f=os.popen("netstat -rn") # -f inet1208 ok = 01209 mtu_present = False1210 routes = []1211 for l in f.readlines():1212 if not l:1213 break1214 l = l.strip()1215 if l.find("----") >= 0: # a separation line1216 continue1217 if l.find("Destination") >= 0:1218 ok = 11219 if l.find("Mtu") >= 0:1220 mtu_present = True1221 continue1222 if ok == 0:1223 continue1224 if not l:1225 break1226 if SOLARIS:1227 dest,mask,gw,netif,mxfrg,rtt,ref,flg = l.split()[:8]1228 else:1229 if mtu_present:1230 dest,gw,flg,ref,use,mtu,netif = l.split()[:7]1231 else:1232 dest,gw,flg,ref,use,netif = l.split()[:6]1233 if flg.find("Lc") >= 0:1234 continue1235 if dest == "default":1236 dest = 0L1237 netmask = 0L1238 else:1239 if SOLARIS:1240 netmask = atol(mask)1241 elif "/" in dest:1242 dest,netmask = dest.split("/")1243 netmask = itom(int(netmask))1244 else:1245 netmask = itom((dest.count(".") + 1) * 8)1246 dest += ".0"*(3-dest.count("."))1247 dest = atol(dest)1248 if not "G" in flg:1249 gw = '0.0.0.0'1250 ifaddr = get_if_addr(netif)1251 routes.append((dest,netmask,gw,netif,ifaddr))1252 f.close()1253 return routes1255 def read_interfaces():1256 i = dnet.intf()1257 ifflist = {}1258 def addif(iff,lst):1259 if not iff.has_key("addr"):1260 return1261 if not iff.has_key("link_addr"):1262 return1263 rawip = iff["addr"].data1264 ip = inet_ntoa(rawip)1265 rawll = iff["link_addr"].data1266 ll = str2mac(rawll)1267 lst[iff["name"]] = (rawll,ll,rawip,ip)1268 i.loop(addif, ifflist)1269 return ifflist1272else:1274 def read_routes():1275 f=open("/proc/net/route","r")1276 routes = []1277 s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)1278 ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x","lo"))1279 addrfamily = struct.unpack("h",ifreq[16:18])[0]1280 if addrfamily == socket.AF_INET:1281 ifreq2 = ioctl(s, SIOCGIFNETMASK,struct.pack("16s16x","lo"))1282 msk = socket.ntohl(struct.unpack("I",ifreq2[20:24])[0])1283 dst = socket.ntohl(struct.unpack("I",ifreq[20:24])[0]) & msk1284 ifaddr = inet_ntoa(ifreq[20:24])1285 routes.append((dst, msk, "0.0.0.0", "lo", ifaddr))1286 else:1287 warning("Interface lo: unkown address family (%i)"% addrfamily)1289 for l in f.readlines()[1:]:1290 iff,dst,gw,flags,x,x,x,msk,x,x,x = l.split()1291 flags = int(flags,16)1292 if flags & RTF_UP == 0:1293 continue1294 if flags & RTF_REJECT:1295 continue1296 try:1297 ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x",iff))1298 except IOError: # interface is present in routing tables but does not have any assigned IP1299 ifaddr="0.0.0.0"1300 else:1301 addrfamily = struct.unpack("h",ifreq[16:18])[0]1302 if addrfamily == socket.AF_INET:1303 ifaddr = inet_ntoa(ifreq[20:24])1304 else:1305 warning("Interface %s: unkown address family (%i)"%(iff, addrfamily))1306 continue1307 routes.append((socket.htonl(long(dst,16))&0xffffffffL,1308 socket.htonl(long(msk,16))&0xffffffffL,1309 inet_ntoa(struct.pack("I",long(gw,16))),1310 iff, ifaddr))1312 f.close()1313 return routes1315 def get_if(iff,cmd):1316 s=socket.socket()1317 ifreq = ioctl(s, cmd, struct.pack("16s16x",iff))1318 s.close()1319 return ifreq1322 def get_if_index(iff):1323 return int(struct.unpack("I",get_if(iff, SIOCGIFINDEX)[16:20])[0])1325 def get_last_packet_timestamp(sock):1326 ts = ioctl(sock, SIOCGSTAMP, "12345678")1327 s,us = struct.unpack("II",ts)1328 return s+us/1000000.01331def get_if_addr(iff):1332 return inet_ntoa(get_if_raw_addr(iff))1334def get_if_hwaddr(iff):1335 addrfamily, mac = get_if_raw_hwaddr(iff)1336 if addrfamily in [ARPHDR_ETHER,ARPHDR_LOOPBACK]:1337 return str2mac(mac)1338 else:1339 raise Scapy_Exception("Unsupported address family (%i) for interface [%s]" % (addrfamily,iff))1343#####################1344## ARP cache stuff ##1345#####################1347ARPTIMEOUT=1201349# XXX Fill arp_cache with /etc/ether and arp cache1350arp_cache={}1352if 0 and DNET: ## XXX Can't use this because it does not resolve IPs not in cache1353 dnet_arp_object = dnet.arp()1354 def getmacbyip(ip, chainCC=0):1355 tmp = map(ord, inet_aton(ip))1356 if (tmp[0] & 0xf0) == 0xe0: # mcast @1357 return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3])1358 iff,a,gw = conf.route.route(ip)1359 if iff == "lo":1360 return "ff:ff:ff:ff:ff:ff"1361 if gw != "0.0.0.0":1362 ip = gw1363 res = dnet_arp_object.get(dnet.addr(ip))1364 if res is None:1365 return None1366 else:1367 return res.ntoa()1368else:1369 def getmacbyip(ip, chainCC=0):1370 tmp = map(ord, inet_aton(ip))1371 if (tmp[0] & 0xf0) == 0xe0: # mcast @1372 return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3])1373 iff,a,gw = conf.route.route(ip)1374 if ( (iff == "lo") or (ip == conf.route.get_if_bcast(iff)) ):1375 return "ff:ff:ff:ff:ff:ff"1376 if gw != "0.0.0.0":1377 ip = gw1379 if arp_cache.has_key(ip):1380 mac, timeout = arp_cache[ip]1381 if not timeout or (time.time()-timeout < ARPTIMEOUT):1382 return mac1384 res = srp1(Ether(dst=ETHER_BROADCAST)/ARP(op="who-has", pdst=ip),1385 type=ETH_P_ARP,1386 iface = iff,1387 timeout=2,1388 verbose=0,1389 chainCC=chainCC,1390 nofilter=1)1391 if res is not None:1392 mac = res.payload.hwsrc1393 arp_cache[ip] = (mac,time.time())1394 return mac1395 return None1398####################1399## Random numbers ##1400####################1402def randseq(inf, sup, seed=None, forever=1, renewkeys=0):1403 """iterate through a sequence in random order.1404 When all the values have been drawn, if forever=1, the drawing is done again.1405 If renewkeys=0, the draw will be in the same order, guaranteeing that the same1406 number will be drawn in not less than the number of integers of the sequence"""1407 rnd = random.Random(seed)1408 sbox_size = 2561410 top = sup-inf+11412 n=01413 while (1<<n) < top:1414 n += 11416 fs = min(3,(n+1)/2)1417 fsmask = 2**fs-11418 rounds = max(n,3)1419 turns = 01421 while 1:1422 if turns == 0 or renewkeys:1423 sbox = [rnd.randint(0,fsmask) for k in xrange(sbox_size)]1424 turns += 11425 i = 01426 while i < 2**n:1427 ct = i1428 i += 11429 for k in range(rounds): # Unbalanced Feistel Network1430 lsb = ct & fsmask1431 ct >>= fs1432 lsb ^= sbox[ct%sbox_size]1433 ct |= lsb << (n-fs)1435 if ct < top:1436 yield inf+ct1437 if not forever:1438 break1441class VolatileValue:1442 def __repr__(self):1443 return "<%s>" % self.__class__.__name__1444 def __getattr__(self, attr):1445 if attr == "__setstate__":1446 raise AttributeError(attr)1447 return getattr(self._fix(),attr)1448 def _fix(self):1449 return None1452class RandField(VolatileValue):1453 pass1456class RandNum(RandField):1457 min = 01458 max = 01459 def __init__(self, min, max):1460 self.seq = randseq(min,max)1461 def _fix(self):1462 return self.seq.next()1464class RandNumGamma(RandField):1465 def __init__(self, alpha, beta):1466 self.alpha = alpha1467 self.beta = beta1468 def _fix(self):1469 return int(round(random.gammavariate(self.alpha, self.beta)))1471class RandNumGauss(RandField):1472 def __init__(self, mu, sigma):1473 self.mu = mu1474 self.sigma = sigma1475 def _fix(self):1476 return int(round(random.gauss(self.mu, self.sigma)))1478class RandNumExpo(RandField):1479 def __init__(self, lambd):1480 self.lambd = lambd1481 def _fix(self):1482 return int(round(random.expovariate(self.lambd)))1484class RandByte(RandNum):1485 def __init__(self):1486 RandNum.__init__(self, 0, 2L**8-1)1488class RandShort(RandNum):1489 def __init__(self):1490 RandNum.__init__(self, 0, 2L**16-1)1492class RandInt(RandNum):1493 def __init__(self):1494 RandNum.__init__(self, 0, 2L**32-1)1496class RandSInt(RandNum):1497 def __init__(self):1498 RandNum.__init__(self, -2L**31, 2L**31-1)1500class RandLong(RandNum):1501 def __init__(self):1502 RandNum.__init__(self, 0, 2L**64-1)1504class RandSLong(RandNum):1505 def __init__(self):1506 RandNum.__init__(self, -2L**63, 2L**63-1)1508class RandChoice(RandField):1509 def __init__(self, *args):1510 if not args:1511 raise TypeError("RandChoice needs at least one choice")1512 self._choice = args1513 def _fix(self):1514 return random.choice(self._choice)1516class RandString(RandField):1517 def __init__(self, size, chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"):1518 self.chars = chars1519 self.size = size1520 def _fix(self):1521 s = ""1522 for i in range(self.size):1523 s += random.choice(self.chars)1524 return s1526class RandBin(RandString):1527 def __init__(self, size):1528 RandString.__init__(self, size, "".join(map(chr,range(256))))1531class RandTermString(RandString):1532 def __init__(self, size, term):1533 RandString.__init__(self, size, "".join(map(chr,range(1,256))))1534 self.term = term1535 def _fix(self):1536 return RandString._fix(self)+self.term1540class RandIP(RandString):1541 def __init__(self, iptemplate="0.0.0.0/0"):1542 self.ip = Net(iptemplate)1543 def _fix(self):1544 return self.ip.choice()1546class RandMAC(RandString):1547 def __init__(self, template="*"):1548 template += ":*:*:*:*:*"1549 template = template.split(":")1550 self.mac = ()1551 for i in range(6):1552 if template[i] == "*":1553 v = RandByte()1554 elif "-" in template[i]:1555 x,y = template[i].split("-")1556 v = RandNum(int(x,16), int(y,16))1557 else:1558 v = int(template[i],16)1559 self.mac += (v,)1560 def _fix(self):1561 return "%02x:%02x:%02x:%02x:%02x:%02x" % self.mac1564class RandOID(RandString):1565 def __init__(self, fmt=None, depth=RandNumExpo(0.1), idnum=RandNumExpo(0.01)):1566 self.ori_fmt = fmt1567 if fmt is not None:1568 fmt = fmt.split(".")1569 for i in range(len(fmt)):1570 if "-" in fmt[i]:1571 fmt[i] = tuple(map(int, fmt[i].split("-")))1572 self.fmt = fmt1573 self.depth = depth1574 self.idnum = idnum1575 def __repr__(self):1576 if self.ori_fmt is None:1577 return "<%s>" % self.__class__.__name__1578 else:1579 return "<%s [%s]>" % (self.__class__.__name__, self.ori_fmt)1580 def _fix(self):1581 if self.fmt is None:1582 return ".".join(map(str, [self.idnum for i in xrange(1+self.depth)]))1583 else:1584 oid = []1585 for i in self.fmt:1586 if i == "*":1587 oid.append(str(self.idnum))1588 elif i == "**":1589 oid += map(str, [self.idnum for i in xrange(1+self.depth)])1590 elif type(i) is tuple:1591 oid.append(str(random.randrange(*i)))1592 else:1593 oid.append(i)1594 return ".".join(oid)1598class RandASN1Object(RandField):1599 def __init__(self, objlist=None):1600 if objlist is None:1601 objlist = map(lambda x:x._asn1_obj,1602 filter(lambda x:hasattr(x,"_asn1_obj"), ASN1_Class_UNIVERSAL.__rdict__.values()))1603 self.objlist = objlist1604 self.chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"1605 def _fix(self, n=0):1606 o = random.choice(self.objlist)1607 if issubclass(o, ASN1_INTEGER):1608 return o(int(random.gauss(0,1000)))1609 elif issubclass(o, ASN1_STRING):1610 z = int(random.expovariate(0.05)+1)1611 return o("".join([random.choice(self.chars) for i in range(z)]))1612 elif issubclass(o, ASN1_SEQUENCE) and (n < 10):1613 z = int(random.expovariate(0.08)+1)1614 return o(map(lambda x:x._fix(n+1), [self.__class__(objlist=self.objlist)]*z))1615 return ASN1_INTEGER(int(random.gauss(0,1000)))1617class RandDHCPOptions(RandField):1618 def __init__(self, size=None, rndstr=None):1619 if size is None:1620 size = RandNumExpo(0.05)1621 self.size = size1622 if rndstr is None:1623 rndstr = RandBin(RandNum(0,255))1624 self.rndstr=rndstr1625 self._opts = DHCPOptions.values()1626 self._opts.remove("pad")1627 self._opts.remove("end")1628 def _fix(self):1629 op = []1630 for k in range(self.size):1631 o = random.choice(self._opts)1632 if type(o) is str:1633 op.append((o,self.rndstr*1))1634 else:1635 op.append((o.name, o.randval()._fix()))1636 return op1639# Automatic timestamp1641class AutoTime(VolatileValue):1642 def __init__(self, base=None):1643 if base == None:1644 self.diff = 01645 else:1646 self.diff = time.time()-base1647 def _fix(self):1648 return time.time()-self.diff1650class IntAutoTime(AutoTime):1651 def _fix(self):1652 return int(time.time()-self.diff)1655class ZuluTime(AutoTime):1656 def __init__(self, diff=None):1657 self.diff=diff1658 def _fix(self):1659 return time.strftime("%y%m%d%H%M%SZ",time.gmtime(time.time()+self.diff))1662class DelayedEval(VolatileValue):1663 """ Exemple of usage: DelayedEval("time.time()") """1664 def __init__(self, expr):1665 self.expr = expr1666 def _fix(self):1667 return eval(self.expr)1670class IncrementalValue(VolatileValue):1671 def __init__(self, start=0, step=1, restart=-1):1672 self.start = self.val = start1673 self.step = step1674 self.restart = restart1675 def _fix(self):1676 v = self.val1677 if self.val == self.restart :1678 self.val = self.start1679 else:1680 self.val += self.step1681 return v1683def corrupt_bytes(s, p=0.01, n=None):1684 s = array.array("B",str(s))1685 l = len(s)1686 if n is None:1687 n = max(1,int(l*p))1688 for i in random.sample(xrange(l), n):1689 s[i] = random.randint(0,255)1690 return s.tostring()1692def corrupt_bits(s, p=0.01, n=None):1693 s = array.array("B",str(s))1694 l = len(s)*81695 if n is None:1696 n = max(1,int(l*p))1697 for i in random.sample(xrange(l), n):1698 s[i/8] ^= 1 << (i%8)1699 return s.tostring()1702class CorruptedBytes(VolatileValue):1703 def __init__(self, s, p=0.01, n=None):1704 self.s = s1705 self.p = p1706 self.n = n1707 def _fix(self):1708 return corrupt_bytes(self.s, self.p, self.n)1710class CorruptedBits(CorruptedBytes):1711 def _fix(self):1712 return corrupt_bits(self.s, self.p, self.n)1714##############1715#### ASN1 ####1716##############1718class ASN1_Error(Exception):1719 pass1721class ASN1_Encoding_Error(ASN1_Error):1722 pass1724class ASN1_Decoding_Error(ASN1_Error):1725 pass1727class ASN1_BadTag_Decoding_Error(ASN1_Decoding_Error):1728 pass1732class ASN1Codec(EnumElement):1733 def register_stem(cls, stem):1734 cls._stem = stem1735 def dec(cls, s, context=None):1736 return cls._stem.dec(s, context=context)1737 def safedec(cls, s, context=None):1738 return cls._stem.safedec(s, context=context)1739 def get_stem(cls):1740 return cls.stem1743class ASN1_Codecs_metaclass(Enum_metaclass):1744 element_class = ASN1Codec1746class ASN1_Codecs:1747 __metaclass__ = ASN1_Codecs_metaclass1748 BER = 11749 DER = 21750 PER = 31751 CER = 41752 LWER = 51753 BACnet = 61754 OER = 71755 SER = 81756 XER = 91758class ASN1Tag(EnumElement):1759 def __init__(self, key, value, context=None, codec=None):1760 EnumElement.__init__(self, key, value)1761 self._context = context1762 if codec == None:1763 codec = {}1764 self._codec = codec1765 def clone(self): # /!\ not a real deep copy. self.codec is shared1766 return self.__class__(self._key, self._value, self._context, self._codec)1767 def register_asn1_object(self, asn1obj):1768 self._asn1_obj = asn1obj1769 def asn1_object(self, val):1770 if hasattr(self,"_asn1_obj"):1771 return self._asn1_obj(val)1772 raise ASN1_Error("%r does not have any assigned ASN1 object" % self)1773 def register(self, codecnum, codec):1774 self._codec[codecnum] = codec1775 def get_codec(self, codec):1776 try:1777 c = self._codec[codec]1778 except KeyError,msg:1779 raise ASN1_Error("Codec %r not found for tag %r" % (codec, self))1780 return c1782class ASN1_Class_metaclass(Enum_metaclass):1783 element_class = ASN1Tag1784 def __new__(cls, name, bases, dct): # XXX factorise a bit with Enum_metaclass.__new__()1785 for b in bases:1786 for k,v in b.__dict__.iteritems():1787 if k not in dct and isinstance(v,ASN1Tag):1788 dct[k] = v.clone()1790 rdict = {}1791 for k,v in dct.iteritems():1792 if type(v) is int:1793 v = ASN1Tag(k,v)1794 dct[k] = v1795 rdict[v] = v1796 elif isinstance(v, ASN1Tag):1797 rdict[v] = v1798 dct["__rdict__"] = rdict1800 cls = type.__new__(cls, name, bases, dct)1801 for v in cls.__dict__.values():1802 if isinstance(v, ASN1Tag):1803 v.context = cls # overwrite ASN1Tag contexts, even cloned ones1804 return cls1807class ASN1_Class:1808 __metaclass__ = ASN1_Class_metaclass1810class ASN1_Class_UNIVERSAL(ASN1_Class):1811 name = "UNIVERSAL"1812 ERROR = -31813 RAW = -21814 NONE = -11815 ANY = 01816 BOOLEAN = 11817 INTEGER = 21818 BIT_STRING = 31819 STRING = 41820 NULL = 51821 OID = 61822 OBJECT_DESCRIPTOR = 71823 EXTERNAL = 81824 REAL = 91825 ENUMERATED = 101826 EMBEDDED_PDF = 111827 UTF8_STRING = 121828 RELATIVE_OID = 131829 SEQUENCE = 0x30#XXX 16 ??1830 SET = 0x31 #XXX 17 ??1831 NUMERIC_STRING = 181832 PRINTABLE_STRING = 191833 T61_STRING = 201834 VIDEOTEX_STRING = 211835 IA5_STRING = 221836 UTC_TIME = 231837 GENERALIZED_TIME = 241838 GRAPHIC_STRING = 251839 ISO646_STRING = 261840 GENERAL_STRING = 271841 UNIVERSAL_STRING = 281842 CHAR_STRING = 291843 BMP_STRING = 301844 COUNTER32 = 0x411845 TIME_TICKS = 0x431847class ASN1_Object_metaclass(type):1848 def __new__(cls, name, bases, dct):1849 c = super(ASN1_Object_metaclass, cls).__new__(cls, name, bases, dct)1850 try:1851 c.tag.register_asn1_object(c)1852 except:1853 warning("Error registering %r for %r" % (c.tag, c.codec))1854 return c1857class ASN1_Object:1858 __metaclass__ = ASN1_Object_metaclass1859 tag = ASN1_Class_UNIVERSAL.ANY1860 def __init__(self, val):1861 self.val = val1862 def enc(self, codec):1863 return self.tag.get_codec(codec).enc(self.val)1864 def __repr__(self):1865 return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), self.val)1866 def __str__(self):1867 return self.enc(conf.ASN1_default_codec)1868 def strshow(self, lvl=0):1869 return (" "*lvl)+repr(self)+"\n"1870 def show(self, lvl=0):1871 print self.strshow(lvl)1872 def __eq__(self, other):1873 return self.val == other1874 def __cmp__(self, other):1875 return cmp(self.val, other)1877class ASN1_DECODING_ERROR(ASN1_Object):1878 tag = ASN1_Class_UNIVERSAL.ERROR1879 def __init__(self, val, exc=None):1880 ASN1_Object.__init__(self, val)1881 self.exc = exc1882 def __repr__(self):1883 return "<%s[%r]{{%s}}>" % (self.__dict__.get("name", self.__class__.__name__),1884 self.val, self.exc.args[0])1885 def enc(self, codec):1886 if isinstance(self.val, ASN1_Object):1887 return self.val.enc(codec)1888 return self.val1890class ASN1_force(ASN1_Object):1891 tag = ASN1_Class_UNIVERSAL.RAW1892 def enc(self, codec):1893 if isinstance(self.val, ASN1_Object):1894 return self.val.enc(codec)1895 return self.val1897class ASN1_BADTAG(ASN1_force):1898 pass1900class ASN1_INTEGER(ASN1_Object):1901 tag = ASN1_Class_UNIVERSAL.INTEGER1903class ASN1_STRING(ASN1_Object):1904 tag = ASN1_Class_UNIVERSAL.STRING1906class ASN1_BIT_STRING(ASN1_STRING):1907 tag = ASN1_Class_UNIVERSAL.BIT_STRING1909class ASN1_PRINTABLE_STRING(ASN1_STRING):1910 tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING1912class ASN1_T61_STRING(ASN1_STRING):1913 tag = ASN1_Class_UNIVERSAL.T61_STRING1915class ASN1_IA5_STRING(ASN1_STRING):1916 tag = ASN1_Class_UNIVERSAL.IA5_STRING1918class ASN1_NUMERIC_STRING(ASN1_STRING):1919 tag = ASN1_Class_UNIVERSAL.NUMERIC_STRING1921class ASN1_VIDEOTEX_STRING(ASN1_STRING):1922 tag = ASN1_Class_UNIVERSAL.VIDEOTEX_STRING1924class ASN1_UTC_TIME(ASN1_STRING):1925 tag = ASN1_Class_UNIVERSAL.UTC_TIME1927class ASN1_TIME_TICKS(ASN1_INTEGER):1928 tag = ASN1_Class_UNIVERSAL.TIME_TICKS1930class ASN1_BOOLEAN(ASN1_INTEGER):1931 tag = ASN1_Class_UNIVERSAL.BOOLEAN1933class ASN1_NULL(ASN1_INTEGER):1934 tag = ASN1_Class_UNIVERSAL.NULL1936class ASN1_COUNTER32(ASN1_INTEGER):1937 tag = ASN1_Class_UNIVERSAL.COUNTER321939class ASN1_SEQUENCE(ASN1_Object):1940 tag = ASN1_Class_UNIVERSAL.SEQUENCE1941 def strshow(self, lvl=0):1942 s = (" "*lvl)+("# %s:" % self.__class__.__name__)+"\n"1943 for o in self.val:1944 s += o.strshow(lvl=lvl+1)1945 return s1947class ASN1_SET(ASN1_SEQUENCE):1948 tag = ASN1_Class_UNIVERSAL.SET1950class ASN1_OID(ASN1_Object):1951 tag = ASN1_Class_UNIVERSAL.OID1952 def __init__(self, val):1953 val = conf.mib._oid(val)1954 ASN1_Object.__init__(self, val)1955 def __repr__(self):1956 return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), conf.mib._oidname(self.val))1960##################1961## BER encoding ##1962##################1966#####[ BER tools ]#####1969class BER_Exception(Exception):1970 pass1972class BER_Decoding_Error(ASN1_Decoding_Error):1973 def __init__(self, msg, decoded=None, remaining=None):1974 Exception.__init__(self, msg)1975 self.remaining = remaining1976 self.decoded = decoded1977 def __str__(self):1978 s = Exception.__str__(self)1979 if isinstance(self.decoded, BERcodec_Object):1980 s+="\n### Already decoded ###\n%s" % self.decoded.strshow()1981 else:1982 s+="\n### Already decoded ###\n%r" % self.decoded1983 s+="\n### Remaining ###\n%r" % self.remaining1984 return s1986class BER_BadTag_Decoding_Error(BER_Decoding_Error, ASN1_BadTag_Decoding_Error):1987 pass1989def BER_len_enc(l, size=0):1990 if l <= 127 and size==0:1991 return chr(l)1992 s = ""1993 while l or size>0:1994 s = chr(l&0xff)+s1995 l >>= 8L1996 size -= 11997 if len(s) > 127:1998 raise BER_Exception("BER_len_enc: Length too long (%i) to be encoded [%r]" % (len(s),s))1999 return chr(len(s)|0x80)+s2000def BER_len_dec(s):2001 l = ord(s[0])2002 if not l & 0x80:2003 return l,s[1:]2004 l &= 0x7f2005 if len(s) <= l:2006 raise BER_Decoding_Error("BER_len_dec: Got %i bytes while expecting %i" % (len(s)-1, l),remaining=s)2007 ll = 0L2008 for c in s[1:l+1]:2009 ll <<= 8L2010 ll |= ord(c)2011 return ll,s[l+1:]2013def BER_num_enc(l, size=1):2014 x=[]2015 while l or size>0:2016 x.insert(0, l & 0x7f)2017 if len(x) > 1:2018 x[0] |= 0x802019 l >>= 72020 size -= 12021 return "".join([chr(k) for k in x])2022def BER_num_dec(s):2023 x = 02024 for i in range(len(s)):2025 c = ord(s[i])2026 x <<= 72027 x |= c&0x7f2028 if not c&0x80:2029 break2030 if c&0x80:2031 raise BER_Decoding_Error("BER_num_dec: unfinished number description", remaining=s)2032 return x, s[i+1:]2034#####[ BER classes ]#####2036class BERcodec_metaclass(type):2037 def __new__(cls, name, bases, dct):2038 c = super(BERcodec_metaclass, cls).__new__(cls, name, bases, dct)2039 try:2040 c.tag.register(c.codec, c)2041 except:2042 warning("Error registering %r for %r" % (c.tag, c.codec))2043 return c2046class BERcodec_Object:2047 __metaclass__ = BERcodec_metaclass2048 codec = ASN1_Codecs.BER2049 tag = ASN1_Class_UNIVERSAL.ANY2051 @classmethod2052 def asn1_object(cls, val):2053 return cls.tag.asn1_object(val)2055 @classmethod2056 def check_string(cls, s):2057 if not s:2058 raise BER_Decoding_Error("%s: Got empty object while expecting tag %r" %2059 (cls.__name__,cls.tag), remaining=s)2060 @classmethod2061 def check_type(cls, s):2062 cls.check_string(s)2063 if cls.tag != ord(s[0]):2064 raise BER_BadTag_Decoding_Error("%s: Got tag [%i/%#x] while expecting %r" %2065 (cls.__name__, ord(s[0]), ord(s[0]),cls.tag), remaining=s)2066 return s[1:]2067 @classmethod2068 def check_type_get_len(cls, s):2069 s2 = cls.check_type(s)2070 if not s2:2071 raise BER_Decoding_Error("%s: No bytes while expecting a length" %2072 cls.__name__, remaining=s)2073 return BER_len_dec(s2)2074 @classmethod2075 def check_type_check_len(cls, s):2076 l,s3 = cls.check_type_get_len(s)2077 if len(s3) < l:2078 raise BER_Decoding_Error("%s: Got %i bytes while expecting %i" %2079 (cls.__name__, len(s3), l), remaining=s)2080 return l,s3[:l],s3[l:]2082 @classmethod2083 def do_dec(cls, s, context=None, safe=False):2084 if context is None:2085 context = cls.tag.context2086 cls.check_string(s)2087 p = ord(s[0])2088 if p not in context:2089 t = s2090 if len(t) > 18:2091 t = t[:15]+"..."2092 raise BER_Decoding_Error("Unknown prefix [%02x] for [%r]" % (p,t), remaining=s)2093 codec = context[p].get_codec(ASN1_Codecs.BER)2094 return codec.dec(s,context,safe)2096 @classmethod2097 def dec(cls, s, context=None, safe=False):2098 if not safe:2099 return cls.do_dec(s, context, safe)2100 try:2101 return cls.do_dec(s, context, safe)2102 except BER_BadTag_Decoding_Error,e:2103 o,remain = BERcodec_Object.dec(e.remaining, context, safe)2104 return ASN1_BADTAG(o),remain2105 except BER_Decoding_Error, e:2106 return ASN1_DECODING_ERROR(s, exc=e),""2107 except ASN1_Error, e:2108 return ASN1_DECODING_ERROR(s, exc=e),""2110 @classmethod2111 def safedec(cls, s, context=None):2112 return cls.dec(s, context, safe=True)2115 @classmethod2116 def enc(cls, s):2117 if type(s) is str:2118 return BERcodec_STRING.enc(s)2119 else:2120 return BERcodec_INTEGER.enc(int(s))2124ASN1_Codecs.BER.register_stem(BERcodec_Object)2127class BERcodec_INTEGER(BERcodec_Object):2128 tag = ASN1_Class_UNIVERSAL.INTEGER2129 @classmethod2130 def enc(cls, i):2131 s = []2132 while 1:2133 s.append(i&0xff)2134 if -127 <= i < 0:2135 break2136 if 128 <= i <= 255:2137 s.append(0)2138 i >>= 82139 if not i:2140 break2141 s = map(chr, s)2142 s.append(BER_len_enc(len(s)))2143 s.append(chr(cls.tag))2144 s.reverse()2145 return "".join(s)2146 @classmethod2147 def do_dec(cls, s, context=None, safe=False):2148 l,s,t = cls.check_type_check_len(s)2149 x = 0L2150 if s:2151 if ord(s[0])&0x80: # negative int2152 x = -1L2153 for c in s:2154 x <<= 82155 x |= ord(c)2156 return cls.asn1_object(x),t2159class BERcodec_BOOLEAN(BERcodec_INTEGER):2160 tag = ASN1_Class_UNIVERSAL.BOOLEAN2162class BERcodec_NULL(BERcodec_INTEGER):2163 tag = ASN1_Class_UNIVERSAL.NULL2164 @classmethod2165 def enc(cls, i):2166 if i == 0:2167 return chr(cls.tag)+"\0"2168 else:2169 return super(cls,cls).enc(i)2171class BERcodec_STRING(BERcodec_Object):2172 tag = ASN1_Class_UNIVERSAL.STRING2173 @classmethod2174 def enc(cls,s):2175 return chr(cls.tag)+BER_len_enc(len(s))+s2176 @classmethod2177 def do_dec(cls, s, context=None, safe=False):2178 l,s,t = cls.check_type_check_len(s)2179 return cls.tag.asn1_object(s),t2181class BERcodec_BIT_STRING(BERcodec_STRING):2182 tag = ASN1_Class_UNIVERSAL.BIT_STRING2184class BERcodec_PRINTABLE_STRING(BERcodec_STRING):2185 tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING2187class BERcodec_T61_STRING (BERcodec_STRING):2188 tag = ASN1_Class_UNIVERSAL.T61_STRING2190class BERcodec_IA5_STRING(BERcodec_STRING):2191 tag = ASN1_Class_UNIVERSAL.IA5_STRING2193class BERcodec_UTC_TIME(BERcodec_STRING):2194 tag = ASN1_Class_UNIVERSAL.UTC_TIME2196class BERcodec_TIME_TICKS(BERcodec_INTEGER):2197 tag = ASN1_Class_UNIVERSAL.TIME_TICKS2199class BERcodec_COUNTER32(BERcodec_INTEGER):2200 tag = ASN1_Class_UNIVERSAL.COUNTER322202class BERcodec_SEQUENCE(BERcodec_Object):2203 tag = ASN1_Class_UNIVERSAL.SEQUENCE2204 @classmethod2205 def enc(cls, l):2206 if type(l) is not str:2207 l = "".join(map(lambda x: x.enc(cls.codec), l))2208 return chr(cls.tag)+BER_len_enc(len(l))+l2209 @classmethod2210 def do_dec(cls, s, context=None, safe=False):2211 if context is None:2212 context = cls.tag.context2213 l,st = cls.check_type_get_len(s) # we may have len(s) < l2214 s,t = st[:l],st[l:]2215 obj = []2216 while s:2217 try:2218 o,s = BERcodec_Object.dec(s, context, safe)2219 except BER_Decoding_Error, err:2220 err.remaining += t2221 if err.decoded is not None:2222 obj.append(err.decoded)2223 err.decoded = obj2224 raise2225 obj.append(o)2226 if len(st) < l:2227 raise BER_Decoding_Error("Not enough bytes to decode sequence", decoded=obj)2228 return cls.asn1_object(obj),t2230class BERcodec_SET(BERcodec_SEQUENCE):2231 tag = ASN1_Class_UNIVERSAL.SET2234class BERcodec_OID(BERcodec_Object):2235 tag = ASN1_Class_UNIVERSAL.OID2237 @classmethod2238 def enc(cls, oid):2239 lst = [int(x) for x in oid.strip(".").split(".")]2240 if len(lst) >= 2:2241 lst[1] += 40*lst[0]2242 del(lst[0])2243 s = "".join([BER_num_enc(k) for k in lst])2244 return chr(cls.tag)+BER_len_enc(len(s))+s2245 @classmethod2246 def do_dec(cls, s, context=None, safe=False):2247 l,s,t = cls.check_type_check_len(s)2248 lst = []2249 while s:2250 l,s = BER_num_dec(s)2251 lst.append(l)2252 if (len(lst) > 0):2253 lst.insert(0,lst[0]/40)2254 lst[1] %= 402255 return cls.asn1_object(".".join([str(k) for k in lst])), t2258#################2259## MIB parsing ##2260#################2262_mib_re_integer = re.compile("^[0-9]+$")2263_mib_re_both = re.compile("^([a-zA-Z_][a-zA-Z0-9_-]*)\(([0-9]+)\)$")2264_mib_re_oiddecl = re.compile("$\s*([a-zA-Z0-9_-]+)\s+OBJECT([^:\{\}]|\{[^:]+\})+::=\s*\{([^\}]+)\}",re.M)2265_mib_re_strings = re.compile('"[^"]*"')2266_mib_re_comments = re.compile('--.*(\r|\n)')2268class MIBDict(DADict):2269 def _findroot(self, x):2270 if x.startswith("."):2271 x = x[1:]2272 if not x.endswith("."):2273 x += "."2274 max=02275 root="."2276 for k in self.keys():2277 if x.startswith(self[k]+"."):2278 if max < len(self[k]):2279 max = len(self[k])2280 root = k2281 return root, x[max:-1]2282 def _oidname(self, x):2283 root,remainder = self._findroot(x)2284 return root+remainder2285 def _oid(self, x):2286 xl = x.strip(".").split(".")2287 p = len(xl)-12288 while p >= 0 and _mib_re_integer.match(xl[p]):2289 p -= 12290 if p != 0 or xl[p] not in self:2291 return x2292 xl[p] = self[xl[p]]2293 return ".".join(xl[p:])2294 def _make_graph(self, other_keys=[], **kargs):2295 nodes = [(k,self[k]) for k in self.keys()]2296 oids = [self[k] for k in self.keys()]2297 for k in other_keys:2298 if k not in oids:2299 nodes.append(self.oidname(k),k)2300 s = 'digraph "mib" {\n\trankdir=LR;\n\n'2301 for k,o in nodes:2302 s += '\t"%s" [ label="%s" ];\n' % (o,k)2303 s += "\n"2304 for k,o in nodes:2305 parent,remainder = self._findroot(o[:-1])2306 remainder = remainder[1:]+o[-1]2307 if parent != ".":2308 parent = self[parent]2309 s += '\t"%s" -> "%s" [label="%s"];\n' % (parent, o,remainder)2310 s += "}\n"2311 do_graph(s, **kargs)2314def mib_register(ident, value, the_mib, unresolved):2315 if ident in the_mib or ident in unresolved:2316 return ident in the_mib2317 resval = []2318 not_resolved = 02319 for v in value:2320 if _mib_re_integer.match(v):2321 resval.append(v)2322 else:2323 v = fixname(v)2324 if v not in the_mib:2325 not_resolved = 12326 if v in the_mib:2327 v = the_mib[v]2328 elif v in unresolved:2329 v = unresolved[v]2330 if type(v) is list:2331 resval += v2332 else:2333 resval.append(v)2334 if not_resolved:2335 unresolved[ident] = resval2336 return False2337 else:2338 the_mib[ident] = resval2339 keys = unresolved.keys()2340 i = 02341 while i < len(keys):2342 k = keys[i]2343 if mib_register(k,unresolved[k], the_mib, {}):2344 del(unresolved[k])2345 del(keys[i])2346 i = 02347 else:2348 i += 12350 return True2353def load_mib(filenames):2354 the_mib = {'iso': ['1']}2355 unresolved = {}2356 for k in conf.mib.keys():2357 mib_register(k, conf.mib[k].split("."), the_mib, unresolved)2359 if type(filenames) is str:2360 filenames = [filenames]2361 for fnames in filenames:2362 for fname in glob(fnames):2363 f = open(fname)2364 text = f.read()2365 cleantext = " ".join(_mib_re_strings.split(" ".join(_mib_re_comments.split(text))))2366 for m in _mib_re_oiddecl.finditer(cleantext):2367 gr = m.groups()2368 ident,oid = gr[0],gr[-1]2369 ident=fixname(ident)2370 oid = oid.split()2371 for i in range(len(oid)):2372 m = _mib_re_both.match(oid[i])2373 if m:2374 oid[i] = m.groups()[1]2375 mib_register(ident, oid, the_mib, unresolved)2377 newmib = MIBDict(_name="MIB")2378 for k,o in the_mib.iteritems():2379 newmib[k]=".".join(o)2380 for k,o in unresolved.iteritems():2381 newmib[k]=".".join(o)2383 conf.mib=newmib2387################2388## Generators ##2389################2391class Gen(object):2392 def __iter__(self):2393 return iter([])2395class SetGen(Gen):2396 def __init__(self, set, _iterpacket=1):2397 self._iterpacket=_iterpacket2398 if type(set) is list:2399 self.set = set2400 elif isinstance(set, PacketList):2401 self.set = list(set)2402 else:2403 self.set = [set]2404 def transf(self, element):2405 return element2406 def __iter__(self):2407 for i in self.set:2408 if (type(i) is tuple) and (len(i) == 2) and type(i[0]) is int and type(i[1]) is int:2409 if (i[0] <= i[1]):2410 j=i[0]2411 while j <= i[1]:2412 yield j2413 j += 12414 elif isinstance(i, Gen) and (self._iterpacket or not isinstance(i,Packet)):2415 for j in i:2416 yield j2417 else:2418 yield i2419 def __repr__(self):2420 return "<SetGen %s>" % self.set.__repr__()2422class Net(Gen):2423 """Generate a list of IPs from a network address or a name"""2424 name = "ip"2425 ipaddress = re.compile(r"^(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)(/[0-3]?[0-9])?$")2426 def __init__(self, net):2427 self.repr=net2429 tmp=net.split('/')+["32"]2430 if not self.ipaddress.match(net):2431 tmp[0]=socket.gethostbyname(tmp[0])2432 netmask = int(tmp[1])2434 def parse_digit(a,netmask):2435 netmask = min(8,max(netmask,0))2436 if a == "*":2437 a = (0,256)2438 elif a.find("-") >= 0:2439 x,y = map(int,a.split("-"))2440 if x > y:2441 y = x2442 a = (x & (0xffL<<netmask) , max(y, (x | (0xffL>>(8-netmask))))+1)2443 else:2444 a = (int(a) & (0xffL<<netmask),(int(a) | (0xffL>>(8-netmask)))+1)2445 return a2447 self.parsed = map(lambda x,y: parse_digit(x,y), tmp[0].split("."), map(lambda x,nm=netmask: x-nm, (8,16,24,32)))2449 def __iter__(self):2450 for d in xrange(*self.parsed[3]):2451 for c in xrange(*self.parsed[2]):2452 for b in xrange(*self.parsed[1]):2453 for a in xrange(*self.parsed[0]):2454 yield "%i.%i.%i.%i" % (a,b,c,d)2455 def choice(self):2456 ip = []2457 for v in self.parsed:2458 ip.append(str(random.randint(v[0],v[1]-1)))2459 return ".".join(ip)2461 def __repr__(self):2462 return "Net(%r)" % self.repr2464class OID(Gen):2465 name = "OID"2466 def __init__(self, oid):2467 self.oid = oid2468 self.cmpt = []2469 fmt = []2470 for i in oid.split("."):2471 if "-" in i:2472 fmt.append("%i")2473 self.cmpt.append(tuple(map(int, i.split("-"))))2474 else:2475 fmt.append(i)2476 self.fmt = ".".join(fmt)2477 def __repr__(self):2478 return "OID(%r)" % self.oid2479 def __iter__(self):2480 ii = [k[0] for k in self.cmpt]2481 while 1:2482 yield self.fmt % tuple(ii)2483 i = 02484 while 1:2485 if i >= len(ii):2486 raise StopIteration2487 if ii[i] < self.cmpt[i][1]:2488 ii[i]+=12489 break2490 else:2491 ii[i] = self.cmpt[i][0]2492 i += 12495#############2496## Results ##2497#############2499class PacketList:2500 res = []2501 def __init__(self, res=None, name="PacketList", stats=None):2502 """create a packet list from a list of packets2503 res: the list of packets2504 stats: a list of classes that will appear in the stats (defaults to [TCP,UDP,ICMP])"""2505 if stats is None:2506 stats = [ TCP,UDP,ICMP ]2507 self.stats = stats2508 if res is None:2509 res = []2510 if isinstance(res, PacketList):2511 res = res.res2512 self.res = res2513 self.listname = name2514 def _elt2pkt(self, elt):2515 return elt2516 def _elt2sum(self, elt):2517 return elt.summary()2518 def _elt2show(self, elt):2519 return self._elt2sum(elt)2520 def __repr__(self):2521# stats=dict.fromkeys(self.stats,0) ## needs python >= 2.3 :(2522 stats = dict(map(lambda x: (x,0), self.stats))2523 other = 02524 for r in self.res:2525 f = 02526 for p in stats:2527 if self._elt2pkt(r).haslayer(p):2528 stats[p] += 12529 f = 12530 break2531 if not f:2532 other += 12533 s = ""2534 ct = conf.color_theme2535 for p in self.stats:2536 s += " %s%s%s" % (ct.packetlist_proto(p.name),2537 ct.punct(":"),2538 ct.packetlist_value(stats[p]))2539 s += " %s%s%s" % (ct.packetlist_proto("Other"),2540 ct.punct(":"),2541 ct.packetlist_value(other))2542 return "%s%s%s%s%s" % (ct.punct("<"),2543 ct.packetlist_name(self.listname),2544 ct.punct(":"),2545 s,2546 ct.punct(">"))2547 def __getattr__(self, attr):2548 return getattr(self.res, attr)2549 def __getitem__(self, item):2550 if isinstance(item,type) and issubclass(item,Packet):2551 return self.__class__(filter(lambda x: item in self._elt2pkt(x),self.res),2552 name="%s from %s"%(item.__name__,self.listname))2553 if type(item) is slice:2554 return self.__class__(self.res.__getitem__(item),2555 name = "mod %s" % self.listname)2556 return self.res.__getitem__(item)2557 def __getslice__(self, *args, **kargs):2558 return self.__class__(self.res.__getslice__(*args, **kargs),2559 name="mod %s"%self.listname)2560 def __add__(self, other):2561 return self.__class__(self.res+other.res,2562 name="%s+%s"%(self.listname,other.listname))2563 def summary(self, prn=None, lfilter=None):2564 """prints a summary of each packet2565prn: function to apply to each packet instead of lambda x:x.summary()2566lfilter: truth function to apply to each packet to decide whether it will be displayed"""2567 for r in self.res:2568 if lfilter is not None:2569 if not lfilter(r):2570 continue2571 if prn is None:2572 print self._elt2sum(r)2573 else:2574 print prn(r)2575 def nsummary(self,prn=None, lfilter=None):2576 """prints a summary of each packet with the packet's number2577prn: function to apply to each packet instead of lambda x:x.summary()2578lfilter: truth function to apply to each packet to decide whether it will be displayed"""2579 for i in range(len(self.res)):2580 if lfilter is not None:2581 if not lfilter(self.res[i]):2582 continue2583 print conf.color_theme.id(i,"%04i"),2584 if prn is None:2585 print self._elt2sum(self.res[i])2586 else:2587 print prn(self.res[i])2588 def display(self): # Deprecated. Use show()2589 """deprecated. is show()"""2590 self.show()2591 def show(self, *args, **kargs):2592 """Best way to display the packet list. Defaults to nsummary() method"""2593 return self.nsummary(*args, **kargs)2595 def filter(self, func):2596 """Returns a packet list filtered by a truth function"""2597 return self.__class__(filter(func,self.res),2598 name="filtered %s"%self.listname)2599 def make_table(self, *args, **kargs):2600 """Prints a table using a function that returs for each packet its head column value, head row value and displayed value2601 ex: p.make_table(lambda x:(x[IP].dst, x[TCP].dport, x[TCP].sprintf("%flags%")) """2602 return make_table(self.res, *args, **kargs)2603 def make_lined_table(self, *args, **kargs):2604 """Same as make_table, but print a table with lines"""2605 return make_lined_table(self.res, *args, **kargs)2606 def make_tex_table(self, *args, **kargs):2607 """Same as make_table, but print a table with LaTeX syntax"""2608 return make_tex_table(self.res, *args, **kargs)2610 def plot(self, f, lfilter=None,**kargs):2611 """Applies a function to each packet to get a value that will be plotted with GnuPlot. A gnuplot object is returned2612 lfilter: a truth function that decides whether a packet must be ploted"""2613 g=Gnuplot.Gnuplot()2614 l = self.res2615 if lfilter is not None:2616 l = filter(lfilter, l)2617 l = map(f,l)2618 g.plot(Gnuplot.Data(l, **kargs))2619 return g2621 def diffplot(self, f, delay=1, lfilter=None, **kargs):2622 """diffplot(f, delay=1, lfilter=None)2623 Applies a function to couples (l[i],l[i+delay])"""2624 g = Gnuplot.Gnuplot()2625 l = self.res2626 if lfilter is not None:2627 l = filter(lfilter, l)2628 l = map(f,l[:-delay],l[delay:])2629 g.plot(Gnuplot.Data(l, **kargs))2630 return g2632 def multiplot(self, f, lfilter=None, **kargs):2633 """Uses a function that returns a label and a value for this label, then plots all the values label by label"""2634 g=Gnuplot.Gnuplot()2635 l = self.res2636 if lfilter is not None:2637 l = filter(lfilter, l)2639 d={}2640 for e in l:2641 k,v = f(e)2642 if k in d:2643 d[k].append(v)2644 else:2645 d[k] = [v]2646 data=[]2647 for k in d:2648 data.append(Gnuplot.Data(d[k], title=k, **kargs))2650 g.plot(*data)2651 return g2654 def rawhexdump(self):2655 """Prints an hexadecimal dump of each packet in the list"""2656 for p in self:2657 hexdump(self._elt2pkt(p))2659 def hexraw(self, lfilter=None):2660 """Same as nsummary(), except that if a packet has a Raw layer, it will be hexdumped2661 lfilter: a truth function that decides whether a packet must be displayed"""2662 for i in range(len(self.res)):2663 p = self._elt2pkt(self.res[i])2664 if lfilter is not None and not lfilter(p):2665 continue2666 print "%s %s %s" % (conf.color_theme.id(i,"%04i"),2667 p.sprintf("%.time%"),2668 self._elt2sum(self.res[i]))2669 if p.haslayer(Raw):2670 hexdump(p.getlayer(Raw).load)2672 def hexdump(self, lfilter=None):2673 """Same as nsummary(), except that packets are also hexdumped2674 lfilter: a truth function that decides whether a packet must be displayed"""2675 for i in range(len(self.res)):2676 p = self._elt2pkt(self.res[i])2677 if lfilter is not None and not lfilter(p):2678 continue2679 print "%s %s %s" % (conf.color_theme.id(i,"%04i"),2680 p.sprintf("%.time%"),2681 self._elt2sum(self.res[i]))2682 hexdump(p)2684 def padding(self, lfilter=None):2685 """Same as hexraw(), for Padding layer"""2686 for i in range(len(self.res)):2687 p = self._elt2pkt(self.res[i])2688 if p.haslayer(Padding):2689 if lfilter is None or lfilter(p):2690 print "%s %s %s" % (conf.color_theme.id(i,"%04i"),2691 p.sprintf("%.time%"),2692 self._elt2sum(self.res[i]))2693 hexdump(p.getlayer(Padding).load)2695 def nzpadding(self, lfilter=None):2696 """Same as padding() but only non null padding"""2697 for i in range(len(self.res)):2698 p = self._elt2pkt(self.res[i])2699 if p.haslayer(Padding):2700 pad = p.getlayer(Padding).load2701 if pad == pad[0]*len(pad):2702 continue2703 if lfilter is None or lfilter(p):2704 print "%s %s %s" % (conf.color_theme.id(i,"%04i"),2705 p.sprintf("%.time%"),2706 self._elt2sum(self.res[i]))2707 hexdump(p.getlayer(Padding).load)2710 def conversations(self, getsrcdst=None,**kargs):2711 """Graphes a conversations between sources and destinations and display it2712 (using graphviz and imagemagick)2713 getsrcdst: a function that takes an element of the list and return the source and dest2714 by defaults, return source and destination IP2715 type: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option2716 target: filename or redirect. Defaults pipe to Imagemagick's display program2717 prog: which graphviz program to use"""2718 if getsrcdst is None:2719 getsrcdst = lambda x:(x[IP].src, x[IP].dst)2720 conv = {}2721 for p in self.res:2722 p = self._elt2pkt(p)2723 try:2724 c = getsrcdst(p)2725 except:2726 #XXX warning()2727 continue2728 conv[c] = conv.get(c,0)+12729 gr = 'digraph "conv" {\n'2730 for s,d in conv:2731 gr += '\t "%s" -> "%s"\n' % (s,d)2732 gr += "}\n"2733 return do_graph(gr, **kargs)2735 def afterglow(self, src=None, event=None, dst=None, **kargs):2736 """Experimental clone attempt of http://sourceforge.net/projects/afterglow2737 each datum is reduced as src -> event -> dst and the data are graphed.2738 by default we have IP.src -> IP.dport -> IP.dst"""2739 if src is None:2740 src = lambda x: x[IP].src2741 if event is None:2742 event = lambda x: x[IP].dport2743 if dst is None:2744 dst = lambda x: x[IP].dst2745 sl = {}2746 el = {}2747 dl = {}2748 for i in self.res:2749 try:2750 s,e,d = src(i),event(i),dst(i)2751 if s in sl:2752 n,l = sl[s]2753 n += 12754 if e not in l:2755 l.append(e)2756 sl[s] = (n,l)2757 else:2758 sl[s] = (1,[e])2759 if e in el:2760 n,l = el[e]2761 n+=12762 if d not in l:2763 l.append(d)2764 el[e] = (n,l)2765 else:2766 el[e] = (1,[d])2767 dl[d] = dl.get(d,0)+12768 except:2769 continue2771 import math2772 def normalize(n):2773 return 2+math.log(n)/4.02775 def minmax(x):2776 m,M = min(x),max(x)2777 if m == M:2778 m = 02779 if M == 0:2780 M = 12781 return m,M2783 mins,maxs = minmax(map(lambda (x,y): x, sl.values()))2784 mine,maxe = minmax(map(lambda (x,y): x, el.values()))2785 mind,maxd = minmax(dl.values())2787 gr = 'digraph "afterglow" {\n\tedge [len=2.5];\n'2789 gr += "# src nodes\n"2790 for s in sl:2791 n,l = sl[s]; n = 1+float(n-mins)/(maxs-mins)2792 gr += '"src.%s" [label = "%s", shape=box, fillcolor="#FF0000", style=filled, fixedsize=1, height=%.2f,width=%.2f];\n' % (`s`,`s`,n,n)2793 gr += "# event nodes\n"2794 for e in el:2795 n,l = el[e]; n = n = 1+float(n-mine)/(maxe-mine)2796 gr += '"evt.%s" [label = "%s", shape=circle, fillcolor="#00FFFF", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (`e`,`e`,n,n)2797 for d in dl:2798 n = dl[d]; n = n = 1+float(n-mind)/(maxd-mind)2799 gr += '"dst.%s" [label = "%s", shape=triangle, fillcolor="#0000ff", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (`d`,`d`,n,n)2801 gr += "###\n"2802 for s in sl:2803 n,l = sl[s]2804 for e in l:2805 gr += ' "src.%s" -> "evt.%s";\n' % (`s`,`e`)2806 for e in el:2807 n,l = el[e]2808 for d in l:2809 gr += ' "evt.%s" -> "dst.%s";\n' % (`e`,`d`)2811 gr += "}"2812 open("/tmp/aze","w").write(gr)2813 return do_graph(gr, **kargs)2817 def timeskew_graph(self, ip, **kargs):2818 """Tries to graph the timeskew between the timestamps and real time for a given ip"""2819 res = map(lambda x: self._elt2pkt(x), self.res)2820 b = filter(lambda x:x.haslayer(IP) and x.getlayer(IP).src == ip and x.haslayer(TCP), res)2821 c = []2822 for p in b:2823 opts = p.getlayer(TCP).options2824 for o in opts:2825 if o[0] == "Timestamp":2826 c.append((p.time,o[1][0]))2827 if not c:2828 warning("No timestamps found in packet list")2829 return2830 d = map(lambda (x,y): (x%2000,((x-c[0][0])-((y-c[0][1])/1000.0))),c)2831 g = Gnuplot.Gnuplot()2832 g.plot(Gnuplot.Data(d,**kargs))2833 return g2835 def _dump_document(self, **kargs):2836 d = pyx.document.document()2837 l = len(self.res)2838 for i in range(len(self.res)):2839 elt = self.res[i]2840 c = self._elt2pkt(elt).canvas_dump(**kargs)2841 cbb = c.bbox()2842 c.text(cbb.left(),cbb.top()+1,r"\font\cmssfont=cmss12\cmssfont{Frame %i/%i}" % (i,l),[pyx.text.size.LARGE])2843 if conf.verb >= 2:2844 os.write(1,".")2845 d.append(pyx.document.page(c, paperformat=pyx.document.paperformat.A4,2846 margin=1*pyx.unit.t_cm,2847 fittosize=1))2848 return d2852 def psdump(self, filename = None, **kargs):2853 """Creates a multipage poscript file with a psdump of every packet2854 filename: name of the file to write to. If empty, a temporary file is used and2855 conf.prog.psreader is called"""2856 d = self._dump_document(**kargs)2857 if filename is None:2858 filename = "/tmp/scapy.psd.%i" % os.getpid()2859 d.writePSfile(filename)2860 os.system("%s %s.ps &" % (conf.prog.psreader,filename))2861 else:2862 d.writePSfile(filename)2863 print2865 def pdfdump(self, filename = None, **kargs):2866 """Creates a PDF file with a psdump of every packet2867 filename: name of the file to write to. If empty, a temporary file is used and2868 conf.prog.pdfreader is called"""2869 d = self._dump_document(**kargs)2870 if filename is None:2871 filename = "/tmp/scapy.psd.%i" % os.getpid()2872 d.writePDFfile(filename)2873 os.system("%s %s.pdf &" % (conf.prog.pdfreader,filename))2874 else:2875 d.writePDFfile(filename)2876 print2878 def sr(self,multi=0):2879 """sr([multi=1]) -> (SndRcvList, PacketList)2880 Matches packets in the list and return ( (matched couples), (unmatched packets) )"""2881 remain = self.res[:]2882 sr = []2883 i = 02884 while i < len(remain):2885 s = remain[i]2886 j = i2887 while j < len(remain)-1:2888 j += 12889 r = remain[j]2890 if r.answers(s):2891 sr.append((s,r))2892 if multi:2893 remain[i]._answered=12894 remain[j]._answered=22895 continue2896 del(remain[j])2897 del(remain[i])2898 i -= 12899 break2900 i += 12901 if multi:2902 remain = filter(lambda x:not hasattr(x,"_answered"), remain)2903 return SndRcvList(sr),PacketList(remain)2910class Dot11PacketList(PacketList):2911 def __init__(self, res=None, name="Dot11List", stats=None):2912 if stats is None:2913 stats = [Dot11WEP, Dot11Beacon, UDP, ICMP, TCP]2915 PacketList.__init__(self, res, name, stats)2916 def toEthernet(self):2917 data = map(lambda x:x.getlayer(Dot11), filter(lambda x : x.haslayer(Dot11) and x.type == 2, self.res))2918 r2 = []2919 for p in data:2920 q = p.copy()2921 q.unwep()2922 r2.append(Ether()/q.payload.payload.payload) #Dot11/LLC/SNAP/IP2923 return PacketList(r2,name="Ether from %s"%self.listname)2927class SndRcvList(PacketList):2928 def __init__(self, res=None, name="Results", stats=None):2929 PacketList.__init__(self, res, name, stats)2930 def _elt2pkt(self, elt):2931 return elt[1]2932 def _elt2sum(self, elt):2933 return "%s ==> %s" % (elt[0].summary(),elt[1].summary())2936class ARPingResult(SndRcvList):2937 def __init__(self, res=None, name="ARPing", stats=None):2938 PacketList.__init__(self, res, name, stats)2940 def show(self):2941 for s,r in self.res:2942 print r.sprintf("%Ether.src% %ARP.psrc%")2945class AS_resolver:2946 server = None2947 options = "-k"2948 def __init__(self, server=None, port=43, options=None):2949 if server is not None:2950 self.server = server2951 self.port = port2952 if options is not None:2953 self.options = options2955 def _start(self):2956 self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)2957 self.s.connect((self.server,self.port))2958 if self.options:2959 self.s.send(self.options+"\n")2960 self.s.recv(8192)2961 def _stop(self):2962 self.s.close()2964 def _parse_whois(self, txt):2965 asn,desc = None,""2966 for l in txt.splitlines():2967 if not asn and l.startswith("origin:"):2968 asn = l[7:].strip()2969 if l.startswith("descr:"):2970 if desc:2971 desc += r"\n"2972 desc += l[6:].strip()2973 if asn is not None and desc:2974 break2975 return asn,desc.strip()2977 def _resolve_one(self, ip):2978 self.s.send("%s\n" % ip)2979 x = ""2980 while not ("%" in x or "source" in x):2981 x += self.s.recv(8192)2982 asn, desc = self._parse_whois(x)2983 return ip,asn,desc2984 def resolve(self, *ips):2985 self._start()2986 ret = []2987 for ip in ips:2988 ip,asn,desc = self._resolve_one(ip)2989 if asn is not None:2990 ret.append((ip,asn,desc))2991 self._stop()2992 return ret2994class AS_resolver_riswhois(AS_resolver):2995 server = "riswhois.ripe.net"2996 options = "-k -M -1"2999class AS_resolver_radb(AS_resolver):3000 server = "whois.ra.net"3001 options = "-k -M"3004class AS_resolver_cymru(AS_resolver):3005 server = "whois.cymru.com"3006 options = None3007 def resolve(self, *ips):3008 ASNlist = []3009 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)3010 s.connect((self.server,self.port))3011 s.send("begin\r\n"+"\r\n".join(ips)+"\r\nend\r\n")3012 r = ""3013 while 1:3014 l = s.recv(8192)3015 if l == "":3016 break3017 r += l3018 s.close()3019 for l in r.splitlines()[1:]:3020 if "|" not in l:3021 continue3022 asn,ip,desc = map(str.strip, l.split("|"))3023 if asn == "NA":3024 continue3025 asn = int(asn)3026 ASNlist.append((ip,asn,desc))3027 return ASNlist3029class AS_resolver_multi(AS_resolver):3030 resolvers_list = ( AS_resolver_cymru(),AS_resolver_riswhois(),AS_resolver_radb() )3031 def __init__(self, *reslist):3032 if reslist:3033 self.resolvers_list = reslist3034 def resolve(self, *ips):3035 todo = ips3036 ret = []3037 for ASres in self.resolvers_list:3038 res = ASres.resolve(*todo)3039 resolved = [ ip for ip,asn,desc in res ]3040 todo = [ ip for ip in todo if ip not in resolved ]3041 ret += res3042 return ret3046class TracerouteResult(SndRcvList):3047 def __init__(self, res=None, name="Traceroute", stats=None):3048 PacketList.__init__(self, res, name, stats)3049 self.graphdef = None3050 self.graphASres = 03051 self.padding = 03052 self.hloc = None3053 self.nloc = None3055 def show(self):3056 return self.make_table(lambda (s,r): (s.sprintf("%IP.dst%:{TCP:tcp%ir,TCP.dport%}{UDP:udp%ir,UDP.dport%}{ICMP:ICMP}"),3057 s.ttl,3058 r.sprintf("%-15s,IP.src% {TCP:%TCP.flags%}{ICMP:%ir,ICMP.type%}")))3061 def get_trace(self):3062 trace = {}3063 for s,r in self.res:3064 if IP not in s:3065 continue3066 d = s[IP].dst3067 if d not in trace:3068 trace[d] = {}3069 trace[d][s[IP].ttl] = r[IP].src, ICMP not in r3070 for k in trace.values():3071 m = filter(lambda x:k[x][1], k.keys())3072 if not m:3073 continue3074 m = min(m)3075 for l in k.keys():3076 if l > m:3077 del(k[l])3078 return trace3080 def trace3D(self):3081 """Give a 3D representation of the traceroute.3082 right button: rotate the scene3083 middle button: zoom3084 left button: move the scene3085 left button on a ball: toggle IP displaying3086 ctrl-left button on a ball: scan ports 21,22,23,25,80 and 443 and display the result"""3087 trace = self.get_trace()3088 import visual3090 class IPsphere(visual.sphere):3091 def __init__(self, ip, **kargs):3092 visual.sphere.__init__(self, **kargs)3093 self.ip=ip3094 self.label=None3095 self.setlabel(self.ip)3096 def setlabel(self, txt,visible=None):3097 if self.label is not None:3098 if visible is None:3099 visible = self.label.visible3100 self.label.visible = 03101 elif visible is None:3102 visible=03103 self.label=visual.label(text=txt, pos=self.pos, space=self.radius, xoffset=10, yoffset=20, visible=visible)3104 def action(self):3105 self.label.visible ^= 13107 visual.scene = visual.display()3108 visual.scene.exit_on_close(0)3109 start = visual.box()3110 rings={}3111 tr3d = {}3112 for i in trace:3113 tr = trace[i]3114 tr3d[i] = []3115 ttl = tr.keys()3116 for t in range(1,max(ttl)+1):3117 if t not in rings:3118 rings[t] = []3119 if t in tr:3120 if tr[t] not in rings[t]:3121 rings[t].append(tr[t])3122 tr3d[i].append(rings[t].index(tr[t]))3123 else:3124 rings[t].append(("unk",-1))3125 tr3d[i].append(len(rings[t])-1)3126 for t in rings:3127 r = rings[t]3128 l = len(r)3129 for i in range(l):3130 if r[i][1] == -1:3131 col = (0.75,0.75,0.75)3132 elif r[i][1]:3133 col = visual.color.green3134 else:3135 col = visual.color.blue3137 s = IPsphere(pos=((l-1)*visual.cos(2*i*visual.pi/l),(l-1)*visual.sin(2*i*visual.pi/l),2*t),3138 ip = r[i][0],3139 color = col)3140 for trlst in tr3d.values():3141 if t <= len(trlst):3142 if trlst[t-1] == i:3143 trlst[t-1] = s3144 forecol = colgen(0.625, 0.4375, 0.25, 0.125)3145 for trlst in tr3d.values():3146 col = forecol.next()3147 start = (0,0,0)3148 for ip in trlst:3149 visual.cylinder(pos=start,axis=ip.pos-start,color=col,radius=0.2)3150 start = ip.pos3152 movcenter=None3153 while 1:3154 if visual.scene.kb.keys:3155 k = visual.scene.kb.getkey()3156 if k == "esc":3157 break3158 if visual.scene.mouse.events:3159 ev = visual.scene.mouse.getevent()3160 if ev.press == "left":3161 o = ev.pick3162 if o:3163 if ev.ctrl:3164 if o.ip == "unk":3165 continue3166 savcolor = o.color3167 o.color = (1,0,0)3168 a,b=sr(IP(dst=o.ip)/TCP(dport=[21,22,23,25,80,443]),timeout=2)3169 o.color = savcolor3170 if len(a) == 0:3171 txt = "%s:\nno results" % o.ip3172 else:3173 txt = "%s:\n" % o.ip3174 for s,r in a:3175 txt += r.sprintf("{TCP:%IP.src%:%TCP.sport% %TCP.flags%}{TCPerror:%IPerror.dst%:%TCPerror.dport% %IP.src% %ir,ICMP.type%}\n")3176 o.setlabel(txt, visible=1)3177 else:3178 if hasattr(o, "action"):3179 o.action()3180 elif ev.drag == "left":3181 movcenter = ev.pos3182 elif ev.drop == "left":3183 movcenter = None3184 if movcenter:3185 visual.scene.center -= visual.scene.mouse.pos-movcenter3186 movcenter = visual.scene.mouse.pos3189 def world_trace(self):3190 ips = {}3191 rt = {}3192 ports_done = {}3193 for s,r in self.res:3194 ips[r.src] = None3195 if s.haslayer(TCP) or s.haslayer(UDP):3196 trace_id = (s.src,s.dst,s.proto,s.dport)3197 elif s.haslayer(ICMP):3198 trace_id = (s.src,s.dst,s.proto,s.type)3199 else:3200 trace_id = (s.src,s.dst,s.proto,0)3201 trace = rt.get(trace_id,{})3202 if not r.haslayer(ICMP) or r.type != 11:3203 if ports_done.has_key(trace_id):3204 continue3205 ports_done[trace_id] = None3206 trace[s.ttl] = r.src3207 rt[trace_id] = trace3209 trt = {}3210 for trace_id in rt:3211 trace = rt[trace_id]3212 loctrace = []3213 for i in range(max(trace.keys())):3214 ip = trace.get(i,None)3215 if ip is None:3216 continue3217 loc = locate_ip(ip)3218 if loc is None:3219 continue3220# loctrace.append((ip,loc)) # no labels yet3221 loctrace.append(loc)3222 if loctrace:3223 trt[trace_id] = loctrace3225 tr = map(lambda x: Gnuplot.Data(x,with="lines"), trt.values())3226 g = Gnuplot.Gnuplot()3227 world = Gnuplot.File(conf.gnuplot_world,with="lines")3228 g.plot(world,*tr)3229 return g3231 def make_graph(self,ASres=None,padding=0):3232 if ASres is None:3233 ASres = conf.AS_resolver3234 self.graphASres = ASres3235 self.graphpadding = padding3236 ips = {}3237 rt = {}3238 ports = {}3239 ports_done = {}3240 for s,r in self.res:3241 r = r[IP] or r[IPv6] or r3242 s = s[IP] or s[IPv6] or s3243 ips[r.src] = None3244 if TCP in s:3245 trace_id = (s.src,s.dst,6,s.dport)3246 elif UDP in s:3247 trace_id = (s.src,s.dst,17,s.dport)3248 elif ICMP in s:3249 trace_id = (s.src,s.dst,1,s.type)3250 else:3251 trace_id = (s.src,s.dst,s.proto,0)3252 trace = rt.get(trace_id,{})3253 ttl = IPv6 in s and s.hlim or s.ttl3254 if not (ICMP in r and r[ICMP].type == 11) and not (IPv6 in r and ICMPv6TimeExceeded in r):3255 if trace_id in ports_done:3256 continue3257 ports_done[trace_id] = None3258 p = ports.get(r.src,[])3259 if TCP in r:3260 p.append(r.sprintf("<T%ir,TCP.sport%> %TCP.sport% %TCP.flags%"))3261 trace[ttl] = r.sprintf('"%r,src%":T%ir,TCP.sport%')3262 elif UDP in r:3263 p.append(r.sprintf("<U%ir,UDP.sport%> %UDP.sport%"))3264 trace[ttl] = r.sprintf('"%r,src%":U%ir,UDP.sport%')3265 elif ICMP in r:3266 p.append(r.sprintf("<I%ir,ICMP.type%> ICMP %ICMP.type%"))3267 trace[ttl] = r.sprintf('"%r,src%":I%ir,ICMP.type%')3268 else:3269 p.append(r.sprintf("{IP:<P%ir,proto%> IP %proto%}{IPv6:<P%ir,nh%> IPv6 %nh%}"))3270 trace[ttl] = r.sprintf('"%r,src%":{IP:P%ir,proto%}{IPv6:P%ir,nh%}')3271 ports[r.src] = p3272 else:3273 trace[ttl] = r.sprintf('"%r,src%"')3274 rt[trace_id] = trace3276 # Fill holes with unk%i nodes3277 unknown_label = incremental_label("unk%i")3278 blackholes = []3279 bhip = {}3280 for rtk in rt:3281 trace = rt[rtk]3282 k = trace.keys()3283 for n in range(min(k), max(k)):3284 if not trace.has_key(n):3285 trace[n] = unknown_label.next()3286 if not ports_done.has_key(rtk):3287 if rtk[2] == 1: #ICMP3288 bh = "%s %i/icmp" % (rtk[1],rtk[3])3289 elif rtk[2] == 6: #TCP3290 bh = "%s %i/tcp" % (rtk[1],rtk[3])3291 elif rtk[2] == 17: #UDP3292 bh = '%s %i/udp' % (rtk[1],rtk[3])3293 else:3294 bh = '%s %i/proto' % (rtk[1],rtk[2])3295 ips[bh] = None3296 bhip[rtk[1]] = bh3297 bh = '"%s"' % bh3298 trace[max(k)+1] = bh3299 blackholes.append(bh)3301 # Find AS numbers3302 ASN_query_list = dict.fromkeys(map(lambda x:x.rsplit(" ",1)[0],ips)).keys()3303 if ASres is None:3304 ASNlist = []3305 else:3306 ASNlist = ASres.resolve(*ASN_query_list)3308 ASNs = {}3309 ASDs = {}3310 for ip,asn,desc, in ASNlist:3311 if asn is None:3312 continue3313 iplist = ASNs.get(asn,[])3314 if ip in bhip:3315 if ip in ports:3316 iplist.append(ip)3317 iplist.append(bhip[ip])3318 else:3319 iplist.append(ip)3320 ASNs[asn] = iplist3321 ASDs[asn] = desc3324 backcolorlist=colgen("60","86","ba","ff")3325 forecolorlist=colgen("a0","70","40","20")3327 s = "digraph trace {\n"3329 s += "\n\tnode [shape=ellipse,color=black,style=solid];\n\n"3331 s += "\n#ASN clustering\n"3332 for asn in ASNs:3333 s += '\tsubgraph cluster_%s {\n' % asn3334 col = backcolorlist.next()3335 s += '\t\tcolor="#%s%s%s";' % col3336 s += '\t\tnode [fillcolor="#%s%s%s",style=filled];' % col3337 s += '\t\tfontsize = 10;'3338 s += '\t\tlabel = "%s\\n[%s]"\n' % (asn,ASDs[asn])3339 for ip in ASNs[asn]:3341 s += '\t\t"%s";\n'%ip3342 s += "\t}\n"3347 s += "#endpoints\n"3348 for p in ports:3349 s += '\t"%s" [shape=record,color=black,fillcolor=green,style=filled,label="%s|%s"];\n' % (p,p,"|".join(ports[p]))3351 s += "\n#Blackholes\n"3352 for bh in blackholes:3353 s += '\t%s [shape=octagon,color=black,fillcolor=red,style=filled];\n' % bh3355 if padding:3356 s += "\n#Padding\n"3357 pad={}3358 for snd,rcv in self.res:3359 if rcv.src not in ports and rcv.haslayer(Padding):3360 p = rcv.getlayer(Padding).load3361 if p != "\x00"*len(p):3362 pad[rcv.src]=None3363 for rcv in pad:3364 s += '\t"%s" [shape=triangle,color=black,fillcolor=red,style=filled];\n' % rcv3368 s += "\n\tnode [shape=ellipse,color=black,style=solid];\n\n"3371 for rtk in rt:3372 s += "#---[%s\n" % `rtk`3373 s += '\t\tedge [color="#%s%s%s"];\n' % forecolorlist.next()3374 trace = rt[rtk]3375 k = trace.keys()3376 for n in range(min(k), max(k)):3377 s += '\t%s ->\n' % trace[n]3378 s += '\t%s;\n' % trace[max(k)]3380 s += "}\n";3381 self.graphdef = s3383 def graph(self, ASres=None, padding=0, **kargs):3384 """x.graph(ASres=conf.AS_resolver, other args):3385 ASres=None : no AS resolver => no clustering3386 ASres=AS_resolver() : default whois AS resolver (riswhois.ripe.net)3387 ASres=AS_resolver_cymru(): use whois.cymru.com whois database3388 ASres=AS_resolver(server="whois.ra.net")3389 type: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option3390 target: filename or redirect. Defaults pipe to Imagemagick's display program3391 prog: which graphviz program to use"""3392 if ASres is None:3393 ASres = conf.AS_resolver3394 if (self.graphdef is None or3395 self.graphASres != ASres or3396 self.graphpadding != padding):3397 self.make_graph(ASres,padding)3399 return do_graph(self.graphdef, **kargs)3404############3405## Fields ##3406############3408class Field:3409 """For more informations on how this work, please refer to3410 http://www.secdev.org/projects/scapy/files/scapydoc.pdf3411 chapter ``Adding a New Field''"""3412 islist=03413 holds_packets=03414 def __init__(self, name, default, fmt="H"):3415 self.name = name3416 if fmt[0] in "@=<>!":3417 self.fmt = fmt3418 else:3419 self.fmt = "!"+fmt3420 self.default = self.any2i(None,default)3421 self.sz = struct.calcsize(self.fmt)3422 self.owners = []3424 def register_owner(self, cls):3425 self.owners.append(cls)3427 def i2len(self, pkt, x):3428 """Convert internal value to a length usable by a FieldLenField"""3429 return self.sz3430 def i2count(self, pkt, x):3431 """Convert internal value to a number of elements usable by a FieldLenField.3432 Always 1 except for list fields"""3433 return 13434 def h2i(self, pkt, x):3435 """Convert human value to internal value"""3436 return x3437 def i2h(self, pkt, x):3438 """Convert internal value to human value"""3439 return x3440 def m2i(self, pkt, x):3441 """Convert machine value to internal value"""3442 return x3443 def i2m(self, pkt, x):3444 """Convert internal value to machine value"""3445 if x is None:3446 x = 03447 return x3448 def any2i(self, pkt, x):3449 """Try to understand the most input values possible and make an internal value from them"""3450 return self.h2i(pkt, x)3451 def i2repr(self, pkt, x):3452 """Convert internal value to a nice representation"""3453 if x is None:3454 x = 03455 return repr(self.i2h(pkt,x))3456 def addfield(self, pkt, s, val):3457 """Add an internal value to a string"""3458 return s+struct.pack(self.fmt, self.i2m(pkt,val))3459 def getfield(self, pkt, s):3460 """Extract an internal value from a string"""3461 return s[self.sz:], self.m2i(pkt, struct.unpack(self.fmt, s[:self.sz])[0])3462 def do_copy(self, x):3463 if hasattr(x, "copy"):3464 return x.copy()3465 if type(x) is list:3466 x = x[:]3467 for i in xrange(len(x)):3468 if isinstance(x[i], Packet):3469 x[i] = x[i].copy()3470 return x3471 def __repr__(self):3472 return "<Field (%s).%s>" % (",".join(x.__name__ for x in self.owners),self.name)3473 def copy(self):3474 return copy.deepcopy(self)3475 def randval(self):3476 """Return a volatile object whose value is both random and suitable for this field"""3477 fmtt = self.fmt[-1]3478 if fmtt in "BHIQ":3479 return {"B":RandByte,"H":RandShort,"I":RandInt, "Q":RandLong}[fmtt]()3480 elif fmtt == "s":3481 if self.fmt[0] in "0123456789":3482 l = int(self.fmt[:-1])3483 else:3484 l = int(self.fmt[1:-1])3485 return RandBin(l)3486 else:3487 warning("no random class for [%s] (fmt=%s)." % (self.name, self.fmt))3492class Emph:3493 fld = ""3494 def __init__(self, fld):3495 self.fld = fld3496 def __getattr__(self, attr):3497 return getattr(self.fld,attr)3498 def __hash__(self):3499 return hash(self.fld)3500 def __eq__(self, other):3501 return self.fld == other3504class ActionField:3505 _fld = None3506 def __init__(self, fld, action_method, **kargs):3507 self._fld = fld3508 self._action_method = action_method3509 self._privdata = kargs3510 def any2i(self, pkt, val):3511 getattr(pkt, self._action_method)(val, self._fld, **self._privdata)3512 return getattr(self._fld, "any2i")(pkt, val)3513 def __getattr__(self, attr):3514 return getattr(self._fld,attr)3517class ConditionalField:3518 fld = None3519 def __init__(self, fld, cond):3520 self.fld = fld3521 self.cond = cond3522 def _evalcond(self,pkt):3523 return self.cond(pkt)3525 def getfield(self, pkt, s):3526 if self._evalcond(pkt):3527 return self.fld.getfield(pkt,s)3528 else:3529 return s,None3531 def addfield(self, pkt, s, val):3532 if self._evalcond(pkt):3533 return self.fld.addfield(pkt,s,val)3534 else:3535 return s3536 def __getattr__(self, attr):3537 return getattr(self.fld,attr)3540class PadField:3541 """Add bytes after the proxified field so that it ends at the specified3542 alignment from its begining"""3543 _fld = None3544 def __init__(self, fld, align, padwith=None):3545 self._fld = fld3546 self._align = align3547 self._padwith = padwith or ""3549 def addfield(self, pkt, s, val):3550 sval = self._fld.addfield(pkt, "", val)3551 return s+sval+struct.pack("%is" % (-len(sval)%self._align), self._padwith)3553 def __getattr__(self, attr):3554 return getattr(self._fld,attr)3557class MACField(Field):3558 def __init__(self, name, default):3559 Field.__init__(self, name, default, "6s")3560 def i2m(self, pkt, x):3561 if x is None:3562 return "\0\0\0\0\0\0"3563 return mac2str(x)3564 def m2i(self, pkt, x):3565 return str2mac(x)3566 def any2i(self, pkt, x):3567 if type(x) is str and len(x) is 6:3568 x = self.m2i(pkt, x)3569 return x3570 def i2repr(self, pkt, x):3571 x = self.i2h(pkt, x)3572 if self in conf.resolve:3573 x = conf.manufdb._resolve_MAC(x)3574 return x3575 def randval(self):3576 return RandMAC()3578class DestMACField(MACField):3579 def __init__(self, name):3580 MACField.__init__(self, name, None)3581 def i2h(self, pkt, x):3582 if x is None:3583 dstip = None3584 if isinstance(pkt.payload, IPv6):3585 dstip = pkt.payload.dst3586 elif isinstance(pkt.payload, IP):3587 dstip = pkt.payload.dst3588 elif isinstance(pkt.payload, ARP):3589 dstip = pkt.payload.pdst3590 if isinstance(dstip, Gen):3591 dstip = dstip.__iter__().next()3592 if dstip is not None:3593 if isinstance(pkt.payload, IPv6):3594 x = getmacbyip6(dstip, chainCC=1)3595 else:3596 x = getmacbyip(dstip, chainCC=1)3597 if x is None:3598 x = "ff:ff:ff:ff:ff:ff"3599 warning("Mac address to reach %s not found\n"%dstip)3600 return MACField.i2h(self, pkt, x)3601 def i2m(self, pkt, x):3602 return MACField.i2m(self, pkt, self.i2h(pkt, x))3604class SourceMACField(MACField):3605 def __init__(self, name):3606 MACField.__init__(self, name, None)3607 def i2h(self, pkt, x):3608 if x is None:3609 dstip = None3610 if isinstance(pkt.payload, IPv6):3611 dstip = pkt.payload.dst3612 elif isinstance(pkt.payload, IP):3613 dstip = pkt.payload.dst3614 elif isinstance(pkt.payload, ARP):3615 dstip = pkt.payload.pdst3616 if isinstance(dstip, Gen):3617 dstip = dstip.__iter__().next()3618 if dstip is not None:3619 if isinstance(pkt.payload, IPv6):3620 iff,a,nh = conf.route6.route(dstip)3621 else:3622 iff,a,gw = conf.route.route(dstip)3623 try:3624 x = get_if_hwaddr(iff)3625 except:3626 pass3627 if x is None:3628 x = "00:00:00:00:00:00"3629 return MACField.i2h(self, pkt, x)3630 def i2m(self, pkt, x):3631 return MACField.i2m(self, pkt, self.i2h(pkt, x))3633class ARPSourceMACField(MACField):3634 def __init__(self, name):3635 MACField.__init__(self, name, None)3636 def i2h(self, pkt, x):3637 if x is None:3638 dstip = pkt.pdst3639 if isinstance(dstip, Gen):3640 dstip = dstip.__iter__().next()3641 if dstip is not None:3642 iff,a,gw = conf.route.route(dstip)3643 try:3644 x = get_if_hwaddr(iff)3645 except:3646 pass3647 if x is None:3648 x = "00:00:00:00:00:00"3649 return MACField.i2h(self, pkt, x)3650 def i2m(self, pkt, x):3651 return MACField.i2m(self, pkt, self.i2h(pkt, x))3653class Dot11AddrMACField(MACField):3654 def is_applicable(self, pkt):3655 return 13656 def addfield(self, pkt, s, val):3657 if self.is_applicable(pkt):3658 return MACField.addfield(self, pkt, s, val)3659 else:3660 return s3661 def getfield(self, pkt, s):3662 if self.is_applicable(pkt):3663 return MACField.getfield(self, pkt, s)3664 else:3665 return s,None3667class Dot11Addr2MACField(Dot11AddrMACField):3668 def is_applicable(self, pkt):3669 if pkt.type == 1:3670 return pkt.subtype in [ 0xb, 0xa, 0xe, 0xf] # RTS, PS-Poll, CF-End, CF-End+CF-Ack3671 return 13673class Dot11Addr3MACField(Dot11AddrMACField):3674 def is_applicable(self, pkt):3675 if pkt.type in [0,2]:3676 return 13677 return 03679class Dot11Addr4MACField(Dot11AddrMACField):3680 def is_applicable(self, pkt):3681 if pkt.type == 2:3682 if pkt.FCfield & 0x3 == 0x3: # To-DS and From-DS are set3683 return 13684 return 03686class IPField(Field):3687 def __init__(self, name, default):3688 Field.__init__(self, name, default, "4s")3689 def h2i(self, pkt, x):3690 if type(x) is str:3691 try:3692 inet_aton(x)3693 except socket.error:3694 x = Net(x)3695 elif type(x) is list:3696 x = [self.h2i(pkt, n) for n in x]3697 return x3698 def resolve(self, x):3699 if self in conf.resolve:3700 try:3701 ret = socket.gethostbyaddr(x)[0]3702 except:3703 pass3704 else:3705 if ret:3706 return ret3707 return x3708 def i2m(self, pkt, x):3709 return inet_aton(x)3710 def m2i(self, pkt, x):3711 return inet_ntoa(x)3712 def any2i(self, pkt, x):3713 return self.h2i(pkt,x)3714 def i2repr(self, pkt, x):3715 return self.resolve(self.i2h(pkt, x))3716 def randval(self):3717 return RandIP()3719class SourceIPField(IPField):3720 def __init__(self, name, dstname):3721 IPField.__init__(self, name, None)3722 self.dstname = dstname3723 def i2m(self, pkt, x):3724 if x is None:3725 iff,x,gw = conf.route.route(getattr(pkt,self.dstname))3726 return IPField.i2m(self, pkt, x)3727 def i2h(self, pkt, x):3728 if x is None:3729 dst=getattr(pkt,self.dstname)3730 if isinstance(dst,Gen):3731 r = map(conf.route.route, dst)3732 r.sort()3733 if r[0] == r[-1]:3734 x=r[0][1]3735 else:3736 warning("More than one possible route for %s"%repr(dst))3737 return None3738 else:3739 iff,x,gw = conf.route.route(dst)3740 return IPField.i2h(self, pkt, x)3745class ByteField(Field):3746 def __init__(self, name, default):3747 Field.__init__(self, name, default, "B")3749class XByteField(ByteField):3750 def i2repr(self, pkt, x):3751 if x is None:3752 x = 03753 return lhex(self.i2h(pkt, x))3755class X3BytesField(XByteField):3756 def __init__(self, name, default):3757 Field.__init__(self, name, default, "!I")3758 def addfield(self, pkt, s, val):3759 return s+struct.pack(self.fmt, self.i2m(pkt,val))[1:4]3760 def getfield(self, pkt, s):3761 return s[3:], self.m2i(pkt, struct.unpack(self.fmt, "\x00"+s[:3])[0])3764class ShortField(Field):3765 def __init__(self, name, default):3766 Field.__init__(self, name, default, "H")3768class LEShortField(Field):3769 def __init__(self, name, default):3770 Field.__init__(self, name, default, "<H")3772class XShortField(ShortField):3773 def i2repr(self, pkt, x):3774 if x is None:3775 x = 03776 return lhex(self.i2h(pkt, x))3779class IntField(Field):3780 def __init__(self, name, default):3781 Field.__init__(self, name, default, "I")3783class SignedIntField(Field):3784 def __init__(self, name, default):3785 Field.__init__(self, name, default, "i")3786 def randval(self):3787 return RandSInt()3789class LEIntField(Field):3790 def __init__(self, name, default):3791 Field.__init__(self, name, default, "<I")3793class LESignedIntField(Field):3794 def __init__(self, name, default):3795 Field.__init__(self, name, default, "<i")3796 def randval(self):3797 return RandSInt()3799class XIntField(IntField):3800 def i2repr(self, pkt, x):3801 if x is None:3802 x = 03803 return lhex(self.i2h(pkt, x))3806class LongField(Field):3807 def __init__(self, name, default):3808 Field.__init__(self, name, default, "Q")3810class XLongField(LongField):3811 def i2repr(self, pkt, x):3812 if x is None:3813 x = 03814 return lhex(self.i2h(pkt, x))3816class IEEEFloatField(Field):3817 def __init__(self, name, default):3818 Field.__init__(self, name, default, "f")3820class IEEEDoubleField(Field):3821 def __init__(self, name, default):3822 Field.__init__(self, name, default, "d")3825def FIELD_LENGTH_MANAGEMENT_DEPRECATION(x):3826 try:3827 for tb in traceback.extract_stack()+[("??",-1,None,"")]:3828 f,l,_,line = tb3829 if line.startswith("fields_desc"):3830 break3831 except:3832 f,l="??",-13833 log_loading.warning("Deprecated use of %s (%s l. %i). See http://trac.secdev.org/scapy/wiki/LengthFields" % (x,f,l))3835class StrField(Field):3836 def __init__(self, name, default, fmt="H", remain=0, shift=0):3837 Field.__init__(self,name,default,fmt)3838 self.remain = remain3839 self.shift = shift3840 if shift != 0:3841 FIELD_LENGTH_MANAGEMENT_DEPRECATION(self.__class__.__name__)3842 def i2len(self, pkt, i):3843 return len(i)+self.shift3844 def i2m(self, pkt, x):3845 if x is None:3846 x = ""3847 elif type(x) is not str:3848 x=str(x)3849 return x3850 def addfield(self, pkt, s, val):3851 return s+self.i2m(pkt, val)3852 def getfield(self, pkt, s):3853 if self.remain == 0:3854 return "",self.m2i(pkt, s)3855 else:3856 return s[-self.remain:],self.m2i(pkt, s[:-self.remain])3857 def randval(self):3858 return RandBin(RandNum(0,1200))3860class PacketField(StrField):3861 holds_packets=13862 def __init__(self, name, default, cls, remain=0, shift=0):3863 StrField.__init__(self, name, default, remain=remain, shift=shift)3864 self.cls = cls3865 def i2m(self, pkt, i):3866 return str(i)3867 def m2i(self, pkt, m):3868 return self.cls(m)3869 def getfield(self, pkt, s):3870 i = self.m2i(pkt, s)3871 remain = ""3872 if i.haslayer(Padding):3873 r = i.getlayer(Padding)3874 del(r.underlayer.payload)3875 remain = r.load3876 return remain,i3878class PacketLenField(PacketField):3879 holds_packets=13880 def __init__(self, name, default, cls, fld=None, length_from=None, shift=0):3881 PacketField.__init__(self, name, default, cls, shift=shift)3882 self.length_from = length_from3883 if fld is not None or shift != 0:3884 FIELD_LENGTH_MANAGEMENT_DEPRECATION(self.__class__.__name__)3885 self.count_from = lambda pkt,fld=fld,shift=shift: getattr(pkt,fld)-shift3886 def getfield(self, pkt, s):3887 l = self.length_from(pkt)3888 i = self.m2i(pkt, s[:l])3889 return s[l:],i3892class PacketListField(PacketField):3893 islist = 13894 holds_packets=13895 def __init__(self, name, default, cls, fld=None, count_from=None, length_from=None, shift=0):3896 if default is None:3897 default = [] # Create a new list for each instance3898 PacketField.__init__(self, name, default, cls, shift=shift)3899 self.count_from = count_from3900 self.length_from = length_from3902 if fld is not None or shift != 0:3903 FIELD_LENGTH_MANAGEMENT_DEPRECATION(self.__class__.__name__)3904 if fld is not None:3905 self.count_from = lambda pkt,fld=fld,shift=shift: getattr(pkt,fld)-shift3907 def any2i(self, pkt, x):3908 if type(x) is not list:3909 return [x]3910 else:3911 return x3912 def i2count(self, pkt, val):3913 if type(val) is list:3914 return len(val)3915 return 13916 def i2len(self, pkt, val):3917 return sum( len(p) for p in val )3918 def do_copy(self, x):3919 return map(lambda p:p.copy(), x)3920 def getfield(self, pkt, s):3921 c = l = None3922 if self.length_from is not None:3923 l = self.length_from(pkt)3924 elif self.count_from is not None:3925 c = self.count_from(pkt)3927 lst = []3928 ret = ""3929 remain = s3930 if l is not None: