| #! /usr/bin/env python |
| |
| ############################################################################# |
| ## ## |
| ## scapy.py --- Interactive packet manipulation tool ## |
| ## see http://www.secdev.org/projects/scapy/ ## |
| ## for more informations ## |
| ## ## |
| ## Copyright (C) 2003 Philippe Biondi <phil@secdev.org> ## |
| ## ## |
| ## This program is free software; you can redistribute it and/or modify it ## |
| ## under the terms of the GNU General Public License version 2 as ## |
| ## published by the Free Software Foundation; version 2. ## |
| ## ## |
| ## This program is distributed in the hope that it will be useful, but ## |
| ## WITHOUT ANY WARRANTY; without even the implied warranty of ## |
| ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ## |
| ## General Public License for more details. ## |
| ## ## |
| ############################################################################# |
| |
| |
| from __future__ import generators |
| import os |
| |
| BASE_VERSION = "1.1.0" |
| |
| HG_NODE = "$Node$" |
| REVISION = "$Revision$" |
| |
| VERSION = "v%s / %s" % (BASE_VERSION, (REVISION+"--")[11:23]) |
| |
| DEFAULT_CONFIG_FILE = os.path.join(os.environ["HOME"], ".scapy_startup.py") |
| |
| try: |
| os.stat(DEFAULT_CONFIG_FILE) |
| except OSError: |
| DEFAULT_CONFIG_FILE = None |
| |
| def usage(): |
| print """Usage: scapy.py [-s sessionfile] [-c new_startup_file] [-C] |
| -C: do not read startup file""" |
| sys.exit(0) |
| |
| |
| ############################# |
| ##### Logging subsystem ##### |
| ############################# |
| |
| class Scapy_Exception(Exception): |
| pass |
| |
| import logging,traceback,time |
| |
| class ScapyFreqFilter(logging.Filter): |
| def __init__(self): |
| logging.Filter.__init__(self) |
| self.warning_table = {} |
| def filter(self, record): |
| wt = conf.warning_threshold |
| if wt > 0: |
| stk = traceback.extract_stack() |
| caller=None |
| for f,l,n,c in stk: |
| if n == 'warning': |
| break |
| caller = l |
| tm,nb = self.warning_table.get(caller, (0,0)) |
| ltm = time.time() |
| if ltm-tm > wt: |
| tm = ltm |
| nb = 0 |
| else: |
| if nb < 2: |
| nb += 1 |
| if nb == 2: |
| record.msg = "more "+record.msg |
| else: |
| return 0 |
| self.warning_table[caller] = (tm,nb) |
| return 1 |
| |
| log_scapy = logging.getLogger("scapy") |
| console_handler = logging.StreamHandler() |
| console_handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s")) |
| log_scapy.addHandler(console_handler) |
| log_runtime = logging.getLogger("scapy.runtime") # logs at runtime |
| log_runtime.addFilter(ScapyFreqFilter()) |
| log_interactive = logging.getLogger("scapy.interactive") # logs in interactive functions |
| log_loading = logging.getLogger("scapy.loading") # logs when loading scapy |
| |
| if __name__ == "__main__": |
| log_scapy.setLevel(1) |
| |
| |
| ################## |
| ##### Module ##### |
| ################## |
| |
| import socket, sys, getopt, string, struct, random, code |
| import cPickle, copy, types, gzip, base64, re, zlib, array |
| from sets import Set |
| from select import select |
| from glob import glob |
| from fcntl import ioctl |
| import fcntl |
| import warnings |
| warnings.filterwarnings("ignore","tempnam",RuntimeWarning, __name__) |
| |
| |
| try: |
| import Gnuplot |
| GNUPLOT=1 |
| except ImportError: |
| log_loading.info("did not find python gnuplot wrapper . Won't be able to plot") |
| GNUPLOT=0 |
| |
| try: |
| import pyx |
| PYX=1 |
| except ImportError: |
| log_loading.info("Can't import PyX. Won't be able to use psdump() or pdfdump()") |
| PYX=0 |
| |
| |
| LINUX=sys.platform.startswith("linux") |
| OPENBSD=sys.platform.startswith("openbsd") |
| FREEBSD=sys.platform.startswith("freebsd") |
| DARWIN=sys.platform.startswith("darwin") |
| BIG_ENDIAN= struct.pack("H",1) == "\x00\x01" |
| X86_64 = (os.uname()[4] == 'x86_64') |
| SOLARIS=sys.platform.startswith("sunos") |
| |
| |
| if LINUX: |
| DNET=PCAP=0 |
| else: |
| DNET=PCAP=1 |
| |
| |
| if PCAP: |
| try: |
| import pcap |
| PCAP = 1 |
| except ImportError: |
| if LINUX: |
| log_loading.warning("did not find pcap module. Fallback to linux primitives") |
| PCAP = 0 |
| else: |
| if __name__ == "__main__": |
| log_loading.error("did not find pcap module") |
| raise SystemExit |
| else: |
| raise |
| |
| if DNET: |
| try: |
| import dnet |
| DNET = 1 |
| except ImportError: |
| if LINUX: |
| log_loading.warning("did not find dnet module. Fallback to linux primitives") |
| DNET = 0 |
| else: |
| if __name__ == "__main__": |
| log_loading.error("did not find dnet module") |
| raise SystemExit |
| else: |
| raise |
| |
| if not PCAP: |
| f = os.popen("tcpdump -V 2> /dev/null") |
| if f.close() >> 8 == 0x7f: |
| log_loading.warning("Failed to execute tcpdump. Check it is installed and in the PATH") |
| TCPDUMP=0 |
| else: |
| TCPDUMP=1 |
| |
| |
| |
| try: |
| from Crypto.Cipher import ARC4 |
| except ImportError: |
| log_loading.info("Can't find Crypto python lib. Won't be able to decrypt WEP") |
| |
| |
| # Workarround bug 643005 : https://sourceforge.net/tracker/?func=detail&atid=105470&aid=643005&group_id=5470 |
| try: |
| socket.inet_aton("255.255.255.255") |
| except socket.error: |
| def inet_aton(x): |
| if x == "255.255.255.255": |
| return "\xff"*4 |
| else: |
| return socket.inet_aton(x) |
| else: |
| inet_aton = socket.inet_aton |
| |
| inet_ntoa = socket.inet_ntoa |
| try: |
| inet_ntop = socket.inet_ntop |
| inet_pton = socket.inet_pton |
| except AttributeError: |
| log_loading.info("inet_ntop/pton functions not found. Python IPv6 support not present") |
| |
| |
| if SOLARIS: |
| # GRE is missing on Solaris |
| socket.IPPROTO_GRE = 47 |
| |
| ############################### |
| ## Direct Access dictionnary ## |
| ############################### |
| |
| def fixname(x): |
| if x and x[0] in "0123456789": |
| x = "n_"+x |
| return x.translate("________________________________________________0123456789_______ABCDEFGHIJKLMNOPQRSTUVWXYZ______abcdefghijklmnopqrstuvwxyz_____________________________________________________________________________________________________________________________________") |
| |
| |
| class DADict_Exception(Scapy_Exception): |
| pass |
| |
| class DADict: |
| def __init__(self, _name="DADict", **kargs): |
| self._name=_name |
| self.__dict__.update(kargs) |
| def fixname(self,val): |
| return fixname(val) |
| def __contains__(self, val): |
| return val in self.__dict__ |
| def __getitem__(self, attr): |
| return getattr(self, attr) |
| def __setitem__(self, attr, val): |
| return setattr(self, self.fixname(attr), val) |
| def __iter__(self): |
| return iter(map(lambda (x,y):y,filter(lambda (x,y):x[0]!="_", self.__dict__.items()))) |
| def _show(self): |
| for k in self.__dict__.keys(): |
| if k[0] != "_": |
| print "%10s = %r" % (k,getattr(self,k)) |
| def __repr__(self): |
| return "<%s/ %s>" % (self._name," ".join(filter(lambda x:x[0]!="_",self.__dict__.keys()))) |
| |
| def _branch(self, br, uniq=0): |
| if uniq and br._name in self: |
| raise DADict_Exception("DADict: [%s] already branched in [%s]" % (br._name, self._name)) |
| self[br._name] = br |
| |
| def _my_find(self, *args, **kargs): |
| if args and self._name not in args: |
| return False |
| for k in kargs: |
| if k not in self or self[k] != kargs[k]: |
| return False |
| return True |
| |
| def _find(self, *args, **kargs): |
| return self._recurs_find((), *args, **kargs) |
| def _recurs_find(self, path, *args, **kargs): |
| if self in path: |
| return None |
| if self._my_find(*args, **kargs): |
| return self |
| for o in self: |
| if isinstance(o, DADict): |
| p = o._recurs_find(path+(self,), *args, **kargs) |
| if p is not None: |
| return p |
| return None |
| def _find_all(self, *args, **kargs): |
| return self._recurs_find_all((), *args, **kargs) |
| def _recurs_find_all(self, path, *args, **kargs): |
| r = [] |
| if self in path: |
| return r |
| if self._my_find(*args, **kargs): |
| r.append(self) |
| for o in self: |
| if isinstance(o, DADict): |
| p = o._recurs_find_all(path+(self,), *args, **kargs) |
| r += p |
| return r |
| def keys(self): |
| return filter(lambda x:x[0]!="_", self.__dict__.keys()) |
| |
| |
| |
| ############ |
| ## Consts ## |
| ############ |
| |
| ETHER_ANY = "\x00"*6 |
| ETHER_BROADCAST = "\xff"*6 |
| |
| ETH_P_ALL = 3 |
| ETH_P_IP = 0x800 |
| ETH_P_ARP = 0x806 |
| |
| # From net/if_arp.h |
| ARPHDR_ETHER = 1 |
| ARPHDR_METRICOM = 23 |
| ARPHDR_PPP = 512 |
| ARPHDR_LOOPBACK = 772 |
| ARPHDR_TUN = 65534 |
| |
| # From bits/ioctls.h |
| SIOCGIFHWADDR = 0x8927 # Get hardware address |
| SIOCGIFADDR = 0x8915 # get PA address |
| SIOCGIFNETMASK = 0x891b # get network PA mask |
| SIOCGIFNAME = 0x8910 # get iface name |
| SIOCSIFLINK = 0x8911 # set iface channel |
| SIOCGIFCONF = 0x8912 # get iface list |
| SIOCGIFFLAGS = 0x8913 # get flags |
| SIOCSIFFLAGS = 0x8914 # set flags |
| SIOCGIFINDEX = 0x8933 # name -> if_index mapping |
| SIOCGIFCOUNT = 0x8938 # get number of devices |
| |
| |
| # From if.h |
| IFF_UP = 0x1 # Interface is up. |
| IFF_BROADCAST = 0x2 # Broadcast address valid. |
| IFF_DEBUG = 0x4 # Turn on debugging. |
| IFF_LOOPBACK = 0x8 # Is a loopback net. |
| IFF_POINTOPOINT = 0x10 # Interface is point-to-point link. |
| IFF_NOTRAILERS = 0x20 # Avoid use of trailers. |
| IFF_RUNNING = 0x40 # Resources allocated. |
| IFF_NOARP = 0x80 # No address resolution protocol. |
| IFF_PROMISC = 0x100 # Receive all packets. |
| |
| |
| |
| # From netpacket/packet.h |
| PACKET_ADD_MEMBERSHIP = 1 |
| PACKET_DROP_MEMBERSHIP = 2 |
| PACKET_RECV_OUTPUT = 3 |
| PACKET_RX_RING = 5 |
| PACKET_STATISTICS = 6 |
| PACKET_MR_MULTICAST = 0 |
| PACKET_MR_PROMISC = 1 |
| PACKET_MR_ALLMULTI = 2 |
| |
| |
| # From bits/socket.h |
| SOL_PACKET = 263 |
| # From asm/socket.h |
| SO_ATTACH_FILTER = 26 |
| SOL_SOCKET = 1 |
| |
| # From net/route.h |
| RTF_UP = 0x0001 # Route usable |
| RTF_REJECT = 0x0200 |
| |
| # From BSD net/bpf.h |
| #BIOCIMMEDIATE=0x80044270 |
| BIOCIMMEDIATE=-2147204496 |
| |
| MTU = 1600 |
| |
| |
| # file parsing to get some values : |
| |
| def load_protocols(filename): |
| spaces = re.compile("[ \t]+|\n") |
| dct = DADict(_name=filename) |
| try: |
| for l in open(filename): |
| try: |
| if l[0] in ["#","\n"]: |
| continue |
| lt = tuple(re.split(spaces, l)) |
| if len(lt) < 3: |
| continue |
| dct[lt[2]] = int(lt[1]) |
| except Exception,e: |
| log_loading.info("Couldn't parse file [%s]: line [%r] (%s)" % (filename,l,e)) |
| f.close() |
| except IOError: |
| log_loading.info("Can't open /etc/protocols file") |
| return dct |
| |
| IP_PROTOS=load_protocols("/etc/protocols") |
| |
| def load_ethertypes(filename): |
| spaces = re.compile("[ \t]+|\n") |
| dct = DADict(_name=filename) |
| try: |
| f=open(filename) |
| for l in f: |
| try: |
| if l[0] in ["#","\n"]: |
| continue |
| lt = tuple(re.split(spaces, l)) |
| if len(lt) < 2: |
| continue |
| dct[lt[0]] = int(lt[1], 16) |
| except Exception,e: |
| log_loading.info("Couldn't parse file [%s]: line [%r] (%s)" % (filename,l,e)) |
| f.close() |
| except IOError,msg: |
| pass |
| return dct |
| |
| ETHER_TYPES=load_ethertypes("/etc/ethertypes") |
| |
| def load_services(filename): |
| spaces = re.compile("[ \t]+|\n") |
| tdct=DADict(_name="%s-tcp"%filename) |
| udct=DADict(_name="%s-udp"%filename) |
| try: |
| f=open(filename) |
| for l in f: |
| try: |
| if l[0] in ["#","\n"]: |
| continue |
| lt = tuple(re.split(spaces, l)) |
| if len(lt) < 2: |
| continue |
| if lt[1].endswith("/tcp"): |
| tdct[lt[0]] = int(lt[1].split('/')[0]) |
| elif lt[1].endswith("/udp"): |
| udct[lt[0]] = int(lt[1].split('/')[0]) |
| except Exception,e: |
| log_loading.warning("Couldn't file [%s]: line [%r] (%s)" % (filename,l,e)) |
| f.close() |
| except IOError: |
| log_loading.info("Can't open /etc/services file") |
| return tdct,udct |
| |
| TCP_SERVICES,UDP_SERVICES=load_services("/etc/services") |
| |
| class ManufDA(DADict): |
| def fixname(self, val): |
| return val |
| def _get_manuf_couple(self, mac): |
| oui = ":".join(mac.split(":")[:3]).upper() |
| return self.__dict__.get(oui,(mac,mac)) |
| def _get_manuf(self, mac): |
| return self._get_manuf_couple(mac)[1] |
| def _get_short_manuf(self, mac): |
| return self._get_manuf_couple(mac)[0] |
| def _resolve_MAC(self, mac): |
| oui = ":".join(mac.split(":")[:3]).upper() |
| if oui in self: |
| return ":".join([self[oui][0]]+ mac.split(":")[3:]) |
| return mac |
| |
| |
| |
| |
| def load_manuf(filename): |
| try: |
| manufdb=ManufDA(_name=filename) |
| for l in open(filename): |
| try: |
| l = l.strip() |
| if not l or l.startswith("#"): |
| continue |
| oui,shrt=l.split()[:2] |
| i = l.find("#") |
| if i < 0: |
| lng=shrt |
| else: |
| lng = l[i+2:] |
| manufdb[oui] = shrt,lng |
| except Exception,e: |
| log_loadding.warning("Couldn't parse one line from [%s] [%r] (%s)" % (filename, l, e)) |
| except IOError: |
| #log_loading.warning("Couldn't open [%s] file" % filename) |
| pass |
| return manufdb |
| |
| MANUFDB = load_manuf("/usr/share/wireshark/wireshark/manuf") |
| |
| |
| |
| |
| ########### |
| ## Tools ## |
| ########### |
| |
| def sane_color(x): |
| r="" |
| for i in x: |
| j = ord(i) |
| if (j < 32) or (j >= 127): |
| r=r+conf.color_theme.not_printable(".") |
| else: |
| r=r+i |
| return r |
| |
| def sane(x): |
| r="" |
| for i in x: |
| j = ord(i) |
| if (j < 32) or (j >= 127): |
| r=r+"." |
| else: |
| r=r+i |
| return r |
| |
| def lhex(x): |
| if type(x) is int: |
| return hex(x) |
| elif type(x) is tuple: |
| return "(%s)" % ", ".join(map(lhex, x)) |
| elif type(x) is list: |
| return "[%s]" % ", ".join(map(lhex, x)) |
| else: |
| return x |
| |
| def hexdump(x): |
| x=str(x) |
| l = len(x) |
| i = 0 |
| while i < l: |
| print "%04x " % i, |
| for j in range(16): |
| if i+j < l: |
| print "%02X" % ord(x[i+j]), |
| else: |
| print " ", |
| if j%16 == 7: |
| print "", |
| print " ", |
| print sane_color(x[i:i+16]) |
| i += 16 |
| |
| def linehexdump(x, onlyasc=0, onlyhex=0): |
| x = str(x) |
| l = len(x) |
| if not onlyasc: |
| for i in range(l): |
| print "%02X" % ord(x[i]), |
| print "", |
| if not onlyhex: |
| print sane_color(x) |
| |
| def chexdump(x): |
| x=str(x) |
| print ", ".join(map(lambda x: "%#04x"%ord(x), x)) |
| |
| def hexstr(x, onlyasc=0, onlyhex=0): |
| s = [] |
| if not onlyasc: |
| s.append(" ".join(map(lambda x:"%02x"%ord(x), x))) |
| if not onlyhex: |
| s.append(sane(x)) |
| return " ".join(s) |
| |
| |
| def hexdiff(x,y, gran=5): |
| """hexdiff(before, after, gran=5) |
| gran: granularity in bytes for similarity matching. Must be >= 1""" |
| x=str(x) |
| y=str(y) |
| if gran <= 0: |
| gran = 1 |
| |
| i=j=0 |
| ii=jj=-1 |
| |
| diff = [] |
| cdiff = "" |
| while i < len(x) and j < len(y): |
| if x[i] == y[j] and ii == jj == -1: |
| cdiff += x[i] |
| i+=1; j+=1 |
| continue |
| if ii == jj == -1: |
| if cdiff: |
| diff.append((0,cdiff)) |
| cdiff = "" |
| ii = i; jj = j |
| i += 1; j+= 1 |
| continue |
| k = l = -1 |
| if i+gran < len(x) or j+gran >= len(y): |
| k = y[jj:j+gran].find(x[i:i+gran]) |
| if k != -1: |
| j = jj+k |
| if j+gran < len(y) or i+gran >= len(x): |
| l = x[ii:i+gran].find(y[j:j+gran]) |
| if l != -1: |
| i = ii+l |
| |
| if k != -1 or l != -1: |
| if i != ii: |
| diff.append((-1, x[ii:i])) |
| if j != jj: |
| diff.append((+1, y[jj:j])) |
| ii = jj = -1 |
| else: |
| i += 1 |
| j += 1 |
| |
| if cdiff: |
| diff.append((0,cdiff)) |
| |
| if ii>=0: |
| i=ii |
| if i < len(x): |
| diff.append((-1,x[i:])) |
| if jj>=0: |
| j=jj |
| if j < len(y): |
| diff.append((+1,y[j:])) |
| |
| colorize = { 0: lambda x:x, |
| -1: conf.color_theme.left, |
| 1: conf.color_theme.right } |
| i = j = 0 |
| for s,h in diff: |
| |
| l = len(h) |
| u = -(j%16) |
| while u < l: |
| line = "" |
| if s <= 0: |
| line += "%04x " % (i+u) |
| else: |
| line += " " |
| if s >= 0: |
| line += "%04x " % (j+u) |
| else: |
| line += " " |
| ch = "" |
| for v in range(16): |
| if 0 <= u+v < l: |
| c = h[u+v] |
| line += "%02X " % ord(c) |
| if 32 <= ord(c) < 127: |
| ch += colorize[s](c) |
| else: |
| ch += conf.color_theme.not_printable(".") |
| else: |
| line += " " |
| ch += " " |
| if v%16 == 7: |
| line += " " |
| line += " " |
| line = colorize[s](line) |
| line += ch |
| u += 16 |
| print line |
| if s <= 0: |
| i += l |
| if s >= 0: |
| j += l |
| |
| |
| if BIG_ENDIAN: |
| CRCPOLY=0x04c11db7L |
| else: |
| CRCPOLY=0xedb88320L |
| |
| crc32 = zlib.crc32 |
| |
| |
| def checksum(pkt): |
| pkt=str(pkt) |
| s=0 |
| if len(pkt) % 2 == 1: |
| pkt += "\0" |
| for i in range(len(pkt)/2): |
| s = s + (struct.unpack("!H",pkt[2*i:2*i+2])[0]) |
| s = (s >> 16) + (s & 0xffff) |
| s += s >> 16 |
| return ~s & 0xffff |
| |
| def warning(x): |
| log_runtime.warning(x) |
| |
| def mac2str(mac): |
| return "".join(map(lambda x: chr(int(x,16)), mac.split(":"))) |
| |
| def str2mac(s): |
| return ("%02x:"*6)[:-1] % tuple(map(ord, s)) |
| |
| def strxor(x,y): |
| return "".join(map(lambda x,y:chr(ord(x)^ord(y)),x,y)) |
| |
| def atol(x): |
| try: |
| ip = inet_aton(x) |
| except socket.error: |
| ip = inet_aton(socket.gethostbyname(x)) |
| return struct.unpack("I", ip)[0] |
| def ltoa(x): |
| return inet_ntoa(struct.pack("I", x)) |
| |
| def itom(x): |
| return socket.ntohl((0xffffffff00000000L>>x)&0xffffffffL)&0xffffffffL |
| |
| def do_graph(graph,prog=None,type="svg",target=None): |
| """do_graph(graph, prog=conf.prog.dot, type="svg",target="| conf.prog.display"): |
| graph: GraphViz graph description |
| type: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option |
| target: filename or redirect. Defaults pipe to Imagemagick's display program |
| prog: which graphviz program to use""" |
| if prog is None: |
| prog = conf.prog.dot |
| if target is None: |
| target = "| %s" % conf.prog.display |
| w,r = os.popen2("%s -T %s %s" % (prog,type,target)) |
| w.write(graph) |
| w.close() |
| |
| _TEX_TR = { |
| "{":"{\\tt\\char123}", |
| "}":"{\\tt\\char125}", |
| "\\":"{\\tt\\char92}", |
| "^":"\\^{}", |
| "$":"\\$", |
| "#":"\\#", |
| "~":"\\~", |
| "_":"\\_", |
| "&":"\\&", |
| "%":"\\%", |
| "|":"{\\tt\\char124}", |
| "~":"{\\tt\\char126}", |
| "<":"{\\tt\\char60}", |
| ">":"{\\tt\\char62}", |
| } |
| |
| def tex_escape(x): |
| s = "" |
| for c in x: |
| s += _TEX_TR.get(c,c) |
| return s |
| |
| def colgen(*lstcol,**kargs): |
| """Returns a generator that mixes provided quantities forever |
| trans: a function to convert the three arguments into a color. lambda x,y,z:(x,y,z) by default""" |
| if len(lstcol) < 2: |
| lstcol *= 2 |
| trans = kargs.get("trans", lambda x,y,z: (x,y,z)) |
| while 1: |
| for i in range(len(lstcol)): |
| for j in range(len(lstcol)): |
| for k in range(len(lstcol)): |
| if i != j or j != k or k != i: |
| yield trans(lstcol[(i+j)%len(lstcol)],lstcol[(j+k)%len(lstcol)],lstcol[(k+i)%len(lstcol)]) |
| |
| def incremental_label(label="tag%05i", start=0): |
| while True: |
| yield label % start |
| start += 1 |
| |
| ######################### |
| #### Enum management #### |
| ######################### |
| |
| class EnumElement: |
| def __init__(self, key, value): |
| self._key = key |
| self._value = value |
| def __repr__(self): |
| return "<%s %s[%r]>" % (self.__dict__.get("_name", self.__class__.__name__), self._key, self._value) |
| def __getattr__(self, attr): |
| return getattr(self._value, attr) |
| def __str__(self): |
| return self._key |
| def __eq__(self, other): |
| return self._value == int(other) |
| |
| |
| class Enum_metaclass(type): |
| element_class = EnumElement |
| def __new__(cls, name, bases, dct): |
| rdict={} |
| for k,v in dct.iteritems(): |
| if type(v) is int: |
| v = cls.element_class(k,v) |
| dct[k] = v |
| rdict[v] = k |
| dct["__rdict__"] = rdict |
| return super(Enum_metaclass, cls).__new__(cls, name, bases, dct) |
| def __getitem__(self, attr): |
| return self.__rdict__[attr] |
| def __contains__(self, val): |
| return val in self.__rdict__ |
| def get(self, attr, val=None): |
| return self._rdict__.get(attr, val) |
| def __repr__(self): |
| return "<%s>" % self.__dict__.get("name", self.__name__) |
| |
| |
| |
| |
| ############################## |
| ## Session saving/restoring ## |
| ############################## |
| |
| |
| def save_session(fname, session=None, pickleProto=-1): |
| if session is None: |
| session = scapy_session |
| |
| to_be_saved = session.copy() |
| |
| if to_be_saved.has_key("__builtins__"): |
| del(to_be_saved["__builtins__"]) |
| |
| for k in to_be_saved.keys(): |
| if type(to_be_saved[k]) in [types.TypeType, types.ClassType, types.ModuleType]: |
| log_interactive.error("[%s] (%s) can't be saved." % (k, type(to_be_saved[k]))) |
| del(to_be_saved[k]) |
| |
| try: |
| os.rename(fname, fname+".bak") |
| except OSError: |
| pass |
| f=gzip.open(fname,"wb") |
| cPickle.dump(to_be_saved, f, pickleProto) |
| f.close() |
| |
| def load_session(fname): |
| try: |
| s = cPickle.load(gzip.open(fname,"rb")) |
| except IOError: |
| s = cPickle.load(open(fname,"rb")) |
| scapy_session.clear() |
| scapy_session.update(s) |
| |
| def update_session(fname): |
| try: |
| s = cPickle.load(gzip.open(fname,"rb")) |
| except IOError: |
| s = cPickle.load(open(fname,"rb")) |
| scapy_session.update(s) |
| |
| |
| def export_object(obj): |
| print base64.encodestring(gzip.zlib.compress(cPickle.dumps(obj,2),9)) |
| |
| def import_object(obj=None): |
| if obj is None: |
| obj = sys.stdin.read() |
| return cPickle.loads(gzip.zlib.decompress(base64.decodestring(obj.strip()))) |
| |
| |
| def save_object(fname, obj): |
| cPickle.dump(obj,gzip.open(fname,"wb")) |
| |
| def load_object(fname): |
| return cPickle.load(gzip.open(fname,"rb")) |
| |
| |
| ################# |
| ## Debug class ## |
| ################# |
| |
| class debug: |
| recv=[] |
| sent=[] |
| match=[] |
| |
| |
| #################### |
| ## IP Tools class ## |
| #################### |
| |
| class IPTools: |
| """Add more powers to a class that have a "src" attribute.""" |
| def whois(self): |
| os.system("whois %s" % self.src) |
| def ottl(self): |
| t = [32,64,128,255]+[self.ttl] |
| t.sort() |
| return t[t.index(self.ttl)+1] |
| def hops(self): |
| return self.ottl()-self.ttl-1 |
| |
| |
| ############################## |
| ## Routing/Interfaces stuff ## |
| ############################## |
| |
| class Route: |
| def __init__(self): |
| self.resync() |
| self.s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
| |
| def resync(self): |
| self.routes = read_routes() |
| |
| def __repr__(self): |
| rt = "Network Netmask Gateway Iface Output IP\n" |
| for net,msk,gw,iface,addr in self.routes: |
| rt += "%-15s %-15s %-15s %-15s %-15s\n" % (ltoa(net), |
| ltoa(msk), |
| gw, |
| iface, |
| addr) |
| return rt |
| |
| def make_route(self, host=None, net=None, gw=None, dev=None): |
| if host is not None: |
| thenet,msk = host,32 |
| elif net is not None: |
| thenet,msk = net.split("/") |
| msk = int(msk) |
| else: |
| raise Scapy_Exception("make_route: Incorrect parameters. You should specify a host or a net") |
| if gw is None: |
| gw="0.0.0.0" |
| if dev is None: |
| if gw: |
| nhop = gw |
| else: |
| nhop = thenet |
| dev,ifaddr,x = self.route(nhop) |
| else: |
| ifaddr = get_if_addr(dev) |
| return (atol(thenet), itom(msk), gw, dev, ifaddr) |
| |
| def add(self, *args, **kargs): |
| """Ex: |
| add(net="192.168.1.0/24",gw="1.2.3.4") |
| """ |
| self.routes.append(self.make_route(*args,**kargs)) |
| |
| |
| def delt(self, *args, **kargs): |
| """delt(host|net, gw|dev)""" |
| route = self.make_route(*args,**kargs) |
| try: |
| i=self.routes.index(route) |
| del(self.routes[i]) |
| except ValueError: |
| warning("no matching route found") |
| |
| def ifchange(self, iff, addr): |
| the_addr,the_msk = (addr.split("/")+["32"])[:2] |
| the_msk = itom(int(the_msk)) |
| the_rawaddr, = struct.unpack("I",inet_aton(the_addr)) |
| the_net = the_rawaddr & the_msk |
| |
| |
| for i in range(len(self.routes)): |
| net,msk,gw,iface,addr = self.routes[i] |
| if iface != iff: |
| continue |
| if gw == '0.0.0.0': |
| self.routes[i] = (the_net,the_msk,gw,iface,the_addr) |
| else: |
| self.routes[i] = (net,msk,gw,iface,the_addr) |
| for i in arp_cache.keys(): |
| del(arp_cache[i]) |
| |
| |
| |
| def ifdel(self, iff): |
| new_routes=[] |
| for rt in self.routes: |
| if rt[3] != iff: |
| new_routes.append(rt) |
| self.routes=new_routes |
| |
| def ifadd(self, iff, addr): |
| the_addr,the_msk = (addr.split("/")+["32"])[:2] |
| the_msk = itom(int(the_msk)) |
| the_rawaddr, = struct.unpack("I",inet_aton(the_addr)) |
| the_net = the_rawaddr & the_msk |
| self.routes.append((the_net,the_msk,'0.0.0.0',iff,the_addr)) |
| |
| |
| def route(self,dst): |
| # Transform "192.168.*.1-5" to one IP of the set |
| dst = dst.split("/")[0] |
| dst = dst.replace("*","0") |
| while 1: |
| l = dst.find("-") |
| if l < 0: |
| break |
| m = (dst[l:]+".").find(".") |
| dst = dst[:l]+dst[l+m:] |
| |
| |
| try: |
| dst=inet_aton(dst) |
| except socket.error: |
| dst=inet_aton(socket.gethostbyname(dst)) |
| dst,=struct.unpack("I",dst) |
| pathes=[] |
| for d,m,gw,i,a in self.routes: |
| aa, = struct.unpack("I",inet_aton(a)) |
| if aa == dst: |
| pathes.append((0xffffffffL,("lo",a,"0.0.0.0"))) |
| if (dst & m) == (d & m): |
| pathes.append((m,(i,a,gw))) |
| if not pathes: |
| warning("No route found (no default route?)") |
| return "lo","0.0.0.0","0.0.0.0" #XXX linux specific! |
| # Choose the more specific route (greatest netmask). |
| # XXX: we don't care about metrics |
| pathes.sort() |
| return pathes[-1][1] |
| |
| def get_if_bcast(self, iff): |
| for net, msk, gw, iface, addr in self.routes: |
| if (iff == iface and net != 0L): |
| bcast = atol(addr)|(~msk&0xffffffffL); # FIXME: check error in atol() |
| return ltoa(bcast); |
| warning("No broadcast address found for iface %s\n" % iff); |
| |
| if DNET: |
| def get_if_raw_hwaddr(iff): |
| if iff[:2] == "lo": |
| return (772, '\x00'*6) |
| try: |
| l = dnet.intf().get(iff) |
| l = l["link_addr"] |
| except: |
| raise Scapy_Exception("Error in attempting to get hw address for interface [%s]" % iff) |
| return l.type,l.data |
| def get_if_raw_addr(ifname): |
| i = dnet.intf() |
| return i.get(ifname)["addr"].data |
| else: |
| def get_if_raw_hwaddr(iff): |
| return struct.unpack("16xh6s8x",get_if(iff,SIOCGIFHWADDR)) |
| |
| def get_if_raw_addr(iff): |
| try: |
| return get_if(iff, SIOCGIFADDR)[20:24] |
| except IOError: |
| return "\0\0\0\0" |
| |
| |
| if PCAP: |
| def get_if_list(): |
| # remove 'any' interface |
| return map(lambda x:x[0],filter(lambda x:x[1] is None,pcap.findalldevs())) |
| def get_working_if(): |
| try: |
| return pcap.lookupdev() |
| except pcap.pcapc.EXCEPTION: |
| return 'lo' |
| |
| def attach_filter(s, filter): |
| warning("attach_filter() should not be called in PCAP mode") |
| def set_promisc(s,iff,val=1): |
| warning("set_promisc() should not be called in DNET/PCAP mode") |
| |
| else: |
| def get_if_list(): |
| f=open("/proc/net/dev","r") |
| lst = [] |
| f.readline() |
| f.readline() |
| for l in f: |
| lst.append(l.split(":")[0].strip()) |
| return lst |
| def get_working_if(): |
| for i in get_if_list(): |
| if i == 'lo': |
| continue |
| ifflags = struct.unpack("16xH14x",get_if(i,SIOCGIFFLAGS))[0] |
| if ifflags & IFF_UP: |
| return i |
| return "lo" |
| def attach_filter(s, filter): |
| # XXX We generate the filter on the interface conf.iface |
| # because tcpdump open the "any" interface and ppp interfaces |
| # in cooked mode. As we use them in raw mode, the filter will not |
| # work... one solution could be to use "any" interface and translate |
| # the filter from cooked mode to raw mode |
| # mode |
| if not TCPDUMP: |
| return |
| try: |
| f = os.popen("%s -i %s -ddd -s 1600 '%s'" % (conf.prog.tcpdump,conf.iface,filter)) |
| except OSError,msg: |
| log_interactive.warning("Failed to execute tcpdump: (%s)") |
| return |
| lines = f.readlines() |
| if f.close(): |
| raise Scapy_Exception("Filter parse error") |
| nb = int(lines[0]) |
| bpf = "" |
| for l in lines[1:]: |
| bpf += struct.pack("HBBI",*map(long,l.split())) |
| |
| # XXX. Argl! We need to give the kernel a pointer on the BPF, |
| # python object header seems to be 20 bytes. 36 bytes for x86 64bits arch. |
| if X86_64: |
| bpfh = struct.pack("HL", nb, id(bpf)+36) |
| else: |
| bpfh = struct.pack("HI", nb, id(bpf)+20) |
| s.setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, bpfh) |
| |
| def set_promisc(s,iff,val=1): |
| mreq = struct.pack("IHH8s", get_if_index(iff), PACKET_MR_PROMISC, 0, "") |
| if val: |
| cmd = PACKET_ADD_MEMBERSHIP |
| else: |
| cmd = PACKET_DROP_MEMBERSHIP |
| s.setsockopt(SOL_PACKET, cmd, mreq) |
| |
| |
| if not LINUX: |
| |
| def new_read_routes(): |
| |
| rtlst = [] |
| def addrt(rt,lst): |
| dst,gw = rt |
| lst.append(rt) |
| |
| r = dnet.route() |
| print r.loop(addrt, rtlst) |
| return rtlst |
| |
| def read_routes(): |
| if SOLARIS: |
| f=os.popen("netstat -rvn") # -f inet |
| else: |
| f=os.popen("netstat -rn") # -f inet |
| ok = 0 |
| mtu_present = False |
| routes = [] |
| for l in f.readlines(): |
| if not l: |
| break |
| l = l.strip() |
| if l.find("----") >= 0: # a separation line |
| continue |
| if l.find("Destination") >= 0: |
| ok = 1 |
| if l.find("Mtu") >= 0: |
| mtu_present = True |
| continue |
| if ok == 0: |
| continue |
| if not l: |
| break |
| if SOLARIS: |
| dest,mask,gw,netif,mxfrg,rtt,ref,flg = l.split()[:8] |
| else: |
| if mtu_present: |
| dest,gw,flg,ref,use,mtu,netif = l.split()[:7] |
| else: |
| dest,gw,flg,ref,use,netif = l.split()[:6] |
| if flg.find("Lc") >= 0: |
| continue |
| if dest == "default": |
| dest = 0L |
| netmask = 0L |
| else: |
| if SOLARIS: |
| netmask, = struct.unpack("I",inet_aton(mask)) |
| elif "/" in dest: |
| dest,netmask = dest.split("/") |
| netmask = itom(int(netmask)) |
| else: |
| netmask = itom((dest.count(".") + 1) * 8) |
| dest += ".0"*(3-dest.count(".")) |
| dest, = struct.unpack("I",inet_aton(dest)) |
| if not "G" in flg: |
| gw = '0.0.0.0' |
| ifaddr = get_if_addr(netif) |
| routes.append((dest,netmask,gw,netif,ifaddr)) |
| f.close() |
| return routes |
| |
| def read_interfaces(): |
| i = dnet.intf() |
| ifflist = {} |
| def addif(iff,lst): |
| if not iff.has_key("addr"): |
| return |
| if not iff.has_key("link_addr"): |
| return |
| rawip = iff["addr"].data |
| ip = inet_ntoa(rawip) |
| rawll = iff["link_addr"].data |
| ll = str2mac(rawll) |
| lst[iff["name"]] = (rawll,ll,rawip,ip) |
| i.loop(addif, ifflist) |
| return ifflist |
| |
| |
| else: |
| |
| def read_routes(): |
| f=open("/proc/net/route","r") |
| routes = [] |
| s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM) |
| ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x","lo")) |
| addrfamily = struct.unpack("h",ifreq[16:18])[0] |
| if addrfamily == socket.AF_INET: |
| ifreq2 = ioctl(s, SIOCGIFNETMASK,struct.pack("16s16x","lo")) |
| msk = struct.unpack("I",ifreq2[20:24])[0] |
| dst = struct.unpack("I",ifreq[20:24])[0] & msk |
| ifaddr = inet_ntoa(ifreq[20:24]) |
| routes.append((dst, msk, "0.0.0.0", "lo", ifaddr)) |
| else: |
| warning("Interface lo: unkownn address family (%i)"% addrfamily) |
| |
| for l in f.readlines()[1:]: |
| iff,dst,gw,flags,x,x,x,msk,x,x,x = l.split() |
| flags = int(flags,16) |
| if flags & RTF_UP == 0: |
| continue |
| if flags & RTF_REJECT: |
| continue |
| ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x",iff)) |
| addrfamily = struct.unpack("h",ifreq[16:18])[0] |
| if addrfamily == socket.AF_INET: |
| ifaddr = inet_ntoa(ifreq[20:24]) |
| else: |
| warning("Interface %s: unkownn address family (%i)"%(iff, addrfamily)) |
| continue |
| routes.append((long(dst,16), |
| long(msk,16), |
| inet_ntoa(struct.pack("I",long(gw,16))), |
| iff, ifaddr)) |
| |
| f.close() |
| return routes |
| |
| def get_if(iff,cmd): |
| s=socket.socket() |
| ifreq = ioctl(s, cmd, struct.pack("16s16x",iff)) |
| s.close() |
| return ifreq |
| |
| |
| def get_if_index(iff): |
| return int(struct.unpack("I",get_if(iff, SIOCGIFINDEX)[16:20])[0]) |
| |
| |
| |
| def get_if_addr(iff): |
| return inet_ntoa(get_if_raw_addr(iff)) |
| |
| def get_if_hwaddr(iff): |
| addrfamily, mac = get_if_raw_hwaddr(iff) |
| if addrfamily in [ARPHDR_ETHER,ARPHDR_LOOPBACK]: |
| return str2mac(mac) |
| else: |
| raise Scapy_Exception("Unsupported address family (%i) for interface [%s]" % (addrfamily,iff)) |
| |
| |
| |
| ##################### |
| ## ARP cache stuff ## |
| ##################### |
| |
| ARPTIMEOUT=120 |
| |
| # XXX Fill arp_cache with /etc/ether and arp cache |
| arp_cache={} |
| |
| if 0 and DNET: ## XXX Can't use this because it does not resolve IPs not in cache |
| dnet_arp_object = dnet.arp() |
| def getmacbyip(ip): |
| tmp = map(ord, inet_aton(ip)) |
| if (tmp[0] & 0xf0) == 0xe0: # mcast @ |
| return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3]) |
| iff,a,gw = conf.route.route(ip) |
| if iff == "lo": |
| return "ff:ff:ff:ff:ff:ff" |
| if gw != "0.0.0.0": |
| ip = gw |
| res = dnet_arp_object.get(dnet.addr(ip)) |
| if res is None: |
| return None |
| else: |
| return res.ntoa() |
| else: |
| def getmacbyip(ip): |
| tmp = map(ord, inet_aton(ip)) |
| if (tmp[0] & 0xf0) == 0xe0: # mcast @ |
| return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3]) |
| iff,a,gw = conf.route.route(ip) |
| if ( (iff == "lo") or (ip == conf.route.get_if_bcast(iff)) ): |
| return "ff:ff:ff:ff:ff:ff" |
| if gw != "0.0.0.0": |
| ip = gw |
| |
| if arp_cache.has_key(ip): |
| mac, timeout = arp_cache[ip] |
| if not timeout or (time.time()-timeout < ARPTIMEOUT): |
| return mac |
| |
| res = srp1(Ether(dst=ETHER_BROADCAST)/ARP(op="who-has", pdst=ip), |
| type=ETH_P_ARP, |
| iface = iff, |
| timeout=2, |
| verbose=0, |
| nofilter=1) |
| if res is not None: |
| mac = res.payload.hwsrc |
| arp_cache[ip] = (mac,time.time()) |
| return mac |
| return None |
| |
| |
| #################### |
| ## Random numbers ## |
| #################### |
| |
| class VolatileValue: |
| def __repr__(self): |
| return "<%s>" % self.__class__.__name__ |
| def __getattr__(self, attr): |
| return getattr(self._fix(),attr) |
| def _fix(self): |
| return None |
| |
| |
| class RandField(VolatileValue): |
| pass |
| |
| |
| class RandNum(RandField): |
| min = 0 |
| max = 0 |
| def __init__(self, min, max): |
| self.min = min |
| self.max = max |
| def _fix(self): |
| # XXX: replace with sth that guarantee unicity |
| return random.randrange(self.min, self.max) |
| |
| class RandNumGamma(RandField): |
| def __init__(self, alpha, beta): |
| self.alpha = alpha |
| self.beta = beta |
| def _fix(self): |
| return int(round(random.gammavariate(self.alpha, self.beta))) |
| |
| class RandNumGauss(RandField): |
| def __init__(self, mu, sigma): |
| self.mu = mu |
| self.sigma = sigma |
| def _fix(self): |
| return int(round(random.gauss(self.mu, self.sigma))) |
| |
| class RandNumExpo(RandField): |
| def __init__(self, lambd): |
| self.lambd = lambd |
| def _fix(self): |
| return int(round(random.expovariate(self.lambd))) |
| |
| class RandByte(RandNum): |
| def __init__(self): |
| RandNum.__init__(self, 0, 2L**8) |
| |
| class RandShort(RandNum): |
| def __init__(self): |
| RandNum.__init__(self, 0, 2L**16) |
| |
| class RandInt(RandNum): |
| def __init__(self): |
| RandNum.__init__(self, 0, 2L**32) |
| |
| class RandSInt(RandNum): |
| def __init__(self): |
| RandNum.__init__(self, -2L**31, 2L**31) |
| |
| class RandLong(RandNum): |
| def __init__(self): |
| RandNum.__init__(self, 0, 2L**64) |
| |
| class RandSLong(RandNum): |
| def __init__(self): |
| RandNum.__init__(self, -2L**63, 2L**63) |
| |
| class RandChoice(RandField): |
| def __init__(self, *args): |
| self._choice = args |
| def _fix(self): |
| return random.choice(self._choice) |
| |
| class RandString(RandField): |
| def __init__(self, size, chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"): |
| self.chars = chars |
| self.size = size |
| def _fix(self): |
| s = "" |
| for i in range(self.size): |
| s += random.choice(self.chars) |
| return s |
| |
| class RandBin(RandString): |
| def __init__(self, size): |
| RandString.__init__(self, size, "".join(map(chr,range(256)))) |
| |
| |
| class RandTermString(RandString): |
| def __init__(self, size, term): |
| RandString.__init__(self, size, "".join(map(chr,range(1,256)))) |
| self.term = term |
| def _fix(self): |
| return RandString._fix(self)+self.term |
| |
| |
| |
| class RandIP(RandString): |
| def __init__(self, iptemplate="0.0.0.0/0"): |
| self.ip = Net(iptemplate) |
| def _fix(self): |
| return self.ip.choice() |
| |
| class RandMAC(RandString): |
| def __init__(self, template="*"): |
| template += ":*:*:*:*:*" |
| template = template.split(":") |
| self.mac = () |
| for i in range(6): |
| if template[i] == "*": |
| v = RandByte() |
| elif "-" in template[i]: |
| x,y = template[i].split("-") |
| v = RandNum(int(x,16), int(y,16)) |
| else: |
| v = int(template[i],16) |
| self.mac += (v,) |
| def _fix(self): |
| return "%02x:%02x:%02x:%02x:%02x:%02x" % self.mac |
| |
| |
| class RandOID(RandString): |
| def __init__(self, fmt=None, depth=RandNumExpo(0.1), idnum=RandNumExpo(0.01)): |
| self.ori_fmt = fmt |
| if fmt is not None: |
| fmt = fmt.split(".") |
| for i in range(len(fmt)): |
| if "-" in fmt[i]: |
| fmt[i] = tuple(map(int, fmt[i].split("-"))) |
| self.fmt = fmt |
| self.depth = depth |
| self.idnum = idnum |
| def __repr__(self): |
| if self.ori_fmt is None: |
| return "<%s>" % self.__class__.__name__ |
| else: |
| return "<%s [%s]>" % (self.__class__.__name__, self.ori_fmt) |
| def _fix(self): |
| if self.fmt is None: |
| return ".".join(map(str, [self.idnum for i in xrange(1+self.depth)])) |
| else: |
| oid = [] |
| for i in self.fmt: |
| if i == "*": |
| oid.append(str(self.idnum)) |
| elif i == "**": |
| oid += map(str, [self.idnum for i in xrange(1+self.depth)]) |
| elif type(i) is tuple: |
| oid.append(str(random.randrange(*i))) |
| else: |
| oid.append(i) |
| return ".".join(oid) |
| |
| |
| |
| class RandASN1Object(RandField): |
| def __init__(self, objlist=None): |
| if objlist is None: |
| objlist = map(lambda x:x._asn1_obj, |
| filter(lambda x:hasattr(x,"_asn1_obj"), ASN1_Class_UNIVERSAL.__rdict__.values())) |
| self.objlist = objlist |
| self.chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" |
| def _fix(self, n=0): |
| o = random.choice(self.objlist) |
| if issubclass(o, ASN1_INTEGER): |
| return o(int(random.gauss(0,1000))) |
| elif issubclass(o, ASN1_STRING): |
| z = int(random.expovariate(0.05)+1) |
| return o("".join([random.choice(self.chars) for i in range(z)])) |
| elif issubclass(o, ASN1_SEQUENCE) and (n < 10): |
| z = int(random.expovariate(0.08)+1) |
| return o(map(lambda x:x._fix(n+1), [self.__class__(objlist=self.objlist)]*z)) |
| return ASN1_INTEGER(int(random.gauss(0,1000))) |
| |
| |
| # Automatic timestamp |
| |
| class AutoTime(VolatileValue): |
| def __init__(self, base=None): |
| if base == None: |
| self.diff = 0 |
| else: |
| self.diff = time.time()-base |
| def _fix(self): |
| return time.time()-self.diff |
| |
| class IntAutoTime(AutoTime): |
| def _fix(self): |
| return int(time.time()-self.diff) |
| |
| |
| |
| class DelayedEval(VolatileValue): |
| """ Exemple of usage: DelayedEval("time.time()") """ |
| def __init__(self, expr): |
| self.expr = expr |
| def _fix(self): |
| return eval(self.expr) |
| |
| |
| class IncrementalValue(VolatileValue): |
| def __init__(self, start=0, step=1, restart=-1): |
| self.start = self.val = start |
| self.step = step |
| self.restart = restart |
| def _fix(self): |
| v = self.val |
| if self.val == self.restart : |
| self.val = self.start |
| else: |
| self.val += self.step |
| return v |
| |
| def corrupt_bytes(s, p=0.01, n=None): |
| s = array.array("B",str(s)) |
| l = len(s) |
| if n is None: |
| n = max(1,int(l*p)) |
| for i in random.sample(xrange(l), n): |
| s[i] = random.randint(0,255) |
| return s.tostring() |
| |
| def corrupt_bits(s, p=0.01, n=None): |
| s = array.array("B",str(s)) |
| l = len(s)*8 |
| if n is None: |
| n = max(1,int(l*p)) |
| for i in random.sample(xrange(l), n): |
| s[i/8] ^= 1 << (i%8) |
| return s.tostring() |
| |
| |
| class CorruptedBytes(VolatileValue): |
| def __init__(self, s, p=0.01, n=None): |
| self.s = s |
| self.p = p |
| self.n = n |
| def _fix(self): |
| return corrupt_bytes(self.s, self.p, self.n) |
| |
| class CorruptedBits(CorruptedBytes): |
| def _fix(self): |
| return corrupt_bits(self.s, self.p, self.n) |
| |
| ############## |
| #### ASN1 #### |
| ############## |
| |
| class ASN1_Error(Exception): |
| pass |
| |
| class ASN1_Encoding_Error(ASN1_Error): |
| pass |
| |
| class ASN1_Decoding_Error(ASN1_Error): |
| pass |
| |
| class ASN1_BadTag_Decoding_Error(ASN1_Decoding_Error): |
| pass |
| |
| |
| |
| class ASN1Codec(EnumElement): |
| def register_stem(cls, stem): |
| cls._stem = stem |
| def dec(cls, s, context=None): |
| return cls._stem.dec(s, context=context) |
| def safedec(cls, s, context=None): |
| return cls._stem.safedec(s, context=context) |
| def get_stem(cls): |
| return cls.stem |
| |
| |
| class ASN1_Codecs_metaclass(Enum_metaclass): |
| element_class = ASN1Codec |
| |
| class ASN1_Codecs: |
| __metaclass__ = ASN1_Codecs_metaclass |
| BER = 1 |
| DER = 2 |
| PER = 3 |
| CER = 4 |
| LWER = 5 |
| BACnet = 6 |
| OER = 7 |
| SER = 8 |
| XER = 9 |
| |
| class ASN1Tag(EnumElement): |
| def __init__(self, key, value, context=None, codec=None): |
| EnumElement.__init__(self, key, value) |
| self._context = context |
| if codec == None: |
| codec = {} |
| self._codec = codec |
| def clone(self): # /!\ not a real deep copy. self.codec is shared |
| return self.__class__(self._key, self._value, self._context, self._codec) |
| def register_asn1_object(self, asn1obj): |
| self._asn1_obj = asn1obj |
| def asn1_object(self, val): |
| if hasattr(self,"_asn1_obj"): |
| return self._asn1_obj(val) |
| raise ASN1_Error("%r does not have any assigned ASN1 object" % self) |
| def register(self, codecnum, codec): |
| self._codec[codecnum] = codec |
| def get_codec(self, codec): |
| try: |
| c = self._codec[codec] |
| except KeyError,msg: |
| raise ASN1_Error("Codec %r not found for tag %r" % (codec, self)) |
| return c |
| |
| class ASN1_Class_metaclass(Enum_metaclass): |
| element_class = ASN1Tag |
| def __new__(cls, name, bases, dct): # XXX factorise a bit with Enum_metaclass.__new__() |
| for b in bases: |
| for k,v in b.__dict__.iteritems(): |
| if k not in dct and isinstance(v,ASN1Tag): |
| dct[k] = v.clone() |
| |
| rdict = {} |
| for k,v in dct.iteritems(): |
| if type(v) is int: |
| v = ASN1Tag(k,v) |
| dct[k] = v |
| rdict[v] = v |
| elif isinstance(v, ASN1Tag): |
| rdict[v] = v |
| dct["__rdict__"] = rdict |
| |
| cls = type.__new__(cls, name, bases, dct) |
| for v in cls.__dict__.values(): |
| if isinstance(v, ASN1Tag): |
| v.context = cls # overwrite ASN1Tag contexts, even cloned ones |
| return cls |
| |
| |
| class ASN1_Class: |
| __metaclass__ = ASN1_Class_metaclass |
| |
| class ASN1_Class_UNIVERSAL(ASN1_Class): |
| name = "UNIVERSAL" |
| ERROR = -3 |
| RAW = -2 |
| NONE = -1 |
| ANY = 0 |
| BOOLEAN = 1 |
| INTEGER = 2 |
| BIT_STRING = 3 |
| STRING = 4 |
| NULL = 5 |
| OID = 6 |
| OBJECT_DESCRIPTOR = 7 |
| EXTERNAL = 8 |
| REAL = 9 |
| ENUMERATED = 10 |
| EMBEDDED_PDF = 11 |
| UTF8_STRING = 12 |
| RELATIVE_OID = 13 |
| SEQUENCE = 0x30#XXX 16 ?? |
| SET = 17 |
| NUMERIC_STRING = 18 |
| PRINTABLE_STRING = 19 |
| T61_STRING = 20 |
| VIDEOTEX_STRING = 21 |
| IA5_STRING = 22 |
| UTC_TIME = 23 |
| GENERALIZED_TIME = 24 |
| GRAPHIC_STRING = 25 |
| ISO646_STRING = 26 |
| GENERAL_STRING = 27 |
| UNIVERSAL_STRING = 28 |
| CHAR_STRING = 29 |
| BMP_STRING = 30 |
| COUNTER32 = 0x41 |
| TIME_TICKS = 0x43 |
| |
| class ASN1_Object_metaclass(type): |
| def __new__(cls, name, bases, dct): |
| c = super(ASN1_Object_metaclass, cls).__new__(cls, name, bases, dct) |
| try: |
| c.tag.register_asn1_object(c) |
| except: |
| warning("Error registering %r for %r" % (c.tag, c.codec)) |
| return c |
| |
| |
| class ASN1_Object: |
| __metaclass__ = ASN1_Object_metaclass |
| tag = ASN1_Class_UNIVERSAL.ANY |
| def __init__(self, val): |
| self.val = val |
| def enc(self, codec): |
| return self.tag.get_codec(codec).enc(self.val) |
| def __repr__(self): |
| return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), self.val) |
| def __str__(self): |
| return self.enc(conf.ASN1_default_codec) |
| def strshow(self, lvl=0): |
| return (" "*lvl)+repr(self)+"\n" |
| def show(self, lvl=0): |
| print self.strshow(lvl) |
| def __eq__(self, other): |
| return self.val == other |
| def __cmp__(self, other): |
| return cmp(self.val, other) |
| |
| class ASN1_DECODING_ERROR(ASN1_Object): |
| tag = ASN1_Class_UNIVERSAL.ERROR |
| def __init__(self, val, exc=None): |
| ASN1_Object.__init__(self, val) |
| self.exc = exc |
| def __repr__(self): |
| return "<%s[%r]{{%s}}>" % (self.__dict__.get("name", self.__class__.__name__), |
| self.val, self.exc.args[0]) |
| def enc(self, codec): |
| if isinstance(self.val, ASN1_Object): |
| return self.val.enc(codec) |
| return self.val |
| |
| class ASN1_force(ASN1_Object): |
| tag = ASN1_Class_UNIVERSAL.RAW |
| def enc(self, codec): |
| if isinstance(self.val, ASN1_Object): |
| return self.val.enc(codec) |
| return self.val |
| |
| class ASN1_BADTAG(ASN1_force): |
| pass |
| |
| class ASN1_INTEGER(ASN1_Object): |
| tag = ASN1_Class_UNIVERSAL.INTEGER |
| |
| class ASN1_STRING(ASN1_Object): |
| tag = ASN1_Class_UNIVERSAL.STRING |
| |
| class ASN1_BIT_STRING(ASN1_STRING): |
| tag = ASN1_Class_UNIVERSAL.BIT_STRING |
| |
| class ASN1_PRINTABLE_STRING(ASN1_STRING): |
| tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING |
| |
| class ASN1_T61_STRING(ASN1_STRING): |
| tag = ASN1_Class_UNIVERSAL.T61_STRING |
| |
| class ASN1_IA5_STRING(ASN1_STRING): |
| tag = ASN1_Class_UNIVERSAL.IA5_STRING |
| |
| class ASN1_NUMERIC_STRING(ASN1_STRING): |
| tag = ASN1_Class_UNIVERSAL.NUMERIC_STRING |
| |
| class ASN1_VIDEOTEX_STRING(ASN1_STRING): |
| tag = ASN1_Class_UNIVERSAL.VIDEOTEX_STRING |
| |
| class ASN1_UTC_TIME(ASN1_STRING): |
| tag = ASN1_Class_UNIVERSAL.UTC_TIME |
| |
| class ASN1_TIME_TICKS(ASN1_INTEGER): |
| tag = ASN1_Class_UNIVERSAL.TIME_TICKS |
| |
| class ASN1_BOOLEAN(ASN1_INTEGER): |
| tag = ASN1_Class_UNIVERSAL.BOOLEAN |
| |
| class ASN1_NULL(ASN1_INTEGER): |
| tag = ASN1_Class_UNIVERSAL.NULL |
| |
| class ASN1_COUNTER32(ASN1_INTEGER): |
| tag = ASN1_Class_UNIVERSAL.COUNTER32 |
| |
| class ASN1_SEQUENCE(ASN1_Object): |
| tag = ASN1_Class_UNIVERSAL.SEQUENCE |
| def strshow(self, lvl=0): |
| s = (" "*lvl)+("# %s:" % self.__class__.__name__)+"\n" |
| for o in self.val: |
| s += o.strshow(lvl=lvl+1) |
| return s |
| |
| class ASN1_SET(ASN1_SEQUENCE): |
| tag = ASN1_Class_UNIVERSAL.SET |
| |
| class ASN1_OID(ASN1_Object): |
| tag = ASN1_Class_UNIVERSAL.OID |
| def __init__(self, val): |
| val = conf.mib._oid(val) |
| ASN1_Object.__init__(self, val) |
| def __repr__(self): |
| return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), conf.mib._oidname(self.val)) |
| |
| |
| |
| ################## |
| ## BER encoding ## |
| ################## |
| |
| |
| |
| #####[ BER tools ]##### |
| |
| |
| class BER_Exception(Exception): |
| pass |
| |
| class BER_Decoding_Error(ASN1_Decoding_Error): |
| def __init__(self, msg, decoded=None, remaining=None): |
| Exception.__init__(self, msg) |
| self.remaining = remaining |
| self.decoded = decoded |
| def __str__(self): |
| s = Exception.__str__(self) |
| if isinstance(self.decoded, BERcodec_Object): |
| s+="\n### Already decoded ###\n%s" % self.decoded.strshow() |
| else: |
| s+="\n### Already decoded ###\n%r" % self.decoded |
| s+="\n### Remaining ###\n%r" % self.remaining |
| return s |
| |
| class BER_BadTag_Decoding_Error(BER_Decoding_Error, ASN1_BadTag_Decoding_Error): |
| pass |
| |
| def BER_len_enc(l, size=0): |
| if l <= 127 and size==0: |
| return chr(l) |
| s = "" |
| while l or size>0: |
| s = chr(l&0xff)+s |
| l >>= 8L |
| size -= 1 |
| if len(s) > 127: |
| raise BER_Exception("BER_len_enc: Length too long (%i) to be encoded [%r]" % (len(s),s)) |
| return chr(len(s)|0x80)+s |
| def BER_len_dec(s): |
| l = ord(s[0]) |
| if not l & 0x80: |
| return l,s[1:] |
| l &= 0x7f |
| if len(s) <= l: |
| raise BER_Decoding_Error("BER_len_dec: Got %i bytes while expecting %i" % (len(s)-1, l),remaining=s) |
| ll = 0L |
| for c in s[1:l+1]: |
| ll <<= 8L |
| ll |= ord(c) |
| return ll,s[l+1:] |
| |
| def BER_num_enc(l, size=1): |
| x=[] |
| while l or size>0: |
| x.insert(0, l & 0x7f) |
| if len(x) > 1: |
| x[0] |= 0x80 |
| l >>= 7 |
| size -= 1 |
| return "".join([chr(k) for k in x]) |
| def BER_num_dec(s): |
| x = 0 |
| for i in range(len(s)): |
| c = ord(s[i]) |
| x <<= 7 |
| x |= c&0x7f |
| if not c&0x80: |
| break |
| if c&0x80: |
| raise BER_Decoding_Error("BER_num_dec: unfinished number description", remaining=s) |
| return x, s[i+1:] |
| |
| #####[ BER classes ]##### |
| |
| class BERcodec_metaclass(type): |
| def __new__(cls, name, bases, dct): |
| c = super(BERcodec_metaclass, cls).__new__(cls, name, bases, dct) |
| try: |
| c.tag.register(c.codec, c) |
| except: |
| warning("Error registering %r for %r" % (c.tag, c.codec)) |
| return c |
| |
| |
| class BERcodec_Object: |
| __metaclass__ = BERcodec_metaclass |
| codec = ASN1_Codecs.BER |
| tag = ASN1_Class_UNIVERSAL.ANY |
| |
| @classmethod |
| def asn1_object(cls, val): |
| return cls.tag.asn1_object(val) |
| |
| @classmethod |
| def check_string(cls, s): |
| if not s: |
| raise BER_Decoding_Error("%s: Got empty object while expecting tag %r" % |
| (cls.__name__,cls.tag), remaining=s) |
| @classmethod |
| def check_type(cls, s): |
| cls.check_string(s) |
| if cls.tag != ord(s[0]): |
| raise BER_BadTag_Decoding_Error("%s: Got tag [%i/%#x] while expecting %r" % |
| (cls.__name__, ord(s[0]), ord(s[0]),cls.tag), remaining=s) |
| return s[1:] |
| @classmethod |
| def check_type_get_len(cls, s): |
| s2 = cls.check_type(s) |
| if not s2: |
| raise BER_Decoding_Error("%s: No bytes while expecting a length" % |
| cls.__name__, remaining=s) |
| return BER_len_dec(s2) |
| @classmethod |
| def check_type_check_len(cls, s): |
| l,s3 = cls.check_type_get_len(s) |
| if len(s3) < l: |
| raise BER_Decoding_Error("%s: Got %i bytes while expecting %i" % |
| (cls.__name__, len(s3), l), remaining=s) |
| return l,s3[:l],s3[l:] |
| |
| @classmethod |
| def do_dec(cls, s, context=None, safe=False): |
| if context is None: |
| context = cls.tag.context |
| cls.check_string(s) |
| p = ord(s[0]) |
| if p not in context: |
| t = s |
| if len(t) > 18: |
| t = t[:15]+"..." |
| raise BER_Decoding_Error("Unknown prefix [%02x] for [%r]" % (p,t), remaining=s) |
| codec = context[p].get_codec(ASN1_Codecs.BER) |
| return codec.dec(s,context,safe) |
| |
| @classmethod |
| def dec(cls, s, context=None, safe=False): |
| if not safe: |
| return cls.do_dec(s, context, safe) |
| try: |
| return cls.do_dec(s, context, safe) |
| except BER_BadTag_Decoding_Error,e: |
| o,remain = BERcodec_Object.dec(e.remaining, context, safe) |
| return ASN1_BADTAG(o),remain |
| except BER_Decoding_Error, e: |
| return ASN1_DECODING_ERROR(s, exc=e),"" |
| except ASN1_Error, e: |
| return ASN1_DECODING_ERROR(s, exc=e),"" |
| |
| @classmethod |
| def safedec(cls, s, context=None): |
| return cls.dec(s, context, safe=True) |
| |
| |
| @classmethod |
| def enc(cls, s): |
| if type(s) is str: |
| return BERcodec_STRING.enc(s) |
| else: |
| return BERcodec_INTEGER.enc(int(s)) |
| |
| |
| |
| ASN1_Codecs.BER.register_stem(BERcodec_Object) |
| |
| |
| class BERcodec_INTEGER(BERcodec_Object): |
| tag = ASN1_Class_UNIVERSAL.INTEGER |
| @classmethod |
| def enc(cls, i): |
| s = [] |
| while 1: |
| s.append(i&0xff) |
| if -127 <= i < 0: |
| break |
| if 128 <= i <= 255: |
| s.append(0) |
| i >>= 8 |
| if not i: |
| break |
| s.append(len(s)) |
| s.append(cls.tag) |
| s.reverse() |
| return "".join(map(chr, s)) |
| @classmethod |
| def do_dec(cls, s, context=None, safe=False): |
| l,s,t = cls.check_type_check_len(s) |
| x = 0L |
| if s: |
| if ord(s[0])&0x80: # negative int |
| x = -1L |
| for c in s: |
| x <<= 8 |
| x |= ord(c) |
| return cls.asn1_object(x),t |
| |
| |
| class BERcodec_BOOLEAN(BERcodec_INTEGER): |
| tag = ASN1_Class_UNIVERSAL.BOOLEAN |
| |
| class BERcodec_NULL(BERcodec_INTEGER): |
| tag = ASN1_Class_UNIVERSAL.NULL |
| @classmethod |
| def enc(cls, i): |
| if i == 0: |
| return chr(cls.tag)+"\0" |
| |
| class BERcodec_STRING(BERcodec_Object): |
| tag = ASN1_Class_UNIVERSAL.STRING |
| @classmethod |
| def enc(cls,s): |
| return chr(cls.tag)+BER_len_enc(len(s))+s |
| @classmethod |
| def do_dec(cls, s, context=None, safe=False): |
| l,s,t = cls.check_type_check_len(s) |
| return cls.tag.asn1_object(s),t |
| |
| class BERcodec_BIT_STRING(BERcodec_STRING): |
| tag = ASN1_Class_UNIVERSAL.BIT_STRING |
| |
| class BERcodec_PRINTABLE_STRING(BERcodec_STRING): |
| tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING |
| |
| class BERcodec_T61_STRING (BERcodec_STRING): |
| tag = ASN1_Class_UNIVERSAL.T61_STRING |
| |
| class BERcodec_IA5_STRING(BERcodec_STRING): |
| tag = ASN1_Class_UNIVERSAL.IA5_STRING |
| |
| class BERcodec_UTC_TIME(BERcodec_STRING): |
| tag = ASN1_Class_UNIVERSAL.UTC_TIME |
| |
| class BERcodec_TIME_TICKS(BERcodec_INTEGER): |
| tag = ASN1_Class_UNIVERSAL.TIME_TICKS |
| |
| class BERcodec_COUNTER32(BERcodec_INTEGER): |
| tag = ASN1_Class_UNIVERSAL.COUNTER32 |
| |
| class BERcodec_SEQUENCE(BERcodec_Object): |
| tag = ASN1_Class_UNIVERSAL.SEQUENCE |
| @classmethod |
| def enc(cls, l): |
| if type(l) is not str: |
| l = "".join(map(lambda x: x.enc(cls.codec), l)) |
| return chr(cls.tag)+BER_len_enc(len(l))+l |
| @classmethod |
| def do_dec(cls, s, context=None, safe=False): |
| if context is None: |
| context = cls.tag.context |
| l,st = cls.check_type_get_len(s) # we may have len(s) < l |
| s,t = st[:l],st[l:] |
| obj = [] |
| while s: |
| try: |
| o,s = BERcodec_Object.dec(s, context, safe) |
| except BER_Decoding_Error, err: |
| print "enrichi %r <- %r %r" % (err.remaining,t,s), obj |
| err.remaining += t |
| if err.decoded is not None: |
| obj.append(err.decoded) |
| err.decoded = obj |
| raise |
| obj.append(o) |
| if len(st) < l: |
| raise BER_Decoding_Error("Not enough bytes to decode sequence", decoded=obj) |
| return cls.asn1_object(obj),t |
| |
| class BERcodec_SET(BERcodec_SEQUENCE): |
| tag = ASN1_Class_UNIVERSAL.SET |
| |
| |
| class BERcodec_OID(BERcodec_Object): |
| tag = ASN1_Class_UNIVERSAL.OID |
| |
| @classmethod |
| def enc(cls, oid): |
| lst = [int(x) for x in oid.strip(".").split(".")] |
| if len(lst) >= 2: |
| lst[1] += 40*lst[0] |
| del(lst[0]) |
| s = "".join([BER_num_enc(k) for k in lst]) |
| return chr(cls.tag)+BER_len_enc(len(s))+s |
| @classmethod |
| def do_dec(cls, s, context=None, safe=False): |
| l,s,t = cls.check_type_check_len(s) |
| lst = [] |
| while s: |
| l,s = BER_num_dec(s) |
| lst.append(l) |
| if (len(lst) > 0): |
| lst.insert(0,lst[0]/40) |
| lst[1] %= 40 |
| return cls.asn1_object(".".join([str(k) for k in lst])), t |
| |
| |
| ################# |
| ## MIB parsing ## |
| ################# |
| |
| _mib_re_integer = re.compile("^[0-9]+$") |
| _mib_re_both = re.compile("^([a-zA-Z_][a-zA-Z0-9_-]*)\(([0-9]+)\)$") |
| _mib_re_oiddecl = re.compile("$\s*([a-zA-Z0-9_-]+)\s+OBJECT[^:]+::=\s*\{([^\}]+)\}",re.M) |
| _mib_re_strings = re.compile('"[^"]*"') |
| _mib_re_comments = re.compile('--.*(\r|\n)') |
| |
| class MIBDict(DADict): |
| def _findroot(self, x): |
| if x.startswith("."): |
| x = x[1:] |
| if not x.endswith("."): |
| x += "." |
| max=0 |
| root="." |
| for k in self.keys(): |
| if x.startswith(self[k]+"."): |
| if max < len(self[k]): |
| max = len(self[k]) |
| root = k |
| return root, x[max:-1] |
| def _oidname(self, x): |
| root,remainder = self._findroot(x) |
| return root+remainder |
| def _oid(self, x): |
| xl = x.strip(".").split(".") |
| p = len(xl)-1 |
| while p >= 0 and _mib_re_integer.match(xl[p]): |
| p -= 1 |
| if p != 0 or xl[p] not in self: |
| return x |
| xl[p] = self[xl[p]] |
| return ".".join(xl[p:]) |
| def _make_graph(self, other_keys=[]): |
| nodes = [(k,self[k]) for k in self.keys()] |
| oids = [self[k] for k in self.keys()] |
| for k in other_keys: |
| if k not in oids: |
| nodes.append(self.oidname(k),k) |
| s = 'digraph "mib" {\n' |
| for k,o in nodes: |
| s += '\t"%s" [ label="%s" ];\n' % (o,k) |
| s += "\n" |
| for k,o in nodes: |
| parent,remainder = self._findroot(o[:-1]) |
| remainder = remainder[1:]+o[-1] |
| if parent != ".": |
| parent = self[parent] |
| s += '\t"%s" -> "%s" [label="%s"];\n' % (parent, o,remainder) |
| s += "}\n" |
| return s |
| |
| |
| def mib_register(ident, value, the_mib, unresolved): |
| if ident in the_mib or ident in unresolved: |
| return ident in the_mib |
| resval = [] |
| not_resolved = 0 |
| for v in value: |
| if _mib_re_integer.match(v): |
| resval.append(v) |
| else: |
| v = fixname(v) |
| if v not in the_mib: |
| not_resolved = 1 |
| if v in the_mib: |
| v = the_mib[v] |
| elif v in unresolved: |
| v = unresolved[v] |
| if type(v) is list: |
| resval += v |
| else: |
| resval.append(v) |
| if not_resolved: |
| unresolved[ident] = resval |
| return False |
| else: |
| the_mib[ident] = resval |
| keys = unresolved.keys() |
| i = 0 |
| while i < len(keys): |
| k = keys[i] |
| if mib_register(k,unresolved[k], the_mib, {}): |
| del(unresolved[k]) |
| del(keys[i]) |
| i = 0 |
| else: |
| i += 1 |
| |
| return True |
| |
| |
| def load_mib(filenames): |
| the_mib = {'iso': ['1']} |
| unresolved = {} |
| for k in conf.mib.keys(): |
| mib_register(k, conf.mib[k].split("."), the_mib, unresolved) |
| |
| if type(filenames) is str: |
| filenames = [filenames] |
| for fnames in filenames: |
| for fname in glob(fnames): |
| f = open(fname) |
| text = f.read() |
| cleantext = " ".join(_mib_re_strings.split(" ".join(_mib_re_comments.split(text)))) |
| for m in _mib_re_oiddecl.finditer(cleantext): |
| ident,oid = m.groups() |
| ident=fixname(ident) |
| oid = oid.split() |
| for i in range(len(oid)): |
| m = _mib_re_both.match(oid[i]) |
| if m: |
| oid[i] = m.groups()[1] |
| mib_register(ident, oid, the_mib, unresolved) |
| |
| newmib = MIBDict(_name="MIB") |
| for k,o in the_mib.iteritems(): |
| newmib[k]=".".join(o) |
| for k,o in unresolved.iteritems(): |
| newmib[k]=".".join(o) |
| |
| conf.mib=newmib |
| |
| |
| |
| ################ |
| ## Generators ## |
| ################ |
| |
| class Gen(object): |
| def __iter__(self): |
| return iter([]) |
| |
| class SetGen(Gen): |
| def __init__(self, set, _iterpacket=1): |
| self._iterpacket=_iterpacket |
| if type(set) is list: |
| self.set = set |
| elif isinstance(set, PacketList): |
| self.set = list(set) |
| else: |
| self.set = [set] |
| def transf(self, element): |
| return element |
| def __iter__(self): |
| for i in self.set: |
| if (type(i) is tuple) and (len(i) == 2) and type(i[0]) is int and type(i[1]) is int: |
| if (i[0] <= i[1]): |
| j=i[0] |
| while j <= i[1]: |
| yield j |
| j += 1 |
| elif isinstance(i, Gen) and (self._iterpacket or not isinstance(i,Packet)): |
| for j in i: |
| yield j |
| else: |
| yield i |
| def __repr__(self): |
| return "<SetGen %s>" % self.set.__repr__() |
| |
| class Net(Gen): |
| """Generate a list of IPs from a network address or a name""" |
| name = "ip" |
| 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])?$") |
| def __init__(self, net): |
| self.repr=net |
| |
| tmp=net.split('/')+["32"] |
| if not self.ipaddress.match(net): |
| tmp[0]=socket.gethostbyname(tmp[0]) |
| netmask = int(tmp[1]) |
| |
| def parse_digit(a,netmask): |
| netmask = min(8,max(netmask,0)) |
| if a == "*": |
| a = (0,256) |
| elif a.find("-") >= 0: |
| x,y = map(int,a.split("-")) |
| if x > y: |
| y = x |
| a = (x & (0xffL<<netmask) , max(y, (x | (0xffL>>(8-netmask))))+1) |
| else: |
| a = (int(a) & (0xffL<<netmask),(int(a) | (0xffL>>(8-netmask)))+1) |
| return a |
| |
| self.parsed = map(lambda x,y: parse_digit(x,y), tmp[0].split("."), map(lambda x,nm=netmask: x-nm, (8,16,24,32))) |
| |
| def __iter__(self): |
| for d in xrange(*self.parsed[3]): |
| for c in xrange(*self.parsed[2]): |
| for b in xrange(*self.parsed[1]): |
| for a in xrange(*self.parsed[0]): |
| yield "%i.%i.%i.%i" % (a,b,c,d) |
| def choice(self): |
| ip = [] |
| for v in self.parsed: |
| ip.append(str(random.randint(v[0],v[1]-1))) |
| return ".".join(ip) |
| |
| def __repr__(self): |
| return "Net(%r)" % self.repr |
| |
| class OID(Gen): |
| name = "OID" |
| def __init__(self, oid): |
| self.oid = oid |
| self.cmpt = [] |
| fmt = [] |
| for i in oid.split("."): |
| if "-" in i: |
| fmt.append("%i") |
| self.cmpt.append(tuple(map(int, i.split("-")))) |
| else: |
| fmt.append(i) |
| self.fmt = ".".join(fmt) |
| def __repr__(self): |
| return "OID(%r)" % self.oid |
| def __iter__(self): |
| ii = [k[0] for k in self.cmpt] |
| while 1: |
| yield self.fmt % tuple(ii) |
| i = 0 |
| while 1: |
| if i >= len(ii): |
| raise StopIteration |
| if ii[i] < self.cmpt[i][1]: |
| ii[i]+=1 |
| break |
| else: |
| ii[i] = self.cmpt[i][0] |
| i += 1 |
| |
| |
| ############# |
| ## Results ## |
| ############# |
| |
| class PacketList: |
| res = [] |
| def __init__(self, res=None, name="PacketList", stats=None): |
| """create a packet list from a list of packets |
| res: the list of packets |
| stats: a list of classes that will appear in the stats (defaults to [TCP,UDP,ICMP])""" |
| if stats is None: |
| stats = [ TCP,UDP,ICMP ] |
| self.stats = stats |
| if res is None: |
| res = [] |
| if isinstance(res, PacketList): |
| res = res.res |
| self.res = res |
| self.listname = name |
| def _elt2pkt(self, elt): |
| return elt |
| def _elt2sum(self, elt): |
| return elt.summary() |
| def _elt2show(self, elt): |
| return self._elt2sum(elt) |
| def __repr__(self): |
| # stats=dict.fromkeys(self.stats,0) ## needs python >= 2.3 :( |
| stats = dict(map(lambda x: (x,0), self.stats)) |
| other = 0 |
| for r in self.res: |
| f = 0 |
| for p in stats: |
| if self._elt2pkt(r).haslayer(p): |
| stats[p] += 1 |
| f = 1 |
| break |
| if not f: |
| other += 1 |
| s = "" |
| ct = conf.color_theme |
| for p in stats: |
| s += " %s%s%s" % (ct.packetlist_proto(p.name), |
| ct.punct(":"), |
| ct.packetlist_value(stats[p])) |
| s += " %s%s%s" % (ct.packetlist_proto("Other"), |
| ct.punct(":"), |
| ct.packetlist_value(other)) |
| return "%s%s%s%s%s" % (ct.punct("<"), |
| ct.packetlist_name(self.listname), |
| ct.punct(":"), |
| s, |
| ct.punct(">")) |
| def __getattr__(self, attr): |
| return getattr(self.res, attr) |
| def __getitem__(self, item): |
| if isinstance(item,type) and issubclass(item,Packet): |
| return self.__class__(filter(lambda x: item in self._elt2pkt(x),self.res), |
| name="%s from %s"%(item.__name__,self.listname)) |
| if type(item) is slice: |
| return self.__class__(self.res.__getitem__(item), |
| name = "mod %s" % self.listname) |
| return self.res.__getitem__(item) |
| def __getslice__(self, *args, **kargs): |
| return self.__class__(self.res.__getslice__(*args, **kargs), |
| name="mod %s"%self.listname) |
| def __add__(self, other): |
| return self.__class__(self.res+other.res, |
| name="%s+%s"%(self.listname,other.listname)) |
| def summary(self, prn=None, lfilter=None): |
| """prints a summary of each packet |
| prn: function to apply to each packet instead of lambda x:x.summary() |
| lfilter: truth function to apply to each packet to decide whether it will be displayed""" |
| for r in self.res: |
| if lfilter is not None: |
| if not lfilter(r): |
| continue |
| if prn is None: |
| print self._elt2sum(r) |
| else: |
| print prn(r) |
| def nsummary(self,prn=None, lfilter=None): |
| """prints a summary of each packet with the packet's number |
| prn: function to apply to each packet instead of lambda x:x.summary() |
| lfilter: truth function to apply to each packet to decide whether it will be displayed""" |
| for i in range(len(self.res)): |
| if lfilter is not None: |
| if not lfilter(self.res[i]): |
| continue |
| print conf.color_theme.id(i,"%04i"), |
| if prn is None: |
| print self._elt2sum(self.res[i]) |
| else: |
| print prn(self.res[i]) |
| def display(self): # Deprecated. Use show() |
| """deprecated. is show()""" |
| self.show() |
| def show(self, *args, **kargs): |
| """Best way to display the packet list. Defaults to nsummary() method""" |
| return self.nsummary(*args, **kargs) |
| |
| def filter(self, func): |
| """Returns a packet list filtered by a truth function""" |
| return self.__class__(filter(func,self.res), |
| name="filtered %s"%self.listname) |
| def make_table(self, *args, **kargs): |
| """Prints a table using a function that returs for each packet its head column value, head row value and displayed value |
| ex: p.make_table(lambda x:(x[IP].dst, x[TCP].dport, x[TCP].sprintf("%flags%")) """ |
| return make_table(self.res, *args, **kargs) |
| def make_lined_table(self, *args, **kargs): |
| """Same as make_table, but print a table with lines""" |
| return make_lined_table(self.res, *args, **kargs) |
| def make_tex_table(self, *args, **kargs): |
| """Same as make_table, but print a table with LaTeX syntax""" |
| return make_tex_table(self.res, *args, **kargs) |
| |
| def plot(self, f, lfilter=None,**kargs): |
| """Applies a function to each packet to get a value that will be plotted with GnuPlot. A gnuplot object is returned |
| lfilter: a truth function that decides whether a packet must be ploted""" |
| g=Gnuplot.Gnuplot() |
| l = self.res |
| if lfilter is not None: |
| l = filter(lfilter, l) |
| l = map(f,l) |
| g.plot(Gnuplot.Data(l, **kargs)) |
| return g |
| |
| def diffplot(self, f, delay=1, lfilter=None, **kargs): |
| """diffplot(f, delay=1, lfilter=None) |
| Applies a function to couples (l[i],l[i+delay])""" |
| g = Gnuplot.Gnuplot() |
| l = self.res |
| if lfilter is not None: |
| l = filter(lfilter, l) |
| l = map(f,l[:-delay],l[delay:]) |
| g.plot(Gnuplot.Data(l, **kargs)) |
| return g |
| |
| def multiplot(self, f, lfilter=None, **kargs): |
| """Uses a function that returns a label and a value for this label, then plots all the values label by label""" |
| g=Gnuplot.Gnuplot() |
| l = self.res |
| if lfilter is not None: |
| l = filter(lfilter, l) |
| |
| d={} |
| for e in l: |
| k,v = f(e) |
| if k in d: |
| d[k].append(v) |
| else: |
| d[k] = [v] |
| data=[] |
| for k in d: |
| data.append(Gnuplot.Data(d[k], title=k, **kargs)) |
| |
| g.plot(*data) |
| return g |
| |
| |
| def rawhexdump(self): |
| """Prints an hexadecimal dump of each packet in the list""" |
| for p in self: |
| hexdump(self._elt2pkt(p)) |
| |
| def hexraw(self, lfilter=None): |
| """Same as nsummary(), except that if a packet has a Raw layer, it will be hexdumped |
| lfilter: a truth function that decides whether a packet must be displayed""" |
| for i in range(len(self.res)): |
| p = self._elt2pkt(self.res[i]) |
| if lfilter is not None and not lfilter(p): |
| continue |
| print "%s %s %s" % (conf.color_theme.id(i,"%04i"), |
| p.sprintf("%.time%"), |
| self._elt2sum(self.res[i])) |
| if p.haslayer(Raw): |
| hexdump(p.getlayer(Raw).load) |
| |
| def hexdump(self, lfilter=None): |
| """Same as nsummary(), except that packets are also hexdumped |
| lfilter: a truth function that decides whether a packet must be displayed""" |
| for i in range(len(self.res)): |
| p = self._elt2pkt(self.res[i]) |
| if lfilter is not None and not lfilter(p): |
| continue |
| print "%s %s %s" % (conf.color_theme.id(i,"%04i"), |
| p.sprintf("%.time%"), |
| self._elt2sum(self.res[i])) |
| hexdump(p) |
| |
| def padding(self, lfilter=None): |
| """Same as hexraw(), for Padding layer""" |
| for i in range(len(self.res)): |
| p = self._elt2pkt(self.res[i]) |
| if p.haslayer(Padding): |
| if lfilter is None or lfilter(p): |
| print "%s %s %s" % (conf.color_theme.id(i,"%04i"), |
| p.sprintf("%.time%"), |
| self._elt2sum(self.res[i])) |
| hexdump(p.getlayer(Padding).load) |
| |
| def nzpadding(self, lfilter=None): |
| """Same as padding() but only non null padding""" |
| for i in range(len(self.res)): |
| p = self._elt2pkt(self.res[i]) |
| if p.haslayer(Padding): |
| pad = p.getlayer(Padding).load |
| if pad == pad[0]*len(pad): |
| continue |
| if lfilter is None or lfilter(p): |
| print "%s %s %s" % (conf.color_theme.id(i,"%04i"), |
| p.sprintf("%.time%"), |
| self._elt2sum(self.res[i])) |
| hexdump(p.getlayer(Padding).load) |
| |
| |
| def conversations(self, getsrcdst=None,**kargs): |
| """Graphes a conversations between sources and destinations and display it |
| (using graphviz and imagemagick) |
| getsrcdst: a function that takes an element of the list and return the source and dest |
| by defaults, return source and destination IP |
| type: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option |
| target: filename or redirect. Defaults pipe to Imagemagick's display program |
| prog: which graphviz program to use""" |
| if getsrcdst is None: |
| getsrcdst = lambda x:(x[IP].src, x[IP].dst) |
| conv = {} |
| for p in self.res: |
| p = self._elt2pkt(p) |
| try: |
| c = getsrcdst(p) |
| except: |
| #XXX warning() |
| continue |
| conv[c] = conv.get(c,0)+1 |
| gr = 'digraph "conv" {\n' |
| for s,d in conv: |
| gr += '\t "%s" -> "%s"\n' % (s,d) |
| gr += "}\n" |
| do_graph(gr, **kargs) |
| |
| def afterglow(self, src=None, event=None, dst=None, **kargs): |
| """Experimental clone attempt of http://sourceforge.net/projects/afterglow |
| each datum is reduced as src -> event -> dst and the data are graphed. |
| by default we have IP.src -> IP.dport -> IP.dst""" |
| if src is None: |
| src = lambda x: x[IP].src |
| if event is None: |
| event = lambda x: x[IP].dport |
| if dst is None: |
| dst = lambda x: x[IP].dst |
| sl = {} |
| el = {} |
| dl = {} |
| for i in self.res: |
| try: |
| s,e,d = src(i),event(i),dst(i) |
| if s in sl: |
| n,l = sl[s] |
| n += 1 |
| if e not in l: |
| l.append(e) |
| sl[s] = (n,l) |
| else: |
| sl[s] = (1,[e]) |
| if e in el: |
| n,l = el[e] |
| n+=1 |
| if d not in l: |
| l.append(d) |
| el[e] = (n,l) |
| else: |
| el[e] = (1,[d]) |
| dl[d] = dl.get(d,0)+1 |
| except: |
| continue |
| |
| import math |
| def normalize(n): |
| return 2+math.log(n)/4.0 |
| |
| def minmax(x): |
| m,M = min(x),max(x) |
| if m == M: |
| m = 0 |
| if M == 0: |
| M = 1 |
| return m,M |
| |
| mins,maxs = minmax(map(lambda (x,y): x, sl.values())) |
| mine,maxe = minmax(map(lambda (x,y): x, el.values())) |
| mind,maxd = minmax(dl.values()) |
| |
| gr = 'digraph "afterglow" {\n\tedge [len=2.5];\n' |
| |
| gr += "# src nodes\n" |
| for s in sl: |
| n,l = sl[s]; n = 1+float(n-mins)/(maxs-mins) |
| gr += '"src.%s" [label = "%s", shape=box, fillcolor="#FF0000", style=filled, fixedsize=1, height=%.2f,width=%.2f];\n' % (`s`,`s`,n,n) |
| gr += "# event nodes\n" |
| for e in el: |
| n,l = el[e]; n = n = 1+float(n-mine)/(maxe-mine) |
| gr += '"evt.%s" [label = "%s", shape=circle, fillcolor="#00FFFF", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (`e`,`e`,n,n) |
| for d in dl: |
| n = dl[d]; n = n = 1+float(n-mind)/(maxd-mind) |
| gr += '"dst.%s" [label = "%s", shape=triangle, fillcolor="#0000ff", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (`d`,`d`,n,n) |
| |
| gr += "###\n" |
| for s in sl: |
| n,l = sl[s] |
| for e in l: |
| gr += ' "src.%s" -> "evt.%s";\n' % (`s`,`e`) |
| for e in el: |
| n,l = el[e] |
| for d in l: |
| gr += ' "evt.%s" -> "dst.%s";\n' % (`e`,`d`) |
| |
| gr += "}" |
| open("/tmp/aze","w").write(gr) |
| do_graph(gr, **kargs) |
| |
| |
| |
| def timeskew_graph(self, ip, **kargs): |
| """Tries to graph the timeskew between the timestamps and real time for a given ip""" |
| res = map(lambda x: self._elt2pkt(x), self.res) |
| b = filter(lambda x:x.haslayer(IP) and x.getlayer(IP).src == ip and x.haslayer(TCP), res) |
| c = [] |
| for p in b: |
| opts = p.getlayer(TCP).options |
| for o in opts: |
| if o[0] == "Timestamp": |
| c.append((p.time,o[1][0])) |
| if not c: |
| warning("No timestamps found in packet list") |
| return |
| d = map(lambda (x,y): (x%2000,((x-c[0][0])-((y-c[0][1])/1000.0))),c) |
| g = Gnuplot.Gnuplot() |
| g.plot(Gnuplot.Data(d,**kargs)) |
| return g |
| |
| def _dump_document(self, **kargs): |
| d = pyx.document.document() |
| l = len(self.res) |
| for i in range(len(self.res)): |
| elt = self.res[i] |
| c = self._elt2pkt(elt).canvas_dump(**kargs) |
| cbb = c.bbox() |
| c.text(cbb.left(),cbb.top()+1,r"\font\cmssfont=cmss12\cmssfont{Frame %i/%i}" % (i,l),[pyx.text.size.LARGE]) |
| if conf.verb >= 2: |
| os.write(1,".") |
| d.append(pyx.document.page(c, paperformat=pyx.document.paperformat.A4, |
| margin=1*pyx.unit.t_cm, |
| fittosize=1)) |
| return d |
| |
| |
| |
| def psdump(self, filename = None, **kargs): |
| """Creates a multipage poscript file with a psdump of every packet |
| filename: name of the file to write to. If empty, a temporary file is used and |
| conf.prog.psreader is called""" |
| d = self._dump_document(**kargs) |
| if filename is None: |
| filename = "/tmp/scapy.psd.%i" % os.getpid() |
| d.writePSfile(filename) |
| os.system("%s %s.ps &" % (conf.prog.psreader,filename)) |
| else: |
| d.writePSfile(filename) |
| print |
| |
| def pdfdump(self, filename = None, **kargs): |
| """Creates a PDF file with a psdump of every packet |
| filename: name of the file to write to. If empty, a temporary file is used and |
| conf.prog.pdfreader is called""" |
| d = self._dump_document(**kargs) |
| if filename is None: |
| filename = "/tmp/scapy.psd.%i" % os.getpid() |
| d.writePDFfile(filename) |
| os.system("%s %s.pdf &" % (conf.prog.pdfreader,filename)) |
| else: |
| d.writePDFfile(filename) |
| print |
| |
| def sr(self,multi=0): |
| """sr([multi=1]) -> (SndRcvList, PacketList) |
| Matches packets in the list and return ( (matched couples), (unmatched packets) )""" |
| remain = self.res[:] |
| sr = [] |
| i = 0 |
| while i < len(remain): |
| s = remain[i] |
| j = i |
| while j < len(remain)-1: |
| j += 1 |
| r = remain[j] |
| if r.answers(s): |
| sr.append((s,r)) |
| if multi: |
| remain[i]._answered=1 |
| remain[j]._answered=2 |
| continue |
| del(remain[j]) |
| del(remain[i]) |
| i -= 1 |
| break |
| i += 1 |
| if multi: |
| remain = filter(lambda x:not hasattr(x,"_answered"), remain) |
| return SndRcvList(sr),PacketList(remain) |
| |
| |
| |
| |
| |
| |
| class Dot11PacketList(PacketList): |
| def __init__(self, res=None, name="Dot11List", stats=None): |
| if stats is None: |
| stats = [Dot11WEP, Dot11Beacon, UDP, ICMP, TCP] |
| |
| PacketList.__init__(self, res, name, stats) |
| def toEthernet(self): |
| data = map(lambda x:x.getlayer(Dot11), filter(lambda x : x.haslayer(Dot11) and x.type == 2, self.res)) |
| r2 = [] |
| for p in data: |
| q = p.copy() |
| q.unwep() |
| r2.append(Ether()/q.payload.payload.payload) #Dot11/LLC/SNAP/IP |
| return PacketList(r2,name="Ether from %s"%self.listname) |
| |
| |
| |
| class SndRcvList(PacketList): |
| def __init__(self, res=None, name="Results", stats=None): |
| PacketList.__init__(self, res, name, stats) |
| def _elt2pkt(self, elt): |
| return elt[1] |
| def _elt2sum(self, elt): |
| return "%s ==> %s" % (elt[0].summary(),elt[1].summary()) |
| |
| |
| class ARPingResult(SndRcvList): |
| def __init__(self, res=None, name="ARPing", stats=None): |
| PacketList.__init__(self, res, name, stats) |
| |
| def show(self): |
| for s,r in self.res: |
| print r.sprintf("%Ether.src% %ARP.psrc%") |
| |
| |
| class AS_resolver: |
| server = None |
| options = "-k" |
| def __init__(self, server=None, port=43, options=None): |
| if server is not None: |
| self.server = server |
| self.port = port |
| if options is not None: |
| self.options = options |
| |
| def _start(self): |
| self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| self.s.connect((self.server,self.port)) |
| if self.options: |
| self.s.send(self.options+"\n") |
| self.s.recv(8192) |
| def _stop(self): |
| self.s.close() |
| |
| def _parse_whois(self, txt): |
| asn,desc = None,"" |
| for l in txt.splitlines(): |
| if not asn and l.startswith("origin:"): |
| asn = l[7:].strip() |
| if l.startswith("descr:"): |
| if desc: |
| desc += r"\n" |
| desc += l[6:].strip() |
| if asn is not None and desc: |
| break |
| return asn,desc.strip() |
| |
| def _resolve_one(self, ip): |
| self.s.send("%s\n" % ip) |
| x = "" |
| while not ("%" in x or "source" in x): |
| x += self.s.recv(8192) |
| asn, desc = self._parse_whois(x) |
| return ip,asn,desc |
| def resolve(self, *ips): |
| self._start() |
| ret = [] |
| for ip in ips: |
| ip,asn,desc = self._resolve_one(ip) |
| if asn is not None: |
| ret.append((ip,asn,desc)) |
| self._stop() |
| return ret |
| |
| class AS_resolver_riswhois(AS_resolver): |
| server = "riswhois.ripe.net" |
| options = "-k -M -1" |
| |
| |
| class AS_resolver_radb(AS_resolver): |
| server = "whois.ra.net" |
| options = "-k -M" |
| |
| |
| class AS_resolver_cymru(AS_resolver): |
| server = "whois.cymru.com" |
| options = None |
| def resolve(self, *ips): |
| ASNlist = [] |
| s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| s.connect((self.server,self.port)) |
| s.send("begin\r\n"+"\r\n".join(ips)+"\r\nend\r\n") |
| r = "" |
| while 1: |
| l = s.recv(8192) |
| if l == "": |
| break |
| r += l |
| s.close() |
| for l in r.splitlines()[1:]: |
| if "|" not in l: |
| continue |
| asn,ip,desc = map(str.strip, l.split("|")) |
| if asn == "NA": |
| continue |
| asn = int(asn) |
| ASNlist.append((ip,asn,desc)) |
| return ASNlist |
| |
| class AS_resolver_multi(AS_resolver): |
| resolvers_list = ( AS_resolver_cymru(),AS_resolver_riswhois(),AS_resolver_radb() ) |
| def __init__(self, *reslist): |
| if reslist: |
| self.resolvers_list = reslist |
| def resolve(self, *ips): |
| todo = ips |
| ret = [] |
| for ASres in self.resolvers_list: |
| res = ASres.resolve(*todo) |
| resolved = [ ip for ip,asn,desc in res ] |
| todo = [ ip for ip in todo if ip not in resolved ] |
| ret += res |
| return ret |
| |
| |
| |
| class TracerouteResult(SndRcvList): |
| def __init__(self, res=None, name="Traceroute", stats=None): |
| PacketList.__init__(self, res, name, stats) |
| self.graphdef = None |
| self.graphASres = 0 |
| self.padding = 0 |
| self.hloc = None |
| self.nloc = None |
| |
| def show(self): |
| return self.make_table(lambda (s,r): (s.sprintf("%IP.dst%:{TCP:tcp%ir,TCP.dport%}{UDP:udp%ir,UDP.dport%}{ICMP:ICMP}"), |
| s.ttl, |
| r.sprintf("%-15s,IP.src% {TCP:%TCP.flags%}{ICMP:%ir,ICMP.type%}"))) |
| |
| |
| def get_trace(self): |
| trace = {} |
| for s,r in self.res: |
| if IP not in s: |
| continue |
| d = s[IP].dst |
| if d not in trace: |
| trace[d] = {} |
| trace[d][s[IP].ttl] = r[IP].src, ICMP not in r |
| for k in trace.values(): |
| m = filter(lambda x:k[x][1], k.keys()) |
| if not m: |
| continue |
| m = min(m) |
| for l in k.keys(): |
| if l > m: |
| del(k[l]) |
| return trace |
| |
| def trace3D(self): |
| """Give a 3D representation of the traceroute. |
| right button: rotate the scene |
| middle button: zoom |
| left button: move the scene |
| left button on a ball: toggle IP displaying |
| ctrl-left button on a ball: scan ports 21,22,23,25,80 and 443 and display the result""" |
| trace = self.get_trace() |
| import visual |
| |
| class IPsphere(visual.sphere): |
| def __init__(self, ip, **kargs): |
| visual.sphere.__init__(self, **kargs) |
| self.ip=ip |
| self.label=None |
| self.setlabel(self.ip) |
| def setlabel(self, txt,visible=None): |
| if self.label is not None: |
| if visible is None: |
| visible = self.label.visible |
| self.label.visible = 0 |
| elif visible is None: |
| visible=0 |
| self.label=visual.label(text=txt, pos=self.pos, space=self.radius, xoffset=10, yoffset=20, visible=visible) |
| def action(self): |
| self.label.visible ^= 1 |
| |
| visual.scene = visual.display() |
| visual.scene.exit_on_close(0) |
| start = visual.box() |
| rings={} |
| tr3d = {} |
| for i in trace: |
| tr = trace[i] |
| tr3d[i] = [] |
| ttl = tr.keys() |
| for t in range(1,max(ttl)+1): |
| if t not in rings: |
| rings[t] = [] |
| if t in tr: |
| if tr[t] not in rings[t]: |
| rings[t].append(tr[t]) |
| tr3d[i].append(rings[t].index(tr[t])) |
| else: |
| rings[t].append(("unk",-1)) |
| tr3d[i].append(len(rings[t])-1) |
| for t in rings: |
| r = rings[t] |
| l = len(r) |
| for i in range(l): |
| if r[i][1] == -1: |
| col = (0.75,0.75,0.75) |
| elif r[i][1]: |
| col = visual.color.green |
| else: |
| col = visual.color.blue |
| |
| s = IPsphere(pos=((l-1)*visual.cos(2*i*visual.pi/l),(l-1)*visual.sin(2*i*visual.pi/l),2*t), |
| ip = r[i][0], |
| color = col) |
| for trlst in tr3d.values(): |
| if t <= len(trlst): |
| if trlst[t-1] == i: |
| trlst[t-1] = s |
| forecol = colgen(0.625, 0.4375, 0.25, 0.125) |
| for trlst in tr3d.values(): |
| col = forecol.next() |
| start = (0,0,0) |
| for ip in trlst: |
| visual.cylinder(pos=start,axis=ip.pos-start,color=col,radius=0.2) |
| start = ip.pos |
| |
| movcenter=None |
| while 1: |
| if visual.scene.kb.keys: |
| k = visual.scene.kb.getkey() |
| if k == "esc": |
| break |
| if visual.scene.mouse.events: |
| ev = visual.scene.mouse.getevent() |
| if ev.press == "left": |
| o = ev.pick |
| if o: |
| if ev.ctrl: |
| if o.ip == "unk": |
| continue |
| savcolor = o.color |
| o.color = (1,0,0) |
| a,b=sr(IP(dst=o.ip)/TCP(dport=[21,22,23,25,80,443]),timeout=2) |
| o.color = savcolor |
| if len(a) == 0: |
| txt = "%s:\nno results" % o.ip |
| else: |
| txt = "%s:\n" % o.ip |
| for s,r in a: |
| txt += r.sprintf("{TCP:%IP.src%:%TCP.sport% %TCP.flags%}{TCPerror:%IPerror.dst%:%TCPerror.dport% %IP.src% %ir,ICMP.type%}\n") |
| o.setlabel(txt, visible=1) |
| else: |
| if hasattr(o, "action"): |
| o.action() |
| elif ev.drag == "left": |
| movcenter = ev.pos |
| elif ev.drop == "left": |
| movcenter = None |
| if movcenter: |
| visual.scene.center -= visual.scene.mouse.pos-movcenter |
| movcenter = visual.scene.mouse.pos |
| |
| |
| def world_trace(self): |
| ips = {} |
| rt = {} |
| ports_done = {} |
| for s,r in self.res: |
| ips[r.src] = None |
| if s.haslayer(TCP) or s.haslayer(UDP): |
| trace_id = (s.src,s.dst,s.proto,s.dport) |
| elif s.haslayer(ICMP): |
| trace_id = (s.src,s.dst,s.proto,s.type) |
| else: |
| trace_id = (s.src,s.dst,s.proto,0) |
| trace = rt.get(trace_id,{}) |
| if not r.haslayer(ICMP) or r.type != 11: |
| if ports_done.has_key(trace_id): |
| continue |
| ports_done[trace_id] = None |
| trace[s.ttl] = r.src |
| rt[trace_id] = trace |
| |
| trt = {} |
| for trace_id in rt: |
| trace = rt[trace_id] |
| loctrace = [] |
| for i in range(max(trace.keys())): |
| ip = trace.get(i,None) |
| if ip is None: |
| continue |
| loc = locate_ip(ip) |
| if loc is None: |
| continue |
| # loctrace.append((ip,loc)) # no labels yet |
| loctrace.append(loc) |
| if loctrace: |
| trt[trace_id] = loctrace |
| |
| tr = map(lambda x: Gnuplot.Data(x,with="lines"), trt.values()) |
| g = Gnuplot.Gnuplot() |
| world = Gnuplot.File(conf.gnuplot_world,with="lines") |
| g.plot(world,*tr) |
| return g |
| |
| def make_graph(self,ASres=None,padding=0): |
| if ASres is None: |
| ASres = conf.AS_resolver |
| self.graphASres = ASres |
| self.graphpadding = padding |
| ips = {} |
| rt = {} |
| ports = {} |
| ports_done = {} |
| for s,r in self.res: |
| r = r[IP] or r[IPv6] or r |
| s = s[IP] or s[IPv6] or s |
| ips[r.src] = None |
| if TCP in s: |
| trace_id = (s.src,s.dst,6,s.dport) |
| elif UDP in s: |
| trace_id = (s.src,s.dst,17,s.dport) |
| elif ICMP in s: |
| trace_id = (s.src,s.dst,1,s.type) |
| else: |
| trace_id = (s.src,s.dst,s.proto,0) |
| trace = rt.get(trace_id,{}) |
| ttl = IPv6 in s and s.hlim or s.ttl |
| if not (ICMP in r and r[ICMP].type == 11) and not (IPv6 in r and ICMPv6TimeExceeded in r): |
| if trace_id in ports_done: |
| continue |
| ports_done[trace_id] = None |
| p = ports.get(r.src,[]) |
| if TCP in r: |
| p.append(r.sprintf("<T%ir,TCP.sport%> %TCP.sport% %TCP.flags%")) |
| trace[ttl] = r.sprintf('"%r,src%":T%ir,TCP.sport%') |
| elif UDP in r: |
| p.append(r.sprintf("<U%ir,UDP.sport%> %UDP.sport%")) |
| trace[ttl] = r.sprintf('"%r,src%":U%ir,UDP.sport%') |
| elif ICMP in r: |
| p.append(r.sprintf("<I%ir,ICMP.type%> ICMP %ICMP.type%")) |
| trace[ttl] = r.sprintf('"%r,src%":I%ir,ICMP.type%') |
| else: |
| p.append(r.sprintf("{IP:<P%ir,proto%> IP %proto%}{IPv6:<P%ir,nh%> IPv6 %nh%}")) |
| trace[ttl] = r.sprintf('"%r,src%":{IP:P%ir,proto%}{IPv6:P%ir,nh%}') |
| ports[r.src] = p |
| else: |
| trace[ttl] = r.sprintf('"%r,src%"') |
| rt[trace_id] = trace |
| |
| # Fill holes with unk%i nodes |
| unknown_label = incremental_label("unk%i") |
| blackholes = [] |
| bhip = {} |
| for rtk in rt: |
| trace = rt[rtk] |
| k = trace.keys() |
| for n in range(min(k), max(k)): |
| if not trace.has_key(n): |
| trace[n] = unknown_label.next() |
| if not ports_done.has_key(rtk): |
| if rtk[2] == 1: #ICMP |
| bh = "%s %i/icmp" % (rtk[1],rtk[3]) |
| elif rtk[2] == 6: #TCP |
| bh = "%s %i/tcp" % (rtk[1],rtk[3]) |
| elif rtk[2] == 17: #UDP |
| bh = '%s %i/udp' % (rtk[1],rtk[3]) |
| else: |
| bh = '%s %i/proto' % (rtk[1],rtk[2]) |
| ips[bh] = None |
| bhip[rtk[1]] = bh |
| bh = '"%s"' % bh |
| trace[max(k)+1] = bh |
| blackholes.append(bh) |
| |
| # Find AS numbers |
| ASN_query_list = dict.fromkeys(map(lambda x:x.rsplit(" ",1)[0],ips)).keys() |
| if ASres is None: |
| ASNlist = [] |
| else: |
| ASNlist = ASres.resolve(*ASN_query_list) |
| |
| ASNs = {} |
| ASDs = {} |
| for ip,asn,desc, in ASNlist: |
| if asn is None: |
| continue |
| iplist = ASNs.get(asn,[]) |
| if ip in bhip: |
| if ip in ports: |
| iplist.append(ip) |
| iplist.append(bhip[ip]) |
| else: |
| iplist.append(ip) |
| ASNs[asn] = iplist |
| ASDs[asn] = desc |
| |
| |
| backcolorlist=colgen("60","86","ba","ff") |
| forecolorlist=colgen("a0","70","40","20") |
| |
| s = "digraph trace {\n" |
| |
| s += "\n\tnode [shape=ellipse,color=black,style=solid];\n\n" |
| |
| s += "\n#ASN clustering\n" |
| for asn in ASNs: |
| s += '\tsubgraph cluster_%s {\n' % asn |
| col = backcolorlist.next() |
| s += '\t\tcolor="#%s%s%s";' % col |
| s += '\t\tnode [fillcolor="#%s%s%s",style=filled];' % col |
| s += '\t\tfontsize = 10;' |
| s += '\t\tlabel = "%s\\n[%s]"\n' % (asn,ASDs[asn]) |
| for ip in ASNs[asn]: |
| |
| s += '\t\t"%s";\n'%ip |
| s += "\t}\n" |
| |
| |
| |
| |
| s += "#endpoints\n" |
| for p in ports: |
| s += '\t"%s" [shape=record,color=black,fillcolor=green,style=filled,label="%s|%s"];\n' % (p,p,"|".join(ports[p])) |
| |
| s += "\n#Blackholes\n" |
| for bh in blackholes: |
| s += '\t%s [shape=octagon,color=black,fillcolor=red,style=filled];\n' % bh |
| |
| if padding: |
| s += "\n#Padding\n" |
| pad={} |
| for snd,rcv in self.res: |
| if rcv.src not in ports and rcv.haslayer(Padding): |
| p = rcv.getlayer(Padding).load |
| if p != "\x00"*len(p): |
| pad[rcv.src]=None |
| for rcv in pad: |
| s += '\t"%s" [shape=triangle,color=black,fillcolor=red,style=filled];\n' % rcv |
| |
| |
| |
| s += "\n\tnode [shape=ellipse,color=black,style=solid];\n\n" |
| |
| |
| for rtk in rt: |
| s += "#---[%s\n" % `rtk` |
| s += '\t\tedge [color="#%s%s%s"];\n' % forecolorlist.next() |
| trace = rt[rtk] |
| k = trace.keys() |
| for n in range(min(k), max(k)): |
| s += '\t%s ->\n' % trace[n] |
| s += '\t%s;\n' % trace[max(k)] |
| |
| s += "}\n"; |
| self.graphdef = s |
| |
| def graph(self, ASres=None, padding=0, **kargs): |
| """x.graph(ASres=conf.AS_resolver, other args): |
| ASres=None : no AS resolver => no clustering |
| ASres=AS_resolver() : default whois AS resolver (riswhois.ripe.net) |
| ASres=AS_resolver_cymru(): use whois.cymru.com whois database |
| ASres=AS_resolver(server="whois.ra.net") |
| type: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option |
| target: filename or redirect. Defaults pipe to Imagemagick's display program |
| prog: which graphviz program to use""" |
| if ASres is None: |
| ASres = conf.AS_resolver |
| if (self.graphdef is None or |
| self.graphASres != ASres or |
| self.graphpadding != padding): |
| self.make_graph(ASres,padding) |
| |
| do_graph(self.graphdef, **kargs) |
| |
| |
| |
| |
| ############ |
| ## Fields ## |
| ############ |
| |
| class Field: |
| """For more informations on how this work, please refer to |
| http://www.secdev.org/projects/scapy/files/scapydoc.pdf |
| chapter ``Adding a New Field''""" |
| islist=0 |
| holds_packets=0 |
| def __init__(self, name, default, fmt="H"): |
| self.name = name |
| if fmt[0] in "@=<>!": |
| self.fmt = fmt |
| else: |
| self.fmt = "!"+fmt |
| self.default = self.any2i(None,default) |
| self.sz = struct.calcsize(self.fmt) |
| self.owners = [] |
| |
| def register_owner(self, cls): |
| self.owners.append(cls) |
| |
| def i2len(self, pkt, x): |
| """Convert internal value to a length usable by a FieldLenField""" |
| return self.sz |
| def h2i(self, pkt, x): |
| """Convert human value to internal value""" |
| return x |
| def i2h(self, pkt, x): |
| """Convert internal value to human value""" |
| return x |
| def m2i(self, pkt, x): |
| """Convert machine value to internal value""" |
| return x |
| def i2m(self, pkt, x): |
| """Convert internal value to machine value""" |
| if x is None: |
| x = 0 |
| return x |
| def any2i(self, pkt, x): |
| """Try to understand the most input values possible and make an internal value from them""" |
| return self.h2i(pkt, x) |
| def i2repr(self, pkt, x): |
| """Convert internal value to a nice representation""" |
| if x is None: |
| x = 0 |
| return repr(self.i2h(pkt,x)) |
| def addfield(self, pkt, s, val): |
| """Add an internal value to a string""" |
| return s+struct.pack(self.fmt, self.i2m(pkt,val)) |
| def getfield(self, pkt, s): |
| """Extract an internal value from a string""" |
| return s[self.sz:], self.m2i(pkt, struct.unpack(self.fmt, s[:self.sz])[0]) |
| def do_copy(self, x): |
| if hasattr(x, "copy"): |
| return x.copy() |
| if type(x) is list: |
| x = x[:] |
| for i in xrange(len(x)): |
| if isinstance(x[i], Packet): |
| x[i] = x[i].copy() |
| return x |
| def __repr__(self): |
| return "<Field (%s).%s>" % (",".join(x.__name__ for x in self.owners),self.name) |
| def copy(self): |
| return copy.deepcopy(self) |
| def randval(self): |
| """Return a volatile object whose value is both random and suitable for this field""" |
| fmtt = self.fmt[-1] |
| if fmtt in "BHIQ": |
| return {"B":RandByte,"H":RandShort,"I":RandInt, "Q":RandLong}[fmtt]() |
| elif fmtt == "s": |
| if self.fmt[0] in "0123456789": |
| l = int(self.fmt[:-1]) |
| else: |
| l = int(self.fmt[1:-1]) |
| return RandBin(l) |
| else: |
| warning("no random class for [%s] (fmt=%s)." % (self.name, self.fmt)) |
| |
| |
| |
| |
| class Emph: |
| fld = "" |
| def __init__(self, fld): |
| self.fld = fld |
| def __getattr__(self, attr): |
| return getattr(self.fld,attr) |
| |
| class ActionField: |
| def __init__(self, fld, action_method, **kargs): |
| self._fld = fld |
| self._action_method = action_method |
| self._privdata = kargs |
| def any2i(self, pkt, val): |
| getattr(pkt, self._action_method)(val, self._fld, **self._privdata) |
| return getattr(self._fld, "any2i")(pkt, val) |
| def __getattr__(self, attr): |
| return getattr(self._fld,attr) |
| |
| |
| class ConditionalField: |
| def __init__(self, fld, fldlst, cond): |
| self.fld = fld |
| self.fldlst = fldlst |
| self.cond = cond |
| def _evalcond(self,pkt): |
| if type(self.fldlst) is list or type(self.fldlst) is tuple: |
| res = map(lambda x,pkt=pkt:getattr(pkt,x), self.fldlst) |
| else: |
| res = getattr(pkt, self.fldlst) |
| return self.cond(res) |
| |
| def getfield(self, pkt, s): |
| if self._evalcond(pkt): |
| return self.fld.getfield(pkt,s) |
| else: |
| return s,None |
| |
| def addfield(self, pkt, s, val): |
| if self._evalcond(pkt): |
| return self.fld.addfield(pkt,s,val) |
| else: |
| return s |
| def __getattr__(self, attr): |
| return getattr(self.fld,attr) |
| |
| |
| class MACField(Field): |
| def __init__(self, name, default): |
| Field.__init__(self, name, default, "6s") |
| def i2m(self, pkt, x): |
| if x is None: |
| return "\0\0\0\0\0\0" |
| return mac2str(x) |
| def m2i(self, pkt, x): |
| return str2mac(x) |
| def any2i(self, pkt, x): |
| if type(x) is str and len(x) is 6: |
| x = self.m2i(pkt, x) |
| return x |
| def i2repr(self, pkt, x): |
| x = self.i2h(pkt, x) |
| if self in conf.resolve: |
| x = conf.manufdb._resolve_MAC(x) |
| return x |
| def randval(self): |
| return RandMAC() |
| |
| class DestMACField(MACField): |
| def __init__(self, name): |
| MACField.__init__(self, name, None) |
| def i2h(self, pkt, x): |
| if x is None: |
| dstip = None |
| if isinstance(pkt.payload, IPv6): |
| dstip = pkt.payload.dst |
| elif isinstance(pkt.payload, IP): |
| dstip = pkt.payload.dst |
| elif isinstance(pkt.payload, ARP): |
| dstip = pkt.payload.pdst |
| if isinstance(dstip, Gen): |
| dstip = dstip.__iter__().next() |
| if dstip is not None: |
| if isinstance(pkt.payload, IPv6): |
| x = getmacbyip6(dstip) |
| else: |
| x = getmacbyip(dstip) |
| if x is None: |
| x = "ff:ff:ff:ff:ff:ff" |
| warning("Mac address to reach %s not found\n"%dstip) |
| return MACField.i2h(self, pkt, x) |
| def i2m(self, pkt, x): |
| return MACField.i2m(self, pkt, self.i2h(pkt, x)) |
| |
| class SourceMACField(MACField): |
| def __init__(self, name): |
| MACField.__init__(self, name, None) |
| def i2h(self, pkt, x): |
| if x is None: |
| dstip = None |
| if isinstance(pkt.payload, IPv6): |
| dstip = pkt.payload.dst |
| elif isinstance(pkt.payload, IP): |
| dstip = pkt.payload.dst |
| elif isinstance(pkt.payload, ARP): |
| dstip = pkt.payload.pdst |
| if isinstance(dstip, Gen): |
| dstip = dstip.__iter__().next() |
| if dstip is not None: |
| if isinstance(pkt.payload, IPv6): |
| iff,a,nh = conf.route6.route(dstip) |
| else: |
| iff,a,gw = conf.route.route(dstip) |
| try: |
| x = get_if_hwaddr(iff) |
| except: |
| pass |
| if x is None: |
| x = "00:00:00:00:00:00" |
| return MACField.i2h(self, pkt, x) |
| def i2m(self, pkt, x): |
| return MACField.i2m(self, pkt, self.i2h(pkt, x)) |
| |
| class ARPSourceMACField(MACField): |
| def __init__(self, name): |
| MACField.__init__(self, name, None) |
| def i2h(self, pkt, x): |
| if x is None: |
| dstip = pkt.pdst |
| if isinstance(dstip, Gen): |
| dstip = dstip.__iter__().next() |
| if dstip is not None: |
| iff,a,gw = conf.route.route(dstip) |
| try: |
| x = get_if_hwaddr(iff) |
| except: |
| pass |
| if x is None: |
| x = "00:00:00:00:00:00" |
| return MACField.i2h(self, pkt, x) |
| def i2m(self, pkt, x): |
| return MACField.i2m(self, pkt, self.i2h(pkt, x)) |
| |
| class Dot11AddrMACField(MACField): |
| def is_applicable(self, pkt): |
| return 1 |
| def addfield(self, pkt, s, val): |
| if self.is_applicable(pkt): |
| return MACField.addfield(self, pkt, s, val) |
| else: |
| return s |
| def getfield(self, pkt, s): |
| if self.is_applicable(pkt): |
| return MACField.getfield(self, pkt, s) |
| else: |
| return s,None |
| |
| class Dot11Addr2MACField(Dot11AddrMACField): |
| def is_applicable(self, pkt): |
| if pkt.type == 1: |
| return pkt.subtype in [ 0xb, 0xa, 0xe, 0xf] # RTS, PS-Poll, CF-End, CF-End+CF-Ack |
| return 1 |
| |
| class Dot11Addr3MACField(Dot11AddrMACField): |
| def is_applicable(self, pkt): |
| if pkt.type in [0,2]: |
| return 1 |
| return 0 |
| |
| class Dot11Addr4MACField(Dot11AddrMACField): |
| def is_applicable(self, pkt): |
| if pkt.type == 2: |
| if pkt.FCfield & 0x3 == 0x3: # To-DS and From-DS are set |
| return 1 |
| return 0 |
| |
| class IPField(Field): |
| def __init__(self, name, default): |
| Field.__init__(self, name, default, "4s") |
| def h2i(self, pkt, x): |
| if type(x) is str: |
| try: |
| inet_aton(x) |
| except socket.error: |
| x = Net(x) |
| elif type(x) is list: |
| x = map(Net, x) |
| return x |
| def resolve(self, x): |
| if self in conf.resolve: |
| try: |
| ret = socket.gethostbyaddr(x)[0] |
| except socket.herror: |
| pass |
| else: |
| if ret: |
| return ret |
| return x |
| def i2m(self, pkt, x): |
| return inet_aton(x) |
| def m2i(self, pkt, x): |
| return inet_ntoa(x) |
| def any2i(self, pkt, x): |
| return self.h2i(pkt,x) |
| def i2repr(self, pkt, x): |
| return self.resolve(self.i2h(pkt, x)) |
| def randval(self): |
| return RandIP() |
| |
| class SourceIPField(IPField): |
| def __init__(self, name, dstname): |
| IPField.__init__(self, name, None) |
| self.dstname = dstname |
| def i2m(self, pkt, x): |
| if x is None: |
| iff,x,gw = conf.route.route(getattr(pkt,self.dstname)) |
| return IPField.i2m(self, pkt, x) |
| def i2h(self, pkt, x): |
| if x is None: |
| dst=getattr(pkt,self.dstname) |
| if isinstance(dst,Gen): |
| r = map(conf.route.route, dst) |
| r.sort() |
| if r[0] == r[-1]: |
| x=r[0][1] |
| else: |
| warning("More than one possible route for %s"%repr(dst)) |
| return None |
| else: |
| iff,x,gw = conf.route.route(dst) |
| return IPField.i2h(self, pkt, x) |
| |
| |
| |
| |
| class ByteField(Field): |
| def __init__(self, name, default): |
| Field.__init__(self, name, default, "B") |
| |
| class XByteField(ByteField): |
| def i2repr(self, pkt, x): |
| if x is None: |
| x = 0 |
| return lhex(self.i2h(pkt, x)) |
| |
| class X3BytesField(XByteField): |
| def __init__(self, name, default): |
| Field.__init__(self, name, default, "!I") |
| def addfield(self, pkt, s, val): |
| return s+struct.pack(self.fmt, self.i2m(pkt,val))[1:4] |
| def getfield(self, pkt, s): |
| return s[3:], self.m2i(pkt, struct.unpack(self.fmt, "\x00"+s[:3])[0]) |
| |
| |
| class ShortField(Field): |
| def __init__(self, name, default): |
| Field.__init__(self, name, default, "H") |
| |
| class LEShortField(Field): |
| def __init__(self, name, default): |
| Field.__init__(self, name, default, "<H") |
| |
| class XShortField(ShortField): |
| def i2repr(self, pkt, x): |
| if x is None: |
| x = 0 |
| return lhex(self.i2h(pkt, x)) |
| |
| |
| class IntField(Field): |
| def __init__(self, name, default): |
| Field.__init__(self, name, default, "I") |
| |
| class SignedIntField(Field): |
| def __init__(self, name, default): |
| Field.__init__(self, name, default, "i") |
| |
| class LEIntField(Field): |
| def __init__(self, name, default): |
| Field.__init__(self, name, default, "<I") |
| |
| class LESignedIntField(Field): |
| def __init__(self, name, default): |
| Field.__init__(self, name, default, "<i") |
| |
| class XIntField(IntField): |
| def i2repr(self, pkt, x): |
| if x is None: |
| x = 0 |
| return lhex(self.i2h(pkt, x)) |
| |
| |
| class LongField(Field): |
| def __init__(self, name, default): |
| Field.__init__(self, name, default, "Q") |
| |
| class XLongField(LongField): |
| def i2repr(self, pkt, x): |
| if x is None: |
| x = 0 |
| return lhex(self.i2h(pkt, x)) |
| |
| |
| class StrField(Field): |
| def __init__(self, name, default, fmt="H", remain=0, shift=0): |
| Field.__init__(self,name,default,fmt) |
| self.remain = remain |
| self.shift = shift |
| def i2len(self, pkt, i): |
| return len(i)+self.shift |
| def i2m(self, pkt, x): |
| if x is None: |
| x = "" |
| return x |
| def addfield(self, pkt, s, val): |
| return s+self.i2m(pkt, val) |
| def getfield(self, pkt, s): |
| if self.remain == 0: |
| return "",self.m2i(pkt, s) |
| else: |
| return s[-self.remain:],self.m2i(pkt, s[:-self.remain]) |
| def randval(self): |
| return RandBin(RandNum(0,1200)) |
| |
| class PacketField(StrField): |
| holds_packets=1 |
| def __init__(self, name, default, cls, remain=0, shift=0): |
| StrField.__init__(self, name, default, remain=remain, shift=shift) |
| self.cls = cls |
| def i2m(self, pkt, i): |
| return str(i) |
| def m2i(self, pkt, m): |
| return self.cls(m) |
| def getfield(self, pkt, s): |
| i = self.m2i(pkt, s) |
| remain = "" |
| if i.haslayer(Padding): |
| r = i.getlayer(Padding) |
| del(r.underlayer.payload) |
| remain = r.load |
| return remain,i |
| |
| class PacketLenField(PacketField): |
| holds_packets=1 |
| def __init__(self, name, default, cls, fld, shift=0): |
| PacketField.__init__(self, name, default, cls, shift=shift) |
| self.fld = fld |
| def getfield(self, pkt, s): |
| l = getattr(pkt, self.fld) |
| l -= self.shift |
| i = self.m2i(pkt, s[:l]) |
| return s[l:],i |
| |
| |
| class PacketListField(PacketLenField): |
| islist = 1 |
| holds_packets=1 |
| def do_copy(self, x): |
| return map(lambda p:p.copy(), x) |
| def getfield(self, pkt, s): |
| l = getattr(pkt, self.fld) |
| l -= self.shift |
| lst = [] |
| remain = s |
| while l>0 and len(remain)>0: |
| l -= 1 |
| p = self.m2i(pkt,remain) |
| if Padding in p: |
| pad = p[Padding] |
| remain = pad.load |
| del(pad.underlayer.payload) |
| else: |
| remain = "" |
| lst.append(p) |
| return remain,lst |
| def addfield(self, pkt, s, val): |
| return s+"".join(map(str, val)) |
| |
| |
| class StrFixedLenField(StrField): |
| def __init__(self, name, default, length, shift=0): |
| StrField.__init__(self, name, default, shift=shift) |
| self.length = length |
| def getfield(self, pkt, s): |
| return s[self.length:], self.m2i(pkt,s[:self.length]) |
| def addfield(self, pkt, s, val): |
| return s+struct.pack("%is"%self.length,self.i2m(pkt, val)) |
| def randval(self): |
| return RandBin(self.length) |
| |
| class NetBIOSNameField(StrFixedLenField): |
| def __init__(self, name, default, length=31, shift=0): |
| StrFixedLenField.__init__(self, name, default, length, shift=shift) |
| def i2m(self, pkt, x): |
| if x is None: |
| x = "" |
| x += " "*(self.length/2) |
| x = x[:(self.length/2)] |
| x = "".join(map(lambda x: chr(0x41+(ord(x)>>4))+chr(0x41+(ord(x)&0xf)), x)) |
| x = " "+x |
| return x |
| def m2i(self, pkt, x): |
| x = x.strip("\x00").strip(" ") |
| return "".join(map(lambda x,y: chr((((ord(x)-1)&0xf)<<4)+((ord(y)-1)&0xf)), x[::2],x[1::2])) |
| |
| class StrLenField(StrField): |
| def __init__(self, name, default, fld, shift=0): |
| StrField.__init__(self, name, default, shift=shift) |
| self.fld = fld |
| def getfield(self, pkt, s): |
| l = getattr(pkt, self.fld) |
| l -= self.shift |
| return s[l:], self.m2i(pkt,s[:l]) |
| |
| class FieldListField(Field): |
| islist=1 |
| def __init__(self, name, default, cls, fld, shift=0): |
| Field.__init__(self, name, default) |
| self.cls = cls |
| self.fld = fld |
| self.shift=shift |
| def i2len(self, pkt, val): |
| if val is None: |
| return self.shift |
| else: |
| return len(val)+self.shift |
| def i2m(self, pkt, val): |
| if val is None: |
| val = [] |
| return val |
| def addfield(self, pkt, s, val): |
| val = self.i2m(pkt, val) |
| for v in val: |
| s = self.cls.addfield(pkt, s, v) |
| return s |
| def getfield(self, pkt, s): |
| l = getattr(pkt, self.fld) |
| # add the shift from the length field |
| f = pkt.get_field(self.fld) |
| l -= self.shift |
| val = [] |
| for i in range(l): |
| s,v = self.cls.getfield(pkt, s) |
| val.append(v) |
| return s, val |
| |
| class FieldLenField(Field): |
| def __init__(self, name, default, fld, fmt = "H"): |
| Field.__init__(self, name, default, fmt) |
| self.fld = fld |
| def i2m(self, pkt, x): |
| if x is None: |
| f = pkt.get_field(self.fld) |
| x = f.i2len(pkt,pkt.getfieldval(self.fld)) |
| return x |
| |
| # see http://www.iana.org/assignments/ipsec-registry for details |
| ISAKMPAttributeTypes= { "Encryption": (1, { "DES-CBC" : 1, |
| "IDEA-CBC" : 2, |
| "Blowfish-CBC" : 3, |
| "RC5-R16-B64-CBC" : 4, |
| "3DES-CBC" : 5, |
| "CAST-CBC" : 6, |
| "AES-CBC" : 7, |
| "CAMELLIA-CBC" : 8, }, 0), |
| "Hash": (2, { "MD5": 1, |
| "SHA": 2, |
| "Tiger": 3, |
| "SHA2-256": 4, |
| "SHA2-384": 5, |
| "SHA2-512": 6,}, 0), |
| "Authentication":(3, { "PSK": 1, |
| "DSS": 2, |
| "RSA Sig": 3, |
| "RSA Encryption": 4, |
| "RSA Encryption Revised": 5, |
| "ElGamal Encryption": 6, |
| "ElGamal Encryption Revised": 7, |
| "ECDSA Sig": 8, |
| "HybridInitRSA": 64221, |
| "HybridRespRSA": 64222, |
| "HybridInitDSS": 64223, |
| "HybridRespDSS": 64224, |
| "XAUTHInitPreShared": 65001, |
| "XAUTHRespPreShared": 65002, |
| "XAUTHInitDSS": 65003, |
| "XAUTHRespDSS": 65004, |
| "XAUTHInitRSA": 65005, |
| "XAUTHRespRSA": 65006, |
| "XAUTHInitRSAEncryption": 65007, |
| "XAUTHRespRSAEncryption": 65008, |
| "XAUTHInitRSARevisedEncryption": 65009, |
| "XAUTHRespRSARevisedEncryptio": 65010, }, 0), |
| "GroupDesc": (4, { "768MODPgr" : 1, |
| "1024MODPgr" : 2, |
| "EC2Ngr155" : 3, |
| "EC2Ngr185" : 4, |
| "1536MODPgr" : 5, |
| "2048MODPgr" : 14, |
| "3072MODPgr" : 15, |
| "4096MODPgr" : 16, |
| "6144MODPgr" : 17, |
| "8192MODPgr" : 18, }, 0), |
| "GroupType": (5, {"MODP": 1, |
| "ECP": 2, |
| "EC2N": 3}, 0), |
| "GroupPrime": (6, {}, 1), |
| "GroupGenerator1":(7, {}, 1), |
| "GroupGenerator2":(8, {}, 1), |
| "GroupCurveA": (9, {}, 1), |
| "GroupCurveB": (10, {}, 1), |
| "LifeType": (11, {"Seconds": 1, |
| "Kilobytes": 2, }, 0), |
| "LifeDuration": (12, {}, 1), |
| "PRF": (13, {}, 0), |
| "KeyLength": (14, {}, 0), |
| "FieldSize": (15, {}, 0), |
| "GroupOrder": (16, {}, 1), |
| } |
| |
| # the name 'ISAKMPTransformTypes' is actually a misnomer (since the table |
| # holds info for all ISAKMP Attribute types, not just transforms, but we'll |
| # keep it for backwards compatibility... for now at least |
| ISAKMPTransformTypes = ISAKMPAttributeTypes |
| |
| ISAKMPTransformNum = {} |
| for n in ISAKMPTransformTypes: |
| val = ISAKMPTransformTypes[n] |
| tmp = {} |
| for e in val[1]: |
| tmp[val[1][e]] = e |
| ISAKMPTransformNum[val[0]] = (n,tmp, val[2]) |
| del(n) |
| del(e) |
| del(tmp) |
| del(val) |
| |
| |
| class ISAKMPTransformSetField(StrLenField): |
| islist=1 |
| def type2num(self, (typ,val)): |
| type_val,enc_dict,tlv = ISAKMPTransformTypes.get(typ, (typ,{},0)) |
| val = enc_dict.get(val, val) |
| s = "" |
| if (val & ~0xffff): |
| if not tlv: |
| warning("%r should not be TLV but is too big => using TLV encoding" % typ) |
| n = 0 |
| while val: |
| s = chr(val&0xff)+s |
| val >>= 8 |
| n += 1 |
| val = n |
| else: |
| type_val |= 0x8000 |
| return struct.pack("!HH",type_val, val)+s |
| def num2type(self, typ, enc): |
| val = ISAKMPTransformNum.get(typ,(typ,{})) |
| enc = val[1].get(enc,enc) |
| return (val[0],enc) |
| def i2m(self, pkt, i): |
| if i is None: |
| return "" |
| i = map(self.type2num, i) |
| return "".join(i) |
| def m2i(self, pkt, m): |
| # I try to ensure that we don't read off the end of our packet based |
| # on bad length fields we're provided in the packet. There are still |
| # conditions where struct.unpack() may not get enough packet data, but |
| # worst case that should result in broken attributes (which would |
| # be expected). (wam) |
| lst = [] |
| while len(m) >= 4: |
| trans_type, = struct.unpack("!H", m[:2]) |
| is_tlv = not (trans_type & 0x8000) |
| if is_tlv: |
| # We should probably check to make sure the attribute type we |
| # are looking at is allowed to have a TLV format and issue a |
| # warning if we're given an TLV on a basic attribute. |
| value_len, = struct.unpack("!H", m[2:4]) |
| if value_len+4 > len(m): |
| warning("Bad length for ISAKMP tranform type=%#6x" % trans_type) |
| value = m[4:4+value_len] |
| value = reduce(lambda x,y: (x<<8L)|y, struct.unpack("!%s" % ("B"*len(value),), value),0) |
| else: |
| trans_type &= 0x7fff |
| value_len=0 |
| value, = struct.unpack("!H", m[2:4]) |
| m=m[4+value_len:] |
| lst.append(self.num2type(trans_type, value)) |
| if len(m) > 0: |
| warning("Extra bytes after ISAKMP transform dissection [%r]" % m) |
| return lst |
| def getfield(self, pkt, s): |
| l = getattr(pkt, self.fld) |
| l -= self.shift |
| i = self.m2i(pkt, s[:l]) |
| return s[l:],i |
| |
| class StrNullField(StrField): |
| def addfield(self, pkt, s, val): |
| return s+self.i2m(pkt, val)+"\x00" |
| def getfield(self, pkt, s): |
| l = s.find("\x00") |
| if l < 0: |
| #XXX \x00 not found |
| return "",s |
| return s[l+1:],self.m2i(pkt, s[:l]) |
| def randval(self): |
| return RandTermString(RandNum(0,1200),"\x00") |
| |
| class StrStopField(StrField): |
| def __init__(self, name, default, stop, additionnal=0): |
| Field.__init__(self, name, default) |
| self.stop=stop |
| self.additionnal=additionnal |
| def getfield(self, pkt, s): |
| l = s.find(self.stop) |
| if l < 0: |
| return "",s |
| # raise Scapy_Exception,"StrStopField: stop value [%s] not found" %stop |
| l += len(self.stop)+self.additionnal |
| return s[l:],s[:l] |
| def randval(self): |
| return RandTermString(RandNum(0,1200),self.stop) |
| |
| class LenField(Field): |
| def i2m(self, pkt, x): |
| if x is None: |
| x = len(pkt.payload) |
| return x |
| |
| class BCDFloatField(Field): |
| def i2m(self, pkt, x): |
| return int(256*x) |
| def m2i(self, pkt, x): |
| return x/256.0 |
| |
| class BitField(Field): |
| def __init__(self, name, default, size): |
| Field.__init__(self, name, default) |
| self.size = size |
| def addfield(self, pkt, s, val): |
| if val is None: |
| val = 0 |
| if type(s) is tuple: |
| s,bitsdone,v = s |
| else: |
| bitsdone = 0 |
| v = 0 |
| v <<= self.size |
| v |= val & ((1L<<self.size) - 1) |
| bitsdone += self.size |
| while bitsdone >= 8: |
| bitsdone -= 8 |
| s = s+struct.pack("!B", v >> bitsdone) |
| v &= (1L<<bitsdone)-1 |
| if bitsdone: |
| return s,bitsdone,v |
| else: |
| return s |
| def getfield(self, pkt, s): |
| if type(s) is tuple: |
| s,bn = s |
| else: |
| bn = 0 |
| # we don't want to process all the string |
| nb_bytes = (self.size+bn-1)/8 + 1 |
| w = s[:nb_bytes] |
| |
| # split the substring byte by byte |
| bytes = struct.unpack('!%dB' % nb_bytes , w) |
| |
| b = 0L |
| for c in range(nb_bytes): |
| b |= long(bytes[c]) << (nb_bytes-c-1)*8 |
| |
| # get rid of high order bits |
| b &= (1L << (nb_bytes*8-bn)) - 1 |
| |
| # remove low order bits |
| b = b >> (nb_bytes*8 - self.size - bn) |
| |
| bn += self.size |
| s = s[bn/8:] |
| bn = bn%8 |
| if bn: |
| return (s,bn),b |
| else: |
| return s,b |
| def randval(self): |
| return RandNum(0,2**self.size-1) |
| |
| class XBitField(BitField): |
| def i2repr(self, pkt, x): |
| return lhex(self.i2h(pkt,x)) |
| |
| |
| class EnumField(Field): |
| def __init__(self, name, default, enum, fmt = "H"): |
| i2s = self.i2s = {} |
| s2i = self.s2i = {} |
| if type(enum) is list: |
| keys = xrange(len(enum)) |
| else: |
| keys = enum.keys() |
| if filter(lambda x: type(x) is str, keys): |
| i2s,s2i = s2i,i2s |
| for k in keys: |
| i2s[k] = enum[k] |
| s2i[enum[k]] = k |
| Field.__init__(self, name, default, fmt) |
| def any2i_one(self, pkt, x): |
| if type(x) is str: |
| x = self.s2i[x] |
| return x |
| def i2repr_one(self, pkt, x): |
| if self not in conf.noenum and x in self.i2s: |
| return self.i2s[x] |
| return repr(x) |
| |
| def any2i(self, pkt, x): |
| if type(x) is list: |
| return map(lambda z,pkt=pkt:self.any2i_one(pkt,z), x) |
| else: |
| return self.any2i_one(pkt,x) |
| def i2repr(self, pkt, x): |
| if type(x) is list: |
| return map(lambda z,pkt=pkt:self.i2repr_one(pkt,z), x) |
| else: |
| return self.i2repr_one(pkt,x) |
| |
| class CharEnumField(EnumField): |
| def __init__(self, name, default, enum, fmt = "1s"): |
| EnumField.__init__(self, name, default, enum, fmt) |
| k = self.i2s.keys() |
| if k and len(k[0]) != 1: |
| self.i2s,self.s2i = self.s2i,self.i2s |
| def any2i_one(self, pkt, x): |
| if len(x) != 1: |
| x = self.s2i[x] |
| return x |
| |
| class BitEnumField(BitField,EnumField): |
| def __init__(self, name, default, size, enum): |
| EnumField.__init__(self, name, default, enum) |
| self.size = size |
| def any2i(self, pkt, x): |
| return EnumField.any2i(self, pkt, x) |
| def i2repr(self, pkt, x): |
| return EnumField.i2repr(self, pkt, x) |
| |
| class ShortEnumField(EnumField): |
| def __init__(self, name, default, enum): |
| EnumField.__init__(self, name, default, enum, "H") |
| |
| class LEShortEnumField(EnumField): |
| def __init__(self, name, default, enum): |
| EnumField.__init__(self, name, default, enum, "<H") |
| |
| class ByteEnumField(EnumField): |
| def __init__(self, name, default, enum): |
| EnumField.__init__(self, name, default, enum, "B") |
| |
| class IntEnumField(EnumField): |
| def __init__(self, name, default, enum): |
| EnumField.__init__(self, name, default, enum, "I") |
| |
| class LEIntEnumField(EnumField): |
| def __init__(self, name, default, enum): |
| EnumField.__init__(self, name, default, enum, "<I") |
| |
| class XShortEnumField(ShortEnumField): |
| def i2repr_one(self, pkt, x): |
| if self not in conf.noenum and x in self.i2s: |
| return self.i2s[x] |
| return lhex(x) |
| |
| # Little endian long field |
| class LELongField(Field): |
| def __init__(self, name, default): |
| Field.__init__(self, name, default, "<Q") |
| |
| # Little endian fixed length field |
| class LEFieldLenField(FieldLenField): |
| def __init__(self, name, default, fld, fmt = "<H"): |
| FieldLenField.__init__(self, name, default, fld=fld, fmt=fmt) |
| |
| |
| class FlagsField(BitField): |
| def __init__(self, name, default, size, names): |
| BitField.__init__(self, name, default, size) |
| self.multi = type(names) is list |
| if self.multi: |
| self.names = map(lambda x:[x], names) |
| else: |
| self.names = names |
| def any2i(self, pkt, x): |
| if type(x) is str: |
| if self.multi: |
| x = map(lambda y:[y], x.split("+")) |
| y = 0 |
| for i in x: |
| y |= 1 << self.names.index(i) |
| x = y |
| return x |
| def i2repr(self, pkt, x): |
| if self.multi: |
| r = [] |
| else: |
| r = "" |
| i=0 |
| while x: |
| if x & 1: |
| r += self.names[i] |
| i += 1 |
| x >>= 1 |
| if self.multi: |
| r = "+".join(r) |
| return r |
| |
| |
| |
| |
| |
| class IPoptionsField(StrField): |
| def i2m(self, pkt, x): |
| return x+"\x00"*(3-((len(x)+3)%4)) |
| def getfield(self, pkt, s): |
| opsz = (pkt.ihl-5)*4 |
| if opsz < 0: |
| warning("bad ihl (%i). Assuming ihl=5"%pkt.ihl) |
| opsz = 0 |
| return s[opsz:],s[:opsz] |
| def randval(self): |
| return RandBin(RandNum(0,39)) |
| |
| |
| TCPOptions = ( |
| { 0 : ("EOL",None), |
| 1 : ("NOP",None), |
| 2 : ("MSS","!H"), |
| 3 : ("WScale","!B"), |
| 4 : ("SAckOK",None), |
| 5 : ("SAck","!"), |
| 8 : ("Timestamp","!II"), |
| 14 : ("AltChkSum","!BH"), |
| 15 : ("AltChkSumOpt",None) |
| }, |
| { "EOL":0, |
| "NOP":1, |
| "MSS":2, |
| "WScale":3, |
| "SAckOK":4, |
| "SAck":5, |
| "Timestamp":8, |
| "AltChkSum":14, |
| "AltChkSumOpt":15, |
| } ) |
| |
| class TCPOptionsField(StrField): |
| islist=1 |
| def getfield(self, pkt, s): |
| opsz = (pkt.dataofs-5)*4 |
| if opsz < 0: |
| warning("bad dataofs (%i). Assuming dataofs=5"%pkt.dataofs) |
| opsz = 0 |
| return s[opsz:],self.m2i(pkt,s[:opsz]) |
| def m2i(self, pkt, x): |
| opt = [] |
| while x: |
| onum = ord(x[0]) |
| if onum == 0: |
| opt.append(("EOL",None)) |
| x=x[1:] |
| break |
| if onum == 1: |
| opt.append(("NOP",None)) |
| x=x[1:] |
| continue |
| olen = ord(x[1]) |
| if olen < 2: |
| warning("Malformed TCP option (announced length is %i)" % olen) |
| olen = 2 |
| oval = x[2:olen] |
| if TCPOptions[0].has_key(onum): |
| oname, ofmt = TCPOptions[0][onum] |
| if onum == 5: #SAck |
| ofmt += "%iI" % (len(oval)/4) |
| if ofmt and struct.calcsize(ofmt) == len(oval): |
| oval = struct.unpack(ofmt, oval) |
| if len(oval) == 1: |
| oval = oval[0] |
| opt.append((oname, oval)) |
| else: |
| opt.append((onum, oval)) |
| x = x[olen:] |
| return opt |
| |
| def i2m(self, pkt, x): |
| opt = "" |
| for oname,oval in x: |
| if type(oname) is str: |
| if oname == "NOP": |
| opt += "\x01" |
| continue |
| elif oname == "EOL": |
| opt += "\x00" |
| continue |
| elif TCPOptions[1].has_key(oname): |
| onum = TCPOptions[1][oname] |
| ofmt = TCPOptions[0][onum][1] |
| if onum == 5: #SAck |
| ofmt += "%iI" % len(oval) |
| if ofmt is not None: |
| if type(oval) is not tuple: |
| oval = (oval,) |
| oval = struct.pack(ofmt, *oval) |
| else: |
| warning("option [%s] unknown. Skipped."%oname) |
| continue |
| else: |
| onum = oname |
| if type(oval) is not str: |
| warning("option [%i] is not string."%onum) |
| continue |
| opt += chr(onum)+chr(2+len(oval))+oval |
| return opt+"\x00"*(3-((len(opt)+3)%4)) |
| def randval(self): |
| return [] # XXX |
| |
| |
| class DNSStrField(StrField): |
| def i2m(self, pkt, x): |
| x = x.split(".") |
| x = map(lambda y: chr(len(y))+y, x) |
| x = "".join(x) |
| if x[-1] != "\x00": |
| x += "\x00" |
| return x |
| def getfield(self, pkt, s): |
| n = "" |
| while 1: |
| l = ord(s[0]) |
| s = s[1:] |
| if not l: |
| break |
| if l & 0xc0: |
| raise Scapy_Exception("DNS message can't be compressed at this point!") |
| else: |
| n += s[:l]+"." |
| s = s[l:] |
| return s, n |
| |
| |
| class DNSRRCountField(ShortField): |
| holds_packets=1 |
| def __init__(self, name, default, rr): |
| ShortField.__init__(self, name, default) |
| self.rr = rr |
| def _countRR(self, pkt): |
| x = getattr(pkt,self.rr) |
| i = 0 |
| while isinstance(x, DNSRR) or isinstance(x, DNSQR): |
| x = x.payload |
| i += 1 |
| return i |
| |
| def i2m(self, pkt, x): |
| if x is None: |
| x = self._countRR(pkt) |
| return x |
| def i2h(self, pkt, x): |
| if x is None: |
| x = self._countRR(pkt) |
| return x |
| |
| |
| def DNSgetstr(s,p): |
| name = "" |
| q = 0 |
| jpath = [p] |
| while 1: |
| if p >= len(s): |
| warning("DNS RR prematured end (ofs=%i, len=%i)"%(p,len(s))) |
| break |
| l = ord(s[p]) |
| p += 1 |
| if l & 0xc0: |
| if not q: |
| q = p+1 |
| if p >= len(s): |
| warning("DNS incomplete jump token at (ofs=%i)" % p) |
| break |
| p = ((l & 0x3f) << 8) + ord(s[p]) - 12 |
| if p in jpath: |
| warning("DNS decompression loop detected") |
| break |
| jpath.append(p) |
| continue |
| elif l > 0: |
| name += s[p:p+l]+"." |
| p += l |
| continue |
| break |
| if q: |
| p = q |
| return name,p |
| |
| |
| class DNSRRField(StrField): |
| holds_packets=1 |
| def __init__(self, name, countfld, passon=1): |
| StrField.__init__(self, name, None) |
| self.countfld = countfld |
| self.passon = passon |
| def i2m(self, pkt, x): |
| if x is None: |
| return "" |
| return str(x) |
| def decodeRR(self, name, s, p): |
| ret = s[p:p+10] |
| type,cls,ttl,rdlen = struct.unpack("!HHIH", ret) |
| p += 10 |
| rr = DNSRR("\x00"+ret+s[p:p+rdlen]) |
| if rr.type in [2, 3, 4, 5]: |
| rr.rdata = DNSgetstr(s,p)[0] |
| del(rr.rdlen) |
| |
| p += rdlen |
| |
| rr.rrname = name |
| return rr,p |
| def getfield(self, pkt, s): |
| if type(s) is tuple : |
| s,p = s |
| else: |
| p = 0 |
| ret = None |
| c = getattr(pkt, self.countfld) |
| if c > len(s): |
| warning("wrong value: DNS.%s=%i" % (self.countfld,c)) |
| return s,"" |
| while c: |
| c -= 1 |
| name,p = DNSgetstr(s,p) |
| rr,p = self.decodeRR(name, s, p) |
| if ret is None: |
| ret = rr |
| else: |
| ret.add_payload(rr) |
| if self.passon: |
| return (s,p),ret |
| else: |
| return s[p:],ret |
| |
| |
| class DNSQRField(DNSRRField): |
| holds_packets=1 |
| def decodeRR(self, name, s, p): |
| ret = s[p:p+4] |
| p += 4 |
| rr = DNSQR("\x00"+ret) |
| rr.qname = name |
| return rr,p |
| |
| |
| |
| class RDataField(StrLenField): |
| def m2i(self, pkt, s): |
| family = None |
| if pkt.type == 1: |
| family = socket.AF_INET |
| elif pkt.type == 28: |
| family = socket.AF_INET6 |
| elif pkt.type == 12: |
| s = DNSgetstr(s, 0)[0] |
| if family is not None: |
| s = inet_ntop(family, s) |
| return s |
| def i2m(self, pkt, s): |
| if pkt.type == 1: |
| if s: |
| s = inet_aton(s) |
| elif pkt.type == 28: |
| if s: |
| s = inet_pton(socket.AF_INET6, s) |
| elif pkt.type in [2,3,4,5]: |
| s = "".join(map(lambda x: chr(len(x))+x, s.split("."))) |
| if ord(s[-1]): |
| s += "\x00" |
| return s |
| |
| class RDLenField(Field): |
| def __init__(self, name): |
| Field.__init__(self, name, None, "H") |
| def i2m(self, pkt, x): |
| if x is None: |
| rdataf = pkt.get_field("rdata") |
| x = len(rdataf.i2m(pkt, pkt.rdata)) |
| return x |
| def i2h(self, pkt, x): |
| if x is None: |
| rdataf = pkt.get_field("rdata") |
| x = len(rdataf.i2m(pkt, pkt.rdata)) |
| return x |
| |
| # seconds between 01-01-1900 and 01-01-1970 |
| ntp_basetime = 2208988800 |
| |
| class TimeStampField(BitField): |
| def __init__(self, name, default, size): |
| BitField.__init__(self, name, default, size) |
| self.size = size |
| def getfield(self, pkt, s): |
| s,timestamp = BitField.getfield(self, pkt, s) |
| |
| if timestamp: |
| # timestamp is a 64 bits field : |
| # + first 32 bits : number of seconds since 1900 |
| # + last 32 bits : fraction part |
| timestamp >>= 32 |
| timestamp -= ntp_basetime |
| |
| from time import gmtime, strftime |
| b = strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime(timestamp)) |
| else: |
| b = 'None' |
| |
| return s, b |
| def addfield(self, pkt, s, val): |
| t = -1 |
| if type(val) is str: |
| from time import strptime, mktime |
| t = int(mktime(strptime(val))) + ntp_basetime + 3600 |
| else: |
| if val == -1: |
| from time import time |
| t = int(time()) + ntp_basetime |
| else: |
| t = val |
| t <<= 32 |
| return BitField.addfield(self,pkt,s, t) |
| |
| class FloatField(BitField): |
| def getfield(self, pkt, s): |
| s,b = BitField.getfield(self, pkt, s) |
| |
| # fraction point between bits 15 and 16. |
| sec = b >> 16 |
| frac = b & (1L << (32+1)) - 1 |
| frac /= 65536.0 |
| b = sec+frac |
| return s,b |
| |
| class Dot11SCField(LEShortField): |
| def is_applicable(self, pkt): |
| return pkt.type != 1 # control frame |
| def addfield(self, pkt, s, val): |
| if self.is_applicable(pkt): |
| return LEShortField.addfield(self, pkt, s, val) |
| else: |
| return s |
| def getfield(self, pkt, s): |
| if self.is_applicable(pkt): |
| return LEShortField.getfield(self, pkt, s) |
| else: |
| return s,None |
| |
| ##################### |
| #### ASN1 Fields #### |
| ##################### |
| |
| class ASN1F_badsequence(Exception): |
| pass |
| |
| class ASN1F_element: |
| pass |
| |
| class ASN1F_field(ASN1F_element): |
| holds_packets=0 |
| islist=0 |
| |
| ASN1_tag = ASN1_Class_UNIVERSAL.ANY |
| |
| def __init__(self, name, default): |
| self.name = name |
| self.default = default |
| |
| def i2repr(self, pkt, x): |
| if x is None: |
| x = 0 |
| return repr(x) |
| def i2h(self, pkt, x): |
| if x is None: |
| x = 0 |
| return x |
| def any2i(self, pkt, x): |
| return x |
| def m2i(self, pkt, x): |
| return self.ASN1_tag.get_codec(pkt.ASN1_codec).safedec(x) |
| def i2m(self, pkt, x): |
| if x is None: |
| x = 0 |
| if isinstance(x, ASN1_Object): |
| if ( self.ASN1_tag == ASN1_Class_UNIVERSAL.ANY |
| or x.tag == ASN1_Class_UNIVERSAL.RAW |
| or x.tag == ASN1_Class_UNIVERSAL.ERROR |
| or self.ASN1_tag == x.tag ): |
| return x.enc(pkt.ASN1_codec) |
| else: |
| raise ASN1_Error("Encoding Error: got %r instead of an %r for field [%s]" % (x, self.ASN1_tag, self.name)) |
| return self.ASN1_tag.get_codec(pkt.ASN1_codec).enc(x) |
| |
| def do_copy(self, x): |
| if hasattr(x, "copy"): |
| return x.copy() |
| if type(x) is list: |
| x = x[:] |
| for i in xrange(len(x)): |
| if isinstance(x[i], Packet): |
| x[i] = x[i].copy() |
| return x |
| |
| def build(self, pkt): |
| return self.i2m(pkt, getattr(pkt, self.name)) |
| |
| def set_val(self, pkt, val): |
| setattr(pkt, self.name, val) |
| |
| def dissect(self, pkt, s): |
| v,s = self.m2i(pkt, s) |
| self.set_val(pkt, v) |
| return s |
| |
| def get_fields_list(self): |
| return [self] |
| |
| def __hash__(self): |
| return hash(self.name) |
| def __str__(self): |
| return self.name |
| def __eq__(self, other): |
| return self.name == other |
| def __repr__(self): |
| return self.name |
| def randval(self): |
| return RandInt() |
| |
| |
| class ASN1F_INTEGER(ASN1F_field): |
| ASN1_tag= ASN1_Class_UNIVERSAL.INTEGER |
| def randval(self): |
| return RandNum(-2**64, 2**64) |
| |
| class ASN1F_enum_INTEGER(ASN1F_INTEGER): |
| def __init__(self, name, default, enum): |
| ASN1F_INTEGER.__init__(self, name, default) |
| i2s = self.i2s = {} |
| s2i = self.s2i = {} |
| if type(enum) is list: |
| keys = xrange(len(enum)) |
| else: |
| keys = enum.keys() |
| if filter(lambda x: type(x) is str, keys): |
| i2s,s2i = s2i,i2s |
| for k in keys: |
| i2s[k] = enum[k] |
| s2i[enum[k]] = k |
| def any2i_one(self, pkt, x): |
| if type(x) is str: |
| x = self.s2i[x] |
| return x |
| def i2repr_one(self, pkt, x): |
| return self.i2s.get(x, repr(x)) |
| |
| def any2i(self, pkt, x): |
| if type(x) is list: |
| return map(lambda z,pkt=pkt:self.any2i_one(pkt,z), x) |
| else: |
| return self.any2i_one(pkt,x) |
| def i2repr(self, pkt, x): |
| if type(x) is list: |
| return map(lambda z,pkt=pkt:self.i2repr_one(pkt,z), x) |
| else: |
| return self.i2repr_one(pkt,x) |
| |
| class ASN1F_STRING(ASN1F_field): |
| ASN1_tag = ASN1_Class_UNIVERSAL.STRING |
| def randval(self): |
| return RandString(RandNum(0, 1000)) |
| |
| class ASN1F_OID(ASN1F_field): |
| ASN1_tag = ASN1_Class_UNIVERSAL.OID |
| def randval(self): |
| return RandOID() |
| |
| class ASN1F_SEQUENCE(ASN1F_field): |
| ASN1_tag = ASN1_Class_UNIVERSAL.SEQUENCE |
| def __init__(self, *seq, **kargs): |
| if "ASN1_tag" in kargs: |
| self.ASN1_tag = kargs["ASN1_tag"] |
| self.seq = seq |
| def __repr__(self): |
| return "<%s%r>" % (self.__class__.__name__,self.seq,) |
| def get_fields_list(self): |
| return reduce(lambda x,y: x+y.get_fields_list(), self.seq, []) |
| def build(self, pkt): |
| s = reduce(lambda x,y: x+y.build(pkt), self.seq, "") |
| return self.i2m(pkt, s) |
| def dissect(self, pkt, s): |
| codec = self.ASN1_tag.get_codec(pkt.ASN1_codec) |
| try: |
| i,s,remain = codec.check_type_check_len(s) |
| for obj in self.seq: |
| s = obj.dissect(pkt,s) |
| if s: |
| warning("Too many bytes to decode sequence: [%r]" % s) # XXX not reversible! |
| return remain |
| except ASN1_Error,e: |
| raise ASN1F_badsequence(e) |
| |
| class ASN1F_SEQUENCE_OF(ASN1F_SEQUENCE): |
| holds_packets = 1 |
| islist = 1 |
| def __init__(self, name, default, asn1pkt, ASN1_tag=0x30): |
| self.asn1pkt = asn1pkt |
| self.tag = chr(ASN1_tag) |
| self.name = name |
| self.default = default |
| def get_fields_list(self): |
| return [self] |
| def build(self, pkt): |
| val = getattr(pkt, self.name) |
| if isinstance(val, ASN1_Object) and val.tag == ASN1_Class_UNIVERSAL.RAW: |
| s = val |
| else: |
| s = "".join(map(str, val )) |
| return self.i2m(pkt, s) |
| def dissect(self, pkt, s): |
| codec = self.ASN1_tag.get_codec(pkt.ASN1_codec) |
| i,s1,remain = codec.check_type_check_len(s) |
| lst = [] |
| while s1: |
| try: |
| p = self.asn1pkt(s1) |
| except ASN1F_badsequence: |
| lst.append(Raw(s1)) |
| break |
| lst.append(p) |
| if Raw in p: |
| s1 = p[Raw].load |
| del(p[Raw].underlayer.payload) |
| else: |
| break |
| self.set_val(pkt, lst) |
| return remain |
| def randval(self): |
| return fuzz(self.asn1pkt()) |
| |
| class ASN1F_PACKET(ASN1F_field): |
| holds_packets = 1 |
| def __init__(self, name, default, cls): |
| ASN1_field.__init__(self, name, default) |
| self.cls = cls |
| def i2m(self, pkt, x): |
| if x is None: |
| x = "" |
| return str(x) |
| def extract_packet(self, cls, x): |
| try: |
| c = cls(x) |
| except ASN1F_badsequence: |
| c = Raw(x) |
| cpad = c[Padding] |
| x = "" |
| if cpad is not None: |
| x = cpad.load |
| del(cpad.underlayer.payload) |
| return c,x |
| def m2i(self, pkt, x): |
| return self.extract_packet(self.cls, x) |
| |
| |
| class ASN1F_CHOICE(ASN1F_PACKET): |
| ASN1_tag = ASN1_Class_UNIVERSAL.NONE |
| def __init__(self, name, default, *args): |
| self.name=name |
| self.choice = {} |
| for p in args: |
| self.choice[p.ASN1_root.ASN1_tag] = p |
| # self.context=context |
| self.default=default |
| def m2i(self, pkt, x): |
| if len(x) == 0: |
| return Raw(),"" |
| raise ASN1_Error("ASN1F_CHOICE: got empty string") |
| if ord(x[0]) not in self.choice: |
| return Raw(x),"" # XXX return RawASN1 packet ? Raise error |
| raise ASN1_Error("Decoding Error: choice [%i] not found in %r" % (ord(x[0]), self.choice.keys())) |
| |
| z = ASN1F_PACKET.extract_packet(self, self.choice[ord(x[0])], x) |
| return z |
| def randval(self): |
| return RandChoice(*map(lambda x:fuzz(x()), self.choice.values())) |
| |
| |
| |
| ########################### |
| ## Packet abstract class ## |
| ########################### |
| |
| class Packet_metaclass(type): |
| def __new__(cls, name, bases, dct): |
| newcls = super(Packet_metaclass, cls).__new__(cls, name, bases, dct) |
| for f in newcls.fields_desc: |
| f.register_owner(newcls) |
| return newcls |
| def __getattr__(self, attr): |
| for k in self.fields_desc: |
| if k.name == attr: |
| return k |
| raise AttributeError(attr) |
| |
| class NewDefaultValues(Packet_metaclass): |
| """NewDefaultValues metaclass. Example usage: |
| class MyPacket(Packet): |
| fields_desc = [ StrField("my_field", "my default value"), ] |
| |
| class MyPacket_variant(MyPacket): |
| __metaclass__ = NewDefaultValues |
| my_field = "my new default value" |
| """ |
| def __new__(cls, name, bases, dct): |
| fields = None |
| for b in bases: |
| if hasattr(b,"fields_desc"): |
| fields = b.fields_desc |
| break |
| if fields is None: |
| raise Scapy_Exception("No fields_desc in superclasses") |
| |
| new_fields = [] |
| for f in fields: |
| if f.name in dct: |
| f = f.copy() |
| f.default = dct[f.name] |
| del(dct[f.name]) |
| new_fields.append(f) |
| dct["fields_desc"] = new_fields |
| return super(NewDefaultValues, cls).__new__(cls, name, bases, dct) |
| |
| class Packet(Gen): |
| __metaclass__ = Packet_metaclass |
| name=None |
| |
| fields_desc = [] |
| |
| aliastypes = [] |
| overload_fields = {} |
| |
| underlayer = None |
| |
| payload_guess = [] |
| initialized = 0 |
| show_indent=1 |
| |
| def from_hexcap(cls): |
| return cls(import_hexcap()) |
| from_hexcap = classmethod(from_hexcap) |
| |
| |
| def __init__(self, _pkt="", post_transform=None, _internal=0, _underlayer=None, **fields): |
| self.time = time.time() |
| if self.name is None: |
| self.name = self.__class__.__name__ |
| self.aliastypes = [ self.__class__ ] + self.aliastypes |
| self.default_fields = {} |
| self.overloaded_fields = {} |
| self.fields={} |
| self.fieldtype={} |
| self.packetfields=[] |
| self.__dict__["payload"] = NoPayload() |
| self.init_fields() |
| self.underlayer = _underlayer |
| self.initialized = 1 |
| if _pkt: |
| self.dissect(_pkt) |
| if not _internal: |
| self.dissection_done(self) |
| for f in fields.keys(): |
| self.fields[f] = self.get_field(f).any2i(self,fields[f]) |
| if type(post_transform) is list: |
| self.post_transforms = post_transform |
| elif post_transform is None: |
| self.post_transforms = [] |
| else: |
| self.post_transforms = [post_transform] |
| |
| def init_fields(self): |
| self.do_init_fields(self.fields_desc) |
| |
| def do_init_fields(self, flist): |
| for f in flist: |
| self.default_fields[f.name] = f.default |
| self.fieldtype[f.name] = f |
| if f.holds_packets: |
| self.packetfields.append(f) |
| |
| def dissection_done(self,pkt): |
| """DEV: will be called after a dissection is completed""" |
| self.post_dissection(pkt) |
| self.payload.dissection_done(pkt) |
| |
| def post_dissection(self, pkt): |
| """DEV: is called after the dissection of the whole packet""" |
| pass |
| |
| def get_field(self, fld): |
| """DEV: returns the field instance from the name of the field""" |
| return self.fieldtype[fld] |
| |
| def add_payload(self, payload): |
| if payload is None: |
| return |
| elif not isinstance(self.payload, NoPayload): |
| self.payload.add_payload(payload) |
| else: |
| if isinstance(payload, Packet): |
| self.__dict__["payload"] = payload |
| payload.add_underlayer(self) |
| for t in self.aliastypes: |
| if payload.overload_fields.has_key(t): |
| self.overloaded_fields = payload.overload_fields[t] |
| break |
| elif type(payload) is str: |
| self.__dict__["payload"] = Raw(load=payload) |
| else: |
| raise TypeError("payload must be either 'Packet' or 'str', not [%s]" % repr(payload)) |
| def remove_payload(self): |
| self.payload.remove_underlayer(self) |
| self.__dict__["payload"] = NoPayload() |
| self.overloaded_fields = {} |
| def add_underlayer(self, underlayer): |
| self.underlayer = underlayer |
| def remove_underlayer(self,other): |
| self.underlayer = None |
| def copy(self): |
| """Returns a deep copy of the instance.""" |
| clone = self.__class__() |
| clone.fields = self.fields.copy() |
| for k in clone.fields: |
| clone.fields[k]=self.get_field(k).do_copy(clone.fields[k]) |
| clone.default_fields = self.default_fields.copy() |
| clone.overloaded_fields = self.overloaded_fields.copy() |
| clone.overload_fields = self.overload_fields.copy() |
| clone.underlayer=self.underlayer |
| clone.post_transforms=self.post_transforms[:] |
| clone.__dict__["payload"] = self.payload.copy() |
| clone.payload.add_underlayer(clone) |
| return clone |
| |
| def getfieldval(self, attr): |
| for f in self.fields, self.overloaded_fields, self.default_fields: |
| if f.has_key(attr): |
| return f[attr] |
| return self.payload.getfieldval(attr) |
| |
| def getfield_and_val(self, attr): |
| for f in self.fields, self.overloaded_fields, self.default_fields: |
| if f.has_key(attr): |
| return self.get_field(attr),f[attr] |
| return self.payload.getfield_and_val(attr) |
| |
| def __getattr__(self, attr): |
| if self.initialized: |
| fld,v = self.getfield_and_val(attr) |
| if fld is not None: |
| return fld.i2h(self, v) |
| return v |
| raise AttributeError(attr) |
| |
| def __setattr__(self, attr, val): |
| if self.initialized: |
| if self.default_fields.has_key(attr): |
| fld = self.get_field(attr) |
| if fld is None: |
| any2i = lambda x,y: y |
| else: |
| any2i = fld.any2i |
| self.fields[attr] = any2i(self, val) |
| elif attr == "payload": |
| self.remove_payload() |
| self.add_payload(val) |
| else: |
| self.__dict__[attr] = val |
| else: |
| self.__dict__[attr] = val |
| def __delattr__(self, attr): |
| if self.initialized: |
| if self.fields.has_key(attr): |
| del(self.fields[attr]) |
| return |
| elif self.default_fields.has_key(attr): |
| return |
| elif attr == "payload": |
| self.remove_payload() |
| return |
| if self.__dict__.has_key(attr): |
| del(self.__dict__[attr]) |
| else: |
| raise AttributeError(attr) |
| |
| def __repr__(self): |
| s = "" |
| ct = conf.color_theme |
| for f in self.fields_desc: |
| if f.name in self.fields: |
| val = f.i2repr(self, self.fields[f.name]) |
| elif f.name in self.overloaded_fields: |
| val = f.i2repr(self, self.overloaded_fields[f.name]) |
| else: |
| continue |
| if isinstance(f, Emph): |
| ncol = ct.emph_field_name |
| vcol = ct.emph_field_value |
| else: |
| ncol = ct.field_name |
| vcol = ct.field_value |
| |
| |
| s += " %s%s%s" % (ncol(f.name), |
| ct.punct("="), |
| vcol(val)) |
| return "%s%s %s %s%s%s"% (ct.punct("<"), |
| ct.layer_name(self.__class__.__name__), |
| s, |
| ct.punct("|"), |
| repr(self.payload), |
| ct.punct(">")) |
| def __str__(self): |
| return self.__iter__().next().build() |
| def __div__(self, other): |
| if isinstance(other, Packet): |
| cloneA = self.copy() |
| cloneB = other.copy() |
| cloneA.add_payload(cloneB) |
| return cloneA |
| elif type(other) is str: |
| return self/Raw(load=other) |
| else: |
| return other.__rdiv__(self) |
| def __rdiv__(self, other): |
| if type(other) is str: |
| return Raw(load=other)/self |
| else: |
| raise TypeError |
| def __mul__(self, other): |
| if type(other) is int: |
| return [self]*other |
| else: |
| raise TypeError |
| def __rmul__(self,other): |
| return self.__mul__(other) |
| |
| def __nonzero__(self): |
| return True |
| def __len__(self): |
| return len(self.__str__()) |
| def do_build(self): |
| p="" |
| for f in self.fields_desc: |
| p = f.addfield(self, p, self.getfieldval(f.name)) |
| return p |
| |
| def post_build(self, pkt, pay): |
| """DEV: called right after the current layer is build.""" |
| return pkt+pay |
| |
| def build_payload(self): |
| return self.payload.build(internal=1) |
| |
| def build(self,internal=0): |
| pkt = self.do_build() |
| for t in self.post_transforms: |
| pkt = t(pkt) |
| pay = self.build_payload() |
| try: |
| p = self.post_build(pkt,pay) |
| except TypeError: |
| log_runtime.error("API changed! post_build() now takes 2 arguments. Compatibility is only assured for a short transition time") |
| p = self.post_build(pkt+pay) |
| if not internal: |
| pad = self.payload.getlayer(Padding) |
| if pad: |
| p += pad.build() |
| return p |
| |
| def do_build_ps(self): |
| p="" |
| pl = [] |
| q="" |
| for f in self.fields_desc: |
| p = f.addfield(self, p, self.getfieldval(f.name) ) |
| if type(p) is str: |
| r = p[len(q):] |
| q = p |
| else: |
| r = "" |
| pl.append( (f, f.i2repr(self,self.getfieldval(f.name)), r) ) |
| |
| pkt,lst = self.payload.build_ps(internal=1) |
| p += pkt |
| lst.append( (self, pl) ) |
| |
| return p,lst |
| |
| def build_ps(self,internal=0): |
| p,lst = self.do_build_ps() |
| # if not internal: |
| # pkt = self |
| # while pkt.haslayer(Padding): |
| # pkt = pkt.getlayer(Padding) |
| # lst.append( (pkt, [ ("loakjkjd", pkt.load, pkt.load) ] ) ) |
| # p += pkt.load |
| # pkt = pkt.payload |
| return p,lst |
| |
| |
| def psdump(self, filename=None, **kargs): |
| """psdump(filename=None, layer_shift=0, rebuild=1) |
| Creates an EPS file describing a packet. If filename is not provided a temporary file is created and gs is called.""" |
| canvas = self.canvas_dump(**kargs) |
| if filename is None: |
| fname = "/tmp/scapy.%i"%os.getpid() |
| canvas.writeEPSfile(fname) |
| os.system("%s '%s.eps' &" % (conf.prog.psreader,fname)) |
| else: |
| canvas.writeEPSfile(filename) |
| |
| def pdfdump(self, filename=None, **kargs): |
| """pdfdump(filename=None, layer_shift=0, rebuild=1) |
| Creates a PDF file describing a packet. If filename is not provided a temporary file is created and xpdf is called.""" |
| canvas = self.canvas_dump(**kargs) |
| if filename is None: |
| fname = "/tmp/scapy.%i"%os.getpid() |
| canvas.writePDFfile(fname) |
| os.system("%s '%s.pdf' &" % (conf.prog.pdfreader,fname)) |
| else: |
| canvas.writePDFfile(filename) |
| |
| |
| def canvas_dump(self, layer_shift=0, rebuild=1): |
| canvas = pyx.canvas.canvas() |
| if rebuild: |
| p,t = self.__class__(str(self)).build_ps() |
| else: |
| p,t = self.build_ps() |
| YTXT=len(t) |
| for n,l in t: |
| YTXT += len(l) |
| YTXT = float(YTXT) |
| YDUMP=YTXT |
| |
| XSTART = 1 |
| XDSTART = 10 |
| y = 0.0 |
| yd = 0.0 |
| xd = 0 |
| XMUL= 0.55 |
| YMUL = 0.4 |
| |
| backcolor=colgen(0.6, 0.8, 1.0, trans=pyx.color.rgb) |
| forecolor=colgen(0.2, 0.5, 0.8, trans=pyx.color.rgb) |
| # backcolor=makecol(0.376, 0.729, 0.525, 1.0) |
| |
| |
| def hexstr(x): |
| s = [] |
| for c in x: |
| s.append("%02x" % ord(c)) |
| return " ".join(s) |
| |
| |
| def make_dump_txt(x,y,txt): |
| return pyx.text.text(XDSTART+x*XMUL, (YDUMP-y)*YMUL, r"\tt{%s}"%hexstr(txt), [pyx.text.size.Large]) |
| |
| def make_box(o): |
| return pyx.box.rect(o.left(), o.bottom(), o.width(), o.height(), relcenter=(0.5,0.5)) |
| |
| def make_frame(lst): |
| if len(lst) == 1: |
| b = lst[0].bbox() |
| b.enlarge(pyx.unit.u_pt) |
| return b.path() |
| else: |
| fb = lst[0].bbox() |
| fb.enlarge(pyx.unit.u_pt) |
| lb = lst[-1].bbox() |
| lb.enlarge(pyx.unit.u_pt) |
| if len(lst) == 2 and fb.left() > lb.right(): |
| return pyx.path.path(pyx.path.moveto(fb.right(), fb.top()), |
| pyx.path.lineto(fb.left(), fb.top()), |
| pyx.path.lineto(fb.left(), fb.bottom()), |
| pyx.path.lineto(fb.right(), fb.bottom()), |
| pyx.path.moveto(lb.left(), lb.top()), |
| pyx.path.lineto(lb.right(), lb.top()), |
| pyx.path.lineto(lb.right(), lb.bottom()), |
| pyx.path.lineto(lb.left(), lb.bottom())) |
| else: |
| # XXX |
| gb = lst[1].bbox() |
| if gb != lb: |
| gb.enlarge(pyx.unit.u_pt) |
| kb = lst[-2].bbox() |
| if kb != gb and kb != lb: |
| kb.enlarge(pyx.unit.u_pt) |
| return pyx.path.path(pyx.path.moveto(fb.left(), fb.top()), |
| pyx.path.lineto(fb.right(), fb.top()), |
| pyx.path.lineto(fb.right(), kb.bottom()), |
| pyx.path.lineto(lb.right(), kb.bottom()), |
| pyx.path.lineto(lb.right(), lb.bottom()), |
| pyx.path.lineto(lb.left(), lb.bottom()), |
| pyx.path.lineto(lb.left(), gb.top()), |
| pyx.path.lineto(fb.left(), gb.top()), |
| pyx.path.closepath(),) |
| |
| |
| def make_dump(s, shift=0, y=0, col=None, bkcol=None, larg=16): |
| c = pyx.canvas.canvas() |
| tlist = [] |
| while s: |
| dmp,s = s[:larg-shift],s[larg-shift:] |
| txt = make_dump_txt(shift, y, dmp) |
| tlist.append(txt) |
| shift += len(dmp) |
| if shift >= 16: |
| shift = 0 |
| y += 1 |
| if col is None: |
| col = pyx.color.rgb.red |
| if bkcol is None: |
| col = pyx.color.rgb.white |
| c.stroke(make_frame(tlist),[col,pyx.deco.filled([bkcol]),pyx.style.linewidth.Thick]) |
| for txt in tlist: |
| c.insert(txt) |
| return c, tlist[-1].bbox(), shift, y |
| |
| |
| last_shift,last_y=0,0.0 |
| while t: |
| bkcol = backcolor.next() |
| proto,fields = t.pop() |
| y += 0.5 |
| pt = pyx.text.text(XSTART, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % proto.name, [ pyx.text.size.Large]) |
| y += 1 |
| ptbb=pt.bbox() |
| ptbb.enlarge(pyx.unit.u_pt*2) |
| canvas.stroke(ptbb.path(),[pyx.color.rgb.black, pyx.deco.filled([bkcol])]) |
| canvas.insert(pt) |
| for fname, fval, fdump in fields: |
| col = forecolor.next() |
| ft = pyx.text.text(XSTART, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % tex_escape(fname.name)) |
| if fval is not None: |
| if len(fval) > 18: |
| fval = fval[:18]+"[...]" |
| else: |
| fval="" |
| vt = pyx.text.text(XSTART+3, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % tex_escape(fval)) |
| y += 1.0 |
| if fdump: |
| dt,target,last_shift,last_y = make_dump(fdump, last_shift, last_y, col, bkcol) |
| |
| dtb = dt.bbox() |
| dtb=target |
| vtb = vt.bbox() |
| bxvt = make_box(vtb) |
| bxdt = make_box(dtb) |
| dtb.enlarge(pyx.unit.u_pt) |
| try: |
| if yd < 0: |
| cnx = pyx.connector.curve(bxvt,bxdt,absangle1=0, absangle2=-90) |
| else: |
| cnx = pyx.connector.curve(bxvt,bxdt,absangle1=0, absangle2=90) |
| except: |
| pass |
| else: |
| canvas.stroke(cnx,[pyx.style.linewidth.thin,pyx.deco.earrow.small,col]) |
| |
| canvas.insert(dt) |
| |
| canvas.insert(ft) |
| canvas.insert(vt) |
| last_y += layer_shift |
| |
| return canvas |
| |
| |
| |
| def extract_padding(self, s): |
| """DEV: to be overloaded to extract current layer's padding. Return a couple of strings (actual layer, padding)""" |
| return s,None |
| |
| def post_dissect(self, s): |
| """DEV: is called right after the current layer has been dissected""" |
| return s |
| |
| def pre_dissect(self, s): |
| """DEV: is called right before the current layer is dissected""" |
| return s |
| |
| def do_dissect(self, s): |
| flist = self.fields_desc[:] |
| flist.reverse() |
| while s and flist: |
| f = flist.pop() |
| s,fval = f.getfield(self, s) |
| self.fields[f.name] = fval |
| |
| return s |
| |
| def do_dissect_payload(self, s): |
| if s: |
| cls = self.guess_payload_class(s) |
| try: |
| p = cls(s, _internal=1, _underlayer=self) |
| except KeyboardInterrupt: |
| raise |
| except: |
| if conf.debug_dissector: |
| if isinstance(cls,type) and issubclass(cls,Packet): |
| log_runtime.error("%s dissector failed" % cls.name) |
| else: |
| log_runtime.error("%s.guess_payload_class() returned [%s]" % (self.__class__.__name__,repr(cls))) |
| if cls is not None: |
| raise |
| p = Raw(s, _internal=1, _underlayer=self) |
| self.add_payload(p) |
| |
| def dissect(self, s): |
| s = self.pre_dissect(s) |
| |
| s = self.do_dissect(s) |
| |
| s = self.post_dissect(s) |
| |
| payl,pad = self.extract_padding(s) |
| self.do_dissect_payload(payl) |
| if pad and conf.padding: |
| self.add_payload(Padding(pad)) |
| |
| |
| def guess_payload_class(self, payload): |
| """DEV: Guesses the next payload class from layer bonds. Can be overloaded to use a different mechanism.""" |
| for t in self.aliastypes: |
| for fval, cls in t.payload_guess: |
| ok = 1 |
| for k in fval.keys(): |
| if not hasattr(self, k) or fval[k] != self.getfieldval(k): |
| ok = 0 |
| break |
| if ok: |
| return cls |
| return self.default_payload_class(payload) |
| |
| def default_payload_class(self, payload): |
| """DEV: Returns the default payload class if nothing has been found by the guess_payload_class() method.""" |
| return Raw |
| |
| def hide_defaults(self): |
| """Removes fields' values that are the same as default values.""" |
| for k in self.fields.keys(): |
| if self.default_fields.has_key(k): |
| if self.default_fields[k] == self.fields[k]: |
| del(self.fields[k]) |
| self.payload.hide_defaults() |
| |
| |
| def __iter__(self): |
| def loop(todo, done, self=self): |
| if todo: |
| eltname = todo.pop() |
| elt = self.getfieldval(eltname) |
| if not isinstance(elt, Gen): |
| if self.get_field(eltname).islist: |
| elt = SetGen([elt]) |
| else: |
| elt = SetGen(elt) |
| for e in elt: |
| done[eltname]=e |
| for x in loop(todo[:], done): |
| yield x |
| else: |
| if isinstance(self.payload,NoPayload): |
| payloads = [None] |
| else: |
| payloads = self.payload |
| for payl in payloads: |
| done2=done.copy() |
| for k in done2: |
| if isinstance(done2[k], VolatileValue): |
| done2[k] = done2[k]._fix() |
| pkt = self.__class__() |
| pkt.fields = done2 |
| pkt.time = self.time |
| pkt.underlayer = self.underlayer |
| pkt.overload_fields = self.overload_fields.copy() |
| pkt.post_transforms = self.post_transforms |
| if payl is None: |
| yield pkt |
| else: |
| yield pkt/payl |
| todo = map(lambda (x,y):x, filter(lambda (x,y):isinstance(y,VolatileValue), self.default_fields.items())) |
| todo += map(lambda (x,y):x, filter(lambda (x,y):isinstance(y,VolatileValue), self.overloaded_fields.items())) |
| todo += self.fields.keys() |
| return loop(map(lambda x:str(x), todo), {}) |
| |
| def __gt__(self, other): |
| """True if other is an answer from self (self ==> other).""" |
| if isinstance(other, Packet): |
| return other < self |
| elif type(other) is str: |
| return 1 |
| else: |
| raise TypeError((self, other)) |
| def __lt__(self, other): |
| """True if self is an answer from other (other ==> self).""" |
| if isinstance(other, Packet): |
| return self.answers(other) |
| elif type(other) is str: |
| return 1 |
| else: |
| raise TypeError((self, other)) |
| |
| def __eq__(self, other): |
| if not isinstance(other, self.__class__): |
| return False |
| for f in self.fields_desc: |
| if f not in other.fields_desc: |
| return False |
| if self.getfieldval(f.name) != other.getfieldval(f.name): |
| return False |
| return self.payload == other.payload |
| |
| def __ne__(self, other): |
| return not self.__eq__(other) |
| |
| def hashret(self): |
| """DEV: returns a string that has the same value for a request and its answer.""" |
| return self.payload.hashret() |
| def answers(self, other): |
| """DEV: true if self is an answer from other""" |
| if other.__class__ == self.__class__: |
| return self.payload.answers(other.payload) |
| return 0 |
| |
| def haslayer(self, cls): |
| """true if self has a layer that is an instance of cls. Superseded by "cls in self" syntax.""" |
| if self.__class__ == cls or self.__class__.__name__ == cls: |
| return 1 |
| for f in self.packetfields: |
| fvalue_gen = self.getfieldval(f.name) |
| if fvalue_gen is None: |
| continue |
| if not f.islist: |
| fvalue_gen = SetGen(fvalue_gen,_iterpacket=0) |
| for fvalue in fvalue_gen: |
| if isinstance(fvalue, Packet): |
| ret = fvalue.haslayer(cls) |
| if ret: |
| return ret |
| return self.payload.haslayer(cls) |
| def getlayer(self, cls, nb=1, _track=None): |
| """Return the nb^th layer that is an instance of cls.""" |
| if type(cls) is str and "." in cls: |
| ccls,fld = cls.split(".",1) |
| else: |
| ccls,fld = cls,None |
| if self.__class__ == cls or self.__class__.name == ccls: |
| if nb == 1: |
| if fld is None: |
| return self |
| else: |
| return self.getfieldval(fld) |
| else: |
| nb -=1 |
| for f in self.packetfields: |
| fvalue_gen = self.getfieldval(f.name) |
| if fvalue_gen is None: |
| continue |
| if not f.islist: |
| fvalue_gen = SetGen(fvalue_gen,_iterpacket=0) |
| for fvalue in fvalue_gen: |
| if isinstance(fvalue, Packet): |
| track=[] |
| ret = fvalue.getlayer(cls, nb, _track=track) |
| if ret is not None: |
| return ret |
| nb = track[0] |
| return self.payload.getlayer(cls,nb,_track=_track) |
| |
| def __getitem__(self, cls): |
| if type(cls) is slice: |
| if cls.stop: |
| ret = self.getlayer(cls.start, cls.stop) |
| else: |
| ret = self.getlayer(cls.start) |
| if ret is None and cls.step is not None: |
| ret = cls.step |
| return ret |
| else: |
| return self.getlayer(cls) |
| |
| def __contains__(self, cls): |
| """"cls in self" returns true if self has a layer which is an instance of cls.""" |
| return self.haslayer(cls) |
| |
| |
| |
| def display(self,*args,**kargs): # Deprecated. Use show() |
| """Deprecated. Use show() method.""" |
| self.show(*args,**kargs) |
| def show(self, indent=3, lvl="", label_lvl=""): |
| """Prints a hierarchical view of the packet. "indent" gives the size of indentation for each layer.""" |
| ct = conf.color_theme |
| print "%s%s %s %s" % (label_lvl, |
| ct.punct("###["), |
| ct.layer_name(self.name), |
| ct.punct("]###")) |
| for f in self.fields_desc: |
| if isinstance(f, Emph): |
| ncol = ct.emph_field_name |
| vcol = ct.emph_field_value |
| else: |
| ncol = ct.field_name |
| vcol = ct.field_value |
| fvalue = self.getfieldval(f.name) |
| if isinstance(fvalue, Packet) or (f.islist and f.holds_packets and type(fvalue) is list): |
| print "%s \\%-10s\\" % (label_lvl+lvl, ncol(f.name)) |
| fvalue_gen = SetGen(fvalue,_iterpacket=0) |
| for fvalue in fvalue_gen: |
| fvalue.show(indent=indent, label_lvl=label_lvl+lvl+" |") |
| else: |
| print "%s %-10s%s %s" % (label_lvl+lvl, |
| ncol(f.name), |
| ct.punct("="), |
| vcol(f.i2repr(self,fvalue))) |
| self.payload.show(indent=indent, lvl=lvl+(" "*indent*self.show_indent), label_lvl=label_lvl) |
| def show2(self): |
| """Prints a hierarchical view of an assembled version of the packet, so that automatic fields are calculated (checksums, etc.)""" |
| self.__class__(str(self)).show() |
| |
| def sprintf(self, fmt, relax=1): |
| """sprintf(format, [relax=1]) -> str |
| where format is a string that can include directives. A directive begins and |
| ends by % and has the following format %[fmt[r],][cls[:nb].]field%. |
| |
| fmt is a classic printf directive, "r" can be appended for raw substitution |
| (ex: IP.flags=0x18 instead of SA), nb is the number of the layer we want |
| (ex: for IP/IP packets, IP:2.src is the src of the upper IP layer). |
| Special case : "%.time%" is the creation time. |
| Ex : p.sprintf("%.time% %-15s,IP.src% -> %-15s,IP.dst% %IP.chksum% " |
| "%03xr,IP.proto% %r,TCP.flags%") |
| |
| Moreover, the format string can include conditionnal statements. A conditionnal |
| statement looks like : {layer:string} where layer is a layer name, and string |
| is the string to insert in place of the condition if it is true, i.e. if layer |
| is present. If layer is preceded by a "!", the result si inverted. Conditions |
| can be imbricated. A valid statement can be : |
| p.sprintf("This is a{TCP: TCP}{UDP: UDP}{ICMP:n ICMP} packet") |
| p.sprintf("{IP:%IP.dst% {ICMP:%ICMP.type%}{TCP:%TCP.dport%}}") |
| |
| A side effect is that, to obtain "{" and "}" characters, you must use |
| "%(" and "%)". |
| """ |
| |
| escape = { "%": "%", |
| "(": "{", |
| ")": "}" } |
| |
| |
| # Evaluate conditions |
| while "{" in fmt: |
| i = fmt.rindex("{") |
| j = fmt[i+1:].index("}") |
| cond = fmt[i+1:i+j+1] |
| k = cond.find(":") |
| if k < 0: |
| raise Scapy_Exception("Bad condition in format string: [%s] (read sprintf doc!)"%cond) |
| cond,format = cond[:k],cond[k+1:] |
| res = False |
| if cond[0] == "!": |
| res = True |
| cond = cond[1:] |
| if self.haslayer(cond): |
| res = not res |
| if not res: |
| format = "" |
| fmt = fmt[:i]+format+fmt[i+j+2:] |
| |
| # Evaluate directives |
| s = "" |
| while "%" in fmt: |
| i = fmt.index("%") |
| s += fmt[:i] |
| fmt = fmt[i+1:] |
| if fmt[0] in escape: |
| s += escape[fmt[0]] |
| fmt = fmt[1:] |
| continue |
| try: |
| i = fmt.index("%") |
| sfclsfld = fmt[:i] |
| fclsfld = sfclsfld.split(",") |
| if len(fclsfld) == 1: |
| f = "s" |
| clsfld = fclsfld[0] |
| elif len(fclsfld) == 2: |
| f,clsfld = fclsfld |
| else: |
| raise Scapy_Exception |
| if "." in clsfld: |
| cls,fld = clsfld.split(".") |
| else: |
| cls = self.__class__.__name__ |
| fld = clsfld |
| num = 1 |
| if ":" in cls: |
| cls,num = cls.split(":") |
| num = int(num) |
| fmt = fmt[i+1:] |
| except: |
| raise Scapy_Exception("Bad format string [%%%s%s]" % (fmt[:25], fmt[25:] and "...")) |
| else: |
| if fld == "time": |
| val = time.strftime("%H:%M:%S.%%06i", time.localtime(self.time)) % int((self.time-int(self.time))*1000000) |
| elif cls == self.__class__.__name__ and hasattr(self, fld): |
| if num > 1: |
| val = self.payload.sprintf("%%%s,%s:%s.%s%%" % (f,cls,num-1,fld), relax) |
| f = "s" |
| elif f[-1] == "r": # Raw field value |
| val = getattr(self,fld) |
| f = f[:-1] |
| if not f: |
| f = "s" |
| else: |
| val = getattr(self,fld) |
| if fld in self.fieldtype: |
| val = self.fieldtype[fld].i2repr(self,val) |
| else: |
| val = self.payload.sprintf("%%%s%%" % sfclsfld, relax) |
| f = "s" |
| s += ("%"+f) % val |
| |
| s += fmt |
| return s |
| |
| def mysummary(self): |
| """DEV: can be overloaded to return a string that summarizes the layer. |
| Only one mysummary() is used in a whole packet summary: the one of the upper layer, |
| except if a mysummary() also returns (as a couple) a list of layers whose |
| mysummary() must be called if they are present.""" |
| return "" |
| |
| def summary(self, intern=0): |
| """Prints a one line summary of a packet.""" |
| found,s,needed = self.payload.summary(intern=1) |
| if s: |
| s = " / "+s |
| ret = "" |
| if not found or self.__class__ in needed: |
| ret = self.mysummary() |
| if type(ret) is tuple: |
| ret,n = ret |
| needed += n |
| if ret or needed: |
| found = 1 |
| if not ret: |
| ret = self.__class__.__name__ |
| ret = "%s%s" % (ret,s) |
| if intern: |
| return found,ret,needed |
| else: |
| return ret |
| |
| def lastlayer(self,layer=None): |
| """Returns the uppest layer of the packet""" |
| return self.payload.lastlayer(self) |
| |
| def decode_payload_as(self,cls): |
| """Reassembles the payload and decode it using another packet class""" |
| s = str(self.payload) |
| self.payload = cls(s) |
| |
| def libnet(self): |
| """Not ready yet. Should give the necessary C code that interfaces with libnet to recreate the packet""" |
| print "libnet_build_%s(" % self.__class__.name.lower() |
| det = self.__class__(str(self)) |
| for f in self.fields_desc: |
| val = det.getfieldval(f.name) |
| if val is None: |
| val = 0 |
| elif type(val) is int: |
| val = str(val) |
| else: |
| val = '"%s"' % str(val) |
| print "\t%s, \t\t/* %s */" % (val,f.name) |
| print ");" |
| def command(self): |
| """Returns a string representing the command you have to type to obtain the same packet""" |
| f = [] |
| for fn,fv in self.fields.items(): |
| if isinstance(fv, Packet): |
| fv = fv.command() |
| else: |
| fv = repr(fv) |
| f.append("%s=%s" % (fn, fv)) |
| c = "%s(%s)" % (self.__class__.__name__, ", ".join(f)) |
| pc = self.payload.command() |
| if pc: |
| c += "/"+pc |
| return c |
| |
| |
| class ASN1_Packet(Packet): |
| ASN1_root = None |
| ASN1_codec = None |
| def init_fields(self): |
| flist = self.ASN1_root.get_fields_list() |
| self.do_init_fields(flist) |
| self.fields_desc = flist |
| def do_build(self): |
| return self.ASN1_root.build(self) |
| def do_dissect(self, x): |
| return self.ASN1_root.dissect(self, x) |
| |
| |
| class NoPayload(Packet,object): |
| def __new__(cls, *args, **kargs): |
| singl = cls.__dict__.get("__singl__") |
| if singl is None: |
| cls.__singl__ = singl = object.__new__(cls) |
| Packet.__init__(singl, *args, **kargs) |
| return singl |
| def __init__(self, *args, **kargs): |
| pass |
| def dissection_done(self,pkt): |
| return |
| def add_payload(self, payload): |
| raise Scapy_Exception("Can't add payload to NoPayload instance") |
| def remove_payload(self): |
| pass |
| def add_underlayer(self,underlayer): |
| pass |
| def remove_underlayer(self,other): |
| pass |
| def copy(self): |
| return self |
| def __repr__(self): |
| return "" |
| def __str__(self): |
| return "" |
| def __nonzero__(self): |
| return False |
| def build(self, internal=0): |
| return "" |
| def build_ps(self, internal=0): |
| return "",[] |
| def getfieldval(self, attr): |
| raise AttributeError(attr) |
| def getfield_and_val(self, attr): |
| raise AttributeError(attr) |
| def __getattr__(self, attr): |
| if attr in self.__dict__: |
| return self.__dict__[attr] |
| elif attr in self.__class__.__dict__: |
| return self.__class__.__dict__[attr] |
| else: |
| raise AttributeError, attr |
| def hide_defaults(self): |
| pass |
| def __iter__(self): |
| return iter([]) |
| def __eq__(self, other): |
| if isinstance(other, NoPayload): |
| return True |
| return False |
| def hashret(self): |
| return "" |
| def answers(self, other): |
| return isinstance(other, NoPayload) or isinstance(other, Padding) |
| def haslayer(self, cls): |
| return 0 |
| def getlayer(self, cls, nb=1, _track=None): |
| if _track is not None: |
| _track.append(nb) |
| return None |
| def show(self, indent=3, lvl="", label_lvl=""): |
| pass |
| def sprintf(self, fmt, relax): |
| if relax: |
| return "??" |
| else: |
| raise Scapy_Exception("Format not found [%s]"%fmt) |
| def summary(self, intern=0): |
| return 0,"",[] |
| def lastlayer(self,layer): |
| return layer |
| def command(self): |
| return "" |
| |
| |
| #################### |
| ## packet classes ## |
| #################### |
| |
| |
| class Raw(Packet): |
| name = "Raw" |
| fields_desc = [ StrField("load", "") ] |
| def answers(self, other): |
| return 1 |
| # s = str(other) |
| # t = self.load |
| # l = min(len(s), len(t)) |
| # return s[:l] == t[:l] |
| |
| class Padding(Raw): |
| name = "Padding" |
| def build(self, internal=0): |
| if internal: |
| return "" |
| else: |
| return Raw.build(self) |
| |
| class Ether(Packet): |
| name = "Ethernet" |
| fields_desc = [ DestMACField("dst"), |
| SourceMACField("src"), |
| XShortEnumField("type", 0x0000, ETHER_TYPES) ] |
| def hashret(self): |
| return struct.pack("H",self.type)+self.payload.hashret() |
| def answers(self, other): |
| if isinstance(other,Ether): |
| if self.type == other.type: |
| return self.payload.answers(other.payload) |
| return 0 |
| def mysummary(self): |
| return self.sprintf("%src% > %dst% (%type%)") |
| |
| class PPPoE(Packet): |
| name = "PPP over Ethernet" |
| fields_desc = [ BitField("version", 1, 4), |
| BitField("type", 1, 4), |
| ByteEnumField("code", 0, {0:"Session"}), |
| XShortField("sessionid", 0x0), |
| ShortField("len", None) ] |
| |
| def post_build(self, p, pay): |
| p += pay |
| if self.len is None: |
| l = len(p)-6 |
| p = p[:4]+struct.pack("!H", l)+p[6:] |
| return p |
| |
| class PPPoED(PPPoE): |
| name = "PPP over Ethernet Discovery" |
| fields_desc = [ BitField("version", 1, 4), |
| BitField("type", 1, 4), |
| ByteEnumField("code", 0x09, {0x09:"PADI",0x07:"PADO",0x19:"PADR",0x65:"PADS",0xa7:"PADT"}), |
| XShortField("sessionid", 0x0), |
| ShortField("len", None) ] |
| |
| class Dot3(Packet): |
| name = "802.3" |
| fields_desc = [ MACField("dst", ETHER_BROADCAST), |
| MACField("src", ETHER_ANY), |
| LenField("len", None, "H") ] |
| def extract_padding(self,s): |
| l = self.len |
| return s[:l],s[l:] |
| def answers(self, other): |
| if isinstance(other,Dot3): |
| return self.payload.answers(other.payload) |
| return 0 |
| def mysummary(self): |
| return "802.3 %s > %s" % (self.src, self.dst) |
| |
| |
| class LLC(Packet): |
| name = "LLC" |
| fields_desc = [ XByteField("dsap", 0x00), |
| XByteField("ssap", 0x00), |
| ByteField("ctrl", 0) ] |
| |
| |
| class CookedLinux(Packet): |
| name = "cooked linux" |
| fields_desc = [ ShortEnumField("pkttype",0, {0: "unicast", |
| 4:"sent-by-us"}), #XXX incomplete |
| XShortField("lladdrtype",512), |
| ShortField("lladdrlen",0), |
| StrFixedLenField("src","",8), |
| XShortEnumField("proto",0x800,ETHER_TYPES) ] |
| |
| |
| |
| class SNAP(Packet): |
| name = "SNAP" |
| fields_desc = [ X3BytesField("OUI",0x000000), |
| XShortEnumField("code", 0x000, ETHER_TYPES) ] |
| |
| |
| class Dot1Q(Packet): |
| name = "802.1Q" |
| aliastypes = [ Ether ] |
| fields_desc = [ BitField("prio", 0, 3), |
| BitField("id", 0, 1), |
| BitField("vlan", 1, 12), |
| XShortEnumField("type", 0x0000, ETHER_TYPES) ] |
| def answers(self, other): |
| if isinstance(other,Dot1Q): |
| if ( (self.type == other.type) and |
| (self.vlan == other.vlan) ): |
| return self.payload.answers(other.payload) |
| else: |
| return self.payload.answers(other) |
| return 0 |
| def default_payload_class(self, pay): |
| if self.type <= 1500: |
| return LLC |
| return Raw |
| def extract_padding(self,s): |
| if self.type <= 1500: |
| return s[:self.type],s[self.type:] |
| return s,None |
| def mysummary(self): |
| if isinstance(self.underlayer, Ether): |
| return self.underlayer.sprintf("802.1q %Ether.src% > %Ether.dst% (%Dot1Q.type%) vlan %Dot1Q.vlan%") |
| else: |
| return self.sprintf("802.1q (%Dot1Q.type%) vlan %Dot1Q.vlan%") |
| |
| |
| class STP(Packet): |
| name = "Spanning Tree Protocol" |
| fields_desc = [ ShortField("proto", 0), |
| ByteField("version", 0), |
| ByteField("bpdutype", 0), |
| ByteField("bpduflags", 0), |
| ShortField("rootid", 0), |
| MACField("rootmac", ETHER_ANY), |
| IntField("pathcost", 0), |
| ShortField("bridgeid", 0), |
| MACField("bridgemac", ETHER_ANY), |
| ShortField("portid", 0), |
| ShortField("age", 1), |
| BCDFloatField("maxage", 20), |
| BCDFloatField("hellotime", 2), |
| BCDFloatField("fwddelay", 15) ] |
| |
| |
| class EAPOL(Packet): |
| name = "EAPOL" |
| fields_desc = [ ByteField("version", 1), |
| ByteEnumField("type", 0, ["EAP_PACKET", "START", "LOGOFF", "KEY", "ASF"]), |
| LenField("len", None, "H") ] |
| |
| EAP_PACKET= 0 |
| START = 1 |
| LOGOFF = 2 |
| KEY = 3 |
| ASF = 4 |
| def extract_padding(self, s): |
| l = self.len |
| return s[:l],s[l:] |
| def hashret(self): |
| return chr(self.type)+self.payload.hashret() |
| def answers(self, other): |
| if isinstance(other,EAPOL): |
| if ( (self.type == self.EAP_PACKET) and |
| (other.type == self.EAP_PACKET) ): |
| return self.payload.answers(other.payload) |
| return 0 |
| def mysummary(self): |
| return self.sprintf("EAPOL %EAPOL.type%") |
| |
| |
| class EAP(Packet): |
| name = "EAP" |
| fields_desc = [ ByteEnumField("code", 4, {1:"REQUEST",2:"RESPONSE",3:"SUCCESS",4:"FAILURE"}), |
| ByteField("id", 0), |
| ShortField("len",None), |
| ConditionalField(ByteEnumField("type",0, {1:"ID",4:"MD5"}), "code", lambda x:x not in [EAP.SUCCESS, EAP.FAILURE]) |
| |
| ] |
| |
| REQUEST = 1 |
| RESPONSE = 2 |
| SUCCESS = 3 |
| FAILURE = 4 |
| TYPE_ID = 1 |
| TYPE_MD5 = 4 |
| def answers(self, other): |
| if isinstance(other,EAP): |
| if self.code == self.REQUEST: |
| return 0 |
| elif self.code == self.RESPONSE: |
| if ( (other.code == self.REQUEST) and |
| (other.type == self.type) ): |
| return 1 |
| elif other.code == self.RESPONSE: |
| return 1 |
| return 0 |
| |
| def post_build(self, p, pay): |
| if self.len is None: |
| l = len(p)+len(pay) |
| p = p[:2]+chr((l>>8)&0xff)+chr(l&0xff)+p[4:] |
| return p+pay |
| |
| |
| class ARP(Packet): |
| name = "ARP" |
| fields_desc = [ XShortField("hwtype", 0x0001), |
| XShortEnumField("ptype", 0x0800, ETHER_TYPES), |
| ByteField("hwlen", 6), |
| ByteField("plen", 4), |
| ShortEnumField("op", 1, {"who-has":1, "is-at":2, "RARP-req":3, "RARP-rep":4, "Dyn-RARP-req":5, "Dyn-RAR-rep":6, "Dyn-RARP-err":7, "InARP-req":8, "InARP-rep":9}), |
| ARPSourceMACField("hwsrc"), |
| SourceIPField("psrc","pdst"), |
| MACField("hwdst", ETHER_ANY), |
| IPField("pdst", "0.0.0.0") ] |
| who_has = 1 |
| is_at = 2 |
| def answers(self, other): |
| if isinstance(other,ARP): |
| if ( (self.op == self.is_at) and |
| (other.op == self.who_has) and |
| (self.psrc == other.pdst) ): |
| return 1 |
| return 0 |
| def extract_padding(self, s): |
| return "",s |
| def mysummary(self): |
| if self.op == self.is_at: |
| return "ARP is at %s says %s" % (self.hwsrc, self.psrc) |
| elif self.op == self.who_has: |
| return "ARP who has %s says %s" % (self.pdst, self.psrc) |
| else: |
| return "ARP %ARP.op% %ARP.psrc% > %ARP.pdst%" |
| |
| |
| class IP(Packet, IPTools): |
| name = "IP" |
| fields_desc = [ BitField("version" , 4 , 4), |
| BitField("ihl", None, 4), |
| XByteField("tos", 0), |
| ShortField("len", None), |
| ShortField("id", 1), |
| FlagsField("flags", 0, 3, ["MF","DF","evil"]), |
| BitField("frag", 0, 13), |
| ByteField("ttl", 64), |
| ByteEnumField("proto", 0, IP_PROTOS), |
| XShortField("chksum", None), |
| #IPField("src", "127.0.0.1"), |
| Emph(SourceIPField("src","dst")), |
| Emph(IPField("dst", "127.0.0.1")), |
| IPoptionsField("options", "") ] |
| def post_build(self, p, pay): |
| ihl = self.ihl |
| if ihl is None: |
| ihl = len(p)/4 |
| p = chr(((self.version&0xf)<<4) | ihl&0x0f)+p[1:] |
| if self.len is None: |
| l = len(p)+len(pay) |
| p = p[:2]+struct.pack("!H", l)+p[4:] |
| if self.chksum is None: |
| ck = checksum(p) |
| p = p[:10]+chr(ck>>8)+chr(ck&0xff)+p[12:] |
| return p+pay |
| |
| def extract_padding(self, s): |
| l = self.len - (self.ihl << 2) |
| return s[:l],s[l:] |
| |
| def send(self, s, slp=0): |
| for p in self: |
| try: |
| s.sendto(str(p), (p.dst,0)) |
| except socket.error, msg: |
| log_runtime.error(msg) |
| if slp: |
| time.sleep(slp) |
| def hashret(self): |
| if ( (self.proto == socket.IPPROTO_ICMP) |
| and (isinstance(self.payload, ICMP)) |
| and (self.payload.type in [3,4,5,11,12]) ): |
| return self.payload.payload.hashret() |
| else: |
| if conf.checkIPsrc and conf.checkIPaddr: |
| return strxor(inet_aton(self.src),inet_aton(self.dst))+struct.pack("B",self.proto)+self.payload.hashret() |
| else: |
| return struct.pack("B", self.proto)+self.payload.hashret() |
| def answers(self, other): |
| if not isinstance(other,IP): |
| return 0 |
| if conf.checkIPaddr and (self.dst != other.src): |
| return 0 |
| if ( (self.proto == socket.IPPROTO_ICMP) and |
| (isinstance(self.payload, ICMP)) and |
| (self.payload.type in [3,4,5,11,12]) ): |
| # ICMP error message |
| return self.payload.payload.answers(other) |
| |
| else: |
| if ( (conf.checkIPaddr and (self.src != other.dst)) or |
| (self.proto != other.proto) ): |
| return 0 |
| return self.payload.answers(other.payload) |
| def mysummary(self): |
| s = self.sprintf("%IP.src% > %IP.dst% %IP.proto%") |
| if self.frag: |
| s += " frag:%i" % self.frag |
| return s |
| |
| |
| |
| class TCP(Packet): |
| name = "TCP" |
| fields_desc = [ ShortEnumField("sport", 20, TCP_SERVICES), |
| ShortEnumField("dport", 80, TCP_SERVICES), |
| IntField("seq", 0), |
| IntField("ack", 0), |
| BitField("dataofs", None, 4), |
| BitField("reserved", 0, 4), |
| FlagsField("flags", 0x2, 8, "FSRPAUEC"), |
| ShortField("window", 8192), |
| XShortField("chksum", None), |
| ShortField("urgptr", 0), |
| TCPOptionsField("options", {}) ] |
| def post_build(self, p, pay): |
| p += pay |
| dataofs = self.dataofs |
| if dataofs is None: |
| dataofs = 5+((len(self.get_field("options").i2m(self,self.options))+3)/4) |
| p = p[:12]+chr((dataofs << 4) | ord(p[12])&0x0f)+p[13:] |
| if self.chksum is None: |
| if isinstance(self.underlayer, IP): |
| if self.underlayer.len is not None: |
| ln = self.underlayer.len-20 |
| else: |
| ln = len(p) |
| psdhdr = struct.pack("!4s4sHH", |
| inet_aton(self.underlayer.src), |
| inet_aton(self.underlayer.dst), |
| self.underlayer.proto, |
| ln) |
| ck=checksum(psdhdr+p) |
| p = p[:16]+struct.pack("!H", ck)+p[18:] |
| elif isinstance(self.underlayer, IPv6) or isinstance(self.underlayer, _IPv6OptionHeader): |
| ck = in6_chksum(socket.IPPROTO_TCP, self.underlayer, p) |
| p = p[:16]+struct.pack("!H", ck)+p[18:] |
| else: |
| warning("No IP underlayer to compute checksum. Leaving null.") |
| return p |
| def hashret(self): |
| if conf.checkIPsrc: |
| return struct.pack("H",self.sport ^ self.dport)+self.payload.hashret() |
| else: |
| return self.payload.hashret() |
| def answers(self, other): |
| if not isinstance(other, TCP): |
| return 0 |
| if conf.checkIPsrc: |
| if not ((self.sport == other.dport) and |
| (self.dport == other.sport)): |
| return 0 |
| if (abs(other.seq-self.ack) > 2+len(other.payload)): |
| return 0 |
| return 1 |
| def mysummary(self): |
| if isinstance(self.underlayer, IP): |
| return self.underlayer.sprintf("TCP %IP.src%:%TCP.sport% > %IP.dst%:%TCP.dport% %TCP.flags%") |
| elif isinstance(self.underlayer, IPv6): |
| return self.underlayer.sprintf("TCP %IPv6.src%:%TCP.sport% > %IPv6.dst%:%TCP.dport% %TCP.flags%") |
| else: |
| return self.sprintf("TCP %TCP.sport% > %TCP.dport% %TCP.flags%") |
| |
| class UDP(Packet): |
| name = "UDP" |
| fields_desc = [ ShortEnumField("sport", 53, UDP_SERVICES), |
| ShortEnumField("dport", 53, UDP_SERVICES), |
| ShortField("len", None), |
| XShortField("chksum", None), ] |
| def post_build(self, p, pay): |
| p += pay |
| l = self.len |
| if l is None: |
| l = len(p) |
| p = p[:4]+struct.pack("!H",l)+p[6:] |
| if self.chksum is None: |
| if isinstance(self.underlayer, IP): |
| if self.underlayer.len is not None: |
| ln = self.underlayer.len-20 |
| else: |
| ln = len(p) |
| psdhdr = struct.pack("!4s4sHH", |
| inet_aton(self.underlayer.src), |
| inet_aton(self.underlayer.dst), |
| self.underlayer.proto, |
| ln) |
| ck=checksum(psdhdr+p) |
| p = p[:6]+struct.pack("!H", ck)+p[8:] |
| elif isinstance(self.underlayer, IPv6) or isinstance(self.underlayer, _IPv6OptionHeader): |
| ck = in6_chksum(socket.IPPROTO_UDP, self.underlayer, p) |
| p = p[:6]+struct.pack("!H", ck)+p[8:] |
| else: |
| warning("No IP underlayer to compute checksum. Leaving null.") |
| return p |
| def extract_padding(self, s): |
| l = self.len - 8 |
| return s[:l],s[l:] |
| def hashret(self): |
| if conf.checkIPsrc: |
| return struct.pack("H",self.sport ^ self.dport)+self.payload.hashret() |
| else: |
| return self.payload.hashret() |
| def answers(self, other): |
| if not isinstance(other, UDP): |
| return 0 |
| if conf.checkIPsrc: |
| if not ((self.sport == other.dport) and |
| (self.dport == other.sport)): |
| return 0 |
| return self.payload.answers(other.payload) |
| def mysummary(self): |
| if isinstance(self.underlayer, IP): |
| return self.underlayer.sprintf("UDP %IP.src%:%UDP.sport% > %IP.dst%:%UDP.dport%") |
| elif isinstance(self.underlayer, IPv6): |
| return self.underlayer.sprintf("UDP %IPv6.src%:%UDP.sport% > %IPv6.dst%:%UDP.dport%") |
| else: |
| return self.sprintf("UDP %UDP.sport% > %UDP.dport%") |
| |
| icmptypes = { 0 : "echo-reply", |
| 3 : "dest-unreach", |
| 4 : "source-quench", |
| 5 : "redirect", |
| 8 : "echo-request", |
| 9 : "router-advertisement", |
| 10 : "router-solicitation", |
| 11 : "time-exceeded", |
| 12 : "parameter-problem", |
| 13 : "timestamp-request", |
| 14 : "timestamp-reply", |
| 15 : "information-request", |
| 16 : "information-response", |
| 17 : "address-mask-request", |
| 18 : "address-mask-reply" } |
| |
| class ICMP(Packet): |
| name = "ICMP" |
| fields_desc = [ ByteEnumField("type",8, icmptypes), |
| ByteField("code",0), |
| XShortField("chksum", None), |
| XShortField("id",0), |
| XShortField("seq",0) ] |
| def post_build(self, p, pay): |
| p += pay |
| if self.chksum is None: |
| ck = checksum(p) |
| p = p[:2]+chr(ck>>8)+chr(ck&0xff)+p[4:] |
| return p |
| |
| def hashret(self): |
| return struct.pack("HH",self.id,self.seq)+self.payload.hashret() |
| def answers(self, other): |
| if not isinstance(other,ICMP): |
| return 0 |
| if ( (other.type,self.type) in [(8,0),(13,14),(15,16),(17,18)] and |
| self.id == other.id and |
| self.seq == other.seq ): |
| return 1 |
| return 0 |
| |
| def guess_payload_class(self, payload): |
| if self.type in [3,4,5,11,12]: |
| return IPerror |
| else: |
| return None |
| def mysummary(self): |
| if isinstance(self.underlayer, IP): |
| return self.underlayer.sprintf("ICMP %IP.src% > %IP.dst% %ICMP.type% %ICMP.code%") |
| else: |
| return self.sprintf("ICMP %ICMP.type% %ICMP.code%") |
| |
| |
| |
| |
| |
| class IPerror(IP): |
| name = "IP in ICMP" |
| def answers(self, other): |
| if not isinstance(other, IP): |
| return 0 |
| if not ( ((conf.checkIPsrc == 0) or (self.dst == other.dst)) and |
| (self.src == other.src) and |
| ( ((conf.checkIPID == 0) |
| or (self.id == other.id) |
| or (conf.checkIPID == 1 and self.id == socket.htons(other.id)))) and |
| (self.proto == other.proto) ): |
| return 0 |
| return self.payload.answers(other.payload) |
| def mysummary(self): |
| return Packet.mysummary(self) |
| |
| |
| class TCPerror(TCP): |
| name = "TCP in ICMP" |
| def answers(self, other): |
| if not isinstance(other, TCP): |
| return 0 |
| if conf.checkIPsrc: |
| if not ((self.sport == other.sport) and |
| (self.dport == other.dport)): |
| return 0 |
| if conf.check_TCPerror_seqack: |
| if self.seq is not None: |
| if self.seq != other.seq: |
| return 0 |
| if self.ack is not None: |
| if self.ack != other.ack: |
| return 0 |
| return 1 |
| def mysummary(self): |
| return Packet.mysummary(self) |
| |
| |
| class UDPerror(UDP): |
| name = "UDP in ICMP" |
| def answers(self, other): |
| if not isinstance(other, UDP): |
| return 0 |
| if conf.checkIPsrc: |
| if not ((self.sport == other.sport) and |
| (self.dport == other.dport)): |
| return 0 |
| return 1 |
| def mysummary(self): |
| return Packet.mysummary(self) |
| |
| |
| |
| class ICMPerror(ICMP): |
| name = "ICMP in ICMP" |
| def answers(self, other): |
| if not isinstance(other,ICMP): |
| return 0 |
| if not ((self.type == other.type) and |
| (self.code == other.code)): |
| return 0 |
| if self.code in [0,8,13,14,17,18]: |
| if (self.id == other.id and |
| self.seq == other.seq): |
| return 1 |
| else: |
| return 0 |
| else: |
| return 1 |
| def mysummary(self): |
| return Packet.mysummary(self) |
| |
| class IPv6(Packet): |
| """See http://namabiiru.hongo.wide.ad.jp/scapy6""" |
| name = "IPv6 not implemented here." |
| def __init__(self, *args, **kargs): |
| log_interactive.error(self.name) |
| def __repr__(self): |
| return "<IPv6: ERROR not implemented>" |
| |
| class _IPv6OptionHeader(Packet): |
| """See http://namabiiru.hongo.wide.ad.jp/scapy6""" |
| name = "IPv6 not implemented here." |
| def __init__(self, *args, **kargs): |
| log_interactive.error(self.name) |
| def __repr__(self): |
| return "<IPv6: ERROR not implemented>" |
| |
| class PPP(Packet): |
| name = "PPP Link Layer" |
| fields_desc = [ ShortEnumField("proto", 0x0021, {0x0021: "IP", |
| 0xc021: "LCP"} ) ] |
| |
| |
| class DNS(Packet): |
| name = "DNS" |
| fields_desc = [ ShortField("id",0), |
| BitField("qr",0, 1), |
| BitEnumField("opcode", 0, 4, {0:"QUERY",1:"IQUERY",2:"STATUS"}), |
| BitField("aa", 0, 1), |
| BitField("tc", 0, 1), |
| BitField("rd", 0, 1), |
| BitField("ra", 0 ,1), |
| BitField("z", 0, 3), |
| BitEnumField("rcode", 0, 4, {0:"ok", 1:"format-error", 2:"server-failure", 3:"name-error", 4:"not-implemented", 5:"refused"}), |
| DNSRRCountField("qdcount", None, "qd"), |
| DNSRRCountField("ancount", None, "an"), |
| DNSRRCountField("nscount", None, "ns"), |
| DNSRRCountField("arcount", None, "ar"), |
| DNSQRField("qd", "qdcount"), |
| DNSRRField("an", "ancount"), |
| DNSRRField("ns", "nscount"), |
| DNSRRField("ar", "arcount",0) ] |
| def answers(self, other): |
| return (isinstance(other, DNS) |
| and self.id == other.id |
| and self.qr == 1 |
| and other.qr == 0) |
| |
| def mysummary(self): |
| type = ["Qry","Ans"][self.qr] |
| name = "" |
| if self.qr: |
| type = "Ans" |
| if self.ancount > 0 and isinstance(self.an, DNSRR): |
| name = ' "%s"' % self.an.rdata |
| else: |
| type = "Qry" |
| if self.qdcount > 0 and isinstance(self.qd, DNSQR): |
| name = ' "%s"' % self.qd.qname |
| return 'DNS %s%s ' % (type, name) |
| |
| dnstypes = { 0:"ANY", 255:"ALL", |
| 1:"A", 2:"NS", 3:"MD", 4:"MD", 5:"CNAME", 6:"SOA", 7: "MB", 8:"MG", |
| 9:"MR",10:"NULL",11:"WKS",12:"PTR",13:"HINFO",14:"MINFO",15:"MX",16:"TXT", |
| 17:"RP",18:"AFSDB",28:"AAAA", 33:"SRV",38:"A6",39:"DNAME"} |
| |
| dnsqtypes = {251:"IXFR",252:"AXFR",253:"MAILB",254:"MAILA",255:"ALL"} |
| dnsqtypes.update(dnstypes) |
| dnsclasses = {1: 'IN', 2: 'CS', 3: 'CH', 4: 'HS', 255: 'ANY'} |
| |
| |
| class DNSQR(Packet): |
| name = "DNS Question Record" |
| show_indent=0 |
| fields_desc = [ DNSStrField("qname",""), |
| ShortEnumField("qtype", 1, dnsqtypes), |
| ShortEnumField("qclass", 1, dnsclasses) ] |
| |
| |
| |
| class DNSRR(Packet): |
| name = "DNS Resource Record" |
| show_indent=0 |
| fields_desc = [ DNSStrField("rrname",""), |
| ShortEnumField("type", 1, dnstypes), |
| ShortEnumField("rclass", 1, dnsclasses), |
| IntField("ttl", 0), |
| RDLenField("rdlen"), |
| RDataField("rdata", "", "rdlen") ] |
| |
| dhcpmagic="c\x82Sc" |
| |
| |
| class BOOTP(Packet): |
| name = "BOOTP" |
| fields_desc = [ ByteEnumField("op",1, {1:"BOOTREQUEST", 2:"BOOTREPLY"}), |
| ByteField("htype",1), |
| ByteField("hlen",6), |
| ByteField("hops",0), |
| IntField("xid",0), |
| ShortField("secs",0), |
| FlagsField("flags", 0, 16, "???????????????B"), |
| IPField("ciaddr","0.0.0.0"), |
| IPField("yiaddr","0.0.0.0"), |
| IPField("siaddr","0.0.0.0"), |
| IPField("giaddr","0.0.0.0"), |
| Field("chaddr","", "16s"), |
| Field("sname","","64s"), |
| Field("file","","128s"), |
| StrField("options","") ] |
| def guess_payload_class(self, payload): |
| if self.options[:len(dhcpmagic)] == dhcpmagic: |
| return DHCP |
| else: |
| return Packet.guess_payload_class(self, payload) |
| def extract_padding(self,s): |
| if self.options[:len(dhcpmagic)] == dhcpmagic: |
| # set BOOTP options to DHCP magic cookie and make rest a payload of DHCP options |
| payload = self.options[len(dhcpmagic):] |
| self.options = self.options[:len(dhcpmagic)] |
| return payload, None |
| else: |
| return "", None |
| def hashret(self): |
| return struct.pack("L", self.xid) |
| def answers(self, other): |
| if not isinstance(other, BOOTP): |
| return 0 |
| return self.xid == other.xid |
| |
| |
| |
| #DHCP_UNKNOWN, DHCP_IP, DHCP_IPLIST, DHCP_TYPE \ |
| #= range(4) |
| # |
| |
| DHCPTypes = { |
| 1: "discover", |
| 2: "offer", |
| 3: "request", |
| 4: "decline", |
| 5: "ack", |
| 6: "nak", |
| 7: "release", |
| 8: "inform", |
| 9: "force_renew", |
| 10:"lease_query", |
| 11:"lease_unassigned", |
| 12:"lease_unknown", |
| 13:"lease_active", |
| } |
| |
| DHCPOptions = { |
| 0: "pad", |
| 1: IPField("subnet_mask", "0.0.0.0"), |
| 2: "time_zone", |
| 3: IPField("router","0.0.0.0"), |
| 4: IPField("time_server","0.0.0.0"), |
| 5: IPField("IEN_name_server","0.0.0.0"), |
| 6: IPField("name_server","0.0.0.0"), |
| 7: IPField("log_server","0.0.0.0"), |
| 8: IPField("cookie_server","0.0.0.0"), |
| 9: IPField("lpr_server","0.0.0.0"), |
| 12: "hostname", |
| 14: "dump_path", |
| 15: "domain", |
| 17: "root_disk_path", |
| 22: "max_dgram_reass_size", |
| 23: "default_ttl", |
| 24: "pmtu_timeout", |
| 28: IPField("broadcast_address","0.0.0.0"), |
| 35: "arp_cache_timeout", |
| 36: "ether_or_dot3", |
| 37: "tcp_ttl", |
| 38: "tcp_keepalive_interval", |
| 39: "tcp_keepalive_garbage", |
| 40: "NIS_domain", |
| 41: IPField("NIS_server","0.0.0.0"), |
| 42: IPField("NTP_server","0.0.0.0"), |
| 43: "vendor_specific", |
| 44: IPField("NetBIOS_server","0.0.0.0"), |
| 45: IPField("NetBIOS_dist_server","0.0.0.0"), |
| 50: IPField("requested_addr","0.0.0.0"), |
| 51: IntField("lease_time", 43200), |
| 54: IPField("server_id","0.0.0.0"), |
| 55: "param_req_list", |
| 57: ShortField("max_dhcp_size", 1500), |
| 58: IntField("renewal_time", 21600), |
| 59: IntField("rebinding_time", 37800), |
| 60: "vendor_class_id", |
| 61: "client_id", |
| |
| 64: "NISplus_domain", |
| 65: IPField("NISplus_server","0.0.0.0"), |
| 69: IPField("SMTP_server","0.0.0.0"), |
| 70: IPField("POP3_server","0.0.0.0"), |
| 71: IPField("NNTP_server","0.0.0.0"), |
| 72: IPField("WWW_server","0.0.0.0"), |
| 73: IPField("Finger_server","0.0.0.0"), |
| 74: IPField("IRC_server","0.0.0.0"), |
| 75: IPField("StreetTalk_server","0.0.0.0"), |
| 76: "StreetTalk_Dir_Assistance", |
| 82: "relay_agent_Information", |
| 53: ByteEnumField("message-type", 1, DHCPTypes), |
| # 55: DHCPRequestListField("request-list"), |
| 255: "end" |
| } |
| |
| DHCPRevOptions = {} |
| |
| for k,v in DHCPOptions.iteritems(): |
| if type(v) is str: |
| n = v |
| v = None |
| else: |
| n = str(v) |
| DHCPRevOptions[n] = (k,v) |
| del(n) |
| del(v) |
| del(k) |
| |
| |
| |
| |
| |
| class DHCPOptionsField(StrField): |
| islist=1 |
| def i2repr(self,pkt,x): |
| s = [] |
| for v in x: |
| if type(v) is tuple and len(v) == 2: |
| if DHCPRevOptions.has_key(v[0]) and isinstance(DHCPRevOptions[v[0]][1],Field): |
| f = DHCPRevOptions[v[0]][1] |
| vv = f.i2repr(pkt,v[1]) |
| else: |
| vv = repr(v[1]) |
| s.append("%s=%s" % (v[0],vv)) |
| else: |
| s.append(str(v)) |
| return "[%s]" % (" ".join(s)) |
| |
| def getfield(self, pkt, s): |
| return "", self.m2i(pkt, s) |
| def m2i(self, pkt, x): |
| opt = [] |
| while x: |
| o = ord(x[0]) |
| if o == 255: |
| opt.append("end") |
| x = x[1:] |
| continue |
| if o == 0: |
| opt.append("pad") |
| x = x[1:] |
| continue |
| if DHCPOptions.has_key(o): |
| f = DHCPOptions[o] |
| |
| if isinstance(f, str): |
| olen = ord(x[1]) |
| opt.append( (f,x[2:olen+2]) ) |
| x = x[olen+2:] |
| else: |
| olen = ord(x[1]) |
| left, val = f.getfield(pkt,x[2:olen+2]) |
| # val = f.m2i(pkt,val) |
| # if left: |
| # print "m2i data left left=%s" % left |
| opt.append((f.name, val)) |
| x = x[olen+2:] |
| else: |
| olen = ord(x[1]) |
| opt.append((o, x[2:olen+2])) |
| x = x[olen+2:] |
| return opt |
| def i2m(self, pkt, x): |
| #print "i2m x=%s" % x |
| s = "" |
| for o in x: |
| if type(o) is tuple and len(o) == 2: |
| name, val = o |
| |
| if isinstance(name, int): |
| onum, oval = name, val |
| elif DHCPRevOptions.has_key(name): |
| onum, f = DHCPRevOptions[name] |
| if f is None: |
| oval = val |
| else: |
| # oval = f.addfield(pkt,"",f.i2m(pkt,f.any2i(pkt,val))) |
| oval = f.addfield(pkt,"",f.any2i(pkt,val)) |
| |
| else: |
| warning("Unknown field option %s" % name) |
| continue |
| |
| s += chr(onum) |
| s += chr(len(oval)) |
| s += oval |
| |
| elif (type(o) is str and DHCPRevOptions.has_key(o) and |
| DHCPRevOptions[o][1] == None): |
| s += chr(DHCPRevOptions[o][0]) |
| elif type(o) is int: |
| s += chr(o) |
| else: |
| warning("Malformed option %s" % o) |
| return s |
| |
| |
| class DHCP(Packet): |
| name = "DHCP options" |
| fields_desc = [ DHCPOptionsField("options","") ] |
| |
| |
| class Dot11(Packet): |
| name = "802.11" |
| fields_desc = [ |
| BitField("subtype", 0, 4), |
| BitEnumField("type", 0, 2, ["Management", "Control", "Data", "Reserved"]), |
| BitField("proto", 0, 2), |
| FlagsField("FCfield", 0, 8, ["to-DS", "from-DS", "MF", "retry", "pw-mgt", "MD", "wep", "order"]), |
| ShortField("ID",0), |
| MACField("addr1", ETHER_ANY), |
| Dot11Addr2MACField("addr2", ETHER_ANY), |
| Dot11Addr3MACField("addr3", ETHER_ANY), |
| Dot11SCField("SC", 0), |
| Dot11Addr4MACField("addr4", ETHER_ANY) |
| ] |
| def mysummary(self): |
| return self.sprintf("802.11 %Dot11.type% %Dot11.subtype% %Dot11.addr2% > %Dot11.addr1%") |
| def guess_payload_class(self, payload): |
| if self.FCfield & 0x40: |
| return Dot11WEP |
| else: |
| return Packet.guess_payload_class(self, payload) |
| def answers(self, other): |
| if isinstance(other,Dot11): |
| if self.type == 0: # management |
| if self.addr1 != other.addr2: # check resp DA w/ req SA |
| return 0 |
| if (other.subtype,self.subtype) in [(0,1),(2,3),(4,5)]: |
| return 1 |
| if self.subtype == other.subtype == 11: # auth |
| return self.payload.answers(other.payload) |
| elif self.type == 1: # control |
| return 0 |
| elif self.type == 2: # data |
| return self.payload.answers(other.payload) |
| elif self.type == 3: # reserved |
| return 0 |
| return 0 |
| def unwep(self, key=None, warn=1): |
| if self.FCfield & 0x40 == 0: |
| if warn: |
| warning("No WEP to remove") |
| return |
| if isinstance(self.payload.payload, NoPayload): |
| if key or conf.wepkey: |
| self.payload.decrypt(key) |
| if isinstance(self.payload.payload, NoPayload): |
| if warn: |
| warning("Dot11 can't be decrypted. Check conf.wepkey.") |
| return |
| self.FCfield &= ~0x40 |
| self.payload=self.payload.payload |
| |
| |
| capability_list = [ "res8", "res9", "short-slot", "res11", |
| "res12", "DSSS-OFDM", "res14", "res15", |
| "ESS", "IBSS", "CFP", "CFP-req", |
| "privacy", "short-preamble", "PBCC", "agility"] |
| |
| reason_code = {0:"reserved",1:"unspec", 2:"auth-expired", |
| 3:"deauth-ST-leaving", |
| 4:"inactivity", 5:"AP-full", 6:"class2-from-nonauth", |
| 7:"class3-from-nonass", 8:"disas-ST-leaving", |
| 9:"ST-not-auth"} |
| |
| status_code = {0:"success", 1:"failure", 10:"cannot-support-all-cap", |
| 11:"inexist-asso", 12:"asso-denied", 13:"algo-unsupported", |
| 14:"bad-seq-num", 15:"challenge-failure", |
| 16:"timeout", 17:"AP-full",18:"rate-unsupported" } |
| |
| class Dot11Beacon(Packet): |
| name = "802.11 Beacon" |
| fields_desc = [ LELongField("timestamp", 0), |
| LEShortField("beacon_interval", 0x0064), |
| FlagsField("cap", 0, 16, capability_list) ] |
| |
| |
| class Dot11Elt(Packet): |
| name = "802.11 Information Element" |
| fields_desc = [ ByteEnumField("ID", 0, {0:"SSID", 1:"Rates", 2: "FHset", 3:"DSset", 4:"CFset", 5:"TIM", 6:"IBSSset", 16:"challenge", |
| 42:"ERPinfo", 47:"ERPinfo", 48:"RSNinfo", 50:"ESRates",221:"vendor",68:"reserved"}), |
| FieldLenField("len", None, "info", "B"), |
| StrLenField("info", "", "len") ] |
| def mysummary(self): |
| if self.ID == 0: |
| return "SSID=%s"%repr(self.info),[Dot11] |
| else: |
| return "" |
| |
| class Dot11ATIM(Packet): |
| name = "802.11 ATIM" |
| |
| class Dot11Disas(Packet): |
| name = "802.11 Disassociation" |
| fields_desc = [ LEShortEnumField("reason", 1, reason_code) ] |
| |
| class Dot11AssoReq(Packet): |
| name = "802.11 Association Request" |
| fields_desc = [ FlagsField("cap", 0, 16, capability_list), |
| LEShortField("listen_interval", 0x00c8) ] |
| |
| |
| class Dot11AssoResp(Packet): |
| name = "802.11 Association Response" |
| fields_desc = [ FlagsField("cap", 0, 16, capability_list), |
| LEShortField("status", 0), |
| LEShortField("AID", 0) ] |
| |
| class Dot11ReassoReq(Packet): |
| name = "802.11 Reassociation Request" |
| fields_desc = [ FlagsField("cap", 0, 16, capability_list), |
| MACField("current_AP", ETHER_ANY), |
| LEShortField("listen_interval", 0x00c8) ] |
| |
| |
| class Dot11ReassoResp(Dot11AssoResp): |
| name = "802.11 Reassociation Response" |
| |
| class Dot11ProbeReq(Packet): |
| name = "802.11 Probe Request" |
| |
| class Dot11ProbeResp(Packet): |
| name = "802.11 Probe Response" |
| fields_desc = [ LELongField("timestamp", 0), |
| LEShortField("beacon_interval", 0x0064), |
| FlagsField("cap", 0, 16, capability_list) ] |
| |
| class Dot11Auth(Packet): |
| name = "802.11 Authentication" |
| fields_desc = [ LEShortEnumField("algo", 0, ["open", "sharedkey"]), |
| LEShortField("seqnum", 0), |
| LEShortEnumField("status", 0, status_code) ] |
| def answers(self, other): |
| if self.seqnum == other.seqnum+1: |
| return 1 |
| return 0 |
| |
| class Dot11Deauth(Packet): |
| name = "802.11 Deauthentication" |
| fields_desc = [ LEShortEnumField("reason", 1, reason_code) ] |
| |
| |
| |
| class Dot11WEP(Packet): |
| name = "802.11 WEP packet" |
| fields_desc = [ StrFixedLenField("iv", "\0\0\0", 3), |
| ByteField("keyid", 0), |
| StrField("wepdata",None,remain=4), |
| IntField("icv",None) ] |
| |
| def post_dissect(self, s): |
| # self.icv, = struct.unpack("!I",self.wepdata[-4:]) |
| # self.wepdata = self.wepdata[:-4] |
| self.decrypt() |
| |
| def build_payload(self): |
| if self.wepdata is None: |
| return Packet.build_payload(self) |
| return "" |
| |
| def post_build(self, p, pay): |
| if self.wepdata is None: |
| key = conf.wepkey |
| if key: |
| if self.icv is None: |
| pay += struct.pack("<I",crc32(pay)) |
| icv = "" |
| else: |
| icv = p[4:8] |
| c = ARC4.new(self.iv+key) |
| p = p[:4]+c.encrypt(pay)+icv |
| else: |
| warning("No WEP key set (conf.wepkey).. strange results expected..") |
| return p |
| |
| |
| def decrypt(self,key=None): |
| if key is None: |
| key = conf.wepkey |
| if key: |
| c = ARC4.new(self.iv+key) |
| self.add_payload(LLC(c.decrypt(self.wepdata))) |
| |
| |
| |
| class PrismHeader(Packet): |
| """ iwpriv wlan0 monitor 3 """ |
| name = "Prism header" |
| fields_desc = [ LEIntField("msgcode",68), |
| LEIntField("len",144), |
| StrFixedLenField("dev","",16), |
| LEIntField("hosttime_did",0), |
| LEShortField("hosttime_status",0), |
| LEShortField("hosttime_len",0), |
| LEIntField("hosttime",0), |
| LEIntField("mactime_did",0), |
| LEShortField("mactime_status",0), |
| LEShortField("mactime_len",0), |
| LEIntField("mactime",0), |
| LEIntField("channel_did",0), |
| LEShortField("channel_status",0), |
| LEShortField("channel_len",0), |
| LEIntField("channel",0), |
| LEIntField("rssi_did",0), |
| LEShortField("rssi_status",0), |
| LEShortField("rssi_len",0), |
| LEIntField("rssi",0), |
| LEIntField("sq_did",0), |
| LEShortField("sq_status",0), |
| LEShortField("sq_len",0), |
| LEIntField("sq",0), |
| LEIntField("signal_did",0), |
| LEShortField("signal_status",0), |
| LEShortField("signal_len",0), |
| LESignedIntField("signal",0), |
| LEIntField("noise_did",0), |
| LEShortField("noise_status",0), |
| LEShortField("noise_len",0), |
| LEIntField("noise",0), |
| LEIntField("rate_did",0), |
| LEShortField("rate_status",0), |
| LEShortField("rate_len",0), |
| LEIntField("rate",0), |
| LEIntField("istx_did",0), |
| LEShortField("istx_status",0), |
| LEShortField("istx_len",0), |
| LEIntField("istx",0), |
| LEIntField("frmlen_did",0), |
| LEShortField("frmlen_status",0), |
| LEShortField("frmlen_len",0), |
| LEIntField("frmlen",0), |
| ] |
| |
| |
| |
| class HSRP(Packet): |
| name = "HSRP" |
| fields_desc = [ |
| ByteField("version", 0), |
| ByteEnumField("opcode", 0, { 0:"Hello"}), |
| ByteEnumField("state", 16, { 16:"Active"}), |
| ByteField("hellotime", 3), |
| ByteField("holdtime", 10), |
| ByteField("priority", 120), |
| ByteField("group", 1), |
| ByteField("reserved", 0), |
| StrFixedLenField("auth","cisco",8), |
| IPField("virtualIP","192.168.1.1") ] |
| |
| |
| |
| |
| |
| |
| |
| class NTP(Packet): |
| # RFC 1769 |
| name = "NTP" |
| fields_desc = [ |
| BitEnumField('leap', 0, 2, |
| { 0: 'nowarning', |
| 1: 'longminute', |
| 2: 'shortminute', |
| 3: 'notsync'}), |
| BitField('version', 3, 3), |
| BitEnumField('mode', 3, 3, |
| { 0: 'reserved', |
| 1: 'sym_active', |
| 2: 'sym_passive', |
| 3: 'client', |
| 4: 'server', |
| 5: 'broadcast', |
| 6: 'control', |
| 7: 'private'}), |
| BitField('stratum', 2, 8), |
| BitField('poll', 0xa, 8), ### XXX : it's a signed int |
| BitField('precision', 0, 8), ### XXX : it's a signed int |
| FloatField('delay', 0, 32), |
| FloatField('dispersion', 0, 32), |
| IPField('id', "127.0.0.1"), |
| TimeStampField('ref', 0, 64), |
| TimeStampField('orig', -1, 64), # -1 means current time |
| TimeStampField('recv', 0, 64), |
| TimeStampField('sent', -1, 64) |
| ] |
| def mysummary(self): |
| return self.sprintf("NTP v%ir,NTP.version%, %NTP.mode%") |
| |
| |
| class GRE(Packet): |
| name = "GRE" |
| fields_desc = [ BitField("chksumpresent",0,1), |
| BitField("reserved0",0,12), |
| BitField("version",0,3), |
| XShortEnumField("proto", 0x0000, ETHER_TYPES), |
| ConditionalField(XShortField("chksum",None),"chksumpresent",lambda x:x==1), |
| ConditionalField(XShortField("reserved1",None),"chksumpresent",lambda x:x==1), |
| ] |
| def post_build(self, p, pay): |
| p += pay |
| if self.chksumpresent and self.chksum is None: |
| c = checksum(p) |
| p = p[:4]+chr((c>>8)&0xff)+chr(c&0xff)+p[6:] |
| return p |
| |
| |
| class Radius(Packet): |
| name = "Radius" |
| fields_desc = [ ByteEnumField("code", 1, {1: "Access-Request", |
| 2: "Access-Accept", |
| 3: "Access-Reject", |
| 4: "Accounting-Request", |
| 5: "Accounting-Accept", |
| 6: "Accounting-Status", |
| 7: "Password-Request", |
| 8: "Password-Ack", |
| 9: "Password-Reject", |
| 10: "Accounting-Message", |
| 11: "Access-Challenge", |
| 12: "Status-Server", |
| 13: "Status-Client", |
| 21: "Resource-Free-Request", |
| 22: "Resource-Free-Response", |
| 23: "Resource-Query-Request", |
| 24: "Resource-Query-Response", |
| 25: "Alternate-Resource-Reclaim-Request", |
| 26: "NAS-Reboot-Request", |
| 27: "NAS-Reboot-Response", |
| 29: "Next-Passcode", |
| 30: "New-Pin", |
| 31: "Terminate-Session", |
| 32: "Password-Expired", |
| 33: "Event-Request", |
| 34: "Event-Response", |
| 40: "Disconnect-Request", |
| 41: "Disconnect-ACK", |
| 42: "Disconnect-NAK", |
| 43: "CoA-Request", |
| 44: "CoA-ACK", |
| 45: "CoA-NAK", |
| 50: "IP-Address-Allocate", |
| 51: "IP-Address-Release", |
| 253: "Experimental-use", |
| 254: "Reserved", |
| 255: "Reserved"} ), |
| ByteField("id", 0), |
| ShortField("len", None), |
| StrFixedLenField("authenticator","",16) ] |
| def post_build(self, p, pay): |
| p += pay |
| l = self.len |
| if l is None: |
| l = len(p) |
| p = p[:2]+struct.pack("!H",l)+p[4:] |
| return p |
| |
| |
| |
| |
| class RIP(Packet): |
| name = "RIP header" |
| fields_desc = [ |
| ByteEnumField("command",1,{1:"req",2:"resp",3:"traceOn",4:"traceOff",5:"sun", |
| 6:"trigReq",7:"trigResp",8:"trigAck",9:"updateReq", |
| 10:"updateResp",11:"updateAck"}), |
| ByteField("version",1), |
| ShortField("null",0), |
| ] |
| |
| class RIPEntry(Packet): |
| name = "RIP entry" |
| fields_desc = [ |
| ShortEnumField("AF",2,{2:"IP"}), |
| ShortField("RouteTag",0), |
| IPField("addr","0.0.0.0"), |
| IPField("mask","0.0.0.0"), |
| IPField("nextHop","0.0.0.0"), |
| IntEnumField("metric",1,{16:"Unreach"}), |
| ] |
| |
| |
| |
| |
| ISAKMP_payload_type = ["None","SA","Proposal","Transform","KE","ID","CERT","CR","Hash", |
| "SIG","Nonce","Notification","Delete","VendorID"] |
| |
| ISAKMP_exchange_type = ["None","base","identity prot.", |
| "auth only", "aggressive", "info"] |
| |
| |
| class ISAKMP_class(Packet): |
| def guess_payload_class(self, payload): |
| np = self.next_payload |
| if np == 0: |
| return Raw |
| elif np < len(ISAKMP_payload_type): |
| pt = ISAKMP_payload_type[np] |
| return globals().get("ISAKMP_payload_%s" % pt, ISAKMP_payload) |
| else: |
| return ISAKMP_payload |
| |
| |
| class ISAKMP(ISAKMP_class): # rfc2408 |
| name = "ISAKMP" |
| fields_desc = [ |
| StrFixedLenField("init_cookie","",8), |
| StrFixedLenField("resp_cookie","",8), |
| ByteEnumField("next_payload",0,ISAKMP_payload_type), |
| XByteField("version",0x10), |
| ByteEnumField("exch_type",0,ISAKMP_exchange_type), |
| FlagsField("flags",0, 8, ["encryption","commit","auth_only","res3","res4","res5","res6","res7"]), # XXX use a Flag field |
| IntField("id",0), |
| IntField("length",None) |
| ] |
| |
| def guess_payload_class(self, payload): |
| if self.flags & 1: |
| return Raw |
| return ISAKMP_class.guess_payload_class(self, payload) |
| |
| def answers(self, other): |
| if isinstance(other, ISAKMP): |
| if other.init_cookie == self.init_cookie: |
| return 1 |
| return 0 |
| def post_build(self, p, pay): |
| p += pay |
| if self.length is None: |
| p = p[:24]+struct.pack("!I",len(p))+p[28:] |
| return p |
| |
| |
| |
| |
| class ISAKMP_payload_Transform(ISAKMP_class): |
| name = "IKE Transform" |
| fields_desc = [ |
| ByteEnumField("next_payload",None,ISAKMP_payload_type), |
| ByteField("res",0), |
| # ShortField("len",None), |
| ShortField("length",None), |
| ByteField("num",None), |
| ByteEnumField("id",1,{1:"KEY_IKE"}), |
| ShortField("res2",0), |
| ISAKMPTransformSetField("transforms",None,"length",shift=8) |
| # XIntField("enc",0x80010005L), |
| # XIntField("hash",0x80020002L), |
| # XIntField("auth",0x80030001L), |
| # XIntField("group",0x80040002L), |
| # XIntField("life_type",0x800b0001L), |
| # XIntField("durationh",0x000c0004L), |
| # XIntField("durationl",0x00007080L), |
| ] |
| def post_build(self, p, pay): |
| if self.length is None: |
| l = len(p) |
| p = p[:2]+chr((l>>8)&0xff)+chr(l&0xff)+p[4:] |
| p += pay |
| return p |
| |
| |
| |
| |
| class ISAKMP_payload_Proposal(ISAKMP_class): |
| name = "IKE proposal" |
| # ISAKMP_payload_type = 0 |
| fields_desc = [ |
| ByteEnumField("next_payload",None,ISAKMP_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"trans","H"), |
| ByteField("proposal",1), |
| ByteEnumField("proto",1,{1:"ISAKMP"}), |
| FieldLenField("SPIsize",None,"SPI","B"), |
| ByteField("trans_nb",None), |
| StrLenField("SPI","","SPIsize"), |
| PacketLenField("trans",Raw(),ISAKMP_payload_Transform,"length",shift=8), |
| ] |
| |
| |
| class ISAKMP_payload(ISAKMP_class): |
| name = "ISAKMP payload" |
| fields_desc = [ |
| ByteEnumField("next_payload",None,ISAKMP_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"load","H"), |
| StrLenField("load","","length",shift=4), |
| ] |
| |
| |
| class ISAKMP_payload_VendorID(ISAKMP_class): |
| name = "ISAKMP Vendor ID" |
| overload_fields = { ISAKMP: { "next_payload":13 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,ISAKMP_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"vendorID","H"), |
| StrLenField("vendorID","","length",shift=4), |
| ] |
| |
| class ISAKMP_payload_SA(ISAKMP_class): |
| name = "ISAKMP SA" |
| overload_fields = { ISAKMP: { "next_payload":1 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,ISAKMP_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"prop","H"), |
| IntEnumField("DOI",1,{1:"IPSEC"}), |
| IntEnumField("situation",1,{1:"identity"}), |
| PacketLenField("prop",Raw(),ISAKMP_payload_Proposal,"length",shift=12), |
| ] |
| |
| class ISAKMP_payload_Nonce(ISAKMP_class): |
| name = "ISAKMP Nonce" |
| overload_fields = { ISAKMP: { "next_payload":10 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,ISAKMP_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"load","H"), |
| StrLenField("load","","length",shift=4), |
| ] |
| |
| class ISAKMP_payload_KE(ISAKMP_class): |
| name = "ISAKMP Key Exchange" |
| overload_fields = { ISAKMP: { "next_payload":4 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,ISAKMP_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"load","H"), |
| StrLenField("load","","length",shift=4), |
| ] |
| |
| class ISAKMP_payload_ID(ISAKMP_class): |
| name = "ISAKMP Identification" |
| overload_fields = { ISAKMP: { "next_payload":5 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,ISAKMP_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"load","H"), |
| ByteEnumField("IDtype",1,{1:"IPv4_addr", 11:"Key"}), |
| ByteEnumField("ProtoID",0,{0:"Unused"}), |
| ShortEnumField("Port",0,{0:"Unused"}), |
| # IPField("IdentData","127.0.0.1"), |
| StrLenField("load","","length",shift=8), |
| ] |
| |
| |
| |
| class ISAKMP_payload_Hash(ISAKMP_class): |
| name = "ISAKMP Hash" |
| overload_fields = { ISAKMP: { "next_payload":8 }} |
| fields_desc = [ |
| ByteEnumField("next_payload",None,ISAKMP_payload_type), |
| ByteField("res",0), |
| FieldLenField("length",None,"load","H"), |
| StrLenField("load","","length",shift=4), |
| ] |
| |
| |
| |
| ISAKMP_payload_type_overload = {} |
| for i in range(len(ISAKMP_payload_type)): |
| name = "ISAKMP_payload_%s" % ISAKMP_payload_type[i] |
| if name in globals(): |
| ISAKMP_payload_type_overload[globals()[name]] = {"next_payload":i} |
| |
| del(i) |
| del(name) |
| ISAKMP_class.overload_fields = ISAKMP_payload_type_overload.copy() |
| |
| |
| |
| |
| # Cisco Skinny protocol |
| |
| # shamelessly ripped from Ethereal dissector |
| skinny_messages = { |
| # Station -> Callmanager |
| 0x0000: "KeepAliveMessage", |
| 0x0001: "RegisterMessage", |
| 0x0002: "IpPortMessage", |
| 0x0003: "KeypadButtonMessage", |
| 0x0004: "EnblocCallMessage", |
| 0x0005: "StimulusMessage", |
| 0x0006: "OffHookMessage", |
| 0x0007: "OnHookMessage", |
| 0x0008: "HookFlashMessage", |
| 0x0009: "ForwardStatReqMessage", |
| 0x000A: "SpeedDialStatReqMessage", |
| 0x000B: "LineStatReqMessage", |
| 0x000C: "ConfigStatReqMessage", |
| 0x000D: "TimeDateReqMessage", |
| 0x000E: "ButtonTemplateReqMessage", |
| 0x000F: "VersionReqMessage", |
| 0x0010: "CapabilitiesResMessage", |
| 0x0011: "MediaPortListMessage", |
| 0x0012: "ServerReqMessage", |
| 0x0020: "AlarmMessage", |
| 0x0021: "MulticastMediaReceptionAck", |
| 0x0022: "OpenReceiveChannelAck", |
| 0x0023: "ConnectionStatisticsRes", |
| 0x0024: "OffHookWithCgpnMessage", |
| 0x0025: "SoftKeySetReqMessage", |
| 0x0026: "SoftKeyEventMessage", |
| 0x0027: "UnregisterMessage", |
| 0x0028: "SoftKeyTemplateReqMessage", |
| 0x0029: "RegisterTokenReq", |
| 0x002A: "MediaTransmissionFailure", |
| 0x002B: "HeadsetStatusMessage", |
| 0x002C: "MediaResourceNotification", |
| 0x002D: "RegisterAvailableLinesMessage", |
| 0x002E: "DeviceToUserDataMessage", |
| 0x002F: "DeviceToUserDataResponseMessage", |
| 0x0030: "UpdateCapabilitiesMessage", |
| 0x0031: "OpenMultiMediaReceiveChannelAckMessage", |
| 0x0032: "ClearConferenceMessage", |
| 0x0033: "ServiceURLStatReqMessage", |
| 0x0034: "FeatureStatReqMessage", |
| 0x0035: "CreateConferenceResMessage", |
| 0x0036: "DeleteConferenceResMessage", |
| 0x0037: "ModifyConferenceResMessage", |
| 0x0038: "AddParticipantResMessage", |
| 0x0039: "AuditConferenceResMessage", |
| 0x0040: "AuditParticipantResMessage", |
| 0x0041: "DeviceToUserDataVersion1Message", |
| # Callmanager -> Station */ |
| 0x0081: "RegisterAckMessage", |
| 0x0082: "StartToneMessage", |
| 0x0083: "StopToneMessage", |
| 0x0085: "SetRingerMessage", |
| 0x0086: "SetLampMessage", |
| 0x0087: "SetHkFDetectMessage", |
| 0x0088: "SetSpeakerModeMessage", |
| 0x0089: "SetMicroModeMessage", |
| 0x008A: "StartMediaTransmission", |
| 0x008B: "StopMediaTransmission", |
| 0x008C: "StartMediaReception", |
| 0x008D: "StopMediaReception", |
| 0x008F: "CallInfoMessage", |
| 0x0090: "ForwardStatMessage", |
| 0x0091: "SpeedDialStatMessage", |
| 0x0092: "LineStatMessage", |
| 0x0093: "ConfigStatMessage", |
| 0x0094: "DefineTimeDate", |
| 0x0095: "StartSessionTransmission", |
| 0x0096: "StopSessionTransmission", |
| 0x0097: "ButtonTemplateMessage", |
| 0x0098: "VersionMessage", |
| 0x0099: "DisplayTextMessage", |
| 0x009A: "ClearDisplay", |
| 0x009B: "CapabilitiesReqMessage", |
| 0x009C: "EnunciatorCommandMessage", |
| 0x009D: "RegisterRejectMessage", |
| 0x009E: "ServerResMessage", |
| 0x009F: "Reset", |
| 0x0100: "KeepAliveAckMessage", |
| 0x0101: "StartMulticastMediaReception", |
| 0x0102: "StartMulticastMediaTransmission", |
| 0x0103: "StopMulticastMediaReception", |
| 0x0104: "StopMulticastMediaTransmission", |
| 0x0105: "OpenReceiveChannel", |
| 0x0106: "CloseReceiveChannel", |
| 0x0107: "ConnectionStatisticsReq", |
| 0x0108: "SoftKeyTemplateResMessage", |
| 0x0109: "SoftKeySetResMessage", |
| 0x0110: "SelectSoftKeysMessage", |
| 0x0111: "CallStateMessage", |
| 0x0112: "DisplayPromptStatusMessage", |
| 0x0113: "ClearPromptStatusMessage", |
| 0x0114: "DisplayNotifyMessage", |
| 0x0115: "ClearNotifyMessage", |
| 0x0116: "ActivateCallPlaneMessage", |
| 0x0117: "DeactivateCallPlaneMessage", |
| 0x0118: "UnregisterAckMessage", |
| 0x0119: "BackSpaceReqMessage", |
| 0x011A: "RegisterTokenAck", |
| 0x011B: "RegisterTokenReject", |
| 0x0042: "DeviceToUserDataResponseVersion1Message", |
| 0x011C: "StartMediaFailureDetection", |
| 0x011D: "DialedNumberMessage", |
| 0x011E: "UserToDeviceDataMessage", |
| 0x011F: "FeatureStatMessage", |
| 0x0120: "DisplayPriNotifyMessage", |
| 0x0121: "ClearPriNotifyMessage", |
| 0x0122: "StartAnnouncementMessage", |
| 0x0123: "StopAnnouncementMessage", |
| 0x0124: "AnnouncementFinishMessage", |
| 0x0127: "NotifyDtmfToneMessage", |
| 0x0128: "SendDtmfToneMessage", |
| 0x0129: "SubscribeDtmfPayloadReqMessage", |
| 0x012A: "SubscribeDtmfPayloadResMessage", |
| 0x012B: "SubscribeDtmfPayloadErrMessage", |
| 0x012C: "UnSubscribeDtmfPayloadReqMessage", |
| 0x012D: "UnSubscribeDtmfPayloadResMessage", |
| 0x012E: "UnSubscribeDtmfPayloadErrMessage", |
| 0x012F: "ServiceURLStatMessage", |
| 0x0130: "CallSelectStatMessage", |
| 0x0131: "OpenMultiMediaChannelMessage", |
| 0x0132: "StartMultiMediaTransmission", |
| 0x0133: "StopMultiMediaTransmission", |
| 0x0134: "MiscellaneousCommandMessage", |
| 0x0135: "FlowControlCommandMessage", |
| 0x0136: "CloseMultiMediaReceiveChannel", |
| 0x0137: "CreateConferenceReqMessage", |
| 0x0138: "DeleteConferenceReqMessage", |
| 0x0139: "ModifyConferenceReqMessage", |
| 0x013A: "AddParticipantReqMessage", |
| 0x013B: "DropParticipantReqMessage", |
| 0x013C: "AuditConferenceReqMessage", |
| 0x013D: "AuditParticipantReqMessage", |
| 0x013F: "UserToDeviceDataVersion1Message", |
| } |
| |
| |
| |
| class Skinny(Packet): |
| name="Skinny" |
| fields_desc = [ LEIntField("len",0), |
| LEIntField("res",0), |
| LEIntEnumField("msg",0,skinny_messages) ] |
| |
| |
| |
| ### SEBEK |
| |
| |
| class SebekHead(Packet): |
| name = "Sebek header" |
| fields_desc = [ XIntField("magic", 0xd0d0d0), |
| ShortField("version", 1), |
| ShortEnumField("type", 0, {"read":0, "write":1, |
| "socket":2, "open":3}), |
| IntField("counter", 0), |
| IntField("time_sec", 0), |
| IntField("time_usec", 0) ] |
| def mysummary(self): |
| return self.sprintf("Sebek Header v%SebekHead.version% %SebekHead.type%") |
| |
| # we need this because Sebek headers differ between v1 and v3, and |
| # between v3 type socket and v3 others |
| |
| class SebekV1(Packet): |
| name = "Sebek v1" |
| fields_desc = [ IntField("pid", 0), |
| IntField("uid", 0), |
| IntField("fd", 0), |
| StrFixedLenField("command", "", 12), |
| FieldLenField("data_length", None, "data",fmt="I"), |
| StrLenField("data", "", "data_length") ] |
| def mysummary(self): |
| if isinstance(self.underlayer, SebekHead): |
| return self.underlayer.sprintf("Sebek v1 %SebekHead.type% (%SebekV1.command%)") |
| else: |
| return self.sprintf("Sebek v1 (%SebekV1.command%)") |
| |
| class SebekV3(Packet): |
| name = "Sebek v3" |
| fields_desc = [ IntField("parent_pid", 0), |
| IntField("pid", 0), |
| IntField("uid", 0), |
| IntField("fd", 0), |
| IntField("inode", 0), |
| StrFixedLenField("command", "", 12), |
| FieldLenField("data_length", None, "data",fmt="I"), |
| StrLenField("data", "", "data_length") ] |
| def mysummary(self): |
| if isinstance(self.underlayer, SebekHead): |
| return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV3.command%)") |
| else: |
| return self.sprintf("Sebek v3 (%SebekV3.command%)") |
| |
| class SebekV2(SebekV3): |
| def mysummary(self): |
| if isinstance(self.underlayer, SebekHead): |
| return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV2.command%)") |
| else: |
| return self.sprintf("Sebek v2 (%SebekV2.command%)") |
| |
| class SebekV3Sock(Packet): |
| name = "Sebek v2 socket" |
| fields_desc = [ IntField("parent_pid", 0), |
| IntField("pid", 0), |
| IntField("uid", 0), |
| IntField("fd", 0), |
| IntField("inode", 0), |
| StrFixedLenField("command", "", 12), |
| IntField("data_length", 15), |
| IPField("dip", "127.0.0.1"), |
| ShortField("dport", 0), |
| IPField("sip", "127.0.0.1"), |
| ShortField("sport", 0), |
| ShortEnumField("call", 0, { "bind":2, |
| "connect":3, "listen":4, |
| "accept":5, "sendmsg":16, |
| "recvmsg":17, "sendto":11, |
| "recvfrom":12}), |
| ByteEnumField("proto", 0, IP_PROTOS) ] |
| def mysummary(self): |
| if isinstance(self.underlayer, SebekHead): |
| return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV3Sock.command%)") |
| else: |
| return self.sprintf("Sebek v3 socket (%SebekV3Sock.command%)") |
| |
| class SebekV2Sock(SebekV3Sock): |
| def mysummary(self): |
| if isinstance(self.underlayer, SebekHead): |
| return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV2Sock.command%)") |
| else: |
| return self.sprintf("Sebek v2 socket (%SebekV2Sock.command%)") |
| |
| class MGCP(Packet): |
| name = "MGCP" |
| longname = "Media Gateway Control Protocol" |
| fields_desc = [ StrStopField("verb","AUEP"," ", -1), |
| StrFixedLenField("sep1"," ",1), |
| StrStopField("transaction_id","1234567"," ", -1), |
| StrFixedLenField("sep2"," ",1), |
| StrStopField("endpoint","dummy@dummy.net"," ", -1), |
| StrFixedLenField("sep3"," ",1), |
| StrStopField("version","MGCP 1.0 NCS 1.0","\x0a", -1), |
| StrFixedLenField("sep4","\x0a",1), |
| ] |
| |
| |
| #class MGCP(Packet): |
| # name = "MGCP" |
| # longname = "Media Gateway Control Protocol" |
| # fields_desc = [ ByteEnumField("type",0, ["request","response","others"]), |
| # ByteField("code0",0), |
| # ByteField("code1",0), |
| # ByteField("code2",0), |
| # ByteField("code3",0), |
| # ByteField("code4",0), |
| # IntField("trasid",0), |
| # IntField("req_time",0), |
| # ByteField("is_duplicate",0), |
| # ByteField("req_available",0) ] |
| # |
| class GPRS(Packet): |
| name = "GPRSdummy" |
| fields_desc = [ |
| StrStopField("dummy","","\x65\x00\x00",1) |
| ] |
| |
| |
| class HCI_Hdr(Packet): |
| name = "HCI header" |
| fields_desc = [ ByteEnumField("type",2,{1:"command",2:"ACLdata",3:"SCOdata",4:"event",5:"vendor"}),] |
| |
| def mysummary(self): |
| return self.sprintf("HCI %type%") |
| |
| class HCI_ACL_Hdr(Packet): |
| name = "HCI ACL header" |
| fields_desc = [ ByteField("handle",0), # Actually, handle is 12 bits and flags is 4. |
| ByteField("flags",0), # I wait to write a LEBitField |
| LEShortField("len",None), ] |
| def post_build(self, p, pay): |
| p += pay |
| if self.len is None: |
| l = len(p)-4 |
| p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:] |
| return p |
| |
| |
| class L2CAP_Hdr(Packet): |
| name = "L2CAP header" |
| fields_desc = [ LEShortField("len",None), |
| LEShortEnumField("cid",0,{1:"control"}),] |
| |
| def post_build(self, p, pay): |
| p += pay |
| if self.len is None: |
| l = len(p)-4 |
| p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:] |
| return p |
| |
| |
| |
| class L2CAP_CmdHdr(Packet): |
| name = "L2CAP command header" |
| fields_desc = [ |
| ByteEnumField("code",8,{1:"rej",2:"conn_req",3:"conn_resp", |
| 4:"conf_req",5:"conf_resp",6:"disconn_req", |
| 7:"disconn_resp",8:"echo_req",9:"echo_resp", |
| 10:"info_req",11:"info_resp"}), |
| ByteField("id",0), |
| LEShortField("len",None) ] |
| def post_build(self, p, pay): |
| p += pay |
| if self.len is None: |
| l = len(p)-4 |
| p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:] |
| return p |
| def answers(self, other): |
| if other.id == self.id: |
| if self.code == 1: |
| return 1 |
| if other.code in [2,4,6,8,10] and self.code == other.code+1: |
| if other.code == 8: |
| return 1 |
| return self.payload.answers(other.payload) |
| return 0 |
| |
| class L2CAP_ConnReq(Packet): |
| name = "L2CAP Conn Req" |
| fields_desc = [ LEShortEnumField("psm",0,{1:"SDP",3:"RFCOMM",5:"telephony control"}), |
| LEShortField("scid",0), |
| ] |
| |
| class L2CAP_ConnResp(Packet): |
| name = "L2CAP Conn Resp" |
| fields_desc = [ LEShortField("dcid",0), |
| LEShortField("scid",0), |
| LEShortEnumField("result",0,["no_info","authen_pend","author_pend"]), |
| LEShortEnumField("status",0,["success","pend","bad_psm", |
| "cr_sec_block","cr_no_mem"]), |
| ] |
| def answers(self, other): |
| return self.scid == other.scid |
| |
| class L2CAP_CmdRej(Packet): |
| name = "L2CAP Command Rej" |
| fields_desc = [ LEShortField("reason",0), |
| ] |
| |
| |
| class L2CAP_ConfReq(Packet): |
| name = "L2CAP Conf Req" |
| fields_desc = [ LEShortField("dcid",0), |
| LEShortField("flags",0), |
| ] |
| |
| class L2CAP_ConfResp(Packet): |
| name = "L2CAP Conf Resp" |
| fields_desc = [ LEShortField("scid",0), |
| LEShortField("flags",0), |
| LEShortEnumField("result",0,["success","unaccept","reject","unknown"]), |
| ] |
| def answers(self, other): |
| return self.scid == other.scid |
| |
| |
| class L2CAP_DisconnReq(Packet): |
| name = "L2CAP Disconn Req" |
| fields_desc = [ LEShortField("dcid",0), |
| LEShortField("scid",0), ] |
| |
| class L2CAP_DisconnResp(Packet): |
| name = "L2CAP Disconn Resp" |
| fields_desc = [ LEShortField("dcid",0), |
| LEShortField("scid",0), ] |
| def answers(self, other): |
| return self.scid == other.scid |
| |
| |
| |
| class L2CAP_InfoReq(Packet): |
| name = "L2CAP Info Req" |
| fields_desc = [ LEShortEnumField("type",0,{1:"CL_MTU",2:"FEAT_MASK"}), |
| StrField("data","") |
| ] |
| |
| |
| class L2CAP_InfoResp(Packet): |
| name = "L2CAP Info Resp" |
| fields_desc = [ LEShortField("type",0), |
| LEShortEnumField("result",0,["success","not_supp"]), |
| StrField("data",""), ] |
| def answers(self, other): |
| return self.type == other.type |
| |
| |
| |
| |
| class NetBIOS_DS(Packet): |
| name = "NetBIOS datagram service" |
| fields_desc = [ |
| ByteEnumField("type",17, {17:"direct_group"}), |
| ByteField("flags",0), |
| XShortField("id",0), |
| IPField("src","127.0.0.1"), |
| ShortField("sport",138), |
| ShortField("len",None), |
| ShortField("ofs",0), |
| NetBIOSNameField("srcname",""), |
| NetBIOSNameField("dstname",""), |
| ] |
| def post_build(self, p, pay): |
| p += pay |
| if self.len is None: |
| l = len(p)-14 |
| p = p[:10]+struct.pack("!H", l)+p[12:] |
| return p |
| |
| # ShortField("length",0), |
| # ShortField("Delimitor",0), |
| # ByteField("command",0), |
| # ByteField("data1",0), |
| # ShortField("data2",0), |
| # ShortField("XMIt",0), |
| # ShortField("RSPCor",0), |
| # StrFixedLenField("dest","",16), |
| # StrFixedLenField("source","",16), |
| # |
| # ] |
| # |
| |
| # IR |
| |
| class IrLAPHead(Packet): |
| name = "IrDA Link Access Protocol Header" |
| fields_desc = [ XBitField("Address", 0x7f, 7), |
| BitEnumField("Type", 1, 1, {"Response":0, |
| "Command":1})] |
| |
| class IrLAPCommand(Packet): |
| name = "IrDA Link Access Protocol Command" |
| fields_desc = [ XByteField("Control", 0), |
| XByteField("Format identifier", 0), |
| XIntField("Source address", 0), |
| XIntField("Destination address", 0xffffffffL), |
| XByteField("Discovery flags", 0x1), |
| ByteEnumField("Slot number", 255, {"final":255}), |
| XByteField("Version", 0)] |
| |
| |
| class IrLMP(Packet): |
| name = "IrDA Link Management Protocol" |
| fields_desc = [ XShortField("Service hints", 0), |
| XByteField("Character set", 0), |
| StrField("Device name", "") ] |
| |
| |
| #NetBIOS |
| |
| |
| # Name Query Request |
| # Node Status Request |
| class NBNSQueryRequest(Packet): |
| name="NBNS query request" |
| fields_desc = [ShortField("NAME_TRN_ID",0), |
| ShortField("FLAGS", 0x0110), |
| ShortField("QDCOUNT",1), |
| ShortField("ANCOUNT",0), |
| ShortField("NSCOUNT",0), |
| ShortField("ARCOUNT",0), |
| NetBIOSNameField("QUESTION_NAME","windows"), |
| ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), |
| ByteField("NULL",0), |
| ShortEnumField("QUESTION_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}), |
| ShortEnumField("QUESTION_CLASS",1,{1:"INTERNET"})] |
| |
| # Name Registration Request |
| # Name Refresh Request |
| # Name Release Request or Demand |
| class NBNSRequest(Packet): |
| name="NBNS request" |
| fields_desc = [ShortField("NAME_TRN_ID",0), |
| ShortField("FLAGS", 0x2910), |
| ShortField("QDCOUNT",1), |
| ShortField("ANCOUNT",0), |
| ShortField("NSCOUNT",0), |
| ShortField("ARCOUNT",1), |
| NetBIOSNameField("QUESTION_NAME","windows"), |
| ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), |
| ByteField("NULL",0), |
| ShortEnumField("QUESTION_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}), |
| ShortEnumField("QUESTION_CLASS",1,{1:"INTERNET"}), |
| ShortEnumField("RR_NAME",0xC00C,{0xC00C:"Label String Pointer to QUESTION_NAME"}), |
| ShortEnumField("RR_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}), |
| ShortEnumField("RR_CLASS",1,{1:"INTERNET"}), |
| IntField("TTL", 0), |
| ShortField("RDLENGTH", 6), |
| BitEnumField("G",0,1,{0:"Unique name",1:"Group name"}), |
| BitEnumField("OWNER NODE TYPE",00,2,{00:"B node",01:"P node",02:"M node",03:"H node"}), |
| BitEnumField("UNUSED",0,13,{0:"Unused"}), |
| IPField("NB_ADDRESS", "127.0.0.1")] |
| |
| # Name Query Response |
| # Name Registration Response |
| class NBNSQueryResponse(Packet): |
| name="NBNS query response" |
| fields_desc = [ShortField("NAME_TRN_ID",0), |
| ShortField("FLAGS", 0x8500), |
| ShortField("QDCOUNT",0), |
| ShortField("ANCOUNT",1), |
| ShortField("NSCOUNT",0), |
| ShortField("ARCOUNT",0), |
| NetBIOSNameField("RR_NAME","windows"), |
| ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), |
| ByteField("NULL",0), |
| ShortEnumField("QUESTION_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}), |
| ShortEnumField("QUESTION_CLASS",1,{1:"INTERNET"}), |
| IntField("TTL", 0x493e0), |
| ShortField("RDLENGTH", 6), |
| ShortField("NB_FLAGS", 0), |
| IPField("NB_ADDRESS", "127.0.0.1")] |
| |
| # Name Query Response (negative) |
| # Name Release Response |
| class NBNSQueryResponseNegative(Packet): |
| name="NBNS query response (negative)" |
| fields_desc = [ShortField("NAME_TRN_ID",0), |
| ShortField("FLAGS", 0x8506), |
| ShortField("QDCOUNT",0), |
| ShortField("ANCOUNT",1), |
| ShortField("NSCOUNT",0), |
| ShortField("ARCOUNT",0), |
| NetBIOSNameField("RR_NAME","windows"), |
| ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), |
| ByteField("NULL",0), |
| ShortEnumField("RR_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}), |
| ShortEnumField("RR_CLASS",1,{1:"INTERNET"}), |
| IntField("TTL",0), |
| ShortField("RDLENGTH",6), |
| BitEnumField("G",0,1,{0:"Unique name",1:"Group name"}), |
| BitEnumField("OWNER NODE TYPE",00,2,{00:"B node",01:"P node",02:"M node",03:"H node"}), |
| BitEnumField("UNUSED",0,13,{0:"Unused"}), |
| IPField("NB_ADDRESS", "127.0.0.1")] |
| |
| # Node Status Response |
| class NBNSNodeStatusResponse(Packet): |
| name="NBNS Node Status Response" |
| fields_desc = [ShortField("NAME_TRN_ID",0), |
| ShortField("FLAGS", 0x8500), |
| ShortField("QDCOUNT",0), |
| ShortField("ANCOUNT",1), |
| ShortField("NSCOUNT",0), |
| ShortField("ARCOUNT",0), |
| NetBIOSNameField("RR_NAME","windows"), |
| ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), |
| ByteField("NULL",0), |
| ShortEnumField("RR_TYPE",0x21, {0x20:"NB",0x21:"NBSTAT"}), |
| ShortEnumField("RR_CLASS",1,{1:"INTERNET"}), |
| IntField("TTL",0), |
| ShortField("RDLENGTH",83), |
| ByteField("NUM_NAMES",1)] |
| |
| # Service for Node Status Response |
| class NBNSNodeStatusResponseService(Packet): |
| name="NBNS Node Status Response Service" |
| fields_desc = [StrFixedLenField("NETBIOS_NAME","WINDOWS ",15), |
| ByteEnumField("SUFFIX",0,{0:"workstation",0x03:"messenger service",0x20:"file server service",0x1b:"domain master browser",0x1c:"domain controller", 0x1e:"browser election service"}), |
| ByteField("NAME_FLAGS",0x4), |
| ByteEnumField("UNUSED",0,{0:"unused"})] |
| |
| # End of Node Status Response packet |
| class NBNSNodeStatusResponseEnd(Packet): |
| name="NBNS Node Status Response" |
| fields_desc = [SourceMACField("MAC_ADDRESS"), |
| BitField("STATISTICS",0,57*8)] |
| |
| # Wait for Acknowledgement Response |
| class NBNSWackResponse(Packet): |
| name="NBNS Wait for Acknowledgement Response" |
| fields_desc = [ShortField("NAME_TRN_ID",0), |
| ShortField("FLAGS", 0xBC07), |
| ShortField("QDCOUNT",0), |
| ShortField("ANCOUNT",1), |
| ShortField("NSCOUNT",0), |
| ShortField("ARCOUNT",0), |
| NetBIOSNameField("RR_NAME","windows"), |
| ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), |
| ByteField("NULL",0), |
| ShortEnumField("RR_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}), |
| ShortEnumField("RR_CLASS",1,{1:"INTERNET"}), |
| IntField("TTL", 2), |
| ShortField("RDLENGTH",2), |
| BitField("RDATA",10512,16)] #10512=0010100100010000 |
| |
| class NBTDatagram(Packet): |
| name="NBT Datagram Packet" |
| fields_desc= [ByteField("Type", 0x10), |
| ByteField("Flags", 0x02), |
| ShortField("ID", 0), |
| IPField("SourceIP", "127.0.0.1"), |
| ShortField("SourcePort", 138), |
| ShortField("Length", 272), |
| ShortField("Offset", 0), |
| NetBIOSNameField("SourceName","windows"), |
| ShortEnumField("SUFFIX1",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), |
| ByteField("NULL",0), |
| NetBIOSNameField("DestinationName","windows"), |
| ShortEnumField("SUFFIX2",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}), |
| ByteField("NULL",0)] |
| |
| |
| class NBTSession(Packet): |
| name="NBT Session Packet" |
| fields_desc= [ByteEnumField("TYPE",0,{0x00:"Session Message",0x81:"Session Request",0x82:"Positive Session Response",0x83:"Negative Session Response",0x84:"Retarget Session Response",0x85:"Session Keepalive"}), |
| BitField("RESERVED",0x00,7), |
| BitField("LENGTH",0,17)] |
| |
| |
| # SMB NetLogon Response Header |
| class SMBNetlogon_Protocol_Response_Header(Packet): |
| name="SMBNetlogon Protocol Response Header" |
| fields_desc = [StrFixedLenField("Start","\xffSMB",4), |
| ByteEnumField("Command",0x25,{0x25:"Trans"}), |
| ByteField("Error_Class",0x02), |
| ByteField("Reserved",0), |
| LEShortField("Error_code",4), |
| ByteField("Flags",0), |
| LEShortField("Flags2",0x0000), |
| LEShortField("PIDHigh",0x0000), |
| LELongField("Signature",0x0), |
| LEShortField("Unused",0x0), |
| LEShortField("TID",0), |
| LEShortField("PID",0), |
| LEShortField("UID",0), |
| LEShortField("MID",0), |
| ByteField("WordCount",17), |
| LEShortField("TotalParamCount",0), |
| LEShortField("TotalDataCount",112), |
| LEShortField("MaxParamCount",0), |
| LEShortField("MaxDataCount",0), |
| ByteField("MaxSetupCount",0), |
| ByteField("unused2",0), |
| LEShortField("Flags3",0), |
| ByteField("TimeOut1",0xe8), |
| ByteField("TimeOut2",0x03), |
| LEShortField("unused3",0), |
| LEShortField("unused4",0), |
| LEShortField("ParamCount2",0), |
| LEShortField("ParamOffset",0), |
| LEShortField("DataCount",112), |
| LEShortField("DataOffset",92), |
| ByteField("SetupCount", 3), |
| ByteField("unused5", 0)] |
| |
| # SMB MailSlot Protocol |
| class SMBMailSlot(Packet): |
| name = "SMB Mail Slot Protocol" |
| fields_desc = [LEShortField("opcode", 1), |
| LEShortField("priority", 1), |
| LEShortField("class", 2), |
| LEShortField("size", 135), |
| StrNullField("name","\MAILSLOT\NET\GETDC660")] |
| |
| # SMB NetLogon Protocol Response Tail SAM |
| class SMBNetlogon_Protocol_Response_Tail_SAM(Packet): |
| name = "SMB Netlogon Protocol Response Tail SAM" |
| fields_desc = [ByteEnumField("Command", 0x17, {0x12:"SAM logon request", 0x17:"SAM Active directory Response"}), |
| ByteField("unused", 0), |
| ShortField("Data1", 0), |
| ShortField("Data2", 0xfd01), |
| ShortField("Data3", 0), |
| ShortField("Data4", 0xacde), |
| ShortField("Data5", 0x0fe5), |
| ShortField("Data6", 0xd10a), |
| ShortField("Data7", 0x374c), |
| ShortField("Data8", 0x83e2), |
| ShortField("Data9", 0x7dd9), |
| ShortField("Data10", 0x3a16), |
| ShortField("Data11", 0x73ff), |
| ByteField("Data12", 0x04), |
| StrFixedLenField("Data13", "rmff", 4), |
| ByteField("Data14", 0x0), |
| ShortField("Data16", 0xc018), |
| ByteField("Data18", 0x0a), |
| StrFixedLenField("Data20", "rmff-win2k", 10), |
| ByteField("Data21", 0xc0), |
| ShortField("Data22", 0x18c0), |
| ShortField("Data23", 0x180a), |
| StrFixedLenField("Data24", "RMFF-WIN2K", 10), |
| ShortField("Data25", 0), |
| ByteField("Data26", 0x17), |
| StrFixedLenField("Data27", "Default-First-Site-Name", 23), |
| ShortField("Data28", 0x00c0), |
| ShortField("Data29", 0x3c10), |
| ShortField("Data30", 0x00c0), |
| ShortField("Data31", 0x0200), |
| ShortField("Data32", 0x0), |
| ShortField("Data33", 0xac14), |
| ShortField("Data34", 0x0064), |
| ShortField("Data35", 0x0), |
| ShortField("Data36", 0x0), |
| ShortField("Data37", 0x0), |
| ShortField("Data38", 0x0), |
| ShortField("Data39", 0x0d00), |
| ShortField("Data40", 0x0), |
| ShortField("Data41", 0xffff)] |
| |
| # SMB NetLogon Protocol Response Tail LM2.0 |
| class SMBNetlogon_Protocol_Response_Tail_LM20(Packet): |
| name = "SMB Netlogon Protocol Response Tail LM20" |
| fields_desc = [ByteEnumField("Command",0x06,{0x06:"LM 2.0 Response to logon request"}), |
| ByteField("unused", 0), |
| StrFixedLenField("DblSlash", "\\\\", 2), |
| StrNullField("ServerName","WIN"), |
| LEShortField("LM20Token", 0xffff)] |
| |
| # SMBNegociate Protocol Request Header |
| class SMBNegociate_Protocol_Request_Header(Packet): |
| name="SMBNegociate Protocol Request Header" |
| fields_desc = [StrFixedLenField("Start","\xffSMB",4), |
| ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}), |
| ByteField("Error_Class",0), |
| ByteField("Reserved",0), |
| LEShortField("Error_code",0), |
| ByteField("Flags",0x18), |
| LEShortField("Flags2",0x0000), |
| LEShortField("PIDHigh",0x0000), |
| LELongField("Signature",0x0), |
| LEShortField("Unused",0x0), |
| LEShortField("TID",0), |
| LEShortField("PID",1), |
| LEShortField("UID",0), |
| LEShortField("MID",2), |
| ByteField("WordCount",0), |
| LEShortField("ByteCount",12)] |
| |
| # SMB Negociate Protocol Request Tail |
| class SMBNegociate_Protocol_Request_Tail(Packet): |
| name="SMB Negociate Protocol Request Tail" |
| fields_desc=[ByteField("BufferFormat",0x02), |
| StrNullField("BufferData","NT LM 0.12")] |
| |
| # SMBNegociate Protocol Response Advanced Security |
| class SMBNegociate_Protocol_Response_Advanced_Security(Packet): |
| name="SMBNegociate Protocol Response Advanced Security" |
| fields_desc = [StrFixedLenField("Start","\xffSMB",4), |
| ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}), |
| ByteField("Error_Class",0), |
| ByteField("Reserved",0), |
| LEShortField("Error_Code",0), |
| ByteField("Flags",0x98), |
| LEShortField("Flags2",0x0000), |
| LEShortField("PIDHigh",0x0000), |
| LELongField("Signature",0x0), |
| LEShortField("Unused",0x0), |
| LEShortField("TID",0), |
| LEShortField("PID",1), |
| LEShortField("UID",0), |
| LEShortField("MID",2), |
| ByteField("WordCount",17), |
| LEShortField("DialectIndex",7), |
| ByteField("SecurityMode",0x03), |
| LEShortField("MaxMpxCount",50), |
| LEShortField("MaxNumberVC",1), |
| LEIntField("MaxBufferSize",16144), |
| LEIntField("MaxRawSize",65536), |
| LEIntField("SessionKey",0x0000), |
| LEShortField("ServerCapabilities",0xf3f9), |
| BitField("UnixExtensions",0,1), |
| BitField("Reserved2",0,7), |
| BitField("ExtendedSecurity",1,1), |
| BitField("CompBulk",0,2), |
| BitField("Reserved3",0,5), |
| # There have been 127490112000000000 tenths of micro-seconds between 1st january 1601 and 1st january 2005. 127490112000000000=0x1C4EF94D6228000, so ServerTimeHigh=0xD6228000 and ServerTimeLow=0x1C4EF94. |
| LEIntField("ServerTimeHigh",0xD6228000L), |
| LEIntField("ServerTimeLow",0x1C4EF94), |
| LEShortField("ServerTimeZone",0x3c), |
| ByteField("EncryptionKeyLength",0), |
| LEFieldLenField("ByteCount", None, "SecurityBlob"), |
| BitField("GUID",0,128), |
| StrLenField("SecurityBlob", "", "ByteCount",shift=-16)] |
| |
| # SMBNegociate Protocol Response No Security |
| # When using no security, with EncryptionKeyLength=8, you must have an EncryptionKey before the DomainName |
| class SMBNegociate_Protocol_Response_No_Security(Packet): |
| name="SMBNegociate Protocol Response No Security" |
| fields_desc = [StrFixedLenField("Start","\xffSMB",4), |
| ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}), |
| ByteField("Error_Class",0), |
| ByteField("Reserved",0), |
| LEShortField("Error_Code",0), |
| ByteField("Flags",0x98), |
| LEShortField("Flags2",0x0000), |
| LEShortField("PIDHigh",0x0000), |
| LELongField("Signature",0x0), |
| LEShortField("Unused",0x0), |
| LEShortField("TID",0), |
| LEShortField("PID",1), |
| LEShortField("UID",0), |
| LEShortField("MID",2), |
| ByteField("WordCount",17), |
| LEShortField("DialectIndex",7), |
| ByteField("SecurityMode",0x03), |
| LEShortField("MaxMpxCount",50), |
| LEShortField("MaxNumberVC",1), |
| LEIntField("MaxBufferSize",16144), |
| LEIntField("MaxRawSize",65536), |
| LEIntField("SessionKey",0x0000), |
| LEShortField("ServerCapabilities",0xf3f9), |
| BitField("UnixExtensions",0,1), |
| BitField("Reserved2",0,7), |
| BitField("ExtendedSecurity",0,1), |
| FlagsField("CompBulk",0,2,"CB"), |
| BitField("Reserved3",0,5), |
| # There have been 127490112000000000 tenths of micro-seconds between 1st january 1601 and 1st january 2005. 127490112000000000=0x1C4EF94D6228000, so ServerTimeHigh=0xD6228000 and ServerTimeLow=0x1C4EF94. |
| LEIntField("ServerTimeHigh",0xD6228000L), |
| LEIntField("ServerTimeLow",0x1C4EF94), |
| LEShortField("ServerTimeZone",0x3c), |
| ByteField("EncryptionKeyLength",8), |
| LEShortField("ByteCount",24), |
| BitField("EncryptionKey",0,64), |
| StrNullField("DomainName","WORKGROUP"), |
| StrNullField("ServerName","RMFF1")] |
| |
| # SMBNegociate Protocol Response No Security No Key |
| class SMBNegociate_Protocol_Response_No_Security_No_Key(Packet): |
| namez="SMBNegociate Protocol Response No Security No Key" |
| fields_desc = [StrFixedLenField("Start","\xffSMB",4), |
| ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}), |
| ByteField("Error_Class",0), |
| ByteField("Reserved",0), |
| LEShortField("Error_Code",0), |
| ByteField("Flags",0x98), |
| LEShortField("Flags2",0x0000), |
| LEShortField("PIDHigh",0x0000), |
| LELongField("Signature",0x0), |
| LEShortField("Unused",0x0), |
| LEShortField("TID",0), |
| LEShortField("PID",1), |
| LEShortField("UID",0), |
| LEShortField("MID",2), |
| ByteField("WordCount",17), |
| LEShortField("DialectIndex",7), |
| ByteField("SecurityMode",0x03), |
| LEShortField("MaxMpxCount",50), |
| LEShortField("MaxNumberVC",1), |
| LEIntField("MaxBufferSize",16144), |
| LEIntField("MaxRawSize",65536), |
| LEIntField("SessionKey",0x0000), |
| LEShortField("ServerCapabilities",0xf3f9), |
| BitField("UnixExtensions",0,1), |
| BitField("Reserved2",0,7), |
| BitField("ExtendedSecurity",0,1), |
| FlagsField("CompBulk",0,2,"CB"), |
| BitField("Reserved3",0,5), |
| # There have been 127490112000000000 tenths of micro-seconds between 1st january 1601 and 1st january 2005. 127490112000000000=0x1C4EF94D6228000, so ServerTimeHigh=0xD6228000 and ServerTimeLow=0x1C4EF94. |
| LEIntField("ServerTimeHigh",0xD6228000L), |
| LEIntField("ServerTimeLow",0x1C4EF94), |
| LEShortField("ServerTimeZone",0x3c), |
| ByteField("EncryptionKeyLength",0), |
| LEShortField("ByteCount",16), |
| StrNullField("DomainName","WORKGROUP"), |
| StrNullField("ServerName","RMFF1")] |
| |
| # Session Setup AndX Request |
| class SMBSession_Setup_AndX_Request(Packet): |
| name="Session Setup AndX Request" |
| fields_desc=[StrFixedLenField("Start","\xffSMB",4), |
| ByteEnumField("Command",0x73,{0x73:"SMB_COM_SESSION_SETUP_ANDX"}), |
| ByteField("Error_Class",0), |
| ByteField("Reserved",0), |
| LEShortField("Error_Code",0), |
| ByteField("Flags",0x18), |
| LEShortField("Flags2",0x0001), |
| LEShortField("PIDHigh",0x0000), |
| LELongField("Signature",0x0), |
| LEShortField("Unused",0x0), |
| LEShortField("TID",0), |
| LEShortField("PID",1), |
| LEShortField("UID",0), |
| LEShortField("MID",2), |
| ByteField("WordCount",13), |
| ByteEnumField("AndXCommand",0x75,{0x75:"SMB_COM_TREE_CONNECT_ANDX"}), |
| ByteField("Reserved2",0), |
| LEShortField("AndXOffset",96), |
| LEShortField("MaxBufferS",2920), |
| LEShortField("MaxMPXCount",50), |
| LEShortField("VCNumber",0), |
| LEIntField("SessionKey",0), |
| LEFieldLenField("ANSIPasswordLength",None,"ANSIPassword"), |
| LEShortField("UnicodePasswordLength",0), |
| LEIntField("Reserved3",0), |
| LEShortField("ServerCapabilities",0x05), |
| BitField("UnixExtensions",0,1), |
| BitField("Reserved4",0,7), |
| BitField("ExtendedSecurity",0,1), |
| BitField("CompBulk",0,2), |
| BitField("Reserved5",0,5), |
| LEShortField("ByteCount",35), |
| StrLenField("ANSIPassword", "Pass","ANSIPasswordLength"), |
| StrNullField("Account","GUEST"), |
| StrNullField("PrimaryDomain", ""), |
| StrNullField("NativeOS","Windows 4.0"), |
| StrNullField("NativeLanManager","Windows 4.0"), |
| ByteField("WordCount2",4), |
| ByteEnumField("AndXCommand2",0xFF,{0xFF:"SMB_COM_NONE"}), |
| ByteField("Reserved6",0), |
| LEShortField("AndXOffset2",0), |
| LEShortField("Flags3",0x2), |
| LEShortField("PasswordLength",0x1), |
| LEShortField("ByteCount2",18), |
| ByteField("Password",0), |
| StrNullField("Path","\\\\WIN2K\\IPC$"), |
| StrNullField("Service","IPC")] |
| |
| # Session Setup AndX Response |
| class SMBSession_Setup_AndX_Response(Packet): |
| name="Session Setup AndX Response" |
| fields_desc=[StrFixedLenField("Start","\xffSMB",4), |
| ByteEnumField("Command",0x73,{0x73:"SMB_COM_SESSION_SETUP_ANDX"}), |
| ByteField("Error_Class",0), |
| ByteField("Reserved",0), |
| LEShortField("Error_Code",0), |
| ByteField("Flags",0x90), |
| LEShortField("Flags2",0x1001), |
| LEShortField("PIDHigh",0x0000), |
| LELongField("Signature",0x0), |
| LEShortField("Unused",0x0), |
| LEShortField("TID",0), |
| LEShortField("PID",1), |
| LEShortField("UID",0), |
| LEShortField("MID",2), |
| ByteField("WordCount",3), |
| ByteEnumField("AndXCommand",0x75,{0x75:"SMB_COM_TREE_CONNECT_ANDX"}), |
| ByteField("Reserved2",0), |
| LEShortField("AndXOffset",66), |
| LEShortField("Action",0), |
| LEShortField("ByteCount",25), |
| StrNullField("NativeOS","Windows 4.0"), |
| StrNullField("NativeLanManager","Windows 4.0"), |
| StrNullField("PrimaryDomain",""), |
| ByteField("WordCount2",3), |
| ByteEnumField("AndXCommand2",0xFF,{0xFF:"SMB_COM_NONE"}), |
| ByteField("Reserved3",0), |
| LEShortField("AndXOffset2",80), |
| LEShortField("OptionalSupport",0x01), |
| LEShortField("ByteCount2",5), |
| StrNullField("Service","IPC"), |
| StrNullField("NativeFileSystem","")] |
| |
| class MobileIP(Packet): |
| name = "Mobile IP (RFC3344)" |
| fields_desc = [ ByteEnumField("type", 1, {1:"RRQ", 3:"RRP"}) ] |
| |
| class MobileIPRRQ(Packet): |
| name = "Mobile IP Registration Request (RFC3344)" |
| fields_desc = [ XByteField("flags", 0), |
| ShortField("lifetime", 180), |
| IPField("homeaddr", "0.0.0.0"), |
| IPField("haaddr", "0.0.0.0"), |
| IPField("coaddr", "0.0.0.0"), |
| Field("id", "", "64s") ] |
| |
| class MobileIPRRP(Packet): |
| name = "Mobile IP Registration Reply (RFC3344)" |
| fields_desc = [ ByteField("code", 0), |
| ShortField("lifetime", 180), |
| IPField("homeaddr", "0.0.0.0"), |
| IPField("haaddr", "0.0.0.0"), |
| Field("id", "", "64s") ] |
| |
| class MobileIPTunnelData(Packet): |
| name = "Mobile IP Tunnel Data Message (RFC3519)" |
| fields_desc = [ ByteField("nexthdr", 4), |
| ShortField("res", 0) ] |
| |
| |
| # Cisco Netflow Protocol version 1 |
| class NetflowHeader(Packet): |
| name = "Netflow Header" |
| fields_desc = [ ShortField("version", 1) ] |
| |
| class NetflowHeaderV1(Packet): |
| name = "Netflow Header V1" |
| fields_desc = [ ShortField("count", 0), |
| IntField("sysUptime", 0), |
| IntField("unixSecs", 0), |
| IntField("unixNanoSeconds", 0) ] |
| |
| |
| class NetflowRecordV1(Packet): |
| name = "Netflow Record" |
| fields_desc = [ IPField("ipsrc", "0.0.0.0"), |
| IPField("ipdst", "0.0.0.0"), |
| IPField("nexthop", "0.0.0.0"), |
| ShortField("inputIfIndex", 0), |
| ShortField("outpuIfIndex", 0), |
| IntField("dpkts", 0), |
| IntField("dbytes", 0), |
| IntField("starttime", 0), |
| IntField("endtime", 0), |
| ShortField("srcport", 0), |
| ShortField("dstport", 0), |
| ShortField("padding", 0), |
| ByteField("proto", 0), |
| ByteField("tos", 0), |
| IntField("padding1", 0), |
| IntField("padding2", 0) ] |
| |
| |
| ########## |
| ## SNMP ## |
| ########## |
| |
| ######[ ASN1 class ]###### |
| |
| class ASN1_Class_SNMP(ASN1_Class_UNIVERSAL): |
| name="SNMP" |
| PDU_GET = 0xa0 |
| PDU_NEXT = 0xa1 |
| PDU_RESPONSE = 0xa2 |
| PDU_SET = 0xa3 |
| PDU_TRAPv1 = 0xa4 |
| PDU_BULK = 0xa5 |
| PDU_INFORM = 0xa6 |
| PDU_TRAPv2 = 0xa7 |
| |
| |
| class ASN1_SNMP_PDU_GET(ASN1_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_GET |
| |
| class ASN1_SNMP_PDU_NEXT(ASN1_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_NEXT |
| |
| class ASN1_SNMP_PDU_RESPONSE(ASN1_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_RESPONSE |
| |
| class ASN1_SNMP_PDU_SET(ASN1_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_SET |
| |
| class ASN1_SNMP_PDU_TRAPv1(ASN1_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_TRAPv1 |
| |
| class ASN1_SNMP_PDU_BULK(ASN1_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_BULK |
| |
| class ASN1_SNMP_PDU_INFORM(ASN1_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_INFORM |
| |
| class ASN1_SNMP_PDU_TRAPv2(ASN1_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_TRAPv2 |
| |
| |
| ######[ BER codecs ]####### |
| |
| class BERcodec_SNMP_PDU_GET(BERcodec_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_GET |
| |
| class BERcodec_SNMP_PDU_NEXT(BERcodec_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_NEXT |
| |
| class BERcodec_SNMP_PDU_RESPONSE(BERcodec_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_RESPONSE |
| |
| class BERcodec_SNMP_PDU_SET(BERcodec_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_SET |
| |
| class BERcodec_SNMP_PDU_TRAPv1(BERcodec_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_TRAPv1 |
| |
| class BERcodec_SNMP_PDU_BULK(BERcodec_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_BULK |
| |
| class BERcodec_SNMP_PDU_INFORM(BERcodec_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_INFORM |
| |
| class BERcodec_SNMP_PDU_TRAPv2(BERcodec_SEQUENCE): |
| tag = ASN1_Class_SNMP.PDU_TRAPv2 |
| |
| |
| |
| ######[ ASN1 fields ]###### |
| |
| class ASN1F_SNMP_PDU_GET(ASN1F_SEQUENCE): |
| ASN1_tag = ASN1_Class_SNMP.PDU_GET |
| |
| class ASN1F_SNMP_PDU_NEXT(ASN1F_SEQUENCE): |
| ASN1_tag = ASN1_Class_SNMP.PDU_NEXT |
| |
| class ASN1F_SNMP_PDU_RESPONSE(ASN1F_SEQUENCE): |
| ASN1_tag = ASN1_Class_SNMP.PDU_RESPONSE |
| |
| class ASN1F_SNMP_PDU_SET(ASN1F_SEQUENCE): |
| ASN1_tag = ASN1_Class_SNMP.PDU_SET |
| |
| class ASN1F_SNMP_PDU_TRAPv1(ASN1F_SEQUENCE): |
| ASN1_tag = ASN1_Class_SNMP.PDU_TRAPv1 |
| |
| class ASN1F_SNMP_PDU_BULK(ASN1F_SEQUENCE): |
| ASN1_tag = ASN1_Class_SNMP.PDU_BULK |
| |
| class ASN1F_SNMP_PDU_INFORM(ASN1F_SEQUENCE): |
| ASN1_tag = ASN1_Class_SNMP.PDU_INFORM |
| |
| class ASN1F_SNMP_PDU_TRAPv2(ASN1F_SEQUENCE): |
| ASN1_tag = ASN1_Class_SNMP.PDU_TRAPv2 |
| |
| |
| |
| ######[ SNMP Packet ]###### |
| |
| SNMP_error = { 0: "no_error", |
| 1: "too_big", |
| 2: "no_such_name", |
| 3: "bad_value", |
| 4: "read_only", |
| 5: "generic_error", |
| 6: "no_access", |
| 7: "wrong_type", |
| 8: "wrong_length", |
| 9: "wrong_encoding", |
| 10: "wrong_value", |
| 11: "no_creation", |
| 12: "inconsistent_value", |
| 13: "ressource_unavailable", |
| 14: "commit_failed", |
| 15: "undo_failed", |
| 16: "authorization_error", |
| 17: "not_writable", |
| 18: "inconsistent_name", |
| } |
| |
| SNMP_trap_types = { 0: "cold_start", |
| 1: "warm_start", |
| 2: "link_down", |
| 3: "link_up", |
| 4: "auth_failure", |
| 5: "egp_neigh_loss", |
| 6: "enterprise_specific", |
| } |
| |
| class SNMPvarbind(ASN1_Packet): |
| ASN1_codec = ASN1_Codecs.BER |
| ASN1_root = ASN1F_SEQUENCE( ASN1F_OID("oid","1.3"), |
| ASN1F_field("value",ASN1_NULL(0)) |
| ) |
| |
| |
| class SNMPget(ASN1_Packet): |
| ASN1_codec = ASN1_Codecs.BER |
| ASN1_root = ASN1F_SNMP_PDU_GET( ASN1F_INTEGER("id",0), |
| ASN1F_enum_INTEGER("error",0, SNMP_error), |
| ASN1F_INTEGER("error_index",0), |
| ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) |
| ) |
| |
| class SNMPnext(ASN1_Packet): |
| ASN1_codec = ASN1_Codecs.BER |
| ASN1_root = ASN1F_SNMP_PDU_NEXT( ASN1F_INTEGER("id",0), |
| ASN1F_enum_INTEGER("error",0, SNMP_error), |
| ASN1F_INTEGER("error_index",0), |
| ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) |
| ) |
| |
| class SNMPresponse(ASN1_Packet): |
| ASN1_codec = ASN1_Codecs.BER |
| ASN1_root = ASN1F_SNMP_PDU_RESPONSE( ASN1F_INTEGER("id",0), |
| ASN1F_enum_INTEGER("error",0, SNMP_error), |
| ASN1F_INTEGER("error_index",0), |
| ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) |
| ) |
| |
| class SNMPset(ASN1_Packet): |
| ASN1_codec = ASN1_Codecs.BER |
| ASN1_root = ASN1F_SNMP_PDU_SET( ASN1F_INTEGER("id",0), |
| ASN1F_enum_INTEGER("error",0, SNMP_error), |
| ASN1F_INTEGER("error_index",0), |
| ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) |
| ) |
| |
| class SNMPtrapv1(ASN1_Packet): |
| ASN1_codec = ASN1_Codecs.BER |
| ASN1_root = ASN1F_SNMP_PDU_TRAPv1( ASN1F_INTEGER("id",0), |
| ASN1F_OID("enterprise", "1.3"), |
| ASN1F_STRING("agent_addr",""), |
| ASN1F_enum_INTEGER("generic_trap", 0, SNMP_trap_types), |
| ASN1F_INTEGER("specific_trap", 0), |
| ASN1F_INTEGER("time_stamp", IntAutoTime()), |
| ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) |
| ) |
| |
| class SNMPbulk(ASN1_Packet): |
| ASN1_codec = ASN1_Codecs.BER |
| ASN1_root = ASN1F_SNMP_PDU_BULK( ASN1F_INTEGER("id",0), |
| ASN1F_INTEGER("non_repeaters",0), |
| ASN1F_INTEGER("max_repetitions",0), |
| ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) |
| ) |
| |
| class SNMPinform(ASN1_Packet): |
| ASN1_codec = ASN1_Codecs.BER |
| ASN1_root = ASN1F_SNMP_PDU_INFORM( ASN1F_INTEGER("id",0), |
| ASN1F_enum_INTEGER("error",0, SNMP_error), |
| ASN1F_INTEGER("error_index",0), |
| ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) |
| ) |
| |
| class SNMPtrapv2(ASN1_Packet): |
| ASN1_codec = ASN1_Codecs.BER |
| ASN1_root = ASN1F_SNMP_PDU_TRAPv2( ASN1F_INTEGER("id",0), |
| ASN1F_enum_INTEGER("error",0, SNMP_error), |
| ASN1F_INTEGER("error_index",0), |
| ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind) |
| ) |
| |
| |
| class SNMP(ASN1_Packet): |
| ASN1_codec = ASN1_Codecs.BER |
| ASN1_root = ASN1F_SEQUENCE( |
| ASN1F_enum_INTEGER("version", 1, {0:"v1", 1:"v2c", 2:"v2", 3:"v3"}), |
| ASN1F_STRING("community","public"), |
| ASN1F_CHOICE("PDU", SNMPget(), |
| SNMPget, SNMPnext, SNMPresponse, SNMPset, |
| SNMPtrapv1, SNMPbulk, SNMPinform, SNMPtrapv2) |
| ) |
| def answers(self, other): |
| return ( isinstance(self.PDU, SNMPresponse) and |
| ( isinstance(other.PDU, SNMPget) or |
| isinstance(other.PDU, SNMPnext) or |
| isinstance(other.PDU, SNMPset) ) and |
| self.PDU.id == other.PDU.id ) |
| |
| |
| |
| ################# |
| ## Bind layers ## |
| ################# |
| |
| |
| def bind_bottom_up(lower, upper, __fval=None, **fval): |
| if __fval is not None: |
| fval.update(__fval) |
| lower.payload_guess = lower.payload_guess[:] |
| lower.payload_guess.append((fval, upper)) |
| |
| |
| def bind_top_down(lower, upper, __fval=None, **fval): |
| if __fval is not None: |
| fval.update(__fval) |
| upper.overload_fields = upper.overload_fields.copy() |
| upper.overload_fields[lower] = fval |
| |
| def bind_layers(lower, upper, __fval=None, **fval): |
| if __fval is not None: |
| fval.update(__fval) |
| bind_top_down(lower, upper, **fval) |
| bind_bottom_up(lower, upper, **fval) |
| |
| def split_bottom_up(lower, upper, __fval=None, **fval): |
| if __fval is not None: |
| fval.update(__fval) |
| def do_filter((f,u),upper=upper,fval=fval): |
| if u != upper: |
| return True |
| for k in fval: |
| if k not in f or f[k] != fval[k]: |
| return True |
| return False |
| lower.payload_guess = filter(do_filter, lower.payload_guess) |
| |
| def split_top_down(lower, upper, __fval=None, **fval): |
| if __fval is not None: |
| fval.update(__fval) |
| if lower in upper.overload_fields: |
| ofval = upper.overload_fields[lower] |
| for k in fval: |
| if k not in ofval or ofval[k] != fval[k]: |
| return |
| upper.overload_fields = upper.overload_fields.copy() |
| del(upper.overload_fields[lower]) |
| |
| def split_layers(lower, upper, __fval=None, **fval): |
| if __fval is not None: |
| fval.update(__fval) |
| split_bottom_up(lower, upper, **fval) |
| split_top_down(lower, upper, **fval) |
| |
| layer_bonds = [ ( Dot3, LLC, { } ), |
| ( GPRS, IP, { } ), |
| ( PrismHeader, Dot11, { }), |
| ( Dot11, LLC, { "type" : 2 } ), |
| ( PPP, IP, { "proto" : 0x0021 } ), |
| ( Ether, LLC, { "type" : 0x007a } ), |
| ( Ether, Dot1Q, { "type" : 0x8100 } ), |
| ( Ether, Ether, { "type" : 0x0001 } ), |
| ( Ether, ARP, { "type" : 0x0806 } ), |
| ( Ether, IP, { "type" : 0x0800 } ), |
| ( Ether, EAPOL, { "type" : 0x888e } ), |
| ( Ether, EAPOL, { "type" : 0x888e, "dst" : "01:80:c2:00:00:03" } ), |
| ( Ether, PPPoED, { "type" : 0x8863 } ), |
| ( Ether, PPPoE, { "type" : 0x8864 } ), |
| ( CookedLinux, LLC, { "proto" : 0x007a } ), |
| ( CookedLinux, Dot1Q, { "proto" : 0x8100 } ), |
| ( CookedLinux, Ether, { "proto" : 0x0001 } ), |
| ( CookedLinux, ARP, { "proto" : 0x0806 } ), |
| ( CookedLinux, IP, { "proto" : 0x0800 } ), |
| ( CookedLinux, EAPOL, { "proto" : 0x888e } ), |
| ( CookedLinux, PPPoED, { "proto" : 0x8863 } ), |
| ( CookedLinux, PPPoE, { "proto" : 0x8864 } ), |
| ( GRE, LLC, { "proto" : 0x007a } ), |
| ( GRE, Dot1Q, { "proto" : 0x8100 } ), |
| ( GRE, Ether, { "proto" : 0x0001 } ), |
| ( GRE, ARP, { "proto" : 0x0806 } ), |
| ( GRE, IP, { "proto" : 0x0800 } ), |
| ( GRE, EAPOL, { "proto" : 0x888e } ), |
| ( PPPoE, PPP, { "code" : 0x00 } ), |
| ( EAPOL, EAP, { "type" : EAPOL.EAP_PACKET } ), |
| ( LLC, STP, { "dsap" : 0x42 , "ssap" : 0x42, "ctrl":3 } ), |
| ( LLC, SNAP, { "dsap" : 0xAA , "ssap" : 0xAA, "ctrl":3 } ), |
| ( SNAP, Dot1Q, { "code" : 0x8100 } ), |
| ( SNAP, Ether, { "code" : 0x0001 } ), |
| ( SNAP, ARP, { "code" : 0x0806 } ), |
| ( SNAP, IP, { "code" : 0x0800 } ), |
| ( SNAP, EAPOL, { "code" : 0x888e } ), |
| ( SNAP, STP, { "code" : 0x010b } ), |
| ( IPerror,IPerror, { "frag" : 0, "proto" : socket.IPPROTO_IPIP } ), |
| ( IPerror,ICMPerror,{ "frag" : 0, "proto" : socket.IPPROTO_ICMP } ), |
| ( IPerror,TCPerror, { "frag" : 0, "proto" : socket.IPPROTO_TCP } ), |
| ( IPerror,UDPerror, { "frag" : 0, "proto" : socket.IPPROTO_UDP } ), |
| ( IP, IP, { "frag" : 0, "proto" : socket.IPPROTO_IPIP } ), |
| ( IP, ICMP, { "frag" : 0, "proto" : socket.IPPROTO_ICMP } ), |
| ( IP, TCP, { "frag" : 0, "proto" : socket.IPPROTO_TCP } ), |
| ( IP, UDP, { "frag" : 0, "proto" : socket.IPPROTO_UDP } ), |
| ( IP, GRE, { "frag" : 0, "proto" : socket.IPPROTO_GRE } ), |
| ( UDP, SNMP, { "sport" : 161 } ), |
| ( UDP, SNMP, { "dport" : 161 } ), |
| ( UDP, MGCP, { "dport" : 2727 } ), |
| ( UDP, MGCP, { "sport" : 2727 } ), |
| ( UDP, DNS, { "dport" : 53 } ), |
| ( UDP, DNS, { "sport" : 53 } ), |
| ( UDP, ISAKMP, { "sport" : 500, "dport" : 500 } ), |
| ( UDP, HSRP, { "sport" : 1985, "dport" : 1985} ), |
| ( UDP, NTP, { "sport" : 123, "dport" : 123 } ), |
| ( UDP, BOOTP, { "sport" : 68, "dport" : 67 } ), |
| ( UDP, BOOTP, { "sport" : 67, "dport" : 68 } ), |
| ( BOOTP, DHCP, { "options" : dhcpmagic } ), |
| ( UDP, RIP, { "sport" : 520 } ), |
| ( UDP, RIP, { "dport" : 520 } ), |
| ( RIP, RIPEntry, { } ), |
| ( RIPEntry,RIPEntry,{ } ), |
| ( Dot11, Dot11AssoReq, { "type" : 0, "subtype" : 0 } ), |
| ( Dot11, Dot11AssoResp, { "type" : 0, "subtype" : 1 } ), |
| ( Dot11, Dot11ReassoReq, { "type" : 0, "subtype" : 2 } ), |
| ( Dot11, Dot11ReassoResp, { "type" : 0, "subtype" : 3 } ), |
| ( Dot11, Dot11ProbeReq, { "type" : 0, "subtype" : 4 } ), |
| ( Dot11, Dot11ProbeResp, { "type" : 0, "subtype" : 5 } ), |
| ( Dot11, Dot11Beacon, { "type" : 0, "subtype" : 8 } ), |
| ( Dot11, Dot11ATIM , { "type" : 0, "subtype" : 9 } ), |
| ( Dot11, Dot11Disas , { "type" : 0, "subtype" : 10 } ), |
| ( Dot11, Dot11Auth, { "type" : 0, "subtype" : 11 } ), |
| ( Dot11, Dot11Deauth, { "type" : 0, "subtype" : 12 } ), |
| ( Dot11Beacon, Dot11Elt, {} ), |
| ( Dot11AssoReq, Dot11Elt, {} ), |
| ( Dot11AssoResp, Dot11Elt, {} ), |
| ( Dot11ReassoReq, Dot11Elt, {} ), |
| ( Dot11ReassoResp, Dot11Elt, {} ), |
| ( Dot11ProbeReq, Dot11Elt, {} ), |
| ( Dot11ProbeResp, Dot11Elt, {} ), |
| ( Dot11Auth, Dot11Elt, {} ), |
| ( Dot11Elt, Dot11Elt, {} ), |
| ( TCP, Skinny, { "dport": 2000 } ), |
| ( TCP, Skinny, { "sport": 2000 } ), |
| ( UDP, SebekHead, { "sport" : 1101 } ), |
| ( UDP, SebekHead, { "dport" : 1101 } ), |
| ( UDP, SebekHead, { "sport" : 1101, |
| "dport" : 1101 } ), |
| ( SebekHead, SebekV1, { "version" : 1 } ), |
| ( SebekHead, SebekV2Sock, { "version" : 2, |
| "type" : 2 } ), |
| ( SebekHead, SebekV2, { "version" : 2 } ), |
| ( SebekHead, SebekV3Sock, { "version" : 3, |
| "type" : 2 } ), |
| ( SebekHead, SebekV3, { "version" : 3 } ), |
| ( CookedLinux, IrLAPHead, { "proto" : 0x0017 } ), |
| ( IrLAPHead, IrLAPCommand, { "Type" : 1} ), |
| ( IrLAPCommand, IrLMP, {} ), |
| (UDP, NBNSQueryRequest, {"dport" : 137 }), |
| (UDP, NBNSRequest, {"dport" : 137 }), |
| (UDP, NBNSQueryResponse, {"sport" : 137}), |
| (UDP, NBNSQueryResponseNegative, {"sport" : 137}), |
| (UDP, NBNSNodeStatusResponse, {"sport" : 137}), |
| (NBNSNodeStatusResponse, NBNSNodeStatusResponseService, {}), |
| (NBNSNodeStatusResponse, NBNSNodeStatusResponseService, {}), |
| (NBNSNodeStatusResponseService, NBNSNodeStatusResponseService, {}), |
| (NBNSNodeStatusResponseService, NBNSNodeStatusResponseEnd, {}), |
| (UDP, NBNSWackResponse, {"sport" : 137}), |
| (UDP,NBTDatagram,{ "dport":138}), |
| (TCP,NBTSession,{"dport":139}), |
| (NBTSession, SMBNegociate_Protocol_Request_Header,{}), |
| (SMBNegociate_Protocol_Request_Header,SMBNegociate_Protocol_Request_Tail,{}), |
| (SMBNegociate_Protocol_Request_Tail,SMBNegociate_Protocol_Request_Tail,{}), |
| (NBTSession, SMBNegociate_Protocol_Response_Advanced_Security,{"ExtendedSecurity":1}), |
| (NBTSession, SMBNegociate_Protocol_Response_No_Security,{"ExtendedSecurity":0,"EncryptionKeyLength":8 }), |
| (NBTSession, SMBNegociate_Protocol_Response_No_Security_No_Key,{"ExtendedSecurity":0,"EncryptionKeyLength":0 }), |
| (NBTSession, SMBSession_Setup_AndX_Request,{}), |
| (NBTSession, SMBSession_Setup_AndX_Response,{}), |
| |
| (HCI_Hdr, HCI_ACL_Hdr, {"type":2}), |
| (HCI_Hdr, Raw, {}), |
| (HCI_ACL_Hdr, L2CAP_Hdr, {}), |
| (L2CAP_Hdr, L2CAP_CmdHdr, {"cid":1}), |
| (L2CAP_CmdHdr, L2CAP_CmdRej, {"code":1}), |
| (L2CAP_CmdHdr, L2CAP_ConnReq, {"code":2}), |
| (L2CAP_CmdHdr, L2CAP_ConnResp, {"code":3}), |
| (L2CAP_CmdHdr, L2CAP_ConfReq, {"code":4}), |
| (L2CAP_CmdHdr, L2CAP_ConfResp, {"code":5}), |
| (L2CAP_CmdHdr, L2CAP_DisconnReq, {"code":6}), |
| (L2CAP_CmdHdr, L2CAP_DisconnResp, {"code":7}), |
| (L2CAP_CmdHdr, L2CAP_InfoReq, {"code":10}), |
| (L2CAP_CmdHdr, L2CAP_InfoResp, {"code":11}), |
| ( UDP, MobileIP, { "sport" : 434 } ), |
| ( UDP, MobileIP, { "dport" : 434 } ), |
| ( MobileIP, MobileIPRRQ, { "type" : 1 } ), |
| ( MobileIP, MobileIPRRP, { "type" : 3 } ), |
| ( MobileIP, MobileIPTunnelData, { "type" : 4 } ), |
| ( MobileIPTunnelData, IP, { "nexthdr" : 4 } ), |
| |
| ( NetflowHeader, NetflowHeaderV1, { "version" : 1 } ), |
| ( NetflowHeaderV1, NetflowRecordV1, {} ), |
| |
| ] |
| |
| for l in layer_bonds: |
| bind_layers(*l) |
| del(l) |
| |
| |
| ################### |
| ## Fragmentation ## |
| ################### |
| |
| def fragment(pkt, fragsize=1480): |
| fragsize = (fragsize+7)/8*8 |
| lst = [] |
| for p in pkt: |
| s = str(p[IP].payload) |
| nb = (len(s)+fragsize-1)/fragsize |
| for i in range(nb): |
| q = p.copy() |
| del(q[IP].payload) |
| del(q[IP].chksum) |
| del(q[IP].len) |
| if i == nb-1: |
| q[IP].flags &= ~1 |
| else: |
| q[IP].flags |= 1 |
| q[IP].frag = i*fragsize/8 |
| r = Raw(load=s[i*fragsize:(i+1)*fragsize]) |
| r.overload_fields = p[IP].payload.overload_fields.copy() |
| q.add_payload(r) |
| lst.append(q) |
| return lst |
| |
| def overlap_frag(p, overlap, fragsize=8, overlap_fragsize=None): |
| if overlap_fragsize is None: |
| overlap_fragsize = fragsize |
| q = p.copy() |
| del(q[IP].payload) |
| q[IP].add_payload(overlap) |
| |
| qfrag = fragment(q, overlap_fragsize) |
| qfrag[-1][IP].flags |= 1 |
| return qfrag+fragment(p, fragsize) |
| |
| def defrag(plist): |
| """defrag(plist) -> ([not fragmented], [defragmented], |
| [ [bad fragments], [bad fragments], ... ])""" |
| frags = {} |
| nofrag = PacketList() |
| for p in plist: |
| ip = p[IP] |
| if IP not in p: |
| nofrag.append(p) |
| continue |
| if ip.frag == 0 and ip.flags & 1 == 0: |
| nofrag.append(p) |
| continue |
| uniq = (ip.id,ip.src,ip.dst,ip.proto) |
| if uniq in frags: |
| frags[uniq].append(p) |
| else: |
| frags[uniq] = PacketList([p]) |
| defrag = [] |
| missfrag = [] |
| for lst in frags.itervalues(): |
| lst.sort(lambda x,y:cmp(x.frag, y.frag)) |
| p = lst[0] |
| if p.frag > 0: |
| missfrag.append(lst) |
| continue |
| p = p.copy() |
| if Padding in p: |
| del(p[Padding].underlayer.payload) |
| ip = p[IP] |
| if ip.len is None or ip.ihl is None: |
| clen = len(ip.payload) |
| else: |
| clen = ip.len - (ip.ihl<<2) |
| txt = Raw() |
| for q in lst[1:]: |
| if clen != q.frag<<3: |
| if clen > q.frag<<3: |
| warning("Fragment overlap (%i > %i) %r || %r || %r" % (clen, q.frag<<3, p,txt,q)) |
| missfrag.append(lst) |
| txt = None |
| break |
| if q[IP].len is None or q[IP].ihl is None: |
| clen += len(q[IP].payload) |
| else: |
| clen += q[IP].len - (q[IP].ihl<<2) |
| if Padding in q: |
| del(q[Padding].underlayer.payload) |
| txt.add_payload(q[IP].payload.copy()) |
| |
| if txt is None: |
| continue |
| |
| ip.flags &= ~1 # !MF |
| del(ip.chksum) |
| del(ip.len) |
| p = p/txt |
| defrag.append(p) |
| defrag2=PacketList() |
| for p in defrag: |
| defrag2.append(p.__class__(str(p))) |
| return nofrag,defrag2,missfrag |
| |
| |
| |
| |
| |
| |
| ################### |
| ## Super sockets ## |
| ################### |
| |
| def Ether_Dot3_Dispatcher(pkt=None, **kargs): |
| if type(pkt) is str and len(pkt) >= 14 and struct.unpack("!H", pkt[12:14])[0] <= 1500: |
| return Dot3(pkt, **kargs) |
| return Ether(pkt, **kargs) |
| |
| # According to libdnet |
| LLTypes = { ARPHDR_ETHER : Ether_Dot3_Dispatcher, |
| ARPHDR_METRICOM : Ether_Dot3_Dispatcher, |
| ARPHDR_LOOPBACK : Ether_Dot3_Dispatcher, |
| 12 : IP, |
| 101 : IP, |
| 801 : Dot11, |
| 802 : PrismHeader, |
| 105 : Dot11, |
| 113 : CookedLinux, |
| 119 : PrismHeader, # for atheros |
| 144 : CookedLinux, # called LINUX_IRDA, similar to CookedLinux |
| 783 : IrLAPHead, |
| 0xB1E70073L : HCI_Hdr, # I invented this one |
| } |
| |
| LLNumTypes = { Ether : ARPHDR_ETHER, |
| IP : 12, |
| IP : 101, |
| Dot11 : 801, |
| PrismHeader : 802, |
| Dot11 : 105, |
| CookedLinux : 113, |
| CookedLinux : 144, |
| IrLAPHead : 783 |
| } |
| |
| L3Types = { ETH_P_IP : IP, |
| ETH_P_ARP : ARP, |
| ETH_P_ALL : IP |
| } |
| |
| |
| |
| class SuperSocket: |
| closed=0 |
| def __init__(self, family=socket.AF_INET,type=socket.SOCK_STREAM, proto=0): |
| self.ins = socket.socket(family, type, proto) |
| self.outs = self.ins |
| self.promisc=None |
| def send(self, x): |
| return self.outs.send(str(x)) |
| def recv(self, x): |
| return Raw(self.ins.recv(x)) |
| def fileno(self): |
| return self.ins.fileno() |
| def close(self): |
| if self.closed: |
| return |
| self.closed=1 |
| if self.ins != self.outs: |
| if self.outs and self.outs.fileno() != -1: |
| self.outs.close() |
| if self.ins and self.ins.fileno() != -1: |
| self.ins.close() |
| def bind_in(self, addr): |
| self.ins.bind(addr) |
| def bind_out(self, addr): |
| self.outs.bind(addr) |
| |
| |
| class L3RawSocket(SuperSocket): |
| def __init__(self, type = ETH_P_IP, filter=None, iface=None, promisc=None, nofilter=0): |
| self.outs = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW) |
| self.outs.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1) |
| self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) |
| def recv(self, x): |
| return Ether(self.ins.recv(x)).payload |
| def send(self, x): |
| try: |
| self.outs.sendto(str(x),(x.dst,0)) |
| except socket.error,msg: |
| log_runtime.error(msg) |
| |
| |
| |
| class L3PacketSocket(SuperSocket): |
| def __init__(self, type = ETH_P_ALL, filter=None, promisc=None, iface=None, nofilter=0): |
| self.type = type |
| self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) |
| self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0) |
| if not nofilter: |
| if conf.except_filter: |
| if filter: |
| filter = "(%s) and not (%s)" % (filter, conf.except_filter) |
| else: |
| filter = "not (%s)" % conf.except_filter |
| if filter is not None: |
| attach_filter(self.ins, filter) |
| self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30) |
| self.outs = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) |
| self.outs.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2**30) |
| if promisc is None: |
| promisc = conf.promisc |
| self.promisc = promisc |
| if self.promisc: |
| if iface is None: |
| self.iff = get_if_list() |
| else: |
| if iface.__class__ is list: |
| self.iff = iface |
| else: |
| self.iff = [iface] |
| for i in self.iff: |
| set_promisc(self.ins, i) |
| def close(self): |
| if self.closed: |
| return |
| self.closed=1 |
| if self.promisc: |
| for i in self.iff: |
| set_promisc(self.ins, i, 0) |
| SuperSocket.close(self) |
| def recv(self, x): |
| pkt, sa_ll = self.ins.recvfrom(x) |
| if sa_ll[2] == socket.PACKET_OUTGOING: |
| return None |
| if LLTypes.has_key(sa_ll[3]): |
| cls = LLTypes[sa_ll[3]] |
| lvl = 2 |
| elif L3Types.has_key(sa_ll[1]): |
| cls = L3Types[sa_ll[1]] |
| lvl = 3 |
| else: |
| warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using Ethernet" % (sa_ll[0],sa_ll[1],sa_ll[3])) |
| cls = Ether |
| lvl = 2 |
| |
| try: |
| pkt = cls(pkt) |
| except KeyboardInterrupt: |
| raise |
| except: |
| if conf.debug_dissector: |
| raise |
| pkt = Raw(pkt) |
| if lvl == 2: |
| pkt = pkt.payload |
| return pkt |
| |
| def send(self, x): |
| if isinstance(x, IPv6): |
| iff,a,gw = conf.route6.route(x.dst) |
| elif hasattr(x,"dst"): |
| iff,a,gw = conf.route.route(x.dst) |
| else: |
| iff = conf.iface |
| sdto = (iff, self.type) |
| self.outs.bind(sdto) |
| sn = self.outs.getsockname() |
| ll = lambda x:x |
| if sn[3] in (ARPHDR_PPP,ARPHDR_TUN): |
| sdto = (iff, ETH_P_IP) |
| if LLTypes.has_key(sn[3]): |
| ll = lambda x:LLTypes[sn[3]]()/x |
| try: |
| self.outs.sendto(str(ll(x)), sdto) |
| except socket.error,msg: |
| if conf.auto_fragment and msg[0] == 90: |
| for p in fragment(x): |
| self.outs.sendto(str(ll(p)), sdto) |
| else: |
| raise |
| |
| |
| |
| |
| class L2Socket(SuperSocket): |
| def __init__(self, iface = None, type = ETH_P_ALL, filter=None, nofilter=0): |
| if iface is None: |
| iface = conf.iface |
| self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) |
| self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0) |
| if not nofilter: |
| if conf.except_filter: |
| if filter: |
| filter = "(%s) and not (%s)" % (filter, conf.except_filter) |
| else: |
| filter = "not (%s)" % conf.except_filter |
| if filter is not None: |
| attach_filter(self.ins, filter) |
| self.ins.bind((iface, type)) |
| self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30) |
| self.outs = self.ins |
| self.outs.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2**30) |
| sa_ll = self.outs.getsockname() |
| if LLTypes.has_key(sa_ll[3]): |
| self.LL = LLTypes[sa_ll[3]] |
| elif L3Types.has_key(sa_ll[1]): |
| self.LL = L3Types[sa_ll[1]] |
| else: |
| warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using Ethernet" % (sa_ll[0],sa_ll[1],sa_ll[3])) |
| self.LL = Ether |
| |
| def recv(self, x): |
| pkt, sa_ll = self.ins.recvfrom(x) |
| if sa_ll[2] == socket.PACKET_OUTGOING: |
| return None |
| try: |
| q = self.LL(pkt) |
| except KeyboardInterrupt: |
| raise |
| except: |
| if conf.debug_dissector: |
| raise |
| q = Raw(pkt) |
| return q |
| |
| |
| class L2ListenSocket(SuperSocket): |
| def __init__(self, iface = None, type = ETH_P_ALL, promisc=None, filter=None, nofilter=0): |
| self.type = type |
| self.outs = None |
| self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type)) |
| self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0) |
| if iface is not None: |
| self.ins.bind((iface, type)) |
| if not nofilter: |
| if conf.except_filter: |
| if filter: |
| filter = "(%s) and not (%s)" % (filter, conf.except_filter) |
| else: |
| filter = "not (%s)" % conf.except_filter |
| if filter is not None: |
| attach_filter(self.ins, filter) |
| if promisc is None: |
| promisc = conf.sniff_promisc |
| self.promisc = promisc |
| if iface is None: |
| self.iff = get_if_list() |
| else: |
| if iface.__class__ is list: |
| self.iff = iface |
| else: |
| self.iff = [iface] |
| if self.promisc: |
| for i in self.iff: |
| set_promisc(self.ins, i) |
| self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30) |
| def close(self): |
| if self.promisc: |
| for i in self.iff: |
| set_promisc(self.ins, i, 0) |
| SuperSocket.close(self) |
| |
| def recv(self, x): |
| pkt, sa_ll = self.ins.recvfrom(x) |
| if LLTypes.has_key(sa_ll[3]): |
| cls = LLTypes[sa_ll[3]] |
| elif L3Types.has_key(sa_ll[1]): |
| cls = L3Types[sa_ll[1]] |
| else: |
| warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using Ethernet" % (sa_ll[0],sa_ll[1],sa_ll[3])) |
| cls = Ether |
| |
| try: |
| pkt = cls(pkt) |
| except KeyboardInterrupt: |
| raise |
| except: |
| if conf.debug_dissector: |
| raise |
| pkt = Raw(pkt) |
| return pkt |
| |
| def send(self, x): |
| raise Scapy_Exception("Can't send anything with L2ListenSocket") |
| |
| |
| |
| class L3dnetSocket(SuperSocket): |
| def __init__(self, type = ETH_P_ALL, filter=None, promisc=None, iface=None, nofilter=0): |
| self.iflist = {} |
| self.ins = pcap.pcapObject() |
| if iface is None: |
| iface = conf.iface |
| self.iface = iface |
| self.ins.open_live(iface, 1600, 0, 100) |
| try: |
| ioctl(self.ins.fileno(),BIOCIMMEDIATE,struct.pack("I",1)) |
| except: |
| pass |
| if nofilter: |
| if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap |
| filter = "ether proto %i" % type |
| else: |
| filter = None |
| else: |
| if conf.except_filter: |
| if filter: |
| filter = "(%s) and not (%s)" % (filter, conf.except_filter) |
| else: |
| filter = "not (%s)" % conf.except_filter |
| if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap |
| if filter: |
| filter = "(ether proto %i) and (%s)" % (type,filter) |
| else: |
| filter = "ether proto %i" % type |
| if filter: |
| self.ins.setfilter(filter, 0, 0) |
| def send(self, x): |
| if isinstance(x, IPv6): |
| iff,a,gw = conf.route6.route(x.dst) |
| elif hasattr(x,"dst"): |
| iff,a,gw = conf.route.route(x.dst) |
| else: |
| iff = conf.iface |
| ifs = self.iflist.get(iff) |
| if ifs is None: |
| self.iflist[iff] = ifs = dnet.eth(iff) |
| ifs.send(str(Ether()/x)) |
| def recv(self,x=MTU): |
| ll = self.ins.datalink() |
| if LLTypes.has_key(ll): |
| cls = LLTypes[ll] |
| else: |
| warning("Unable to guess datalink type (interface=%s linktype=%i). Using Ethernet" % (self.iface, ll)) |
| cls = Ether |
| |
| pkt = self.ins.next() |
| if pkt is not None: |
| pkt = pkt[1] |
| if pkt is None: |
| return |
| |
| try: |
| pkt = cls(pkt) |
| except KeyboardInterrupt: |
| raise |
| except: |
| if conf.debug_dissector: |
| raise |
| pkt = Raw(pkt) |
| return pkt.payload |
| |
| def nonblock_recv(self): |
| self.ins.setnonblock(1) |
| p = self.recv() |
| self.ins.setnonblock(0) |
| return p |
| |
| def close(self): |
| if hasattr(self, "ins"): |
| del(self.ins) |
| if hasattr(self, "outs"): |
| del(self.outs) |
| |
| class L2dnetSocket(SuperSocket): |
| def __init__(self, iface = None, type = ETH_P_ALL, filter=None, nofilter=0): |
| if iface is None: |
| iface = conf.iface |
| self.iface = iface |
| self.ins = pcap.pcapObject() |
| self.ins.open_live(iface, 1600, 0, 100) |
| try: |
| ioctl(self.ins.fileno(),BIOCIMMEDIATE,struct.pack("I",1)) |
| except: |
| pass |
| if nofilter: |
| if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap |
| filter = "ether proto %i" % type |
| else: |
| filter = None |
| else: |
| if conf.except_filter: |
| if filter: |
| filter = "(%s) and not (%s)" % (filter, conf.except_filter) |
| else: |
| filter = "not (%s)" % conf.except_filter |
| if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap |
| if filter: |
| filter = "(ether proto %i) and (%s)" % (type,filter) |
| else: |
| filter = "ether proto %i" % type |
| if filter: |
| self.ins.setfilter(filter, 0, 0) |
| self.outs = dnet.eth(iface) |
| def recv(self,x): |
| ll = self.ins.datalink() |
| if LLTypes.has_key(ll): |
| cls = LLTypes[ll] |
| else: |
| warning("Unable to guess datalink type (interface=%s linktype=%i). Using Ethernet" % (self.iface, ll)) |
| cls = Ether |
| |
| pkt = self.ins.next() |
| if pkt is not None: |
| pkt = pkt[1] |
| if pkt is None: |
| return |
| |
| try: |
| pkt = cls(pkt) |
| except KeyboardInterrupt: |
| raise |
| except: |
| if conf.debug_dissector: |
| raise |
| pkt = Raw(pkt) |
| return pkt |
| |
| def nonblock_recv(self): |
| self.ins.setnonblock(1) |
| p = self.recv(MTU) |
| self.ins.setnonblock(0) |
| return p |
| |
| def close(self): |
| if hasattr(self, "ins"): |
| del(self.ins) |
| if hasattr(self, "outs"): |
| del(self.outs) |
| |
| |
| |
| |
| |
| class L2pcapListenSocket(SuperSocket): |
| def __init__(self, iface = None, type = ETH_P_ALL, promisc=None, filter=None): |
| self.type = type |
| self.outs = None |
| self.ins = pcap.pcapObject() |
| self.iface = iface |
| if iface is None: |
| iface = conf.iface |
| if promisc is None: |
| promisc = conf.sniff_promisc |
| self.promisc = promisc |
| self.ins.open_live(iface, 1600, self.promisc, 100) |
| try: |
| ioctl(self.ins.fileno(),BIOCIMMEDIATE,struct.pack("I",1)) |
| except: |
| pass |
| if type == ETH_P_ALL: # Do not apply any filter if Ethernet type is given |
| if conf.except_filter: |
| if filter: |
| filter = "(%s) and not (%s)" % (filter, conf.except_filter) |
| else: |
| filter = "not (%s)" % conf.except_filter |
| if filter: |
| self.ins.setfilter(filter, 0, 0) |
| |
| def close(self): |
| del(self.ins) |
| |
| def recv(self, x): |
| ll = self.ins.datalink() |
| if LLTypes.has_key(ll): |
| cls = LLTypes[ll] |
| else: |
| warning("Unable to guess datalink type (interface=%s linktype=%i). Using Ethernet" % (self.iface, ll)) |
| cls = Ether |
| |
| pkt = None |
| while pkt is None: |
| pkt = self.ins.next() |
| if pkt is not None: |
| pkt = pkt[1] |
| |
| try: |
| pkt = cls(pkt) |
| except KeyboardInterrupt: |
| raise |
| except: |
| if conf.debug_dissector: |
| raise |
| pkt = Raw(pkt) |
| return pkt |
| |
| def send(self, x): |
| raise Scapy_Exception("Can't send anything with L2pcapListenSocket") |
| |
| |
| class SimpleSocket(SuperSocket): |
| def __init__(self, sock): |
| self.ins = sock |
| self.outs = sock |
| |
| |
| class StreamSocket(SimpleSocket): |
| def __init__(self, sock, basecls=Raw): |
| SimpleSocket.__init__(self, sock) |
| self.basecls = basecls |
| |
| def recv(self, x=MTU): |
| pkt = self.ins.recv(x, socket.MSG_PEEK) |
| x = len(pkt) |
| pkt = self.basecls(pkt) |
| pad = pkt[Padding] |
| if pad is not None and pad.underlayer is not None: |
| del(pad.underlayer.payload) |
| while pad is not None and not isinstance(pad, NoPayload): |
| x -= len(pad.load) |
| pad = pad.payload |
| self.ins.recv(x) |
| return pkt |
| |
| |
| class BluetoothL2CAPSocket(SuperSocket): |
| def __init__(self, peer): |
| s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, |
| socket.BTPROTO_L2CAP) |
| s.connect((peer,0)) |
| |
| self.ins = self.outs = s |
| |
| def recv(self, x): |
| return L2CAP_HdrCmd(self.ins.recv(x)) |
| |
| |
| class BluetoothHCISocket(SuperSocket): |
| def __init__(self, iface=0x10000, type=None): |
| s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI) |
| s.setsockopt(socket.SOL_HCI, socket.HCI_DATA_DIR,1) |
| s.setsockopt(socket.SOL_HCI, socket.HCI_TIME_STAMP,1) |
| s.setsockopt(socket.SOL_HCI, socket.HCI_FILTER, struct.pack("IIIh2x", 0xffffffffL,0xffffffffL,0xffffffffL,0)) #type mask, event mask, event mask, opcode |
| s.bind((iface,)) |
| self.ins = self.outs = s |
| # s.connect((peer,0)) |
| |
| |
| def recv(self, x): |
| return HCI_Hdr(self.ins.recv(x)) |
| |
| |
| |
| #################### |
| ## Send / Receive ## |
| #################### |
| |
| |
| |
| |
| def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, multi=0): |
| if not isinstance(pkt, Gen): |
| pkt = SetGen(pkt) |
| |
| if verbose is None: |
| verbose = conf.verb |
| debug.recv = PacketList([],"Unanswered") |
| debug.sent = PacketList([],"Sent") |
| debug.match = SndRcvList([]) |
| nbrecv=0 |
| ans = [] |
| # do it here to fix random fields, so that parent and child have the same |
| tobesent = [p for p in pkt] |
| notans = len(tobesent) |
| |
| hsent={} |
| for i in tobesent: |
| h = i.hashret() |
| if h in hsent: |
| hsent[h].append(i) |
| else: |
| hsent[h] = [i] |
| if retry < 0: |
| retry = -retry |
| autostop=retry |
| else: |
| autostop=0 |
| |
| |
| while retry >= 0: |
| found=0 |
| |
| if timeout < 0: |
| timeout = None |
| |
| rdpipe,wrpipe = os.pipe() |
| rdpipe=os.fdopen(rdpipe) |
| wrpipe=os.fdopen(wrpipe,"w") |
| |
| pid = os.fork() |
| if pid == 0: |
| sys.stdin.close() |
| rdpipe.close() |
| try: |
| i = 0 |
| if verbose: |
| print "Begin emission:" |
| for p in tobesent: |
| pks.send(p) |
| i += 1 |
| time.sleep(inter) |
| if verbose: |
| print "Finished to send %i packets." % i |
| except SystemExit: |
| pass |
| except KeyboardInterrupt: |
| pass |
| except: |
| log_runtime.exception("--- Error in child %i" % os.getpid()) |
| log_runtime.info("--- Error in child %i" % os.getpid()) |
| os._exit(0) |
| else: |
| cPickle.dump(arp_cache, wrpipe) |
| wrpipe.close() |
| os._exit(0) |
| elif pid < 0: |
| log_runtime.error("fork error") |
| else: |
| wrpipe.close() |
| stoptime = 0 |
| remaintime = None |
| inmask = [rdpipe,pks] |
| try: |
| while 1: |
| if stoptime: |
| remaintime = stoptime-time.time() |
| if remaintime <= 0: |
| break |
| r = None |
| if FREEBSD or DARWIN: |
| inp, out, err = select(inmask,[],[], 0.05) |
| if len(inp) == 0 or pks in inp: |
| r = pks.nonblock_recv() |
| else: |
| inp, out, err = select(inmask,[],[], remaintime) |
| if len(inp) == 0: |
| break |
| if pks in inp: |
| r = pks.recv(MTU) |
| if rdpipe in inp: |
| if timeout: |
| stoptime = time.time()+timeout |
| del(inmask[inmask.index(rdpipe)]) |
| if r is None: |
| continue |
| ok = 0 |
| h = r.hashret() |
| if h in hsent: |
| hlst = hsent[h] |
| for i in range(len(hlst)): |
| if r.answers(hlst[i]): |
| ans.append((hlst[i],r)) |
| if verbose > 1: |
| os.write(1, "*") |
| ok = 1 |
| if not multi: |
| del(hlst[i]) |
| notans -= 1; |
| else: |
| if not hasattr(hlst[i], '_answered'): |
| notans -= 1; |
| hlst[i]._answered = 1; |
| break |
| if notans == 0 and not multi: |
| break |
| if not ok: |
| if verbose > 1: |
| os.write(1, ".") |
| nbrecv += 1 |
| if conf.debug_match: |
| debug.recv.append(r) |
| except KeyboardInterrupt: |
| if chainCC: |
| raise |
| |
| try: |
| ac = cPickle.load(rdpipe) |
| except EOFError: |
| warning("Child died unexpectedly. Packets may have not been sent") |
| else: |
| arp_cache.update(ac) |
| os.waitpid(pid,0) |
| |
| remain = reduce(list.__add__, hsent.values(), []) |
| if multi: |
| remain = filter(lambda p: not hasattr(p, '_answered'), remain); |
| |
| if autostop and len(remain) > 0 and len(remain) != len(tobesent): |
| retry = autostop |
| |
| tobesent = remain |
| if len(tobesent) == 0: |
| break |
| retry -= 1 |
| |
| if conf.debug_match: |
| debug.sent=PacketList(remain[:],"Sent") |
| debug.match=SndRcvList(ans[:]) |
| |
| #clean the ans list to delete the field _answered |
| if (multi): |
| for s,r in ans: |
| if hasattr(s, '_answered'): |
| del(s._answered) |
| |
| if verbose: |
| print "\nReceived %i packets, got %i answers, remaining %i packets" % (nbrecv+len(ans), len(ans), notans) |
| return SndRcvList(ans),PacketList(remain,"Unanswered"),debug.recv |
| |
| |
| def __gen_send(s, x, inter=0, loop=0, count=None, verbose=None, *args, **kargs): |
| if not isinstance(x, Gen): |
| x = SetGen(x) |
| if verbose is None: |
| verbose = conf.verb |
| n = 0 |
| if count is not None: |
| loop = -count |
| elif not loop: |
| loop=-1 |
| try: |
| while loop: |
| for p in x: |
| s.send(p) |
| n += 1 |
| if verbose: |
| os.write(1,".") |
| time.sleep(inter) |
| if loop < 0: |
| loop += 1 |
| except KeyboardInterrupt: |
| pass |
| s.close() |
| if verbose: |
| print "\nSent %i packets." % n |
| |
| def send(x, inter=0, loop=0, count=None, verbose=None, *args, **kargs): |
| """Send packets at layer 3 |
| send(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None""" |
| __gen_send(conf.L3socket(*args, **kargs), x, inter=inter, loop=loop, count=count,verbose=verbose) |
| |
| def sendp(x, inter=0, loop=0, iface=None, iface_hint=None, count=None, verbose=None, *args, **kargs): |
| """Send packets at layer 2 |
| send(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None""" |
| if iface is None and iface_hint is not None: |
| iface = conf.route.route(iface_hint)[0] |
| __gen_send(conf.L2socket(iface=iface, *args, **kargs), x, inter=inter, loop=loop, count=count, verbose=verbose) |
| |
| def sr(x,filter=None, iface=None, nofilter=0, *args,**kargs): |
| """Send and receive packets at layer 3 |
| nofilter: put 1 to avoid use of bpf filters |
| retry: if positive, how many times to resend unanswered packets |
| if negative, how many times to retry when no more packets are answered |
| timeout: how much time to wait after the last packet has been sent |
| verbose: set verbosity level |
| multi: whether to accept multiple answers for the same stimulus |
| filter: provide a BPF filter |
| iface: listen answers only on the given interface""" |
| if not kargs.has_key("timeout"): |
| kargs["timeout"] = -1 |
| s = conf.L3socket(filter=filter, iface=iface, nofilter=nofilter) |
| a,b,c=sndrcv(s,x,*args,**kargs) |
| s.close() |
| return a,b |
| |
| def sr1(x,filter=None,iface=None, nofilter=0, *args,**kargs): |
| """Send packets at layer 3 and return only the first answer |
| nofilter: put 1 to avoid use of bpf filters |
| retry: if positive, how many times to resend unanswered packets |
| if negative, how many times to retry when no more packets are answered |
| timeout: how much time to wait after the last packet has been sent |
| verbose: set verbosity level |
| multi: whether to accept multiple answers for the same stimulus |
| filter: provide a BPF filter |
| iface: listen answers only on the given interface""" |
| if not kargs.has_key("timeout"): |
| kargs["timeout"] = -1 |
| s=conf.L3socket(filter=filter, nofilter=nofilter, iface=iface) |
| a,b,c=sndrcv(s,x,*args,**kargs) |
| s.close() |
| if len(a) > 0: |
| return a[0][1] |
| else: |
| return None |
| |
| def srp(x,iface=None, iface_hint=None, filter=None, nofilter=0, type=ETH_P_ALL, *args,**kargs): |
| """Send and receive packets at layer 2 |
| nofilter: put 1 to avoid use of bpf filters |
| retry: if positive, how many times to resend unanswered packets |
| if negative, how many times to retry when no more packets are answered |
| timeout: how much time to wait after the last packet has been sent |
| verbose: set verbosity level |
| multi: whether to accept multiple answers for the same stimulus |
| filter: provide a BPF filter |
| iface: work only on the given interface""" |
| if not kargs.has_key("timeout"): |
| kargs["timeout"] = -1 |
| if iface is None and iface_hint is not None: |
| iface = conf.route.route(iface_hint)[0] |
| a,b,c=sndrcv(conf.L2socket(iface=iface, filter=filter, nofilter=nofilter, type=type),x,*args,**kargs) |
| return a,b |
| |
| def srp1(*args,**kargs): |
| """Send and receive packets at layer 2 and return only the first answer |
| nofilter: put 1 to avoid use of bpf filters |
| retry: if positive, how many times to resend unanswered packets |
| if negative, how many times to retry when no more packets are answered |
| timeout: how much time to wait after the last packet has been sent |
| verbose: set verbosity level |
| multi: whether to accept multiple answers for the same stimulus |
| filter: provide a BPF filter |
| iface: work only on the given interface""" |
| if not kargs.has_key("timeout"): |
| kargs["timeout"] = -1 |
| a,b=srp(*args,**kargs) |
| if len(a) > 0: |
| return a[0][1] |
| else: |
| return None |
| |
| def __sr_loop(srfunc, pkts, prn=lambda x:x[1].summary(), prnfail=lambda x:x.summary(), inter=1, timeout=None, count=None, verbose=0, store=1, *args, **kargs): |
| n = 0 |
| r = 0 |
| ct = conf.color_theme |
| parity = 0 |
| ans=[] |
| unans=[] |
| if timeout is None: |
| timeout = min(2*inter, 5) |
| try: |
| while 1: |
| parity ^= 1 |
| col = [ct.even,ct.odd][parity] |
| if count is not None: |
| if count == 0: |
| break |
| count -= 1 |
| start = time.time() |
| print "\rsend...\r", |
| res = srfunc(pkts, timeout=timeout, verbose=0, chainCC=1, *args, **kargs) |
| n += len(res[0])+len(res[1]) |
| r += len(res[0]) |
| if prn and len(res[0]) > 0: |
| msg = "RECV %i:" % len(res[0]) |
| print "\r"+ct.success(msg), |
| for p in res[0]: |
| print col(prn(p)) |
| print " "*len(msg), |
| if prnfail and len(res[1]) > 0: |
| msg = "fail %i:" % len(res[1]) |
| print "\r"+ct.fail(msg), |
| for p in res[1]: |
| print col(prnfail(p)) |
| print " "*len(msg), |
| if not (prn or prnfail): |
| print "recv:%i fail:%i" % tuple(map(len, res[:2])) |
| if store: |
| ans += res[0] |
| unans += res[1] |
| end=time.time() |
| if end-start < inter: |
| time.sleep(inter+start-end) |
| except KeyboardInterrupt: |
| pass |
| |
| if n>0: |
| print "%s\nSent %i packets, received %i packets. %3.1f%% hits." % (Color.normal,n,r,100.0*r/n) |
| |
| return SndRcvList(ans),PacketList(unans) |
| |
| def srloop(pkts, *args, **kargs): |
| """Send a packet at layer 3 in loop and print the answer each time |
| srloop(pkts, [prn], [inter], [count], ...) --> None""" |
| return __sr_loop(sr, pkts, *args, **kargs) |
| |
| def srploop(pkts, *args, **kargs): |
| """Send a packet at layer 2 in loop and print the answer each time |
| srloop(pkts, [prn], [inter], [count], ...) --> None""" |
| return __sr_loop(srp, pkts, *args, **kargs) |
| |
| |
| def sndrcvflood(pks, pkt, prn=lambda (s,r):r.summary(), chainCC=0, store=1, unique=0): |
| if not isinstance(pkt, Gen): |
| pkt = SetGen(pkt) |
| tobesent = [p for p in pkt] |
| received = SndRcvList() |
| seen = {} |
| |
| hsent={} |
| for i in tobesent: |
| h = i.hashret() |
| if h in hsent: |
| hsent[h].append(i) |
| else: |
| hsent[h] = [i] |
| |
| def send_in_loop(tobesent): |
| while 1: |
| for p in tobesent: |
| yield p |
| |
| packets_to_send = send_in_loop(tobesent) |
| |
| ssock = rsock = pks.fileno() |
| |
| try: |
| while 1: |
| readyr,readys,_ = select([rsock],[ssock],[]) |
| if ssock in readys: |
| pks.send(packets_to_send.next()) |
| |
| if rsock in readyr: |
| p = pks.recv(MTU) |
| if p is None: |
| continue |
| h = p.hashret() |
| if h in hsent: |
| hlst = hsent[h] |
| for i in hlst: |
| if p.answers(i): |
| res = prn((i,p)) |
| if unique: |
| if res in seen: |
| continue |
| seen[res] = None |
| if res is not None: |
| print res |
| if store: |
| received.append((i,p)) |
| except KeyboardInterrupt: |
| if chainCC: |
| raise |
| return received |
| |
| def srflood(x,filter=None, iface=None, nofilter=None, *args,**kargs): |
| """Flood and receive packets at layer 3 |
| prn: function applied to packets received. Ret val is printed if not None |
| store: if 1 (default), store answers and return them |
| unique: only consider packets whose print |
| nofilter: put 1 to avoid use of bpf filters |
| filter: provide a BPF filter |
| iface: listen answers only on the given interface""" |
| s = conf.L3socket(filter=filter, iface=iface, nofilter=nofilter) |
| r=sndrcvflood(s,x,*args,**kargs) |
| s.close() |
| return r |
| |
| def srpflood(x,filter=None, iface=None, iface_hint=None, nofilter=None, *args,**kargs): |
| """Flood and receive packets at layer 2 |
| prn: function applied to packets received. Ret val is printed if not None |
| store: if 1 (default), store answers and return them |
| unique: only consider packets whose print |
| nofilter: put 1 to avoid use of bpf filters |
| filter: provide a BPF filter |
| iface: listen answers only on the given interface""" |
| if iface is None and iface_hint is not None: |
| iface = conf.route.route(iface_hint)[0] |
| s = conf.L2socket(filter=filter, iface=iface, nofilter=nofilter) |
| r=sndrcvflood(s,x,*args,**kargs) |
| s.close() |
| return r |
| |
| |
| ## Bluetooth |
| |
| |
| def srbt(peer, pkts, inter=0.1, *args, **kargs): |
| s = conf.BTsocket(peer=peer) |
| a,b,c=sndrcv(s,pkts,inter=inter,*args,**kargs) |
| s.close() |
| return a,b |
| |
| def srbt1(peer, pkts, *args, **kargs): |
| a,b = srbt(peer, pkts, *args, **kargs) |
| if len(a) > 0: |
| return a[0][1] |
| |
| |
| |
| |
| |
| ############################# |
| ## pcap capture file stuff ## |
| ############################# |
| |
| def wrpcap(filename, pkt, *args, **kargs): |
| """Write a list of packets to a pcap file |
| gz: set to 1 to save a gzipped capture |
| linktype: force linktype value |
| endianness: "<" or ">", force endianness""" |
| PcapWriter(filename, *args, **kargs).write(pkt) |
| |
| def rdpcap(filename, count=-1): |
| """Read a pcap file and return a packet list |
| count: read only <count> packets""" |
| return PcapReader(filename).read_all(count=count) |
| |
| class PcapReader: |
| """A stateful pcap reader |
| |
| Based entirely on scapy.rdpcap(), this class allows for packets |
| to be dispatched without having to be loaded into memory all at |
| once |
| """ |
| |
| def __init__(self, filename): |
| self.filename = filename |
| try: |
| self.f = gzip.open(filename,"rb") |
| magic = self.f.read(4) |
| except IOError: |
| self.f = open(filename,"rb") |
| magic = self.f.read(4) |
| if magic == "\xa1\xb2\xc3\xd4": #big endian |
| self.endian = ">" |
| elif magic == "\xd4\xc3\xb2\xa1": #little endian |
| self.endian = "<" |
| else: |
| raise RuntimeWarning, "Not a pcap capture file (bad magic)" |
| hdr = self.f.read(20) |
| if len(hdr)<20: |
| raise RuntimeWarning, "Invalid pcap file (too short)" |
| vermaj,vermin,tz,sig,snaplen,linktype = struct.unpack(self.endian+"HHIIII",hdr) |
| self.LLcls = LLTypes.get(linktype, Raw) |
| if self.LLcls == Raw: |
| warning("PcapReader: unkonwon LL type [%i]/[%#x]. Using Raw packets" % (linktype,linktype)) |
| |
| def __iter__(self): |
| return self |
| |
| def next(self): |
| """impliment the iterator protocol on a set of packets in a |
| pcap file |
| """ |
| pkt = self.read_packet() |
| if pkt == None: |
| raise StopIteration |
| return pkt |
| |
| |
| def read_packet(self): |
| """return a single packet read from the file |
| |
| returns None when no more packets are available |
| """ |
| hdr = self.f.read(16) |
| if len(hdr) < 16: |
| return None |
| sec,usec,caplen,olen = struct.unpack(self.endian+"IIII", hdr) |
| s = self.f.read(caplen) |
| try: |
| p = self.LLcls(s) |
| except KeyboardInterrupt: |
| raise |
| except: |
| if conf.debug_dissector: |
| raise |
| p = Raw(s) |
| p.time = sec+0.000001*usec |
| return p |
| |
| def dispatch(self, callback): |
| """call the specified callback routine for each packet read |
| |
| This is just a convienience function for the main loop |
| that allows for easy launching of packet processing in a |
| thread. |
| """ |
| p = self.read_packet() |
| while p != None: |
| callback(p) |
| p = self.read_packet() |
| |
| def read_all(self,count=-1): |
| """return a list of all packets in the pcap file |
| """ |
| res=[] |
| while count != 0: |
| count -= 1 |
| p = self.read_packet() |
| if p is None: |
| break |
| res.append(p) |
| return PacketList(res,name = os.path.basename(self.filename)) |
| |
| def recv(self, size): |
| """ Emulate a socket |
| """ |
| return self.read_packet() |
| |
| def fileno(self): |
| return self.f.fileno() |
| |
| |
| |
| class PcapWriter: |
| """A pcap writer with more control than wrpcap() |
| |
| This routine is based entirely on scapy.wrpcap(), but adds capability |
| of writing one packet at a time in a streaming manner. |
| """ |
| def __init__(self, filename, linktype=None, gz=0, endianness=""): |
| self.linktype = linktype |
| self.header_done = 0 |
| if gz: |
| self.f = gzip.open(filename,"wb") |
| else: |
| self.f = open(filename,"wb") |
| self.endian = endianness |
| |
| def fileno(self): |
| return self.f.fileno() |
| |
| def write(self, pkt): |
| """accepts a either a single packet or a list of packets |
| to be written to the dumpfile |
| """ |
| |
| if self.header_done == 0: |
| if self.linktype == None: |
| if isinstance(pkt,Packet): |
| linktype = LLNumTypes.get(pkt.__class__,1) |
| else: |
| linktype = LLNumTypes.get(pkt[0].__class__,1) |
| |
| self.f.write(struct.pack(self.endian+"IHHIIII", 0xa1b2c3d4L, |
| 2, 4, 0, 0, MTU, linktype)) |
| self.header_done = 1 |
| |
| for p in pkt: |
| self._write_packet(p) |
| |
| def _write_packet(self, packet): |
| """writes a single packet to the pcap file |
| """ |
| s = str(packet) |
| l = len(s) |
| sec = int(packet.time) |
| usec = int((packet.time-sec)*1000000) |
| self.f.write(struct.pack(self.endian+"IIII", sec, usec, l, l)) |
| self.f.write(s) |
| |
| re_extract_hexcap = re.compile("^(0x[0-9a-fA-F]{2,}[ :\t]|(0x)?[0-9a-fA-F]{2,}:|(0x)?[0-9a-fA-F]{3,}[: \t]|) *(([0-9a-fA-F]{2} {,2}){,16})") |
| |
| def import_hexcap(): |
| p = "" |
| try: |
| while 1: |
| l = raw_input().strip() |
| try: |
| p += re_extract_hexcap.match(l).groups()[3] |
| except: |
| warning("Parsing error during hexcap") |
| continue |
| except EOFError: |
| pass |
| |
| p = p.replace(" ","") |
| p2="" |
| for i in range(len(p)/2): |
| p2 += chr(int(p[2*i:2*i+2],16)) |
| return p2 |
| |
| |
| |
| def wireshark(pktlist): |
| f = os.tempnam("scapy") |
| wrpcap(f, pktlist) |
| os.spawnlp(os.P_NOWAIT, conf.prog.wireshark, conf.prog.wireshark, "-r", f) |
| |
| def hexedit(x): |
| x = str(x) |
| f = os.tempnam("scapy") |
| open(f,"w").write(x) |
| os.spawnlp(os.P_WAIT, conf.prog.hexedit, conf.prog.hexedit, f) |
| x = open(f).read() |
| os.unlink(f) |
| return x |
| |
| |
| ##################### |
| ## knowledge bases ## |
| ##################### |
| |
| class KnowledgeBase: |
| def __init__(self, filename): |
| self.filename = filename |
| self.base = None |
| |
| def lazy_init(self): |
| self.base = "" |
| |
| def reload(self, filename = None): |
| if filename is not None: |
| self.filename = filename |
| oldbase = self.base |
| self.base = None |
| self.lazy_init() |
| if self.base is None: |
| self.base = oldbase |
| |
| def get_base(self): |
| if self.base is None: |
| self.lazy_init() |
| return self.base |
| |
| |
| |
| ########################## |
| ## IP location database ## |
| ########################## |
| |
| class IPCountryKnowledgeBase(KnowledgeBase): |
| """ |
| How to generate the base : |
| db = [] |
| for l in open("GeoIPCountryWhois.csv").readlines(): |
| s,e,c = l.split(",")[2:5] |
| db.append((int(s[1:-1]),int(e[1:-1]),c[1:-1])) |
| cPickle.dump(gzip.open("xxx","w"),db) |
| """ |
| def lazy_init(self): |
| self.base = load_object(self.filename) |
| |
| |
| class CountryLocKnowledgeBase(KnowledgeBase): |
| def lazy_init(self): |
| f=open(self.filename) |
| self.base = {} |
| while 1: |
| l = f.readline() |
| if not l: |
| break |
| l = l.strip().split(",") |
| if len(l) != 3: |
| continue |
| c,lat,long = l |
| |
| self.base[c] = (float(long),float(lat)) |
| f.close() |
| |
| |
| |
| |
| def locate_ip(ip): |
| ip=map(int,ip.split(".")) |
| ip = ip[3]+(ip[2]<<8L)+(ip[1]<<16L)+(ip[0]<<24L) |
| |
| cloc = country_loc_kdb.get_base() |
| db = IP_country_kdb.get_base() |
| |
| d=0 |
| f=len(db)-1 |
| while (f-d) > 1: |
| guess = (d+f)/2 |
| if ip > db[guess][0]: |
| d = guess |
| else: |
| f = guess |
| s,e,c = db[guess] |
| if s <= ip and ip <= e: |
| return cloc.get(c,None) |
| |
| |
| |
| |
| ############### |
| ## p0f stuff ## |
| ############### |
| |
| # File format (according to p0f.fp) : |
| # |
| # wwww:ttt:D:ss:OOO...:QQ:OS:Details |
| # |
| # wwww - window size |
| # ttt - initial TTL |
| # D - don't fragment bit (0=unset, 1=set) |
| # ss - overall SYN packet size |
| # OOO - option value and order specification |
| # QQ - quirks list |
| # OS - OS genre |
| # details - OS description |
| |
| |
| |
| class p0fKnowledgeBase(KnowledgeBase): |
| def __init__(self, filename): |
| KnowledgeBase.__init__(self, filename) |
| #self.ttl_range=[255] |
| def lazy_init(self): |
| try: |
| f=open(self.filename) |
| except IOError: |
| warning("Can't open base %s" % self.filename) |
| return |
| try: |
| self.base = [] |
| for l in f: |
| if l[0] in ["#","\n"]: |
| continue |
| l = tuple(l.split(":")) |
| if len(l) < 8: |
| continue |
| li = map(int,l[1:4]) |
| #if li[0] not in self.ttl_range: |
| # self.ttl_range.append(li[0]) |
| # self.ttl_range.sort() |
| self.base.append((l[0], li[0], li[1], li[2], l[4], l[5], l[6], l[7][:-1])) |
| except: |
| warning("Can't parse p0f database (new p0f version ?)") |
| self.base = None |
| f.close() |
| |
| |
| def packet2p0f(pkt): |
| while pkt.haslayer(IP) and pkt.haslayer(TCP): |
| pkt = pkt.getlayer(IP) |
| if isinstance(pkt.payload, TCP): |
| break |
| pkt = pkt.payload |
| |
| if not isinstance(pkt, IP) or not isinstance(pkt.payload, TCP): |
| raise TypeError("Not a TCP/IP packet") |
| if pkt.payload.flags & 0x13 != 0x02: #S,!A,!F |
| raise TypeError("Not a syn packet") |
| |
| #t = p0f_kdb.ttl_range[:] |
| #t += [pkt.ttl] |
| #t.sort() |
| #ttl=t[t.index(pkt.ttl)+1] |
| ttl = pkt.ttl |
| |
| df = (pkt.flags & 2) / 2 |
| ss = len(pkt) |
| # from p0f/config.h : PACKET_BIG = 100 |
| if ss > 100: |
| ss = 0 |
| |
| ooo = "" |
| mss = -1 |
| qqT = False |
| qqP = False |
| #qqBroken = False |
| ilen = (pkt[TCP].dataofs << 2) - 20 # from p0f.c |
| for option in pkt.payload.options: |
| ilen -= 1 |
| if option[0] == "MSS": |
| ooo += "M" + str(option[1]) + "," |
| mss = option[1] |
| # FIXME: qqBroken |
| ilen -= 3 |
| elif option[0] == "WScale": |
| ooo += "W" + str(option[1]) + "," |
| # FIXME: qqBroken |
| ilen -= 2 |
| elif option[0] == "Timestamp": |
| if option[1][0] == 0: |
| ooo += "T0," |
| else: |
| ooo += "T," |
| if option[1][1] != 0: |
| qqT = True |
| ilen -= 9 |
| elif option[0] == "SAckOK": |
| ooo += "S," |
| ilen -= 1 |
| elif option[0] == "NOP": |
| ooo += "N," |
| elif option[0] == "EOL": |
| ooo += "E," |
| if ilen > 0: |
| qqP = True |
| else: |
| ooo += "?," |
| # FIXME: ilen |
| ooo = ooo[:-1] |
| if ooo == "": ooo = "." |
| |
| win = pkt.payload.window |
| if mss != -1: |
| if win % mss == 0: |
| win = "S" + str(win/mss) |
| elif win % (mss + 40) == 0: |
| win = "T" + str(win/(mss+40)) |
| win = str(win) |
| |
| qq = "" |
| |
| if qqP: |
| qq += "P" |
| if pkt[IP].id == 0: |
| qq += "Z" |
| if pkt[IP].options != '': |
| qq += "I" |
| if pkt[TCP].urgptr != 0: |
| qq += "U" |
| if pkt[TCP].reserved != 0: |
| qq += "X" |
| if pkt[TCP].ack != 0: |
| qq += "A" |
| if qqT: |
| qq += "T" |
| if pkt[TCP].flags & 40 != 0: |
| # U or P |
| qq += "F" |
| if not isinstance(pkt[TCP].payload, NoPayload): |
| qq += "D" |
| # FIXME : "!" - broken options segment |
| |
| if qq == "": |
| qq = "." |
| |
| return (win, |
| ttl, |
| df, |
| ss, |
| ooo, |
| qq) |
| |
| def p0f_correl(x,y): |
| d = 0 |
| # wwww can be "*" or "%nn" |
| d += (x[0] == y[0] or y[0] == "*" or (y[0][0] == "%" and x[0].isdigit() and (int(x[0]) % int(y[0][1:])) == 0)) |
| # ttl |
| d += (y[1] >= x[1] and y[1] - x[1] < 32) |
| for i in [2, 3, 5]: |
| d += (x[i] == y[i]) |
| xopt = x[4].split(",") |
| yopt = y[4].split(",") |
| if len(xopt) == len(yopt): |
| same = True |
| for i in range(len(xopt)): |
| if not (xopt[i] == yopt[i] or |
| (len(yopt[i]) == 2 and len(xopt[i]) > 1 and |
| yopt[i][1] == "*" and xopt[i][0] == yopt[i][0]) or |
| (len(yopt[i]) > 2 and len(xopt[i]) > 1 and |
| yopt[i][1] == "%" and xopt[i][0] == yopt[i][0] and |
| int(xopt[i][1:]) % int(yopt[i][2:]) == 0)): |
| same = False |
| break |
| if same: |
| d += len(xopt) |
| return d |
| |
| |
| def p0f(pkt): |
| """Passive OS fingerprinting: which OS emitted this TCP SYN ? |
| p0f(packet) -> accuracy, [list of guesses] |
| """ |
| pb = p0f_kdb.get_base() |
| if not pb: |
| warning("p0f base empty.") |
| return [] |
| s = len(pb[0][0]) |
| r = [] |
| sig = packet2p0f(pkt) |
| max = len(sig[4].split(",")) + 5 |
| for b in pb: |
| d = p0f_correl(sig,b) |
| if d == max: |
| r.append((b[6], b[7], b[1] - pkt[IP].ttl)) |
| return r |
| |
| |
| def prnp0f(pkt): |
| try: |
| r = p0f(pkt) |
| except: |
| return |
| if r == []: |
| r = ("UNKNOWN", "[" + ":".join(map(str, packet2p0f(pkt))) + ":?:?]", None) |
| else: |
| r = r[0] |
| uptime = None |
| try: |
| uptime = pkt2uptime(pkt) |
| except: |
| pass |
| if uptime == 0: |
| uptime = None |
| res = pkt.sprintf("%IP.src%:%TCP.sport% - " + r[0] + " " + r[1]) |
| if uptime is not None: |
| res += pkt.sprintf(" (up: " + str(uptime/3600) + " hrs)\n -> %IP.dst%:%TCP.dport%") |
| else: |
| res += pkt.sprintf("\n -> %IP.dst%:%TCP.dport%") |
| if r[2] is not None: |
| res += " (distance " + str(r[2]) + ")" |
| print res |
| |
| |
| def pkt2uptime(pkt, HZ=100): |
| """Calculate the date the machine which emitted the packet booted using TCP timestamp |
| pkt2uptime(pkt, [HZ=100])""" |
| if not isinstance(pkt, Packet): |
| raise TypeError("Not a TCP packet") |
| if isinstance(pkt,NoPayload): |
| raise TypeError("Not a TCP packet") |
| if not isinstance(pkt, TCP): |
| return pkt2uptime(pkt.payload) |
| for opt in pkt.options: |
| if opt[0] == "Timestamp": |
| #t = pkt.time - opt[1][0] * 1.0/HZ |
| #return time.ctime(t) |
| t = opt[1][0] / HZ |
| return t |
| raise TypeError("No timestamp option") |
| |
| |
| |
| ################# |
| ## Queso stuff ## |
| ################# |
| |
| |
| def quesoTCPflags(flags): |
| if flags == "-": |
| return "-" |
| flv = "FSRPAUXY" |
| v = 0 |
| for i in flags: |
| v |= 2**flv.index(i) |
| return "%x" % v |
| |
| class QuesoKnowledgeBase(KnowledgeBase): |
| def lazy_init(self): |
| try: |
| f = open(self.filename) |
| except IOError: |
| return |
| self.base = {} |
| p = None |
| try: |
| for l in f: |
| l = l.strip() |
| if not l or l[0] == ';': |
| continue |
| if l[0] == '*': |
| if p is not None: |
| p[""] = name |
| name = l[1:].strip() |
| p = self.base |
| continue |
| if l[0] not in list("0123456"): |
| continue |
| res = l[2:].split() |
| res[-1] = quesoTCPflags(res[-1]) |
| res = " ".join(res) |
| if not p.has_key(res): |
| p[res] = {} |
| p = p[res] |
| if p is not None: |
| p[""] = name |
| except: |
| self.base = None |
| warning("Can't load queso base [%s]", self.filename) |
| f.close() |
| |
| |
| |
| |
| def queso_sig(target, dport=80, timeout=3): |
| p = queso_kdb.get_base() |
| ret = [] |
| for flags in ["S", "SA", "F", "FA", "SF", "P", "SEC"]: |
| ans, unans = sr(IP(dst=target)/TCP(dport=dport,flags=flags,seq=RandInt()), |
| timeout=timeout, verbose=0) |
| if len(ans) == 0: |
| rs = "- - - -" |
| else: |
| s,r = ans[0] |
| rs = "%i" % (r.seq != 0) |
| if not r.ack: |
| r += " 0" |
| elif r.ack-s.seq > 666: |
| rs += " R" % 0 |
| else: |
| rs += " +%i" % (r.ack-s.seq) |
| rs += " %X" % r.window |
| rs += " %x" % r.payload.flags |
| ret.append(rs) |
| return ret |
| |
| def queso_search(sig): |
| p = queso_kdb.get_base() |
| sig.reverse() |
| ret = [] |
| try: |
| while sig: |
| s = sig.pop() |
| p = p[s] |
| if p.has_key(""): |
| ret.append(p[""]) |
| except KeyError: |
| pass |
| return ret |
| |
| |
| def queso(*args,**kargs): |
| """Queso OS fingerprinting |
| queso(target, dport=80, timeout=3)""" |
| return queso_search(queso_sig(*args, **kargs)) |
| |
| |
| |
| ###################### |
| ## nmap OS fp stuff ## |
| ###################### |
| |
| |
| class NmapKnowledgeBase(KnowledgeBase): |
| def lazy_init(self): |
| try: |
| f=open(self.filename) |
| except IOError: |
| return |
| |
| self.base = [] |
| name = None |
| try: |
| for l in f: |
| l = l.strip() |
| if not l or l[0] == "#": |
| continue |
| if l[:12] == "Fingerprint ": |
| if name is not None: |
| self.base.append((name,sig)) |
| name = l[12:].strip() |
| sig={} |
| p = self.base |
| continue |
| elif l[:6] == "Class ": |
| continue |
| op = l.find("(") |
| cl = l.find(")") |
| if op < 0 or cl < 0: |
| warning("error reading nmap os fp base file") |
| continue |
| test = l[:op] |
| s = map(lambda x: x.split("="), l[op+1:cl].split("%")) |
| si = {} |
| for n,v in s: |
| si[n] = v |
| sig[test]=si |
| if name is not None: |
| self.base.append((name,sig)) |
| except: |
| self.base = None |
| warning("Can't read nmap database [%s](new nmap version ?)" % self.filename) |
| f.close() |
| |
| def TCPflags2str(f): |
| fl="FSRPAUEC" |
| s="" |
| for i in range(len(fl)): |
| if f & 1: |
| s = fl[i]+s |
| f >>= 1 |
| return s |
| |
| def nmap_tcppacket_sig(pkt): |
| r = {} |
| if pkt is not None: |
| # r["Resp"] = "Y" |
| r["DF"] = (pkt.flags & 2) and "Y" or "N" |
| r["W"] = "%X" % pkt.window |
| r["ACK"] = pkt.ack==2 and "S++" or pkt.ack==1 and "S" or "O" |
| r["Flags"] = TCPflags2str(pkt.payload.flags) |
| r["Ops"] = "".join(map(lambda x: x[0][0],pkt.payload.options)) |
| else: |
| r["Resp"] = "N" |
| return r |
| |
| |
| def nmap_udppacket_sig(S,T): |
| r={} |
| if T is None: |
| r["Resp"] = "N" |
| else: |
| r["DF"] = (T.flags & 2) and "Y" or "N" |
| r["TOS"] = "%X" % T.tos |
| r["IPLEN"] = "%X" % T.len |
| r["RIPTL"] = "%X" % T.payload.payload.len |
| r["RID"] = S.id == T.payload.payload.id and "E" or "F" |
| r["RIPCK"] = S.chksum == T.getlayer(IPerror).chksum and "E" or T.getlayer(IPerror).chksum == 0 and "0" or "F" |
| r["UCK"] = S.payload.chksum == T.getlayer(UDPerror).chksum and "E" or T.getlayer(UDPerror).chksum ==0 and "0" or "F" |
| r["ULEN"] = "%X" % T.getlayer(UDPerror).len |
| r["DAT"] = T.getlayer(Raw) is None and "E" or S.getlayer(Raw).load == T.getlayer(Raw).load and "E" or "F" |
| return r |
| |
| |
| |
| def nmap_match_one_sig(seen, ref): |
| c = 0 |
| for k in seen.keys(): |
| if ref.has_key(k): |
| if seen[k] in ref[k].split("|"): |
| c += 1 |
| if c == 0 and seen.get("Resp") == "N": |
| return 0.7 |
| else: |
| return 1.0*c/len(seen.keys()) |
| |
| |
| |
| def nmap_sig(target, oport=80, cport=81, ucport=1): |
| res = {} |
| |
| tcpopt = [ ("WScale", 10), |
| ("NOP",None), |
| ("MSS", 256), |
| ("Timestamp",(123,0)) ] |
| tests = [ IP(dst=target, id=1)/TCP(seq=1, sport=5001, dport=oport, options=tcpopt, flags="CS"), |
| IP(dst=target, id=1)/TCP(seq=1, sport=5002, dport=oport, options=tcpopt, flags=0), |
| IP(dst=target, id=1)/TCP(seq=1, sport=5003, dport=oport, options=tcpopt, flags="SFUP"), |
| IP(dst=target, id=1)/TCP(seq=1, sport=5004, dport=oport, options=tcpopt, flags="A"), |
| IP(dst=target, id=1)/TCP(seq=1, sport=5005, dport=cport, options=tcpopt, flags="S"), |
| IP(dst=target, id=1)/TCP(seq=1, sport=5006, dport=cport, options=tcpopt, flags="A"), |
| IP(dst=target, id=1)/TCP(seq=1, sport=5007, dport=cport, options=tcpopt, flags="FPU"), |
| IP(str(IP(dst=target)/UDP(sport=5008,dport=ucport)/(300*"i"))) ] |
| |
| ans, unans = sr(tests, timeout=2) |
| ans += map(lambda x: (x,None), unans) |
| |
| for S,T in ans: |
| if S.sport == 5008: |
| res["PU"] = nmap_udppacket_sig(S,T) |
| else: |
| t = "T%i" % (S.sport-5000) |
| if T is not None and T.haslayer(ICMP): |
| warning("Test %s answered by an ICMP" % t) |
| T=None |
| res[t] = nmap_tcppacket_sig(T) |
| |
| return res |
| |
| def nmap_probes2sig(tests): |
| tests=tests.copy() |
| res = {} |
| if "PU" in tests: |
| res["PU"] = nmap_udppacket_sig(*tests["PU"]) |
| del(tests["PU"]) |
| for k in tests: |
| res[k] = nmap_tcppacket_sig(tests[k]) |
| return res |
| |
| |
| def nmap_search(sigs): |
| guess = 0,[] |
| for os,fp in nmap_kdb.get_base(): |
| c = 0.0 |
| for t in sigs.keys(): |
| if t in fp: |
| c += nmap_match_one_sig(sigs[t], fp[t]) |
| c /= len(sigs.keys()) |
| if c > guess[0]: |
| guess = c,[ os ] |
| elif c == guess[0]: |
| guess[1].append(os) |
| return guess |
| |
| |
| def nmap_fp(target, oport=80, cport=81): |
| """nmap fingerprinting |
| nmap_fp(target, [oport=80,] [cport=81,]) -> list of best guesses with accuracy |
| """ |
| sigs = nmap_sig(target, oport, cport) |
| return nmap_search(sigs) |
| |
| |
| def nmap_sig2txt(sig): |
| torder = ["TSeq","T1","T2","T3","T4","T5","T6","T7","PU"] |
| korder = ["Class", "gcd", "SI", "IPID", "TS", |
| "Resp", "DF", "W", "ACK", "Flags", "Ops", |
| "TOS", "IPLEN", "RIPTL", "RID", "RIPCK", "UCK", "ULEN", "DAT" ] |
| txt=[] |
| for i in sig.keys(): |
| if i not in torder: |
| torder.append(i) |
| for t in torder: |
| sl = sig.get(t) |
| if sl is None: |
| continue |
| s = [] |
| for k in korder: |
| v = sl.get(k) |
| if v is None: |
| continue |
| s.append("%s=%s"%(k,v)) |
| txt.append("%s(%s)" % (t, "%".join(s))) |
| return "\n".join(txt) |
| |
| |
| |
| |
| |
| ################### |
| ## User commands ## |
| ################### |
| |
| |
| def sniff(count=0, store=1, offline=None, prn = None, lfilter=None, L2socket=None, timeout=None, *arg, **karg): |
| """Sniff packets |
| sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets |
| |
| count: number of packets to capture. 0 means infinity |
| store: wether to store sniffed packets or discard them |
| prn: function to apply to each packet. If something is returned, |
| it is displayed. Ex: |
| ex: prn = lambda x: x.summary() |
| lfilter: python function applied to each packet to determine |
| if further action may be done |
| ex: lfilter = lambda x: x.haslayer(Padding) |
| offline: pcap file to read packets from, instead of sniffing them |
| timeout: stop sniffing after a given time (default: None) |
| L2socket: use the provided L2socket |
| """ |
| c = 0 |
| |
| if offline is None: |
| if L2socket is None: |
| L2socket = conf.L2listen |
| s = L2socket(type=ETH_P_ALL, *arg, **karg) |
| else: |
| s = PcapReader(offline) |
| |
| lst = [] |
| if timeout is not None: |
| stoptime = time.time()+timeout |
| remain = None |
| while 1: |
| try: |
| if timeout is not None: |
| remain = stoptime-time.time() |
| if remain <= 0: |
| break |
| sel = select([s],[],[],remain) |
| if s in sel[0]: |
| p = s.recv(MTU) |
| if p is None: |
| break |
| if lfilter and not lfilter(p): |
| continue |
| if store: |
| lst.append(p) |
| c += 1 |
| if prn: |
| r = prn(p) |
| if r is not None: |
| print r |
| if count > 0 and c >= count: |
| break |
| except KeyboardInterrupt: |
| break |
| return PacketList(lst,"Sniffed") |
| |
| |
| |
| def arpcachepoison(target, victim, interval=60): |
| """Poison target's cache with (your MAC,victim's IP) couple |
| arpcachepoison(target, victim, [interval=60]) -> None |
| """ |
| tmac = getmacbyip(target) |
| p = Ether(dst=tmac)/ARP(op="who-has", psrc=victim, pdst=target) |
| try: |
| while 1: |
| sendp(p, iface_hint=target) |
| if conf.verb > 1: |
| os.write(1,".") |
| time.sleep(interval) |
| except KeyboardInterrupt: |
| pass |
| |
| def traceroute(target, dport=80, minttl=1, maxttl=30, sport=RandShort(), l4 = None, filter=None, timeout=2, **kargs): |
| """Instant TCP traceroute |
| traceroute(target, [maxttl=30], [dport=80], [sport=80]) -> None |
| """ |
| if filter is None: |
| filter="(icmp and icmp[0]=11) or (tcp and (tcp[13] & 0x16 > 0x10))" |
| if l4 is None: |
| a,b = sr(IP(dst=target, id=RandShort(), ttl=(minttl,maxttl))/TCP(seq=RandInt(),sport=sport, dport=dport), |
| timeout=timeout, filter=filter, **kargs) |
| else: |
| a,b = sr(IP(dst=target, id=RandShort(), ttl=(minttl,maxttl))/l4, |
| timeout=timeout, **kargs) |
| |
| a = TracerouteResult(a.res) |
| a.display() |
| return a,b |
| |
| |
| |
| |
| def arping(net, timeout=2, cache=0, **kargs): |
| """Send ARP who-has requests to determine which hosts are up |
| arping(net, cache=0, iface=conf.iface) -> None |
| Set cache=True if you want arping to modify internal ARP-Cache""" |
| ans,unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=net), |
| filter="arp and arp[7] = 2", timeout=timeout, iface_hint=net, **kargs) |
| ans = ARPingResult(ans.res) |
| |
| if cache and ans is not None: |
| for pair in ans: |
| arp_cache[pair[1].psrc] = (pair[1].hwsrc, time.time()) |
| |
| ans.display() |
| return ans,unans |
| |
| def dyndns_add(nameserver, name, rdata, type="A", ttl=10): |
| """Send a DNS add message to a nameserver for "name" to have a new "rdata" |
| dyndns_add(nameserver, name, rdata, type="A", ttl=10) -> result code (0=ok) |
| |
| example: dyndns_add("ns1.toto.com", "dyn.toto.com", "127.0.0.1") |
| RFC2136 |
| """ |
| zone = name[name.find(".")+1:] |
| r=sr1(IP(dst=nameserver)/UDP()/DNS(opcode=5, |
| qd=[DNSQR(qname=zone, qtype="SOA")], |
| ns=[DNSRR(rrname=name, type="A", |
| ttl=ttl, rdata=rdata)]), |
| verbose=0, timeout=5) |
| if r and r.haslayer(DNS): |
| return r.getlayer(DNS).rcode |
| else: |
| return -1 |
| |
| |
| |
| |
| def dyndns_del(nameserver, name, type="ALL", ttl=10): |
| """Send a DNS delete message to a nameserver for "name" |
| dyndns_del(nameserver, name, type="ANY", ttl=10) -> result code (0=ok) |
| |
| example: dyndns_del("ns1.toto.com", "dyn.toto.com") |
| RFC2136 |
| """ |
| zone = name[name.find(".")+1:] |
| r=sr1(IP(dst=nameserver)/UDP()/DNS(opcode=5, |
| qd=[DNSQR(qname=zone, qtype="SOA")], |
| ns=[DNSRR(rrname=name, type=type, |
| rclass="ANY", ttl=0, rdata="")]), |
| verbose=0, timeout=5) |
| if r and r.haslayer(DNS): |
| return r.getlayer(DNS).rcode |
| else: |
| return -1 |
| |
| |
| def is_promisc(ip, fake_bcast="ff:ff:00:00:00:00",**kargs): |
| """Try to guess if target is in Promisc mode. The target is provided by its ip.""" |
| |
| responses = srp1(Ether(dst=fake_bcast) / ARP(op="who-has", pdst=ip),type=ETH_P_ARP, iface_hint=ip, timeout=1, verbose=0,**kargs) |
| |
| return responses is not None |
| |
| def promiscping(net, timeout=2, fake_bcast="ff:ff:ff:ff:ff:fe", **kargs): |
| """Send ARP who-has requests to determine which hosts are in promiscuous mode |
| promiscping(net, iface=conf.iface)""" |
| ans,unans = srp(Ether(dst=fake_bcast)/ARP(pdst=net), |
| filter="arp and arp[7] = 2", timeout=timeout, iface_hint=net, **kargs) |
| ans = ARPingResult(ans.res, name="PROMISCPing") |
| |
| ans.display() |
| return ans,unans |
| |
| def ikescan(ip): |
| return sr(IP(dst=ip)/UDP()/ISAKMP(init_cookie=RandString(8), |
| exch_type=2)/ISAKMP_payload_SA(prop=ISAKMP_payload_Proposal())) |
| |
| |
| def dhcp_request(iface=None,**kargs): |
| if conf.checkIPaddr != 0: |
| warning("conf.checkIPaddr is not 0, I may not be able to match the answer") |
| if iface is None: |
| iface = conf.iface |
| fam,hw = get_if_raw_hwaddr(iface) |
| return srp1(Ether(dst="ff:ff:ff:ff:ff:ff")/IP(src="0.0.0.0",dst="255.255.255.255")/UDP(sport=68,dport=67) |
| /BOOTP(chaddr=hw)/DHCP(options=[("message-type","discover"),"end"]),iface=iface,**kargs) |
| |
| def snmpwalk(dst, oid="1", community="public"): |
| try: |
| while 1: |
| r = sr1(IP(dst=dst)/UDP(sport=RandShort())/SNMP(community=community, PDU=SNMPnext(varbindlist=[SNMPvarbind(oid=oid)])),timeout=2, chainCC=1, verbose=0, retry=2) |
| if ICMP in r: |
| print repr(r) |
| break |
| if r is None: |
| print "No answers" |
| break |
| print "%-40s: %r" % (r[SNMPvarbind].oid.val,r[SNMPvarbind].value) |
| oid = r[SNMPvarbind].oid |
| |
| except KeyboardInterrupt: |
| pass |
| |
| |
| ##################### |
| ## Reporting stuff ## |
| ##################### |
| |
| def report_ports(target, ports): |
| """portscan a target and output a LaTeX table |
| report_ports(target, ports) -> string""" |
| ans,unans = sr(IP(dst=target)/TCP(dport=ports),timeout=5) |
| rep = "\\begin{tabular}{|r|l|l|}\n\\hline\n" |
| for s,r in ans: |
| if not r.haslayer(ICMP): |
| if r.payload.flags == 0x12: |
| rep += r.sprintf("%TCP.sport% & open & SA \\\\\n") |
| rep += "\\hline\n" |
| for s,r in ans: |
| if r.haslayer(ICMP): |
| rep += r.sprintf("%TCPerror.dport% & closed & ICMP type %ICMP.type%/%ICMP.code% from %IP.src% \\\\\n") |
| elif r.payload.flags != 0x12: |
| rep += r.sprintf("%TCP.sport% & closed & TCP %TCP.flags% \\\\\n") |
| rep += "\\hline\n" |
| for i in unans: |
| rep += i.sprintf("%TCP.dport% & ? & unanswered \\\\\n") |
| rep += "\\hline\n\\end{tabular}\n" |
| return rep |
| |
| |
| def __make_table(yfmtfunc, fmtfunc, endline, list, fxyz, sortx=None, sorty=None, seplinefunc=None): |
| vx = {} |
| vy = {} |
| vz = {} |
| vxf = {} |
| vyf = {} |
| l = 0 |
| for e in list: |
| xx,yy,zz = map(str, fxyz(e)) |
| l = max(len(yy),l) |
| vx[xx] = max(vx.get(xx,0), len(xx), len(zz)) |
| vy[yy] = None |
| vz[(xx,yy)] = zz |
| |
| vxk = vx.keys() |
| vyk = vy.keys() |
| if sortx: |
| vxk.sort(sortx) |
| else: |
| try: |
| vxk.sort(lambda x,y:int(x)-int(y)) |
| except: |
| try: |
| vxk.sort(lambda x,y: cmp(struct.unpack("I", inet_aton(x))[0],struct.unpack("I", inet_aton(y))[0])) |
| except: |
| vxk.sort() |
| if sorty: |
| vyk.sort(sorty) |
| else: |
| try: |
| vyk.sort(lambda x,y:int(x)-int(y)) |
| except: |
| try: |
| vyk.sort(lambda x,y: cmp(struct.unpack("I", inet_aton(x))[0],struct.unpack("I", inet_aton(y))[0])) |
| except: |
| vyk.sort() |
| |
| |
| if seplinefunc: |
| sepline = seplinefunc(l, map(lambda x:vx[x],vxk)) |
| print sepline |
| |
| fmt = yfmtfunc(l) |
| print fmt % "", |
| for x in vxk: |
| vxf[x] = fmtfunc(vx[x]) |
| print vxf[x] % x, |
| print endline |
| if seplinefunc: |
| print sepline |
| for y in vyk: |
| print fmt % y, |
| for x in vxk: |
| print vxf[x] % vz.get((x,y), "-"), |
| print endline |
| if seplinefunc: |
| print sepline |
| |
| def make_table(*args, **kargs): |
| __make_table(lambda l:"%%-%is" % l, lambda l:"%%-%is" % l, "", *args, **kargs) |
| |
| def make_lined_table(*args, **kargs): |
| __make_table(lambda l:"%%-%is |" % l, lambda l:"%%-%is |" % l, "", |
| seplinefunc=lambda a,x:"+".join(map(lambda y:"-"*(y+2), [a-1]+x+[-2])), |
| *args, **kargs) |
| |
| def make_tex_table(*args, **kargs): |
| __make_table(lambda l: "%s", lambda l: "& %s", "\\\\", seplinefunc=lambda a,x:"\\hline", *args, **kargs) |
| |
| |
| ###################### |
| ## Online doc stuff ## |
| ###################### |
| |
| |
| def lsc(cmd=None): |
| """List user commands""" |
| if cmd is None: |
| for c in user_commands: |
| doc = "No doc. available" |
| if c.__doc__: |
| doc = c.__doc__.split("\n")[0] |
| |
| print "%-16s : %s" % (c.__name__, doc) |
| else: |
| print cmd.__doc__ |
| |
| def ls(obj=None): |
| """List available layers, or infos on a given layer""" |
| if obj is None: |
| import __builtin__ |
| all = __builtin__.__dict__.copy() |
| all.update(globals()) |
| objlst = filter(lambda (n,o): isinstance(o,type) and issubclass(o,Packet), all.items()) |
| objlst.sort(lambda x,y:cmp(x[0],y[0])) |
| for n,o in objlst: |
| print "%-10s : %s" %(n,o.name) |
| else: |
| if isinstance(obj, type) and issubclass(obj, Packet): |
| for f in obj.fields_desc: |
| print "%-10s : %-20s = (%s)" % (f.name, f.__class__.__name__, repr(f.default)) |
| elif isinstance(obj, Packet): |
| for f in obj.fields_desc: |
| print "%-10s : %-20s = %-15s (%s)" % (f.name, f.__class__.__name__, repr(getattr(obj,f.name)), repr(f.default)) |
| if not isinstance(obj.payload, NoPayload): |
| print "--" |
| ls(obj.payload) |
| |
| |
| else: |
| print "Not a packet class. Type 'ls()' to list packet classes." |
| |
| |
| |
| |
| |
| user_commands = [ sr, sr1, srp, srp1, srloop, srploop, sniff, p0f, arpcachepoison, send, sendp, traceroute, arping, ls, lsc, queso, nmap_fp, report_ports, dyndns_add, dyndns_del, is_promisc, promiscping ] |
| |
| |
| ######################## |
| ## Answering machines ## |
| ######################## |
| |
| class ReferenceAM(type): |
| def __new__(cls, name, bases, dct): |
| o = super(ReferenceAM, cls).__new__(cls, name, bases, dct) |
| if o.function_name: |
| globals()[o.function_name] = lambda o=o,*args,**kargs: o(*args,**kargs)() |
| return o |
| |
| |
| class AnsweringMachine(object): |
| __metaclass__ = ReferenceAM |
| function_name = "" |
| filter = None |
| sniff_options = { "store":0 } |
| sniff_options_list = [ "store", "iface", "count", "promisc", "filter", "type", "prn" ] |
| send_options = { "verbose":0 } |
| send_options_list = ["iface", "inter", "loop", "verbose"] |
| send_function = staticmethod(send) |
| |
| |
| def __init__(self, **kargs): |
| self.mode = 0 |
| if self.filter: |
| kargs.setdefault("filter",self.filter) |
| kargs.setdefault("prn", self.reply) |
| self.optam1 = {} |
| self.optam2 = {} |
| self.optam0 = {} |
| doptsend,doptsniff = self.parse_all_options(1, kargs) |
| self.defoptsend = self.send_options.copy() |
| self.defoptsend.update(doptsend) |
| self.defoptsniff = self.sniff_options.copy() |
| self.defoptsniff.update(doptsniff) |
| self.optsend,self.optsniff = [{},{}] |
| |
| def __getattr__(self, attr): |
| for d in [self.optam2, self.optam1]: |
| if attr in d: |
| return d[attr] |
| raise AttributeError,attr |
| |
| def __setattr__(self, attr, val): |
| mode = self.__dict__.get("mode",0) |
| if mode == 0: |
| self.__dict__[attr] = val |
| else: |
| [self.optam1, self.optam2][mode-1][attr] = val |
| |
| def parse_options(self): |
| pass |
| |
| def parse_all_options(self, mode, kargs): |
| sniffopt = {} |
| sendopt = {} |
| for k in kargs.keys(): |
| if k in self.sniff_options_list: |
| sniffopt[k] = kargs[k] |
| if k in self.send_options_list: |
| sendopt[k] = kargs[k] |
| if k in self.sniff_options_list+self.send_options_list: |
| del(kargs[k]) |
| if mode != 2 or kargs: |
| if mode == 1: |
| self.optam0 = kargs |
| elif mode == 2 and kargs: |
| k = self.optam0.copy() |
| k.update(kargs) |
| self.parse_options(**k) |
| kargs = k |
| omode = self.__dict__.get("mode",0) |
| self.__dict__["mode"] = mode |
| self.parse_options(**kargs) |
| self.__dict__["mode"] = omode |
| return sendopt,sniffopt |
| |
| def is_request(self, req): |
| return 1 |
| |
| def make_reply(self, req): |
| return req |
| |
| def send_reply(self, reply): |
| self.send_function(reply, **self.optsend) |
| |
| def print_reply(self, req, reply): |
| print "%s ==> %s" % (req.summary(),reply.summary()) |
| |
| def reply(self, pkt): |
| if not self.is_request(pkt): |
| return |
| reply = self.make_reply(pkt) |
| self.send_reply(reply) |
| if conf.verb >= 0: |
| self.print_reply(pkt, reply) |
| |
| def run(self, *args, **kargs): |
| log_interactive.warning("run() method deprecated. The intance is now callable") |
| self(*args,**kargs) |
| |
| def __call__(self, *args, **kargs): |
| optsend,optsniff = self.parse_all_options(2,kargs) |
| self.optsend=self.defoptsend.copy() |
| self.optsend.update(optsend) |
| self.optsniff=self.defoptsniff.copy() |
| self.optsniff.update(optsniff) |
| |
| try: |
| self.sniff() |
| except KeyboardInterrupt: |
| print "Interrupted by user" |
| |
| def sniff(self): |
| sniff(**self.optsniff) |
| |
| |
| class BOOTP_am(AnsweringMachine): |
| function_name = "bootpd" |
| filter = "udp and port 68 and port 67" |
| send_function = staticmethod(sendp) |
| def parse_options(self, ipset=Net("192.168.1.128/25"),gw="192.168.1.1"): |
| if type(ipset) is str: |
| ipset = Net(ipset) |
| if isinstance(ipset,Gen): |
| ipset = [k for k in ipset] |
| ipset.reverse() |
| if len(ipset) == 1: |
| ipset, = ipset |
| self.ipset = ipset |
| self.gw = gw |
| self.leases = {} |
| |
| def is_request(self, req): |
| if not req.haslayer(BOOTP): |
| return 0 |
| reqb = req.getlayer(BOOTP) |
| if reqb.op != 1: |
| return 0 |
| return 1 |
| |
| def print_reply(self, req, reply): |
| print "Reply %s to %s" % (reply.getlayer(IP).dst,reply.dst) |
| |
| def make_reply(self, req): |
| mac = req.src |
| if type(self.ipset) is list: |
| if not self.leases.has_key(mac): |
| self.leases[mac] = self.ipset.pop() |
| ip = self.leases[mac] |
| else: |
| ip = self.ipset |
| |
| repb = req.getlayer(BOOTP).copy() |
| repb.options = "" |
| repb.op="BOOTREPLY" |
| repb.yiaddr = ip |
| repb.siaddr = self.gw |
| repb.ciaddr = self.gw |
| repb.giaddr = self.gw |
| rep=Ether(dst=mac)/IP(dst=ip)/UDP(sport=req.dport,dport=req.sport)/repb |
| return rep |
| |
| |
| class DHCP_am(BOOTP_am): |
| function_name="dhcpd" |
| def is_request(self, req): |
| if not BOOTP_am.is_request(self, req): |
| return 0 |
| if req.getlayer(BOOTP).options[:4] != "'c\x82Sc": |
| return 0 |
| return 1 |
| def make_reply(self, req): |
| dhcprespmap={"\x01":"\x02","\x03":"\x05"} |
| resp = BOOTP_am.make_reply(self, req) |
| opt = req.getlayer(BOOTP).options |
| o = opt[:6] |
| if len(opt) > 6: |
| o += dhcprespmap.get(opt[6],opt[6]) |
| if len(opt) > 7: |
| o += opt[7:] |
| resp.getlayer(BOOTP).options = o |
| |
| |
| |
| class DNS_am(AnsweringMachine): |
| function_name="dns_spoof" |
| filter = "udp port 53" |
| |
| def parse_options(self, joker="192.168.1.1", match=None): |
| if match is None: |
| self.match = {} |
| else: |
| self.match = match |
| self.joker=joker |
| |
| def is_request(self, req): |
| return req.haslayer(DNS) and req.getlayer(DNS).qr == 0 |
| |
| def make_reply(self, req): |
| ip = req.getlayer(IP) |
| dns = req.getlayer(DNS) |
| resp = IP(dst=ip.src, src=ip.dst)/UDP(dport=ip.sport,sport=ip.dport) |
| rdata = self.match.get(dns.qd.qname, self.joker) |
| resp /= DNS(id=dns.id, qr=1, qd=dns.qd, |
| an=DNSRR(rrname=dns.qd.qname, ttl=10, rdata=rdata)) |
| return resp |
| |
| |
| class WiFi_am(AnsweringMachine): |
| """Before using this, initialize "iffrom" and "ifto" interfaces: |
| iwconfig iffrom mode monitor |
| iwpriv orig_ifto hostapd 1 |
| ifconfig ifto up |
| note: if ifto=wlan0ap then orig_ifto=wlan0 |
| note: ifto and iffrom must be set on the same channel |
| ex: |
| ifconfig eth1 up |
| iwconfig eth1 mode monitor |
| iwconfig eth1 channel 11 |
| iwpriv wlan0 hostapd 1 |
| ifconfig wlan0ap up |
| iwconfig wlan0 channel 11 |
| iwconfig wlan0 essid dontexist |
| iwconfig wlan0 mode managed |
| """ |
| function_name = "airpwn" |
| filter = None |
| |
| def parse_options(iffrom, ifto, replace, pattern="", ignorepattern=""): |
| self.iffrom = iffrom |
| self.ifto = ifto |
| ptrn = re.compile(pattern) |
| iptrn = re.compile(ignorepattern) |
| |
| def is_request(self, pkt): |
| if not isinstance(pkt,Dot11): |
| return 0 |
| if not pkt.FCfield & 1: |
| return 0 |
| if not pkt.haslayer(TCP): |
| return 0 |
| ip = pkt.getlayer(IP) |
| tcp = pkt.getlayer(TCP) |
| pay = str(tcp.payload) |
| if not self.ptrn.match(pay): |
| return 0 |
| if self.iptrn.match(pay): |
| return 0 |
| |
| def make_reply(self, p): |
| ip = p.getlayer(IP) |
| tcp = p.getlayer(TCP) |
| pay = str(tcp.payload) |
| del(p.payload.payload.payload) |
| p.FCfield="from-DS" |
| p.addr1,p.addr2 = p.addr2,p.addr1 |
| p /= IP(src=ip.dst,dst=ip.src) |
| p /= TCP(sport=tcp.dport, dport=tcp.sport, |
| seq=tcp.ack, ack=tcp.seq+len(pay), |
| flags="PA") |
| q = p.copy() |
| p /= self.replace |
| q.ID += 1 |
| q.getlayer(TCP).flags="RA" |
| q.getlayer(TCP).seq+=len(replace) |
| return [p,q] |
| |
| def print_reply(self): |
| print p.sprintf("Sent %IP.src%:%IP.sport% > %IP.dst%:%TCP.dport%") |
| |
| def send_reply(self, reply): |
| sendp(reply, iface=self.ifto, **self.optsend) |
| |
| def sniff(self): |
| sniff(iface=self.iffrom, **self.optsniff) |
| |
| |
| |
| class ARP_am(AnsweringMachine): |
| function_name="farpd" |
| filter = "arp" |
| send_function = staticmethod(sendp) |
| |
| def parse_options(self, IP_addr=None, iface=None, ARP_addr=None): |
| self.IP_addr=IP_addr |
| self.iface=iface |
| self.ARP_addr=ARP_addr |
| |
| def is_request(self, req): |
| return (req.haslayer(ARP) and |
| req.getlayer(ARP).op == 1 and |
| (self.IP_addr == None or self.IP_addr == req.getlayer(ARP).pdst)) |
| |
| def make_reply(self, req): |
| ether = req.getlayer(Ether) |
| arp = req.getlayer(ARP) |
| iff,a,gw = conf.route.route(arp.psrc) |
| if self.iface != None: |
| iff = iface |
| ARP_addr = self.ARP_addr |
| IP_addr = arp.pdst |
| resp = Ether(dst=ether.src, |
| src=ARP_addr)/ARP(op="is-at", |
| hwsrc=ARP_addr, |
| psrc=IP_addr, |
| hwdst=arp.hwsrc, |
| pdst=arp.pdst) |
| return resp |
| |
| def sniff(self): |
| sniff(iface=self.iface, **self.optsniff) |
| |
| |
| ############# |
| ## Fuzzing ## |
| ############# |
| |
| |
| def fuzz(p, _inplace=0): |
| if not _inplace: |
| p = p.copy() |
| q = p |
| while not isinstance(q, NoPayload): |
| for f in q.fields_desc: |
| if isinstance(f, PacketListField): |
| for r in getattr(q, f.name): |
| print "fuzzing", repr(r) |
| fuzz(r, _inplace=1) |
| elif f.default is not None: |
| rnd = f.randval() |
| if rnd is not None: |
| q.default_fields[f.name] = rnd |
| q = q.payload |
| return p |
| |
| |
| |
| |
| ################### |
| ## Testing stuff ## |
| ################### |
| |
| |
| |
| def merge(x,y): |
| if len(x) > len(y): |
| y += "\x00"*(len(x)-len(y)) |
| elif len(x) < len(y): |
| x += "\x00"*(len(y)-len(x)) |
| m = "" |
| for i in range(len(x)/ss): |
| m += x[ss*i:ss*(i+1)]+y[ss*i:ss*(i+1)] |
| return m |
| # return "".join(map(str.__add__, x, y)) |
| |
| |
| def voip_play(s1,list=None,**kargs): |
| FIFO="/tmp/conv1.%i.%%i" % os.getpid() |
| FIFO1=FIFO % 1 |
| FIFO2=FIFO % 2 |
| |
| os.mkfifo(FIFO1) |
| os.mkfifo(FIFO2) |
| try: |
| os.system("soxmix -t .ul %s -t .ul %s -t ossdsp /dev/dsp &" % (FIFO1,FIFO2)) |
| |
| c1=open(FIFO1,"w", 4096) |
| c2=open(FIFO2,"w", 4096) |
| fcntl.fcntl(c1.fileno(),fcntl.F_SETFL, os.O_NONBLOCK) |
| fcntl.fcntl(c2.fileno(),fcntl.F_SETFL, os.O_NONBLOCK) |
| |
| # dsp,rd = os.popen2("sox -t .ul -c 2 - -t ossdsp /dev/dsp") |
| def play(pkt,last=[]): |
| if not pkt: |
| return |
| if not pkt.haslayer(UDP): |
| return |
| ip=pkt.getlayer(IP) |
| if s1 in [ip.src, ip.dst]: |
| if not last: |
| last.append(pkt) |
| return |
| load=last.pop() |
| # x1 = load.load[12:] |
| c1.write(load.load[12:]) |
| if load.getlayer(IP).src == ip.src: |
| # x2 = "" |
| c2.write("\x00"*len(load.load[12:])) |
| last.append(pkt) |
| else: |
| # x2 = pkt.load[:12] |
| c2.write(pkt.load[12:]) |
| # dsp.write(merge(x1,x2)) |
| |
| if list is None: |
| sniff(store=0, prn=play, **kargs) |
| else: |
| for p in list: |
| play(p) |
| finally: |
| os.unlink(FIFO1) |
| os.unlink(FIFO2) |
| |
| |
| |
| def voip_play1(s1,list=None,**kargs): |
| |
| |
| dsp,rd = os.popen2("sox -t .ul - -t ossdsp /dev/dsp") |
| def play(pkt): |
| if not pkt: |
| return |
| if not pkt.haslayer(UDP): |
| return |
| ip=pkt.getlayer(IP) |
| if s1 in [ip.src, ip.dst]: |
| dsp.write(pkt.getlayer(Raw).load[12:]) |
| try: |
| if list is None: |
| sniff(store=0, prn=play, **kargs) |
| else: |
| for p in list: |
| play(p) |
| finally: |
| dsp.close() |
| rd.close() |
| |
| def voip_play2(s1,**kargs): |
| dsp,rd = os.popen2("sox -t .ul -c 2 - -t ossdsp /dev/dsp") |
| def play(pkt,last=[]): |
| if not pkt: |
| return |
| if not pkt.haslayer(UDP): |
| return |
| ip=pkt.getlayer(IP) |
| if s1 in [ip.src, ip.dst]: |
| if not last: |
| last.append(pkt) |
| return |
| load=last.pop() |
| x1 = load.load[12:] |
| # c1.write(load.load[12:]) |
| if load.getlayer(IP).src == ip.src: |
| x2 = "" |
| # c2.write("\x00"*len(load.load[12:])) |
| last.append(pkt) |
| else: |
| x2 = pkt.load[:12] |
| # c2.write(pkt.load[12:]) |
| dsp.write(merge(x1,x2)) |
| |
| sniff(store=0, prn=play, **kargs) |
| |
| def voip_play3(lst=None,**kargs): |
| dsp,rd = os.popen2("sox -t .ul - -t ossdsp /dev/dsp") |
| try: |
| def play(pkt, dsp=dsp): |
| if pkt and pkt.haslayer(UDP) and pkt.haslayer(Raw): |
| dsp.write(pkt.getlayer(Raw).load[12:]) |
| if lst is None: |
| sniff(store=0, prn=play, **kargs) |
| else: |
| for p in lst: |
| play(p) |
| finally: |
| try: |
| dsp.close() |
| rd.close() |
| except: |
| pass |
| |
| |
| def IPID_count(lst, funcID=lambda x:x[1].id, funcpres=lambda x:x[1].summary()): |
| idlst = map(funcID, lst) |
| idlst.sort() |
| classes = [idlst[0]]+map(lambda x:x[1],filter(lambda (x,y): abs(x-y)>50, map(lambda x,y: (x,y),idlst[:-1], idlst[1:]))) |
| lst = map(lambda x:(funcID(x), funcpres(x)), lst) |
| lst.sort() |
| print "Probably %i classes:" % len(classes), classes |
| for id,pr in lst: |
| print "%5i" % id, pr |
| |
| |
| |
| |
| |
| last=None |
| |
| |
| def tethereal(*args,**kargs): |
| sniff(prn=lambda x: x.display(),*args,**kargs) |
| |
| def etherleak(target, **kargs): |
| return srpflood(Ether()/ARP(pdst=target), prn=lambda (s,r): Padding in r and hexstr(r[Padding].load), |
| filter="arp", **kargs) |
| |
| |
| def fragleak(target,sport=123, dport=123, timeout=0.2, onlyasc=0): |
| load = "XXXXYYYYYYYYYY" |
| # getmacbyip(target) |
| # pkt = IP(dst=target, id=RandShort(), options="\x22"*40)/UDP()/load |
| pkt = IP(dst=target, id=RandShort(), options="\x00"*40, flags=1)/UDP(sport=sport, dport=sport)/load |
| s=conf.L3socket() |
| intr=0 |
| found={} |
| try: |
| while 1: |
| try: |
| if not intr: |
| s.send(pkt) |
| sin,sout,serr = select([s],[],[],timeout) |
| if not sin: |
| continue |
| ans=s.recv(1600) |
| if not isinstance(ans, IP): #TODO: IPv6 |
| continue |
| if not isinstance(ans.payload, ICMP): |
| continue |
| if not isinstance(ans.payload.payload, IPerror): |
| continue |
| if ans.payload.payload.dst != target: |
| continue |
| if ans.src != target: |
| print "leak from", ans.src, |
| |
| |
| # print repr(ans) |
| if not ans.haslayer(Padding): |
| continue |
| |
| |
| # print repr(ans.payload.payload.payload.payload) |
| |
| # if not isinstance(ans.payload.payload.payload.payload, Raw): |
| # continue |
| # leak = ans.payload.payload.payload.payload.load[len(load):] |
| leak = ans.getlayer(Padding).load |
| if leak not in found: |
| found[leak]=None |
| linehexdump(leak, onlyasc=onlyasc) |
| except KeyboardInterrupt: |
| if intr: |
| raise |
| intr=1 |
| except KeyboardInterrupt: |
| pass |
| |
| def fragleak2(target, timeout=0.4, onlyasc=0): |
| found={} |
| try: |
| while 1: |
| p = sr1(IP(dst=target, options="\x00"*40, proto=200)/"XXXXYYYYYYYYYYYY",timeout=timeout,verbose=0) |
| if not p: |
| continue |
| if Padding in p: |
| leak = p[Padding].load |
| if leak not in found: |
| found[leak]=None |
| linehexdump(leak,onlyasc=onlyasc) |
| except: |
| pass |
| |
| |
| |
| plst=[] |
| def get_toDS(): |
| global plst |
| while 1: |
| p,=sniff(iface="eth1",count=1) |
| if not isinstance(p,Dot11): |
| continue |
| if p.FCfield & 1: |
| plst.append(p) |
| print "." |
| |
| |
| # if not ifto.endswith("ap"): |
| # print "iwpriv %s hostapd 1" % ifto |
| # os.system("iwpriv %s hostapd 1" % ifto) |
| # ifto += "ap" |
| # |
| # os.system("iwconfig %s mode monitor" % iffrom) |
| # |
| |
| def airpwn(iffrom, ifto, replace, pattern="", ignorepattern=""): |
| """Before using this, initialize "iffrom" and "ifto" interfaces: |
| iwconfig iffrom mode monitor |
| iwpriv orig_ifto hostapd 1 |
| ifconfig ifto up |
| note: if ifto=wlan0ap then orig_ifto=wlan0 |
| note: ifto and iffrom must be set on the same channel |
| ex: |
| ifconfig eth1 up |
| iwconfig eth1 mode monitor |
| iwconfig eth1 channel 11 |
| iwpriv wlan0 hostapd 1 |
| ifconfig wlan0ap up |
| iwconfig wlan0 channel 11 |
| iwconfig wlan0 essid dontexist |
| iwconfig wlan0 mode managed |
| """ |
| |
| ptrn = re.compile(pattern) |
| iptrn = re.compile(ignorepattern) |
| def do_airpwn(p, ifto=ifto, replace=replace, ptrn=ptrn, iptrn=iptrn): |
| if not isinstance(p,Dot11): |
| return |
| if not p.FCfield & 1: |
| return |
| if not p.haslayer(TCP): |
| return |
| ip = p.getlayer(IP) |
| tcp = p.getlayer(TCP) |
| pay = str(tcp.payload) |
| # print "got tcp" |
| if not ptrn.match(pay): |
| return |
| # print "match 1" |
| if iptrn.match(pay): |
| return |
| # print "match 2" |
| del(p.payload.payload.payload) |
| p.FCfield="from-DS" |
| p.addr1,p.addr2 = p.addr2,p.addr1 |
| q = p.copy() |
| p /= IP(src=ip.dst,dst=ip.src) |
| p /= TCP(sport=tcp.dport, dport=tcp.sport, |
| seq=tcp.ack, ack=tcp.seq+len(pay), |
| flags="PA") |
| q = p.copy() |
| p /= replace |
| q.ID += 1 |
| q.getlayer(TCP).flags="RA" |
| q.getlayer(TCP).seq+=len(replace) |
| |
| sendp([p,q], iface=ifto, verbose=0) |
| # print "send",repr(p) |
| # print "send",repr(q) |
| print p.sprintf("Sent %IP.src%:%IP.sport% > %IP.dst%:%TCP.dport%") |
| |
| sniff(iface=iffrom,prn=do_airpwn) |
| |
| |
| |
| |
| ################## |
| ## Color themes ## |
| ################## |
| |
| class Color: |
| normal = "\033[0m" |
| black = "\033[30m" |
| red = "\033[31m" |
| green = "\033[32m" |
| yellow = "\033[33m" |
| blue = "\033[34m" |
| purple = "\033[35m" |
| cyan = "\033[36m" |
| grey = "\033[37m" |
| |
| bold = "\033[1m" |
| uline = "\033[4m" |
| blink = "\033[5m" |
| invert = "\033[7m" |
| |
| |
| class ColorTheme: |
| def __repr__(self): |
| return "<%s>" % self.__class__.__name__ |
| def __getattr__(self, attr): |
| return lambda x:x |
| |
| |
| class NoTheme(ColorTheme): |
| pass |
| |
| |
| class AnsiColorTheme(ColorTheme): |
| def __getattr__(self, attr): |
| if attr.startswith("__"): |
| raise AttributeError(attr) |
| s = "style_%s" % attr |
| if s in self.__class__.__dict__: |
| before = getattr(self, s) |
| after = self.style_normal |
| else: |
| before = after = "" |
| |
| def do_style(val, fmt=None, before=before, after=after): |
| if fmt is None: |
| if type(val) is not str: |
| val = str(val) |
| else: |
| val = fmt % val |
| return before+val+after |
| return do_style |
| |
| |
| style_normal = "" |
| style_prompt = "" |
| style_punct = "" |
| style_id = "" |
| style_not_printable = "" |
| style_layer_name = "" |
| style_field_name = "" |
| style_field_value = "" |
| style_emph_field_name = "" |
| style_emph_field_value = "" |
| style_packetlist_name = "" |
| style_packetlist_proto = "" |
| style_packetlist_value = "" |
| style_fail = "" |
| style_success = "" |
| style_odd = "" |
| style_even = "" |
| style_opening = "" |
| style_active = "" |
| style_closed = "" |
| style_left = "" |
| style_right = "" |
| |
| class BlackAndWhite(AnsiColorTheme): |
| pass |
| |
| class DefaultTheme(AnsiColorTheme): |
| style_normal = Color.normal |
| style_prompt = Color.blue+Color.bold |
| style_punct = Color.normal |
| style_id = Color.blue+Color.bold |
| style_not_printable = Color.grey |
| style_layer_name = Color.red+Color.bold |
| style_field_name = Color.blue |
| style_field_value = Color.purple |
| style_emph_field_name = Color.blue+Color.uline+Color.bold |
| style_emph_field_value = Color.purple+Color.uline+Color.bold |
| style_packetlist_name = Color.red+Color.bold |
| style_packetlist_proto = Color.blue |
| style_packetlist_value = Color.purple |
| style_fail = Color.red+Color.bold |
| style_success = Color.blue+Color.bold |
| style_even = Color.black+Color.bold |
| style_odd = Color.black |
| style_opening = Color.yellow |
| style_active = Color.black |
| style_closed = Color.grey |
| style_left = Color.blue |
| style_right = Color.red |
| |
| class BrightTheme(AnsiColorTheme): |
| style_normal = Color.normal |
| style_punct = Color.normal |
| style_id = Color.yellow+Color.bold |
| style_layer_name = Color.red+Color.bold |
| style_field_name = Color.yellow+Color.bold |
| style_field_value = Color.purple+Color.bold |
| style_emph_field_name = Color.yellow+Color.bold |
| style_emph_field_value = Color.green+Color.bold |
| style_packetlist_name = Color.red+Color.bold |
| style_packetlist_proto = Color.yellow+Color.bold |
| style_packetlist_value = Color.purple+Color.bold |
| style_fail = Color.red+Color.bold |
| style_success = Color.blue+Color.bold |
| style_even = Color.black+Color.bold |
| style_odd = Color.black |
| style_left = Color.cyan |
| style_right = Color.purple |
| |
| |
| class RastaTheme(AnsiColorTheme): |
| style_normal = Color.green+Color.bold |
| style_prompt = Color.yellow+Color.bold |
| style_punct = Color.red |
| style_id = Color.green+Color.bold |
| style_not_printable = Color.green |
| style_layer_name = Color.red+Color.bold |
| style_field_name = Color.yellow+Color.bold |
| style_field_value = Color.green+Color.bold |
| style_emph_field_name = Color.green |
| style_emph_field_value = Color.green |
| style_packetlist_name = Color.red+Color.bold |
| style_packetlist_proto = Color.yellow+Color.bold |
| style_packetlist_value = Color.green+Color.bold |
| style_fail = Color.red |
| style_success = Color.red+Color.bold |
| style_even = Color.yellow |
| style_odd = Color.green |
| style_left = Color.red |
| style_right = Color.yellow |
| |
| |
| class FormatTheme(ColorTheme): |
| def __getattr__(self, attr): |
| if attr.startswith("__"): |
| raise AttributeError(attr) |
| col = self.__class__.__dict__.get("style_%s" % attr, "%s") |
| def do_style(val, fmt=None, col=col): |
| if fmt is None: |
| if type(val) is not str: |
| val = str(val) |
| else: |
| val = fmt % val |
| return col % val |
| return do_style |
| |
| |
| class LatexTheme(FormatTheme): |
| style_prompt = r"\textcolor{blue}{%s}" |
| style_not_printable = r"\textcolor{gray}{%s}" |
| style_layer_name = r"\textcolor{red}{\bf %s}" |
| style_field_name = r"\textcolor{blue}{%s}" |
| style_field_value = r"\textcolor{purple}{%s}" |
| style_emph_field_name = r"\textcolor{blue}{\underline{%s}}" #ul |
| style_emph_field_value = r"\textcolor{purple}{\underline{%s}}" #ul |
| style_packetlist_name = r"\textcolor{red}{\bf %s}" |
| style_packetlist_proto = r"\textcolor{blue}{%s}" |
| style_packetlist_value = r"\textcolor{purple}{%s}" |
| style_fail = r"\textcolor{red}{\bf %s}" |
| style_success = r"\textcolor{blue}{\bf %s}" |
| style_left = r"\textcolor{blue}{%s}" |
| style_right = r"\textcolor{red}{%s}" |
| # style_even = r"}{\bf " |
| # style_odd = "" |
| |
| class LatexTheme2(FormatTheme): |
| style_prompt = r"@`@textcolor@[@blue@]@@[@%s@]@" |
| style_not_printable = r"@`@textcolor@[@gray@]@@[@%s@]@" |
| style_layer_name = r"@`@textcolor@[@red@]@@[@@`@bfseries@[@@]@%s@]@" |
| style_field_name = r"@`@textcolor@[@blue@]@@[@%s@]@" |
| style_field_value = r"@`@textcolor@[@purple@]@@[@%s@]@" |
| style_emph_field_name = r"@`@textcolor@[@blue@]@@[@@`@underline@[@%s@]@@]@" |
| style_emph_field_value = r"@`@textcolor@[@purple@]@@[@@`@underline@[@%s@]@@]@" |
| style_packetlist_name = r"@`@textcolor@[@red@]@@[@@`@bfseries@[@@]@%s@]@" |
| style_packetlist_proto = r"@`@textcolor@[@blue@]@@[@%s@]@" |
| style_packetlist_value = r"@`@textcolor@[@purple@]@@[@%s@]@" |
| style_fail = r"@`@textcolor@[@red@]@@[@@`@bfseries@[@@]@%s@]@" |
| style_success = r"@`@textcolor@[@blue@]@@[@@`@bfserices@[@@]@%s@]@" |
| style_even = r"@`@textcolor@[@gray@]@@[@@`@bfseries@[@@]@%s@]@" |
| # style_odd = r"@`@textcolor@[@black@]@@[@@`@bfseries@[@@]@%s@]@" |
| style_left = r"@`@textcolor@[@blue@]@@[@%s@]@" |
| style_right = r"@`@textcolor@[@red@]@@[@%s@]@" |
| |
| class HTMLTheme(FormatTheme): |
| style_prompt = "<span class=prompt>%s</span>" |
| style_not_printable = "<span class=not_printable>%s</span>" |
| style_layer_name = "<span class=layer_name>%s</span>" |
| style_field_name = "<span class=field_name>%s</span>" |
| style_field_value = "<span class=field_value>%s</span>" |
| style_emph_field_name = "<span class=emph_field_name>%s</span>" |
| style_emph_field_value = "<span class=emph_field_value>%s</span>" |
| style_packetlist_name = "<span class=packetlist_name>%s</span>" |
| style_packetlist_proto = "<span class=packetlist_proto>%s</span>" |
| style_packetlist_value = "<span class=packetlist_value>%s</span>" |
| style_fail = "<span class=fail>%s</span>" |
| style_success = "<span class=success>%s</span>" |
| style_even = "<span class=even>%s</span>" |
| style_odd = "<span class=odd>%s</span>" |
| style_left = "<span class=left>%s</span>" |
| style_right = "<span class=right>%s</span>" |
| |
| class HTMLTheme2(HTMLTheme): |
| style_prompt = "#[#span class=prompt#]#%s#[#/span#]#" |
| style_not_printable = "#[#span class=not_printable#]#%s#[#/span#]#" |
| style_layer_name = "#[#span class=layer_name#]#%s#[#/span#]#" |
| style_field_name = "#[#span class=field_name#]#%s#[#/span#]#" |
| style_field_value = "#[#span class=field_value#]#%s#[#/span#]#" |
| style_emph_field_name = "#[#span class=emph_field_name#]#%s#[#/span#]#" |
| style_emph_field_value = "#[#span class=emph_field_value#]#%s#[#/span#]#" |
| style_packetlist_name = "#[#span class=packetlist_name#]#%s#[#/span#]#" |
| style_packetlist_proto = "#[#span class=packetlist_proto#]#%s#[#/span#]#" |
| style_packetlist_value = "#[#span class=packetlist_value#]#%s#[#/span#]#" |
| style_fail = "#[#span class=fail#]#%s#[#/span#]#" |
| style_success = "#[#span class=success#]#%s#[#/span#]#" |
| style_even = "#[#span class=even#]#%s#[#/span#]#" |
| style_odd = "#[#span class=odd#]#%s#[#/span#]#" |
| style_left = "#[#span class=left#]#%s#[#/span#]#" |
| style_right = "#[#span class=right#]#%s#[#/span#]#" |
| |
| |
| class ColorPrompt: |
| __prompt = ">>> " |
| def __str__(self): |
| try: |
| ct = conf.color_theme |
| if isinstance(ct, AnsiColorTheme): |
| ## ^A and ^B delimit invisible caracters for readline to count right |
| return "\001%s\002" % ct.prompt("\002"+conf.prompt+"\001") |
| else: |
| return ct.prompt(conf.prompt) |
| except: |
| return self.__prompt |
| |
| ############ |
| ## Config ## |
| ############ |
| |
| class ConfClass: |
| def configure(self, cnf): |
| self.__dict__ = cnf.__dict__.copy() |
| def __repr__(self): |
| return str(self) |
| def __str__(self): |
| s="Version = %s\n" % VERSION |
| keys = self.__class__.__dict__.copy() |
| keys.update(self.__dict__) |
| keys = keys.keys() |
| keys.sort() |
| for i in keys: |
| if i[0] != "_": |
| s += "%-10s = %s\n" % (i, repr(getattr(self, i))) |
| return s[:-1] |
| |
| class ProgPath(ConfClass): |
| pdfreader = "acroread" |
| psreader = "gv" |
| dot = "dot" |
| display = "display" |
| tcpdump = "tcpdump" |
| hexedit = "hexer" |
| wireshark = "wireshark" |
| |
| class Resolve: |
| def __init__(self): |
| self.fields = {} |
| def add(self, *flds): |
| for fld in flds: |
| self.fields[fld]=None |
| def remove(self, *flds): |
| for fld in flds: |
| if fld in self.fields: |
| del(self.fields[fld]) |
| def __contains__(self, elt): |
| return elt in self.fields |
| def __repr__(self): |
| return "<Resolve [%s]>" % " ".join(str(x) for x in self.fields) |
| |
| |
| |
| |
| class Conf(ConfClass): |
| """This object contains the configuration of scapy. |
| session : filename where the session will be saved |
| stealth : if 1, prevents any unwanted packet to go out (ARP, DNS, ...) |
| checkIPID: if 0, doesn't check that IPID matches between IP sent and ICMP IP citation received |
| if 1, checks that they either are equal or byte swapped equals (bug in some IP stacks) |
| if 2, strictly checks that they are equals |
| checkIPsrc: if 1, checks IP src in IP and ICMP IP citation match (bug in some NAT stacks) |
| check_TCPerror_seqack: if 1, also check that TCP seq and ack match the ones in ICMP citation |
| iff : selects the default output interface for srp() and sendp(). default:"eth0") |
| verb : level of verbosity, from 0 (almost mute) to 3 (verbose) |
| promisc : default mode for listening socket (to get answers if you spoof on a lan) |
| sniff_promisc : default mode for sniff() |
| filter : bpf filter added to every sniffing socket to exclude traffic from analysis |
| histfile : history file |
| padding : includes padding in desassembled packets |
| except_filter : BPF filter for packets to ignore |
| debug_match : when 1, store received packet that are not matched into debug.recv |
| route : holds the Scapy routing table and provides methods to manipulate it |
| warning_threshold : how much time between warnings from the same place |
| ASN1_default_codec: Codec used by default for ASN1 objects |
| mib : holds MIB direct access dictionnary |
| resolve : holds list of fields for which resolution should be done |
| noenum : holds list of enum fields for which conversion to string should NOT be done |
| AS_resolver: choose the AS resolver class to use |
| """ |
| session = "" |
| stealth = "not implemented" |
| iface = get_working_if() |
| checkIPID = 0 |
| checkIPsrc = 1 |
| checkIPaddr = 1 |
| check_TCPerror_seqack = 0 |
| verb = 2 |
| prompt = ">>> " |
| promisc = 1 |
| sniff_promisc = 1 |
| L3socket = L3PacketSocket |
| L2socket = L2Socket |
| L2listen = L2ListenSocket |
| BTsocket = BluetoothL2CAPSocket |
| histfile = os.path.join(os.environ["HOME"], ".scapy_history") |
| padding = 1 |
| p0f_base ="/etc/p0f/p0f.fp" |
| queso_base ="/etc/queso.conf" |
| nmap_base ="/usr/share/nmap/nmap-os-fingerprints" |
| IPCountry_base = "GeoIPCountry4Scapy.gz" |
| countryLoc_base = "countryLoc.csv" |
| gnuplot_world = "world.dat" |
| except_filter = "" |
| debug_match = 0 |
| route = Route() |
| wepkey = "" |
| auto_fragment = 1 |
| debug_dissector = 0 |
| color_theme = DefaultTheme() |
| warning_threshold = 5 |
| ASN1_default_codec = ASN1_Codecs.BER |
| mib = MIBDict(_name="MIB") |
| prog = ProgPath() |
| resolve = Resolve() |
| noenum = Resolve() |
| ethertypes = ETHER_TYPES |
| protocols = IP_PROTOS |
| services_tcp = TCP_SERVICES |
| services_udp = UDP_SERVICES |
| manufdb = MANUFDB |
| AS_resolver = AS_resolver_multi() |
| |
| |
| conf=Conf() |
| |
| if PCAP: |
| conf.L2listen=L2pcapListenSocket |
| if DNET: |
| conf.L3socket=L3dnetSocket |
| conf.L2socket=L2dnetSocket |
| |
| |
| p0f_kdb = p0fKnowledgeBase(conf.p0f_base) |
| queso_kdb = QuesoKnowledgeBase(conf.queso_base) |
| nmap_kdb = NmapKnowledgeBase(conf.nmap_base) |
| IP_country_kdb = IPCountryKnowledgeBase(conf.IPCountry_base) |
| country_loc_kdb = CountryLocKnowledgeBase(conf.countryLoc_base) |
| |
| |
| ######################### |
| ##### Autorun stuff ##### |
| ######################### |
| |
| |
| class ScapyAutorunInterpreter(code.InteractiveInterpreter): |
| def __init__(self, *args, **kargs): |
| code.InteractiveInterpreter.__init__(self, *args, **kargs) |
| self.error = 0 |
| def showsyntaxerror(self, *args, **kargs): |
| self.error = 1 |
| return code.InteractiveInterpreter.showsyntaxerror(self, *args, **kargs) |
| def showtraceback(self, *args, **kargs): |
| self.error = 1 |
| return code.InteractiveInterpreter.showtraceback(self, *args, **kargs) |
| |
| |
| def autorun_commands(cmds,my_globals=None,verb=0): |
| sv = conf.verb |
| import __builtin__ |
| try: |
| if my_globals is None: |
| my_globals = globals() |
| conf.verb = verb |
| interp = ScapyAutorunInterpreter(my_globals) |
| cmd = "" |
| cmds = cmds.splitlines() |
| cmds.append("") # ensure we finish multiline commands |
| cmds.reverse() |
| __builtin__.__dict__["_"] = None |
| while 1: |
| if cmd: |
| sys.stderr.write(sys.__dict__.get("ps2","... ")) |
| else: |
| sys.stderr.write(str(sys.__dict__.get("ps1",ColorPrompt()))) |
| |
| l = cmds.pop() |
| print l |
| cmd += "\n"+l |
| if interp.runsource(cmd): |
| continue |
| if interp.error: |
| return 0 |
| cmd = "" |
| if len(cmds) <= 1: |
| break |
| finally: |
| conf.verb = sv |
| return _ |
| |
| def autorun_get_interactive_session(cmds, **kargs): |
| class StringWriter: |
| def __init__(self): |
| self.s = "" |
| def write(self, x): |
| self.s += x |
| |
| sw = StringWriter() |
| sstdout,sstderr = sys.stdout,sys.stderr |
| try: |
| sys.stdout = sys.stderr = sw |
| res = autorun_commands(cmds, **kargs) |
| finally: |
| sys.stdout,sys.stderr = sstdout,sstderr |
| return sw.s,res |
| |
| def autorun_get_text_interactive_session(cmds, **kargs): |
| ct = conf.color_theme |
| try: |
| conf.color_theme = NoTheme() |
| s,res = autorun_get_interactive_session(cmds, **kargs) |
| finally: |
| conf.color_theme = ct |
| return s,res |
| |
| def autorun_get_ansi_interactive_session(cmds, **kargs): |
| ct = conf.color_theme |
| try: |
| conf.color_theme = DefaultTheme() |
| s,res = autorun_get_interactive_session(cmds, **kargs) |
| finally: |
| conf.color_theme = ct |
| return s,res |
| |
| def autorun_get_html_interactive_session(cmds, **kargs): |
| ct = conf.color_theme |
| try: |
| conf.color_theme = HTMLTheme2() |
| s,res = autorun_get_interactive_session(cmds, **kargs) |
| finally: |
| conf.color_theme = ct |
| |
| s = s.replace("<","<").replace(">",">").replace("#[#","<").replace("#]#",">") |
| return s,res |
| |
| def autorun_get_latex_interactive_session(cmds, **kargs): |
| ct = conf.color_theme |
| try: |
| conf.color_theme = LatexTheme2() |
| s,res = autorun_get_interactive_session(cmds, **kargs) |
| finally: |
| conf.color_theme = ct |
| s = tex_escape(s) |
| s = s.replace("@[@","{").replace("@]@","}").replace("@`@","\\") |
| return s,res |
| |
| |
| ################ |
| ##### Main ##### |
| ################ |
| |
| def scapy_write_history_file(readline): |
| if conf.histfile: |
| try: |
| readline.write_history_file(conf.histfile) |
| except IOError,e: |
| try: |
| warning("Could not write history to [%s]\n\t (%s)" % (conf.histfile,e)) |
| tmp = os.tempnam("","scapy") |
| readline.write_history_file(tmp) |
| warning("Wrote history to [%s]" % tmp) |
| except: |
| warning("Cound not write history to [%s]. Discarded" % tmp) |
| |
| |
| def interact(mydict=None,argv=None,mybanner=None,loglevel=1): |
| import code,sys,cPickle,types,os,imp,getopt,logging |
| |
| logging.getLogger("scapy").setLevel(loglevel) |
| |
| the_banner = "Welcome to Scapy (%s)" |
| if mybanner is not None: |
| the_banner += "\n" |
| the_banner += mybanner |
| |
| if argv is None: |
| argv = sys.argv |
| |
| # scapy_module = argv[0][argv[0].rfind("/")+1:] |
| # if not scapy_module: |
| # scapy_module = "scapy" |
| # else: |
| # if scapy_module.endswith(".py"): |
| # scapy_module = scapy_module[:-3] |
| # |
| # scapy=imp.load_module("scapy",*imp.find_module(scapy_module)) |
| |
| |
| import __builtin__ |
| # __builtin__.__dict__.update(scapy.__dict__) |
| __builtin__.__dict__.update(globals()) |
| if mydict is not None: |
| __builtin__.__dict__.update(mydict) |
| |
| |
| import re, atexit |
| try: |
| import rlcompleter,readline |
| except ImportError: |
| log_loading.info("Can't load Python libreadline or completer") |
| READLINE=0 |
| else: |
| READLINE=1 |
| class ScapyCompleter(rlcompleter.Completer): |
| def global_matches(self, text): |
| matches = [] |
| n = len(text) |
| for lst in [dir(__builtin__), session.keys()]: |
| for word in lst: |
| if word[:n] == text and word != "__builtins__": |
| matches.append(word) |
| return matches |
| |
| |
| def attr_matches(self, text): |
| m = re.match(r"(\w+(\.\w+)*)\.(\w*)", text) |
| if not m: |
| return |
| expr, attr = m.group(1, 3) |
| try: |
| object = eval(expr) |
| except: |
| object = eval(expr, session) |
| if isinstance(object, Packet) or isinstance(object, Packet_metaclass): |
| words = filter(lambda x: x[0]!="_",dir(object)) |
| words += [x.name for x in object.fields_desc] |
| else: |
| words = dir(object) |
| if hasattr( object,"__class__" ): |
| words = words + rlcompleter.get_class_members(object.__class__) |
| matches = [] |
| n = len(attr) |
| for word in words: |
| if word[:n] == attr and word != "__builtins__": |
| matches.append("%s.%s" % (expr, word)) |
| return matches |
| |
| readline.set_completer(ScapyCompleter().complete) |
| readline.parse_and_bind("C-o: operate-and-get-next") |
| readline.parse_and_bind("tab: complete") |
| |
| |
| session=None |
| session_name="" |
| CONFIG_FILE = DEFAULT_CONFIG_FILE |
| |
| iface = None |
| try: |
| opts=getopt.getopt(argv[1:], "hs:Cc:") |
| for opt, parm in opts[0]: |
| if opt == "-h": |
| usage() |
| elif opt == "-s": |
| session_name = parm |
| elif opt == "-c": |
| CONFIG_FILE = parm |
| elif opt == "-C": |
| CONFIG_FILE = None |
| |
| if len(opts[1]) > 0: |
| raise getopt.GetoptError("Too many parameters : [%s]" % string.join(opts[1]),None) |
| |
| |
| except getopt.GetoptError, msg: |
| log_loading.error(msg) |
| sys.exit(1) |
| |
| |
| if CONFIG_FILE: |
| read_config_file(CONFIG_FILE) |
| |
| if session_name: |
| try: |
| os.stat(session_name) |
| except OSError: |
| log_loading.info("New session [%s]" % session_name) |
| else: |
| try: |
| try: |
| session = cPickle.load(gzip.open(session_name,"rb")) |
| except IOError: |
| session = cPickle.load(open(session_name,"rb")) |
| log_loading.info("Using session [%s]" % session_name) |
| except EOFError: |
| log_loading.error("Error opening session [%s]" % session_name) |
| except AttributeError: |
| log_loading.error("Error opening session [%s]. Attribute missing" % session_name) |
| |
| if session: |
| if "conf" in session: |
| conf.configure(session["conf"]) |
| session["conf"] = conf |
| else: |
| conf.session = session_name |
| session={"conf":conf} |
| |
| else: |
| session={"conf": conf} |
| |
| __builtin__.__dict__["scapy_session"] = session |
| |
| |
| if READLINE: |
| if conf.histfile: |
| try: |
| readline.read_history_file(conf.histfile) |
| except IOError: |
| pass |
| atexit.register(scapy_write_history_file,readline) |
| |
| sys.ps1 = ColorPrompt() |
| code.interact(banner = the_banner % (VERSION), local=session) |
| |
| if conf.session: |
| save_session(conf.session, session) |
| |
| sys.exit() |
| |
| |
| def read_config_file(configfile): |
| try: |
| execfile(configfile) |
| except IOError,e: |
| log_loading.warning("Cannot read config file [%s] [%s]" % (configfile,e)) |
| except Exception,e: |
| log_loading.exception("Error during evaluation of config file [%s]" % configfile) |
| |
| |
| if __name__ == "__main__": |
| interact() |
| else: |
| read_config_file(DEFAULT_CONFIG_FILE) |