summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorburet2008-07-18 16:02:55 +0000
committerburet2008-07-18 16:02:55 +0000
commit0b9f4bc26ef911b888026149fcdc5b052f8abafb (patch)
tree2c6a37cb5713af5eaeb0c9d8b7dd8f6e8c4dcad4
parent1f3cdb623f2b289a75c2326836127babeee80cc5 (diff)
[Proto] Solve bug of fcall reception in the Python library
git-svn-id: svn+ssh://pessac/svn/cesar/trunk@2634 017c9cb6-072f-447c-8318-d5b54f68fe89
-rw-r--r--cesar/maximus/python/lib/proto/fcall.py2
-rw-r--r--cesar/maximus/python/lib/proto/maximus_proto.py12
-rw-r--r--cesar/maximus/python/lib/proto/my_scapy.py13251
3 files changed, 13257 insertions, 8 deletions
diff --git a/cesar/maximus/python/lib/proto/fcall.py b/cesar/maximus/python/lib/proto/fcall.py
index 5e5c49f57e..5eaff78b67 100644
--- a/cesar/maximus/python/lib/proto/fcall.py
+++ b/cesar/maximus/python/lib/proto/fcall.py
@@ -13,7 +13,7 @@ sys.path.append(path)
from exception import *
from format import *
-from scapy import *
+from my_scapy import *
import signal
# Constants
diff --git a/cesar/maximus/python/lib/proto/maximus_proto.py b/cesar/maximus/python/lib/proto/maximus_proto.py
index fce439870d..67e6d9f012 100644
--- a/cesar/maximus/python/lib/proto/maximus_proto.py
+++ b/cesar/maximus/python/lib/proto/maximus_proto.py
@@ -46,23 +46,22 @@ class Sniff(threading.Thread):
# the destination mac address to filter,
# and the FCALL to have access to the list of received MMEs
self.__maximus = maximus
+
+ # Create a socket
+ self.__my_socket = my_sniff_init(iface=self.__maximus.network_interface)
def run(self):
print "Starting sniff..."
- network_interface = self.__maximus.network_interface
- mac_address = self.__maximus.mac_address
- fcall = self.__maximus.fcall
-
while self.__run is True:
# Sniff until a MME is received
- mme = sniff(iface=network_interface, lfilter=lambda x: x.type == HPAV_MTYPE_MME and x.dst == mac_address, count=1, timeout=3)
+ mme = sniff(my_socket=self.__my_socket, lfilter=lambda x: x.type == HPAV_MTYPE_MME and x.dst == self.__maximus.mac_address, count=1, timeout=1)
if len(mme) != 0:
# When a MME is received, copy it into the list of received MMEs
# (the received MME will be processed later)
self.__maximus.semaphore.acquire()
- fcall.__class__.rsp_list.append(mme[0])
+ self.__maximus.fcall.__class__.rsp_list.append(mme[0])
self.__maximus.semaphore.release()
def stop(self):
@@ -146,7 +145,6 @@ class MaximusProto:
self.semaphore = threading.Semaphore()
self.background = Sniff(self)
self.background.start()
- sleep(1)
# Set the signal handler
signal.signal(signal.SIGINT, self.handler)
diff --git a/cesar/maximus/python/lib/proto/my_scapy.py b/cesar/maximus/python/lib/proto/my_scapy.py
new file mode 100644
index 0000000000..7809769cdc
--- /dev/null
+++ b/cesar/maximus/python/lib/proto/my_scapy.py
@@ -0,0 +1,13251 @@
+#! /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.1"
+
+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 itertools
+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
+ del(f)
+
+
+
+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 and x[0]!="_", self.__dict__.items())))
+ def _show(self):
+ for k in self.__dict__.keys():
+ if k and k[0] != "_":
+ print "%10s = %r" % (k,getattr(self,k))
+ def __repr__(self):
+ return "<%s/ %s>" % (self._name," ".join(filter(lambda x:x and 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 and 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:
+ shrp = l.find("#")
+ if shrp >= 0:
+ l = l[:shrp]
+ l = l.strip()
+ if not l:
+ continue
+ lt = tuple(re.split(spaces, l))
+ if len(lt) < 2 or not lt[0]:
+ continue
+ dct[lt[0]] = int(lt[1])
+ except Exception,e:
+ log_loading.info("Couldn't parse file [%s]: line [%r] (%s)" % (filename,l,e))
+ 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:
+ shrp = l.find("#")
+ if shrp >= 0:
+ l = l[:shrp]
+ l = l.strip()
+ if not l:
+ continue
+ lt = tuple(re.split(spaces, l))
+ if len(lt) < 2 or not lt[0]:
+ 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:
+ shrp = l.find("#")
+ if shrp >= 0:
+ l = l[:shrp]
+ l = l.strip()
+ if not l:
+ continue
+ lt = tuple(re.split(spaces, l))
+ if len(lt) < 2 or not lt[0]:
+ 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_loading.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) in (int,long):
+ 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):
+ x=str(x)[::-1]
+ y=str(y)[::-1]
+ SUBST=1
+ INSERT=1
+ d={}
+ d[-1,-1] = 0,(-1,-1)
+ for j in range(len(y)):
+ d[-1,j] = d[-1,j-1][0]+INSERT, (-1,j-1)
+ for i in range(len(x)):
+ d[i,-1] = d[i-1,-1][0]+INSERT, (i-1,-1)
+
+ for j in range(len(y)):
+ for i in range(len(x)):
+ d[i,j] = min( ( d[i-1,j-1][0]+SUBST*(x[i] != y[j]), (i-1,j-1) ),
+ ( d[i-1,j][0]+INSERT, (i-1,j) ),
+ ( d[i,j-1][0]+INSERT, (i,j-1) ) )
+
+
+ backtrackx = []
+ backtracky = []
+ i=len(x)-1
+ j=len(y)-1
+ while not (i == j == -1):
+ i2,j2 = d[i,j][1]
+ backtrackx.append(x[i2+1:i+1])
+ backtracky.append(y[j2+1:j+1])
+ i,j = i2,j2
+
+
+
+ x = y = i = 0
+ colorize = { 0: lambda x:x,
+ -1: conf.color_theme.left,
+ 1: conf.color_theme.right }
+
+ dox=1
+ doy=0
+ l = len(backtrackx)
+ while i < l:
+ separate=0
+ linex = backtrackx[i:i+16]
+ liney = backtracky[i:i+16]
+ xx = sum(len(k) for k in linex)
+ yy = sum(len(k) for k in liney)
+ if dox and not xx:
+ dox = 0
+ doy = 1
+ if dox and linex == liney:
+ doy=1
+
+ if dox:
+ xd = y
+ j = 0
+ while not linex[j]:
+ j += 1
+ xd -= 1
+ print colorize[doy-dox]("%04x" % xd),
+ x += xx
+ line=linex
+ else:
+ print " ",
+ if doy:
+ yd = y
+ j = 0
+ while not liney[j]:
+ j += 1
+ yd -= 1
+ print colorize[doy-dox]("%04x" % yd),
+ y += yy
+ line=liney
+ else:
+ print " ",
+
+ print " ",
+
+ cl = ""
+ for j in range(16):
+ if i+j < l:
+ if line[j]:
+ col = colorize[(linex[j]!=liney[j])*(doy-dox)]
+ print col("%02X" % ord(line[j])),
+ if linex[j]==liney[j]:
+ cl += sane_color(line[j])
+ else:
+ cl += col(sane(line[j]))
+ else:
+ print " ",
+ cl += " "
+ else:
+ print " ",
+ if j == 7:
+ print "",
+
+
+ print " ",cl
+
+ if doy or not yy:
+ doy=0
+ dox=1
+ i += 16
+ else:
+ if yy:
+ dox=0
+ doy=1
+ else:
+ i += 16
+
+
+crc32 = zlib.crc32
+
+if BIG_ENDIAN:
+ def checksum(pkt):
+ if len(pkt) % 2 == 1:
+ pkt += "\0"
+ s = sum(array.array("H", pkt))
+ s = (s >> 16) + (s & 0xffff)
+ s += s >> 16
+ s = ~s
+ return s & 0xffff
+else:
+ def checksum(pkt):
+ if len(pkt) % 2 == 1:
+ pkt += "\0"
+ s = sum(array.array("H", pkt))
+ s = (s >> 16) + (s & 0xffff)
+ s += s >> 16
+ s = ~s
+ return (((s>>8)&0xff)|s<<8) & 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 (0xffffffff00000000L>>x)&0xffffffffL
+
+def do_graph(graph,prog=None,format="svg",target=None, type=None,string=None,options=None):
+ """do_graph(graph, prog=conf.prog.dot, format="svg",
+ target="| conf.prog.display", options=None, [string=1]):
+ string: if not None, simply return the graph string
+ graph: GraphViz graph description
+ format: 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
+ options: options to be passed to prog"""
+
+
+ if string:
+ return graph
+ if type is not None:
+ format=type
+ if prog is None:
+ prog = conf.prog.dot
+ if target is None:
+ target = "| %s" % conf.prog.display
+ if format is not None:
+ format = "-T %s" % format
+ w,r = os.popen2("%s %s %s %s" % (prog,options or "", format or "", 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:
+ _value=None
+ 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)
+ self.cache = {}
+
+ def invalidate_cache(self):
+ self.cache = {}
+
+ def resync(self):
+ self.invalidate_cache()
+ 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.invalidate_cache()
+ self.routes.append(self.make_route(*args,**kargs))
+
+
+ def delt(self, *args, **kargs):
+ """delt(host|net, gw|dev)"""
+ self.invalidate_cache()
+ 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):
+ self.invalidate_cache()
+ the_addr,the_msk = (addr.split("/")+["32"])[:2]
+ the_msk = itom(int(the_msk))
+ the_rawaddr = atol(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):
+ self.invalidate_cache()
+ new_routes=[]
+ for rt in self.routes:
+ if rt[3] != iff:
+ new_routes.append(rt)
+ self.routes=new_routes
+
+ def ifadd(self, iff, addr):
+ self.invalidate_cache()
+ the_addr,the_msk = (addr.split("/")+["32"])[:2]
+ the_msk = itom(int(the_msk))
+ the_rawaddr = atol(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,dest,verbose=None):
+ if dest in self.cache:
+ return self.cache[dest]
+ if verbose is None:
+ verbose=conf.verb
+ # Transform "192.168.*.1-5" to one IP of the set
+ dst = dest.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:]
+
+
+ dst = atol(dst)
+ pathes=[]
+ for d,m,gw,i,a in self.routes:
+ aa = atol(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:
+ if verbose:
+ 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()
+ ret = pathes[-1][1]
+ self.cache[dest] = ret
+ return ret
+
+ 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
+ elif FREEBSD:
+ f=os.popen("netstat -rnW") # -W to handle long interface names
+ 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 = atol(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 = atol(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 = socket.ntohl(struct.unpack("I",ifreq2[20:24])[0])
+ dst = socket.ntohl(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: unkown 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
+ try:
+ ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x",iff))
+ except IOError: # interface is present in routing tables but does not have any assigned IP
+ ifaddr="0.0.0.0"
+ else:
+ addrfamily = struct.unpack("h",ifreq[16:18])[0]
+ if addrfamily == socket.AF_INET:
+ ifaddr = inet_ntoa(ifreq[20:24])
+ else:
+ warning("Interface %s: unkown address family (%i)"%(iff, addrfamily))
+ continue
+ routes.append((socket.htonl(long(dst,16))&0xffffffffL,
+ socket.htonl(long(msk,16))&0xffffffffL,
+ 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):
+ if attr == "__setstate__":
+ raise AttributeError(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 = 0x31 #XXX 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 = map(chr, s)
+ s.append(BER_len_enc(len(s)))
+ s.append(chr(cls.tag))
+ s.reverse()
+ return "".join(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"
+ else:
+ return super(cls,cls).enc(i)
+
+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=[], **kargs):
+ 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\trankdir=LR;\n\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"
+ do_graph(s, **kargs)
+
+
+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"
+ return 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)
+ return 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)
+
+ return 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 i2count(self, pkt, x):
+ """Convert internal value to a number of elements usable by a FieldLenField.
+ Always 1 except for list fields"""
+ return 1
+ 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)
+ def __hash__(self):
+ return hash(self.fld)
+ def __eq__(self, other):
+ return self.fld == other
+
+
+class ActionField:
+ _fld = None
+ 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:
+ fld = None
+ def __init__(self, fld, cond):
+ self.fld = fld
+ self.cond = cond
+ def _evalcond(self,pkt):
+ return self.cond(pkt)
+
+ 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 PadField:
+ """Add bytes after the proxified field so that it ends at the specified
+ alignment from its begining"""
+ _fld = None
+ def __init__(self, fld, align, padwith=None):
+ self._fld = fld
+ self._align = align
+ self._padwith = padwith or ""
+
+ def addfield(self, pkt, s, val):
+ sval = self._fld.addfield(pkt, "", val)
+ return s+sval+struct.pack("%is" % (-len(sval)%self._align), self._padwith)
+
+ 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 = [self.h2i(pkt, n) for n in x]
+ return x
+ def resolve(self, x):
+ if self in conf.resolve:
+ try:
+ ret = socket.gethostbyaddr(x)[0]
+ except:
+ 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")
+ def randval(self):
+ return RandSInt()
+
+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")
+ def randval(self):
+ return RandSInt()
+
+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))
+
+def FIELD_LENGTH_MANAGEMENT_DEPRECATION(x):
+ try:
+ for tb in traceback.extract_stack()+[("??",-1,None,"")]:
+ f,l,_,line = tb
+ if line.startswith("fields_desc"):
+ break
+ except:
+ f,l="??",-1
+ log_loading.warning("Deprecated use of %s (%s l. %i). See http://trac.secdev.org/scapy/wiki/LengthFields" % (x,f,l))
+
+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
+ if shift != 0:
+ FIELD_LENGTH_MANAGEMENT_DEPRECATION(self.__class__.__name__)
+ 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=None, length_from=None, shift=0):
+ PacketField.__init__(self, name, default, cls, shift=shift)
+ self.length_from = length_from
+ if fld is not None or shift != 0:
+ FIELD_LENGTH_MANAGEMENT_DEPRECATION(self.__class__.__name__)
+ self.count_from = lambda pkt,fld=fld,shift=shift: getattr(pkt,fld)-shift
+ def getfield(self, pkt, s):
+ l = self.length_from(pkt)
+ i = self.m2i(pkt, s[:l])
+ return s[l:],i
+
+
+class PacketListField(PacketField):
+ islist = 1
+ holds_packets=1
+ def __init__(self, name, default, cls, fld=None, count_from=None, length_from=None, shift=0):
+ if default is None:
+ default = [] # Create a new list for each instance
+ PacketField.__init__(self, name, default, cls, shift=shift)
+ self.count_from = count_from
+ self.length_from = length_from
+
+ if fld is not None or shift != 0:
+ FIELD_LENGTH_MANAGEMENT_DEPRECATION(self.__class__.__name__)
+ if fld is not None:
+ self.count_from = lambda pkt,fld=fld,shift=shift: getattr(pkt,fld)-shift
+
+ def any2i(self, pkt, x):
+ if type(x) is not list:
+ return [x]
+ else:
+ return x
+ def i2count(self, pkt, val):
+ if type(val) is list:
+ return len(val)
+ return 1
+ def i2len(self, pkt, val):
+ return sum( len(p) for p in val )
+ def do_copy(self, x):
+ return map(lambda p:p.copy(), x)
+ def getfield(self, pkt, s):
+ c = l = None
+ if self.length_from is not None:
+ l = self.length_from(pkt)
+ elif self.count_from is not None:
+ c = self.count_from(pkt)
+
+ lst = []
+ ret = ""
+ remain = s
+ if l is not None:
+ remain,ret = s[:l],s[l:]
+ while remain:
+ if c is not None:
+ if c <= 0:
+ break
+ c -= 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+ret,lst
+ def addfield(self, pkt, s, val):
+ return s+"".join(map(str, val))
+
+
+class StrFixedLenField(StrField):
+ def __init__(self, name, default, length=None, length_from=None, shift=0):
+ StrField.__init__(self, name, default, shift=shift)
+ self.length_from = length_from
+ if length is not None:
+ self.length_from = lambda pkt,length=length: length
+ def getfield(self, pkt, s):
+ l = self.length_from(pkt)
+ return s[l:], self.m2i(pkt,s[:l])
+ def addfield(self, pkt, s, val):
+ l = self.length_from(pkt)
+ return s+struct.pack("%is"%l,self.i2m(pkt, val))
+ def randval(self):
+ try:
+ l = self.length_from(None)
+ except:
+ l = RandNum(0,200)
+ return RandBin(l)
+
+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=None, length_from=None, shift=0):
+ StrField.__init__(self, name, default, shift=shift)
+ self.length_from = length_from
+ if fld is not None or shift != 0:
+ FIELD_LENGTH_MANAGEMENT_DEPRECATION(self.__class__.__name__)
+ self.length_from = lambda pkt,fld=fld,shift=shift: getattr(pkt,fld)-shift
+ def getfield(self, pkt, s):
+ l = self.length_from(pkt)
+ return s[l:], self.m2i(pkt,s[:l])
+
+class FieldListField(Field):
+ islist=1
+ def __init__(self, name, default, field, fld=None, shift=0, length_from=None, count_from=None):
+ if default is None:
+ default = [] # Create a new list for each instance
+ Field.__init__(self, name, default)
+ self.count_from = count_from
+ self.length_from = length_from
+ self.field = field
+ if fld is not None or shift != 0:
+ FIELD_LENGTH_MANAGEMENT_DEPRECATION(self.__class__.__name__)
+ self.count_from = lambda pkt,fld=fld,shift=shift: getattr(pkt,fld)-shift
+
+
+ def i2count(self, pkt, val):
+ if type(val) is list:
+ return len(val)
+ return 1
+ def i2len(self, pkt, val):
+ return sum( self.field.i2len(pkt,v) for v in val )
+
+ def i2m(self, pkt, val):
+ if val is None:
+ val = []
+ return val
+ def any2i(self, pkt, x):
+ if type(x) is not list:
+ return [x]
+ else:
+ return x
+ def addfield(self, pkt, s, val):
+ val = self.i2m(pkt, val)
+ for v in val:
+ s = self.field.addfield(pkt, s, v)
+ return s
+ def getfield(self, pkt, s):
+ c = l = None
+ if self.length_from is not None:
+ l = self.length_from(pkt)
+ elif self.count_from is not None:
+ c = self.count_from(pkt)
+
+ val = []
+ ret=""
+ if l is not None:
+ s,ret = s[:l],s[l:]
+
+ while s:
+ if c is not None:
+ if c <= 0:
+ break
+ c -= 1
+ s,v = self.field.getfield(pkt, s)
+ val.append(v)
+ return s+ret, val
+
+class FieldLenField(Field):
+ def __init__(self, name, default, length_of=None, fmt = "H", count_of=None, adjust=lambda pkt,x:x, fld=None):
+ Field.__init__(self, name, default, fmt)
+ self.length_of=length_of
+ self.count_of=count_of
+ self.adjust=adjust
+ if fld is not None:
+ FIELD_LENGTH_MANAGEMENT_DEPRECATION(self.__class__.__name__)
+ self.length_of = fld
+ def i2m(self, pkt, x):
+ if x is None:
+ if self.length_of is not None:
+ fld,fval = pkt.getfield_and_val(self.length_of)
+ f = fld.i2len(pkt, fval)
+ else:
+ fld,fval = pkt.getfield_and_val(self.count_of)
+ f = fld.i2count(pkt, fval)
+ x = self.adjust(pkt,f)
+ 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
+
+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.rev = size < 0
+ self.size = abs(size)
+ def reverse(self, val):
+ if self.size == 16:
+ val = socket.ntohs(val)
+ elif self.size == 32:
+ val = socket.ntohl(val)
+ return val
+
+ def addfield(self, pkt, s, val):
+ val = self.i2m(pkt, val)
+ if type(s) is tuple:
+ s,bitsdone,v = s
+ else:
+ bitsdone = 0
+ v = 0
+ if self.rev:
+ val = self.reverse(val)
+ 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)
+
+ if self.rev:
+ b = self.reverse(b)
+
+ bn += self.size
+ s = s[bn/8:]
+ bn = bn%8
+ b = self.m2i(pkt, b)
+ if bn:
+ return (s,bn),b
+ else:
+ return s,b
+ def randval(self):
+ return RandNum(0,2**self.size-1)
+
+
+class BitFieldLenField(BitField):
+ def __init__(self, name, default, size, length_of=None, count_of=None, adjust=lambda pkt,x:x):
+ BitField.__init__(self, name, default, size)
+ self.length_of=length_of
+ self.count_of=count_of
+ self.adjust=adjust
+ def i2m(self, pkt, x):
+ return FieldLenField.i2m.im_func(self, pkt, x)
+
+
+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 not isinstance(x,VolatileValue) 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.rev = size < 0
+ self.size = abs(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 SignedIntEnumField(EnumField):
+ def __init__(self, name, default, enum):
+ EnumField.__init__(self, name, default, enum, "i")
+ def randval(self):
+ return RandSInt()
+
+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 not isinstance(x,VolatileValue) 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, length_of=None, fmt = "<H", count_of=None, adjust=lambda pkt,x:x, fld=None):
+ FieldLenField.__init__(self, name, default, length_of=length_of, fmt=fmt, fld=fld, adjust=adjust)
+
+
+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 and (type(oval) is not str or "s" in ofmt):
+ 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 = [k[:63] for k in x.split(".")] # Truncate chunks that cannont be encoded (more than 63 bytes..)
+ 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
+ explicit = 0
+
+ @classmethod
+ def from_hexcap(cls):
+ return cls(import_hexcap())
+
+ @classmethod
+ def upper_bonds(self):
+ for fval,upper in self.payload_guess:
+ print "%-20s %s" % (upper.__name__, ", ".join("%-12s" % ("%s=%r"%i) for i in fval.iteritems()))
+
+ @classmethod
+ def lower_bonds(self):
+ for lower,fval in self.overload_fields.iteritems():
+ print "%-20s %s" % (lower.__name__, ", ".join("%-12s" % ("%s=%r"%i) for i in fval.iteritems()))
+
+ 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.explicit=self.explicit
+ clone.post_transforms=self.post_transforms[:]
+ clone.__dict__["payload"] = self.payload.copy()
+ clone.payload.add_underlayer(clone)
+ return clone
+
+ def getfieldval(self, attr):
+ if attr in self.fields:
+ return self.fields[attr]
+ if attr in self.overloaded_fields:
+ return self.overloaded_fields[attr]
+ if attr in self.default_fields:
+ return self.default_fields[attr]
+ return self.payload.getfieldval(attr)
+
+ def getfield_and_val(self, attr):
+ if attr in self.fields:
+ return self.get_field(attr),self.fields[attr]
+ if attr in self.overloaded_fields:
+ return self.get_field(attr),self.overloaded_fields[attr]
+ if attr in self.default_fields:
+ return self.get_field(attr),self.default_fields[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)
+ self.explicit=0
+ 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])
+ self.explicit=0 # in case a default value must be explicited
+ 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.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):
+ if not self.explicit:
+ self = self.__iter__().next()
+ 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()
+ p = self.build_done(p)
+ return p
+
+ def build_done(self, p):
+ return self.payload.build_done(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.explicit = 1
+ 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 not None:
+ pkt.add_payload(payl)
+ yield pkt
+
+ if self.explicit:
+ todo = []
+ done = self.fields
+ else:
+ todo = [ k for (k,v) in itertools.chain(self.default_fields.iteritems(),
+ self.overloaded_fields.iteritems())
+ if isinstance(v, VolatileValue) ] + self.fields.keys()
+ done = {}
+ return loop(todo, done)
+
+ 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 and 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():
+ fld = self.get_field(fn)
+ if isinstance(fv, Packet):
+ fv = fv.command()
+ elif fld.islist and fld.holds_packets and type(fv) is list:
+ fv = "[%s]" % ",".join( map(Packet.command, fv))
+ 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_done(self, p):
+ return p
+ 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 RadioTap(Packet):
+ name = "RadioTap dummy"
+ fields_desc = [ ByteField('version', 0),
+ ByteField('pad', 0),
+ FieldLenField('len', None, 'notdecoded', '@H', adjust=lambda pkt,x:x+8),
+ FlagsField('present', None, -32, ['TSFT','Flags','Rate','Channel','FHSS','dBm_AntSignal',
+ 'dBm_AntNoise','Lock_Quality','TX_Attenuation','dB_TX_Attenuation',
+ 'dBm_TX_Power', 'Antenna', 'dB_AntSignal', 'dB_AntNoise',
+ 'b14', 'b15','b16','b17','b18','b19','b20','b21','b22','b23',
+ 'b24','b25','b26','b27','b28','b29','b30','Ext']),
+ StrLenField('notdecoded', "", length_from= lambda pkt:pkt.len-8) ]
+
+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),
+ BCDFloatField("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"}), lambda pkt:pkt.code 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):
+ return self.payload.hashret()
+ def answers(self, other):
+ if not isinstance(other, UDP):
+ return 0
+ if conf.checkIPsrc:
+ if 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", "", length_from=lambda pkt:pkt.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 = v.name
+ 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.lower() != other.addr2.lower(): # 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", "", length_from=lambda x:x.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),
+ ]
+ def answers(self, other):
+ if isinstance(other, PrismHeader):
+ return self.payload.answers(other.payload)
+ else:
+ return self.payload.answers(other)
+
+
+
+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),lambda pkt:pkt.chksumpresent==1),
+ ConditionalField(XShortField("reserved1",None),lambda pkt:pkt.chksumpresent==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_from=lambda x:x.length-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", adjust=lambda pkt,x:x+8),
+ ByteField("proposal",1),
+ ByteEnumField("proto",1,{1:"ISAKMP"}),
+ FieldLenField("SPIsize",None,"SPI","B"),
+ ByteField("trans_nb",None),
+ StrLenField("SPI","",length_from=lambda x:x.SPIsize),
+ PacketLenField("trans",Raw(),ISAKMP_payload_Transform,length_from=lambda x:x.length-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", adjust=lambda pkt,x:x+4),
+ StrLenField("load","",length_from=lambda x:x.length-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", adjust=lambda pkt,x:x+4),
+ StrLenField("vendorID","",length_from=lambda x:x.length-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", adjust=lambda pkt,x:x+12),
+ IntEnumField("DOI",1,{1:"IPSEC"}),
+ IntEnumField("situation",1,{1:"identity"}),
+ PacketLenField("prop",Raw(),ISAKMP_payload_Proposal,length_from=lambda x:x.length-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", adjust=lambda pkt,x:x+4),
+ StrLenField("load","",length_from=lambda x:x.length-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", adjust=lambda pkt,x:x+4),
+ StrLenField("load","",length_from=lambda x:x.length-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",adjust=lambda pkt,x:x+8),
+ 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_from=lambda x:x.length-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",adjust=lambda pkt,x:x+4),
+ StrLenField("load","",length_from=lambda x:x.length-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) ]
+
+_rtp_payload_types = {
+ # http://www.iana.org/assignments/rtp-parameters
+ 0: 'G.711 PCMU', 3: 'GSM',
+ 4: 'G723', 5: 'DVI4',
+ 6: 'DVI4', 7: 'LPC',
+ 8: 'PCMA', 9: 'G722',
+ 10: 'L16', 11: 'L16',
+ 12: 'QCELP', 13: 'CN',
+ 14: 'MPA', 15: 'G728',
+ 16: 'DVI4', 17: 'DVI4',
+ 18: 'G729', 25: 'CelB',
+ 26: 'JPEG', 28: 'nv',
+ 31: 'H261', 32: 'MPV',
+ 33: 'MP2T', 34: 'H263' }
+
+class RTP(Packet):
+ name="RTP"
+ fields_desc = [ BitField('version', 2, 2),
+ BitField('padding', 0, 1),
+ BitField('extension', 0, 1),
+ BitFieldLenField('numsync', None, 4, count_of='sync'),
+ BitField('marker', 0, 1),
+ BitEnumField('payload', 0, 7, _rtp_payload_types),
+ ShortField('sequence', 0),
+ IntField('timestamp', 0),
+ IntField('sourcesync', 0),
+ FieldListField('sync', [], IntField("id",0), count_from=lambda pkt:pkt.numsync) ]
+
+### 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", "", length_from=lambda x:x.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", "", length_from=lambda x:x.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", adjust=lambda pkt,x:x-16),
+ BitField("GUID",0,128),
+ StrLenField("SecurityBlob", "", length_from=lambda x:x.ByteCount+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",length_from=lambda x:x.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) ]
+
+
+TFTP_operations = { 1:"RRQ",2:"WRQ",3:"DATA",4:"ACK",5:"ERROR",6:"OACK" }
+
+
+class TFTP(Packet):
+ name = "TFTP opcode"
+ fields_desc = [ ShortEnumField("op", 1, TFTP_operations), ]
+
+
+
+class TFTP_RRQ(Packet):
+ name = "TFTP Read Request"
+ fields_desc = [ StrNullField("filename", ""),
+ StrNullField("mode", "octet") ]
+ def answers(self, other):
+ return 0
+ def mysummary(self):
+ return self.sprintf("RRQ %filename%"),[UDP]
+
+
+class TFTP_WRQ(Packet):
+ name = "TFTP Write Request"
+ fields_desc = [ StrNullField("filename", ""),
+ StrNullField("mode", "octet") ]
+ def answers(self, other):
+ return 0
+ def mysummary(self):
+ return self.sprintf("WRQ %filename%"),[UDP]
+
+class TFTP_DATA(Packet):
+ name = "TFTP Data"
+ fields_desc = [ ShortField("block", 0) ]
+ def answers(self, other):
+ return self.block == 1 and isinstance(other, TFTP_RRQ)
+ def mysummary(self):
+ return self.sprintf("DATA %block%"),[UDP]
+
+class TFTP_Option(Packet):
+ fields_desc = [ StrNullField("oname",""),
+ StrNullField("value","") ]
+ def extract_padding(self, pkt):
+ return "",pkt
+
+class TFTP_Options(Packet):
+ fields_desc = [ PacketListField("options", [], TFTP_Option, length_from=lambda x:None) ]
+
+
+class TFTP_ACK(Packet):
+ name = "TFTP Ack"
+ fields_desc = [ ShortField("block", 0) ]
+ def answers(self, other):
+ if isinstance(other, TFTP_DATA):
+ return self.block == other.block
+ elif isinstance(other, TFTP_RRQ) or isinstance(other, TFTP_WRQ) or isinstance(other, TFTP_OACK):
+ return self.block == 0
+ return 0
+ def mysummary(self):
+ return self.sprintf("ACK %block%"),[UDP]
+
+TFTP_Error_Codes = { 0: "Not defined",
+ 1: "File not found",
+ 2: "Access violation",
+ 3: "Disk full or allocation exceeded",
+ 4: "Illegal TFTP operation",
+ 5: "Unknown transfer ID",
+ 6: "File already exists",
+ 7: "No such user",
+ 8: "Terminate transfer due to option negotiation",
+ }
+
+class TFTP_ERROR(Packet):
+ name = "TFTP Error"
+ fields_desc = [ ShortEnumField("errorcode", 0, TFTP_Error_Codes),
+ StrNullField("errormsg", "")]
+ def answers(self, other):
+ return (isinstance(other, TFTP_DATA) or
+ isinstance(other, TFTP_RRQ) or
+ isinstance(other, TFTP_WRQ) or
+ isinstance(other, TFTP_ACK))
+ def mysummary(self):
+ return self.sprintf("ERROR %errorcode%: %errormsg%"),[UDP]
+
+
+class TFTP_OACK(Packet):
+ name = "TFTP Option Ack"
+ fields_desc = [ ]
+ def answers(self, other):
+ return isinstance(other, TFTP_WRQ) or isinstance(other, TFTP_RRQ)
+
+
+##########
+## 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)
+
+
+bind_layers( Dot3, LLC, )
+bind_layers( GPRS, IP, )
+bind_layers( PrismHeader, Dot11, )
+bind_layers( RadioTap, Dot11, )
+bind_layers( Dot11, LLC, type=2)
+bind_layers( PPP, IP, proto=33)
+bind_layers( Ether, LLC, type=122)
+bind_layers( Ether, Dot1Q, type=33024)
+bind_layers( Ether, Ether, type=1)
+bind_layers( Ether, ARP, type=2054)
+bind_layers( Ether, IP, type=2048)
+bind_layers( Ether, EAPOL, type=34958)
+bind_layers( Ether, EAPOL, dst='01:80:c2:00:00:03', type=34958)
+bind_layers( Ether, PPPoED, type=34915)
+bind_layers( Ether, PPPoE, type=34916)
+bind_layers( CookedLinux, LLC, proto=122)
+bind_layers( CookedLinux, Dot1Q, proto=33024)
+bind_layers( CookedLinux, Ether, proto=1)
+bind_layers( CookedLinux, ARP, proto=2054)
+bind_layers( CookedLinux, IP, proto=2048)
+bind_layers( CookedLinux, EAPOL, proto=34958)
+bind_layers( CookedLinux, PPPoED, proto=34915)
+bind_layers( CookedLinux, PPPoE, proto=34916)
+bind_layers( GRE, LLC, proto=122)
+bind_layers( GRE, Dot1Q, proto=33024)
+bind_layers( GRE, Ether, proto=1)
+bind_layers( GRE, ARP, proto=2054)
+bind_layers( GRE, IP, proto=2048)
+bind_layers( GRE, EAPOL, proto=34958)
+bind_layers( PPPoE, PPP, code=0)
+bind_layers( EAPOL, EAP, type=0)
+bind_layers( LLC, STP, dsap=66, ssap=66, ctrl=3)
+bind_layers( LLC, SNAP, dsap=170, ssap=170, ctrl=3)
+bind_layers( SNAP, Dot1Q, code=33024)
+bind_layers( SNAP, Ether, code=1)
+bind_layers( SNAP, ARP, code=2054)
+bind_layers( SNAP, IP, code=2048)
+bind_layers( SNAP, EAPOL, code=34958)
+bind_layers( SNAP, STP, code=267)
+bind_layers( IPerror, IPerror, frag=0, proto=4)
+bind_layers( IPerror, ICMPerror, frag=0, proto=1)
+bind_layers( IPerror, TCPerror, frag=0, proto=6)
+bind_layers( IPerror, UDPerror, frag=0, proto=17)
+bind_layers( IP, IP, frag=0, proto=4)
+bind_layers( IP, ICMP, frag=0, proto=1)
+bind_layers( IP, TCP, frag=0, proto=6)
+bind_layers( IP, UDP, frag=0, proto=17)
+bind_layers( IP, GRE, frag=0, proto=47)
+bind_layers( UDP, SNMP, sport=161)
+bind_layers( UDP, SNMP, dport=161)
+bind_layers( UDP, MGCP, dport=2727)
+bind_layers( UDP, MGCP, sport=2727)
+bind_layers( UDP, DNS, dport=53)
+bind_layers( UDP, DNS, sport=53)
+bind_layers( UDP, ISAKMP, dport=500, sport=500)
+bind_layers( UDP, HSRP, dport=1985, sport=1985)
+bind_layers( UDP, NTP, dport=123, sport=123)
+bind_layers( UDP, BOOTP, dport=67, sport=68)
+bind_layers( UDP, BOOTP, dport=68, sport=67)
+bind_layers( BOOTP, DHCP, options='c\x82Sc')
+bind_layers( UDP, RIP, sport=520)
+bind_layers( UDP, RIP, dport=520)
+bind_layers( RIP, RIPEntry, )
+bind_layers( RIPEntry, RIPEntry, )
+bind_layers( Dot11, Dot11AssoReq, subtype=0, type=0)
+bind_layers( Dot11, Dot11AssoResp, subtype=1, type=0)
+bind_layers( Dot11, Dot11ReassoReq, subtype=2, type=0)
+bind_layers( Dot11, Dot11ReassoResp, subtype=3, type=0)
+bind_layers( Dot11, Dot11ProbeReq, subtype=4, type=0)
+bind_layers( Dot11, Dot11ProbeResp, subtype=5, type=0)
+bind_layers( Dot11, Dot11Beacon, subtype=8, type=0)
+bind_layers( Dot11, Dot11ATIM, subtype=9, type=0)
+bind_layers( Dot11, Dot11Disas, subtype=10, type=0)
+bind_layers( Dot11, Dot11Auth, subtype=11, type=0)
+bind_layers( Dot11, Dot11Deauth, subtype=12, type=0)
+bind_layers( Dot11Beacon, Dot11Elt, )
+bind_layers( Dot11AssoReq, Dot11Elt, )
+bind_layers( Dot11AssoResp, Dot11Elt, )
+bind_layers( Dot11ReassoReq, Dot11Elt, )
+bind_layers( Dot11ReassoResp, Dot11Elt, )
+bind_layers( Dot11ProbeReq, Dot11Elt, )
+bind_layers( Dot11ProbeResp, Dot11Elt, )
+bind_layers( Dot11Auth, Dot11Elt, )
+bind_layers( Dot11Elt, Dot11Elt, )
+bind_layers( TCP, Skinny, dport=2000)
+bind_layers( TCP, Skinny, sport=2000)
+bind_layers( UDP, SebekHead, sport=1101)
+bind_layers( UDP, SebekHead, dport=1101)
+bind_layers( UDP, SebekHead, dport=1101, sport=1101)
+bind_layers( SebekHead, SebekV1, version=1)
+bind_layers( SebekHead, SebekV2Sock, version=2, type=2)
+bind_layers( SebekHead, SebekV2, version=2)
+bind_layers( SebekHead, SebekV3Sock, version=3, type=2)
+bind_layers( SebekHead, SebekV3, version=3)
+bind_layers( CookedLinux, IrLAPHead, proto=23)
+bind_layers( IrLAPHead, IrLAPCommand, Type=1)
+bind_layers( IrLAPCommand, IrLMP, )
+bind_layers( UDP, NBNSQueryRequest, dport=137)
+bind_layers( UDP, NBNSRequest, dport=137)
+bind_layers( UDP, NBNSQueryResponse, sport=137)
+bind_layers( UDP, NBNSQueryResponseNegative, sport=137)
+bind_layers( UDP, NBNSNodeStatusResponse, sport=137)
+bind_layers( NBNSNodeStatusResponse, NBNSNodeStatusResponseService, )
+bind_layers( NBNSNodeStatusResponse, NBNSNodeStatusResponseService, )
+bind_layers( NBNSNodeStatusResponseService, NBNSNodeStatusResponseService, )
+bind_layers( NBNSNodeStatusResponseService, NBNSNodeStatusResponseEnd, )
+bind_layers( UDP, NBNSWackResponse, sport=137)
+bind_layers( UDP, NBTDatagram, dport=138)
+bind_layers( TCP, NBTSession, dport=139)
+bind_layers( NBTSession, SMBNegociate_Protocol_Request_Header, )
+bind_layers( SMBNegociate_Protocol_Request_Header, SMBNegociate_Protocol_Request_Tail, )
+bind_layers( SMBNegociate_Protocol_Request_Tail, SMBNegociate_Protocol_Request_Tail, )
+bind_layers( NBTSession, SMBNegociate_Protocol_Response_Advanced_Security, ExtendedSecurity=1)
+bind_layers( NBTSession, SMBNegociate_Protocol_Response_No_Security, ExtendedSecurity=0, EncryptionKeyLength=8)
+bind_layers( NBTSession, SMBNegociate_Protocol_Response_No_Security_No_Key, ExtendedSecurity=0, EncryptionKeyLength=0)
+bind_layers( NBTSession, SMBSession_Setup_AndX_Request, )
+bind_layers( NBTSession, SMBSession_Setup_AndX_Response, )
+bind_layers( HCI_Hdr, HCI_ACL_Hdr, type=2)
+bind_layers( HCI_Hdr, Raw, )
+bind_layers( HCI_ACL_Hdr, L2CAP_Hdr, )
+bind_layers( L2CAP_Hdr, L2CAP_CmdHdr, cid=1)
+bind_layers( L2CAP_CmdHdr, L2CAP_CmdRej, code=1)
+bind_layers( L2CAP_CmdHdr, L2CAP_ConnReq, code=2)
+bind_layers( L2CAP_CmdHdr, L2CAP_ConnResp, code=3)
+bind_layers( L2CAP_CmdHdr, L2CAP_ConfReq, code=4)
+bind_layers( L2CAP_CmdHdr, L2CAP_ConfResp, code=5)
+bind_layers( L2CAP_CmdHdr, L2CAP_DisconnReq, code=6)
+bind_layers( L2CAP_CmdHdr, L2CAP_DisconnResp, code=7)
+bind_layers( L2CAP_CmdHdr, L2CAP_InfoReq, code=10)
+bind_layers( L2CAP_CmdHdr, L2CAP_InfoResp, code=11)
+bind_layers( UDP, MobileIP, sport=434)
+bind_layers( UDP, MobileIP, dport=434)
+bind_layers( MobileIP, MobileIPRRQ, type=1)
+bind_layers( MobileIP, MobileIPRRP, type=3)
+bind_layers( MobileIP, MobileIPTunnelData, type=4)
+bind_layers( MobileIPTunnelData, IP, nexthdr=4)
+bind_layers( NetflowHeader, NetflowHeaderV1, version=1)
+bind_layers( NetflowHeaderV1, NetflowRecordV1, )
+
+bind_layers(UDP, TFTP, dport=69)
+bind_layers(TFTP, TFTP_RRQ, op=1)
+bind_layers(TFTP, TFTP_WRQ, op=2)
+bind_layers(TFTP, TFTP_DATA, op=3)
+bind_layers(TFTP, TFTP_ACK, op=4)
+bind_layers(TFTP, TFTP_ERROR, op=5)
+bind_layers(TFTP, TFTP_OACK, op=6)
+bind_layers(TFTP_RRQ, TFTP_Options)
+bind_layers(TFTP_WRQ, TFTP_Options)
+bind_layers(TFTP_OACK, TFTP_Options)
+
+
+###################
+## 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
+
+def defragment(plist):
+ """defrag(plist) -> plist defragmented as much as possible """
+ frags = {}
+ final = []
+
+ pos = 0
+ for p in plist:
+ p._defrag_pos = pos
+ pos += 1
+ if IP in p:
+ ip = p[IP]
+ if ip.frag != 0 or ip.flags & 1:
+ ip = p[IP]
+ uniq = (ip.id,ip.src,ip.dst,ip.proto)
+ if uniq in frags:
+ frags[uniq].append(p)
+ else:
+ frags[uniq] = [p]
+ continue
+ final.append(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 += 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 += 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
+ p._defrag_pos = lst[-1]._defrag_pos
+ defrag.append(p)
+ defrag2=[]
+ for p in defrag:
+ q = p.__class__(str(p))
+ q._defrag_pos = p._defrag_pos
+ defrag2.append(q)
+ final += defrag2
+ final += missfrag
+ final.sort(lambda x,y: cmp(x._defrag_pos, y._defrag_pos))
+ for p in final:
+ del(p._defrag_pos)
+
+ if hasattr(plist, "listname"):
+ name = "Defragmented %s" % plist.listname
+ else:
+ name = "Defragmented"
+
+
+ return PacketList(final, name=name)
+
+
+
+
+
+
+###################
+## 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,
+ 803 : RadioTap,
+ 105 : Dot11,
+ 113 : CookedLinux,
+ 119 : PrismHeader, # for atheros
+ 127 : RadioTap,
+ 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,
+ RadioTap : 803,
+ RadioTap : 127,
+ 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_CmdHdr(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 sendpfast(x, pps=None, mbps=None, realtime=None, loop=0, iface=None):
+ """Send packets at layer 2 using tcpreplay for performance
+ pps: packets per second
+ mpbs: MBits per second
+ realtime: use packet's timestamp, bending time with realtime value
+ loop: number of times to process the packet list
+ iface: output interface """
+ if iface is None:
+ iface = conf.iface
+ options = ["--intf1=%s" % iface ]
+ if pps is not None:
+ options.append("--pps=%i" % pps)
+ elif mbps is not None:
+ options.append("--mbps=%i" % mbps)
+ elif realtime is not None:
+ options.append("--multiplier=%i" % realtime)
+ else:
+ options.append("--topspeed")
+
+ if loop:
+ options.append("--loop=%i" % loop)
+
+ f = os.tempnam("scapy")
+ options.append(f)
+ wrpcap(f, x)
+ try:
+ try:
+ os.spawnlp(os.P_WAIT, conf.prog.tcpreplay, conf.prog.tcpreplay, *options)
+ except KeyboardInterrupt:
+ log_interactive.info("Interrupted by user")
+ finally:
+ os.unlink(f)
+
+
+
+
+
+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 my_sniff_init(*arg, **karg):
+ L2socket = conf.L2listen
+ s = L2socket(type=ETH_P_ALL, *arg, **karg)
+ return s
+
+def sniff(my_socket=None, 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 my_socket is not None:
+ s = my_socket
+ else:
+ 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, verbose=None, **kargs):
+ """Instant TCP traceroute
+traceroute(target, [maxttl=30,] [dport=80,] [sport=80,] [verbose=conf.verb]) -> None
+"""
+ if verbose is None:
+ verbose = conf.verb
+ 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, verbose=verbose, **kargs)
+ else:
+ a,b = sr(IP(dst=target, id=RandShort(), ttl=(minttl,maxttl))/l4,
+ verbose=verbose, timeout=timeout, **kargs)
+
+ a = TracerouteResult(a.res)
+ if verbose:
+ a.show()
+ return a,b
+
+
+
+
+def arping(net, timeout=2, cache=0, verbose=None, **kargs):
+ """Send ARP who-has requests to determine which hosts are up
+arping(net, [cache=0,] [iface=conf.iface,] [verbose=conf.verb]) -> None
+Set cache=True if you want arping to modify internal ARP-Cache"""
+ if verbose is None:
+ verbose = conf.verb
+ ans,unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=net), verbose=verbose,
+ 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())
+ if verbose:
+ ans.show()
+ 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(atol(x),atol(y)))
+ 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(atol(x),atol(y)))
+ 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 ]
+
+
+##############
+## Automata ##
+##############
+
+class ATMT:
+ STATE = "State"
+ ACTION = "Action"
+ CONDITION = "Condition"
+ RECV = "Receive condition"
+ TIMEOUT = "Timeout condition"
+
+ class NewStateRequested(Exception):
+ def __init__(self, state_func, automaton, *args, **kargs):
+ self.func = state_func
+ self.state = state_func.atmt_state
+ self.initial = state_func.atmt_initial
+ self.error = state_func.atmt_error
+ self.final = state_func.atmt_final
+ Exception.__init__(self, "Request state [%s]" % self.state)
+ self.automaton = automaton
+ self.args = args
+ self.kargs = kargs
+ self.action_parameters() # init action parameters
+ def action_parameters(self, *args, **kargs):
+ self.action_args = args
+ self.action_kargs = kargs
+ return self
+ def run(self):
+ return self.func(self.automaton, *self.args, **self.kargs)
+
+ @staticmethod
+ def state(initial=0,final=0,error=0):
+ def deco(f,initial=initial, final=final):
+ f.atmt_type = ATMT.STATE
+ f.atmt_state = f.func_name
+ f.atmt_initial = initial
+ f.atmt_final = final
+ f.atmt_error = error
+ def state_wrapper(self, *args, **kargs):
+ return ATMT.NewStateRequested(f, self, *args, **kargs)
+
+ state_wrapper.func_name = "%s_wrapper" % f.func_name
+ state_wrapper.atmt_type = ATMT.STATE
+ state_wrapper.atmt_state = f.func_name
+ state_wrapper.atmt_initial = initial
+ state_wrapper.atmt_final = final
+ state_wrapper.atmt_error = error
+ state_wrapper.atmt_origfunc = f
+ return state_wrapper
+ return deco
+ @staticmethod
+ def action(cond, prio=0):
+ def deco(f,cond=cond):
+ if not hasattr(f,"atmt_type"):
+ f.atmt_cond = {}
+ f.atmt_type = ATMT.ACTION
+ f.atmt_cond[cond.atmt_condname] = prio
+ return f
+ return deco
+ @staticmethod
+ def condition(state, prio=0):
+ def deco(f, state=state):
+ f.atmt_type = ATMT.CONDITION
+ f.atmt_state = state.atmt_state
+ f.atmt_condname = f.func_name
+ f.atmt_prio = prio
+ return f
+ return deco
+ @staticmethod
+ def receive_condition(state, prio=0):
+ def deco(f, state=state):
+ f.atmt_type = ATMT.RECV
+ f.atmt_state = state.atmt_state
+ f.atmt_condname = f.func_name
+ f.atmt_prio = prio
+ return f
+ return deco
+ @staticmethod
+ def timeout(state, timeout, name=None):
+ def deco(f, state=state, timeout=timeout,name=name):
+ f.atmt_type = ATMT.TIMEOUT
+ f.atmt_state = state.atmt_state
+ f.atmt_timeout = timeout
+ f.atmt_condname = f.func_name
+ return f
+ return deco
+
+
+class Automaton_metaclass(type):
+ def __new__(cls, name, bases, dct):
+ cls = super(Automaton_metaclass, cls).__new__(cls, name, bases, dct)
+ cls.states={}
+ cls.state = None
+ cls.recv_conditions={}
+ cls.conditions={}
+ cls.timeout={}
+ cls.actions={}
+ cls.initial_states=[]
+
+ members = {}
+ classes = [cls]
+ while classes:
+ c = classes.pop(0) # order is important to avoid breaking method overloading
+ classes += list(c.__bases__)
+ for k,v in c.__dict__.iteritems():
+ if k not in members:
+ members[k] = v
+
+ decorated = [v for v in members.itervalues()
+ if type(v) is types.FunctionType and hasattr(v, "atmt_type")]
+
+ for m in decorated:
+ if m.atmt_type == ATMT.STATE:
+ s = m.atmt_state
+ cls.states[s] = m
+ cls.recv_conditions[s]=[]
+ cls.conditions[s]=[]
+ cls.timeout[s]=[]
+ if m.atmt_initial:
+ cls.initial_states.append(m)
+ elif m.atmt_type in [ATMT.CONDITION, ATMT.RECV, ATMT.TIMEOUT]:
+ cls.actions[m.atmt_condname] = []
+
+ for m in decorated:
+ if m.atmt_type == ATMT.CONDITION:
+ cls.conditions[m.atmt_state].append(m)
+ elif m.atmt_type == ATMT.RECV:
+ cls.recv_conditions[m.atmt_state].append(m)
+ elif m.atmt_type == ATMT.TIMEOUT:
+ cls.timeout[m.atmt_state].append((m.atmt_timeout, m))
+ elif m.atmt_type == ATMT.ACTION:
+ for c in m.atmt_cond:
+ cls.actions[c].append(m)
+
+
+ for v in cls.timeout.itervalues():
+ v.sort(lambda (t1,f1),(t2,f2): cmp(t1,t2))
+ v.append((None, None))
+ for v in itertools.chain(cls.conditions.itervalues(),
+ cls.recv_conditions.itervalues()):
+ v.sort(lambda c1,c2: cmp(c1.atmt_prio,c2.atmt_prio))
+ for condname,actlst in cls.actions.iteritems():
+ actlst.sort(lambda c1,c2: cmp(c1.atmt_cond[condname], c2.atmt_cond[condname]))
+
+ return cls
+
+
+ def graph(self, **kargs):
+ s = 'digraph "%s" {\n' % self.__class__.__name__
+
+ se = "" # Keep initial nodes at the begining for better rendering
+ for st in self.states.itervalues():
+ if st.atmt_initial:
+ se = ('\t"%s" [ style=filled, fillcolor=blue, shape=box, root=true];\n' % st.atmt_state)+se
+ elif st.atmt_final:
+ se += '\t"%s" [ style=filled, fillcolor=green, shape=octagon ];\n' % st.atmt_state
+ elif st.atmt_error:
+ se += '\t"%s" [ style=filled, fillcolor=red, shape=octagon ];\n' % st.atmt_state
+ s += se
+
+ for st in self.states.values():
+ for n in st.atmt_origfunc.func_code.co_names+st.atmt_origfunc.func_code.co_consts:
+ if n in self.states:
+ s += '\t"%s" -> "%s" [ color=green ];\n' % (st.atmt_state,n)
+
+
+ for c,k,v in [("purple",k,v) for k,v in self.conditions.items()]+[("red",k,v) for k,v in self.recv_conditions.items()]:
+ for f in v:
+ for n in f.func_code.co_names+f.func_code.co_consts:
+ if n in self.states:
+ l = f.atmt_condname
+ for x in self.actions[f.atmt_condname]:
+ l += "\\l>[%s]" % x.func_name
+ s += '\t"%s" -> "%s" [label="%s", color=%s];\n' % (k,n,l,c)
+ for k,v in self.timeout.iteritems():
+ for t,f in v:
+ if f is None:
+ continue
+ for n in f.func_code.co_names+f.func_code.co_consts:
+ if n in self.states:
+ l = "%s/%.1fs" % (f.atmt_condname,t)
+ for x in self.actions[f.atmt_condname]:
+ l += "\\l>[%s]" % x.func_name
+ s += '\t"%s" -> "%s" [label="%s",color=blue];\n' % (k,n,l)
+ s += "}\n"
+ return do_graph(s, **kargs)
+
+
+
+class Automaton:
+ __metaclass__ = Automaton_metaclass
+
+ def __init__(self, *args, **kargs):
+ self.debug_level=0
+ self.init_args=args
+ self.init_kargs=kargs
+ self.parse_args(*args, **kargs)
+
+ def debug(self, lvl, msg):
+ if self.debug_level >= lvl:
+ log_interactive.debug(msg)
+
+
+
+
+ class ErrorState(Exception):
+ def __init__(self, msg, result=None):
+ Exception.__init__(self, msg)
+ self.result = result
+ class Stuck(ErrorState):
+ pass
+
+ def parse_args(self, debug=0, store=1, **kargs):
+ self.debug_level=debug
+ self.socket_kargs = kargs
+ self.store_packets = store
+
+
+ def master_filter(self, pkt):
+ return True
+
+ def run_condition(self, cond, *args, **kargs):
+ try:
+ cond(self,*args, **kargs)
+ except ATMT.NewStateRequested, state_req:
+ self.debug(2, "%s [%s] taken to state [%s]" % (cond.atmt_type, cond.atmt_condname, state_req.state))
+ if cond.atmt_type == ATMT.RECV:
+ self.packets.append(args[0])
+ for action in self.actions[cond.atmt_condname]:
+ self.debug(2, " + Running action [%s]" % action.func_name)
+ action(self, *state_req.action_args, **state_req.action_kargs)
+ raise
+ else:
+ self.debug(2, "%s [%s] not taken" % (cond.atmt_type, cond.atmt_condname))
+
+
+ def run(self, *args, **kargs):
+ # Update default parameters
+ a = args+self.init_args[len(args):]
+ k = self.init_kargs
+ k.update(kargs)
+ self.parse_args(*a,**k)
+
+ # Start the automaton
+ self.state=self.initial_states[0](self)
+ self.send_sock = conf.L3socket()
+ l = conf.L2listen(**self.socket_kargs)
+ self.packets = PacketList(name="session[%s]"%self.__class__.__name__)
+ while 1:
+ try:
+ self.debug(1, "## state=[%s]" % self.state.state)
+
+ # Entering a new state. First, call new state function
+ state_output = self.state.run()
+ if self.state.error:
+ raise self.ErrorState("Reached %s: [%r]" % (self.state.state, state_output), result=state_output)
+ if self.state.final:
+ return state_output
+
+ if state_output is None:
+ state_output = ()
+ elif type(state_output) is not list:
+ state_output = state_output,
+
+ # Then check immediate conditions
+ for cond in self.conditions[self.state.state]:
+ self.run_condition(cond, *state_output)
+
+ # If still there and no conditions left, we are stuck!
+ if ( len(self.recv_conditions[self.state.state]) == 0
+ and len(self.timeout[self.state.state]) == 1 ):
+ raise self.Stuck("stuck in [%s]" % self.state.state,result=state_output)
+
+ # Finally listen and pay attention to timeouts
+ expirations = iter(self.timeout[self.state.state])
+ next_timeout,timeout_func = expirations.next()
+ t0 = time.time()
+
+ while 1:
+ t = time.time()-t0
+ if next_timeout is None:
+ remain = None
+ else:
+ if next_timeout <= t:
+ self.run_condition(timeout_func, *state_output)
+ next_timeout,timeout_func = expirations.next()
+ remain = next_timeout-t
+
+ r,_,_ = select([l],[],[],remain)
+ if l in r:
+ pkt = l.recv(MTU)
+ if pkt is not None:
+ if self.master_filter(pkt):
+ self.debug(3, "RECVD: %s" % pkt.summary())
+ for rcvcond in self.recv_conditions[self.state.state]:
+ self.run_condition(rcvcond, pkt, *state_output)
+ else:
+ self.debug(4, "FILTR: %s" % pkt.summary())
+
+ except ATMT.NewStateRequested,state_req:
+ self.debug(2, "switching from [%s] to [%s]" % (self.state.state,state_req.state))
+ self.state = state_req
+ except KeyboardInterrupt:
+ self.debug(1,"Interrupted by user")
+ break
+
+ def my_send(self, pkt):
+ self.send_sock.send(pkt)
+
+ def send(self, pkt):
+ self.my_send(pkt)
+ self.debug(3,"SENT : %s" % pkt.summary())
+ self.packets.append(pkt.copy())
+
+
+
+
+
+
+class TFTP_read(Automaton):
+ def parse_args(self, filename, server, sport = None, port=69, **kargs):
+ Automaton.parse_args(self, **kargs)
+ self.filename = filename
+ self.server = server
+ self.port = port
+ self.sport = sport
+
+
+ def master_filter(self, pkt):
+ return ( IP in pkt and pkt[IP].src == self.server and UDP in pkt
+ and pkt[UDP].dport == self.my_tid
+ and (self.server_tid is None or pkt[UDP].sport == self.server_tid) )
+
+ # BEGIN
+ @ATMT.state(initial=1)
+ def BEGIN(self):
+ self.blocksize=512
+ self.my_tid = self.sport or RandShort()._fix()
+ bind_bottom_up(UDP, TFTP, dport=self.my_tid)
+ self.server_tid = None
+ self.res = ""
+
+ self.l3 = IP(dst=self.server)/UDP(sport=self.my_tid, dport=self.port)/TFTP()
+ self.last_packet = self.l3/TFTP_RRQ(filename=self.filename, mode="octet")
+ self.send(self.last_packet)
+ self.awaiting=1
+
+ raise self.WAITING()
+
+ # WAITING
+ @ATMT.state()
+ def WAITING(self):
+ pass
+
+
+ @ATMT.receive_condition(WAITING)
+ def receive_data(self, pkt):
+ if TFTP_DATA in pkt and pkt[TFTP_DATA].block == self.awaiting:
+ if self.server_tid is None:
+ self.server_tid = pkt[UDP].sport
+ self.l3[UDP].dport = self.server_tid
+ raise self.RECEIVING(pkt)
+
+ @ATMT.receive_condition(WAITING, prio=1)
+ def receive_error(self, pkt):
+ if TFTP_ERROR in pkt:
+ raise self.ERROR(pkt)
+
+
+ @ATMT.timeout(WAITING, 3)
+ def timeout_waiting(self):
+ raise self.WAITING()
+ @ATMT.action(timeout_waiting)
+ def retransmit_last_packet(self):
+ self.send(self.last_packet)
+
+ @ATMT.action(receive_data)
+# @ATMT.action(receive_error)
+ def send_ack(self):
+ self.last_packet = self.l3 / TFTP_ACK(block = self.awaiting)
+ self.send(self.last_packet)
+
+
+ # RECEIVED
+ @ATMT.state()
+ def RECEIVING(self, pkt):
+ recvd = pkt[Raw].load
+ self.res += recvd
+ self.awaiting += 1
+ if len(recvd) == self.blocksize:
+ raise self.WAITING()
+ raise self.END()
+
+ # ERROR
+ @ATMT.state(error=1)
+ def ERROR(self,pkt):
+ split_bottom_up(UDP, TFTP, dport=self.my_tid)
+ return pkt[TFTP_ERROR].summary()
+
+ #END
+ @ATMT.state(final=1)
+ def END(self):
+ split_bottom_up(UDP, TFTP, dport=self.my_tid)
+ return self.res
+
+
+
+
+class TFTP_write(Automaton):
+ def parse_args(self, filename, data, server, sport=None, port=69,**kargs):
+ Automaton.parse_args(self, **kargs)
+ self.filename = filename
+ self.server = server
+ self.port = port
+ self.sport = sport
+ self.blocksize = 512
+ self.origdata = data
+
+ def master_filter(self, pkt):
+ return ( IP in pkt and pkt[IP].src == self.server and UDP in pkt
+ and pkt[UDP].dport == self.my_tid
+ and (self.server_tid is None or pkt[UDP].sport == self.server_tid) )
+
+
+ # BEGIN
+ @ATMT.state(initial=1)
+ def BEGIN(self):
+ self.data = [ self.origdata[i*self.blocksize:(i+1)*self.blocksize]
+ for i in range( len(self.origdata)/self.blocksize+1) ]
+ self.my_tid = self.sport or RandShort()._fix()
+ bind_bottom_up(UDP, TFTP, dport=self.my_tid)
+ self.server_tid = None
+
+ self.l3 = IP(dst=self.server)/UDP(sport=self.my_tid, dport=self.port)/TFTP()
+ self.last_packet = self.l3/TFTP_WRQ(filename=self.filename, mode="octet")
+ self.send(self.last_packet)
+ self.res = ""
+ self.awaiting=0
+
+ raise self.WAITING_ACK()
+
+ # WAITING_ACK
+ @ATMT.state()
+ def WAITING_ACK(self):
+ pass
+
+ @ATMT.receive_condition(WAITING_ACK)
+ def received_ack(self,pkt):
+ if TFTP_ACK in pkt and pkt[TFTP_ACK].block == self.awaiting:
+ if self.server_tid is None:
+ self.server_tid = pkt[UDP].sport
+ self.l3[UDP].dport = self.server_tid
+ raise self.SEND_DATA()
+
+ @ATMT.receive_condition(WAITING_ACK)
+ def received_error(self, pkt):
+ if TFTP_ERROR in pkt:
+ raise self.ERROR(pkt)
+
+ @ATMT.timeout(WAITING_ACK, 3)
+ def timeout_waiting(self):
+ raise self.WAITING_ACK()
+ @ATMT.action(timeout_waiting)
+ def retransmit_last_packet(self):
+ self.send(self.last_packet)
+
+ # SEND_DATA
+ @ATMT.state()
+ def SEND_DATA(self):
+ self.awaiting += 1
+ self.last_packet = self.l3/TFTP_DATA(block=self.awaiting)/self.data.pop(0)
+ self.send(self.last_packet)
+ if self.data:
+ raise self.WAITING_ACK()
+ raise self.END()
+
+
+ # ERROR
+ @ATMT.state(error=1)
+ def ERROR(self,pkt):
+ split_bottom_up(UDP, TFTP, dport=self.my_tid)
+ return pkt[TFTP_ERROR].summary()
+
+ # END
+ @ATMT.state(final=1)
+ def END(self):
+ split_bottom_up(UDP, TFTP, dport=self.my_tid)
+
+
+class TFTP_WRQ_server(Automaton):
+
+ def parse_args(self, ip=None, sport=None, *args, **kargs):
+ Automaton.parse_args(self, *args, **kargs)
+ self.ip = ip
+ self.sport = sport
+
+ def master_filter(self, pkt):
+ return TFTP in pkt and (not self.ip or pkt[IP].dst == self.ip)
+
+ @ATMT.state(initial=1)
+ def BEGIN(self):
+ self.blksize=512
+ self.blk=0
+ self.filedata=""
+ self.my_tid = self.sport or random.randint(10000,65500)
+ bind_bottom_up(UDP, TFTP, dport=self.my_tid)
+
+ @ATMT.receive_condition(BEGIN)
+ def receive_WRQ(self,pkt):
+ if TFTP_WRQ in pkt:
+ raise self.WAIT_DATA().action_parameters(pkt)
+
+ @ATMT.action(receive_WRQ)
+ def ack_WRQ(self, pkt):
+ ip = pkt[IP]
+ self.ip = ip.dst
+ self.dst = ip.src
+ self.filename = pkt[TFTP_WRQ].filename
+ options = pkt[TFTP_Options]
+ self.l3 = IP(src=ip.dst, dst=ip.src)/UDP(sport=self.my_tid, dport=pkt.sport)/TFTP()
+ if options is None:
+ self.last_packet = self.l3/TFTP_ACK(block=0)
+ self.send(self.last_packet)
+ else:
+ opt = [x for x in options.options if x.oname == "BLKSIZE"]
+ if opt:
+ self.blksize = int(opt[0].value)
+ self.debug(2,"Negotiated new blksize at %i" % self.blksize)
+ self.last_packet = self.l3/TFTP_OACK()/TFTP_Options(options=opt)
+ self.send(self.last_packet)
+
+ @ATMT.state()
+ def WAIT_DATA(self):
+ self.blk += 1
+
+ @ATMT.receive_condition(WAIT_DATA)
+ def receive_data(self, pkt):
+ if TFTP_DATA in pkt:
+ data = pkt[TFTP_DATA]
+ if data.block == self.blk:
+ raise self.DATA(data)
+
+ @ATMT.action(receive_data)
+ def ack_data(self):
+ self.last_packet = self.l3/TFTP_ACK(block = self.blk)
+ self.send(self.last_packet)
+
+ @ATMT.state()
+ def DATA(self, data):
+ self.filedata += data.load
+ if len(data.load) < self.blksize:
+ raise self.END()
+ raise self.WAIT_DATA()
+
+ @ATMT.state(final=1)
+ def END(self):
+ return self.filename,self.filedata
+ split_bottom_up(UDP, TFTP, dport=self.my_tid)
+
+
+
+########################
+## 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, pool=Net("192.168.1.128/25"), network="192.168.1.0/24",gw="192.168.1.1",
+ renewal_time=60, lease_time=1800):
+ if type(pool) is str:
+ poom = Net(pool)
+ netw,msk = (network.split("/")+["32"])[:2]
+ msk = itom(int(msk))
+ self.netmask = ltoa(msk)
+ self.network = ltoa(atol(netw)&msk)
+ self.broadcast = ltoa( atol(self.network) | (0xffffffff&~msk) )
+ self.gw = gw
+ if isinstance(pool,Gen):
+ pool = [k for k in pool if k not in [gw, self.network, self.broadcast]]
+ pool.reverse()
+ if len(pool) == 1:
+ pool, = pool
+ self.pool = pool
+ self.lease_time = lease_time
+ self.renewal_time = renewal_time
+ 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.pool) is list:
+ if not self.leases.has_key(mac):
+ self.leases[mac] = self.pool.pop()
+ ip = self.leases[mac]
+ else:
+ ip = self.pool
+
+ repb = req.getlayer(BOOTP).copy()
+ repb.op="BOOTREPLY"
+ repb.yiaddr = ip
+ repb.siaddr = self.gw
+ repb.ciaddr = self.gw
+ repb.giaddr = self.gw
+ del(repb.payload)
+ 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 make_reply(self, req):
+ resp = BOOTP_am.make_reply(self, req)
+ if DHCP in req:
+ dhcp_options = [(op[0],{1:2,3:5}.get(op[1],op[1]))
+ for op in req[DHCP].options
+ if type(op) is tuple and op[0] == "message-type"]
+ dhcp_options += [("router", self.gw),
+ ("name_server", self.gw),
+ ("broadcast_address", self.broadcast),
+ ("subnet_mask", self.netmask),
+ ("renewal_time", self.renewal_time),
+ ("lease_time", self.lease_time),
+ ]
+ resp /= DHCP(options=dhcp_options)
+ return resp
+
+
+
+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(RTP).load)
+ 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+Color.invert
+ style_right = Color.red+Color.invert
+
+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+Color.invert
+ style_right = Color.purple+Color.invert
+
+
+class RastaTheme(AnsiColorTheme):
+ style_normal = Color.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.yellow+Color.invert
+ style_right = Color.red+Color.invert
+
+
+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"
+ tcpreplay = "tcpreplay"
+ 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()
+
+betteriface = conf.route.route("0.0.0.0", verbose=0)[0]
+if betteriface != "lo": #XXX linux specific...
+ conf.iface = betteriface
+del(betteriface)
+
+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("<","&lt;").replace(">","&gt;").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:
+ if DEFAULT_CONFIG_FILE:
+ read_config_file(DEFAULT_CONFIG_FILE)