blob: 8f6b27e5e392093ef359f9625617aa11c58ace0b [file] [log] [blame]
#! /usr/bin/env python
#############################################################################
## ##
## scapy.py --- Interactive packet manipulation tool ##
## see http://www.secdev.org/projects/scapy/ ##
## for more informations ##
## ##
## Copyright (C) 2003 Philippe Biondi <phil@secdev.org> ##
## ##
## This program is free software; you can redistribute it and/or modify it ##
## under the terms of the GNU General Public License version 2 as ##
## published by the Free Software Foundation; version 2. ##
## ##
## This program is distributed in the hope that it will be useful, but ##
## WITHOUT ANY WARRANTY; without even the implied warranty of ##
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ##
## General Public License for more details. ##
## ##
#############################################################################
from __future__ import generators
import os
BASE_VERSION = "1.1.0"
HG_NODE = "$Node$"
REVISION = "$Revision$"
VERSION = "v%s / %s" % (BASE_VERSION, (REVISION+"--")[11:23])
DEFAULT_CONFIG_FILE = os.path.join(os.environ["HOME"], ".scapy_startup.py")
try:
os.stat(DEFAULT_CONFIG_FILE)
except OSError:
DEFAULT_CONFIG_FILE = None
def usage():
print """Usage: scapy.py [-s sessionfile] [-c new_startup_file] [-C]
-C: do not read startup file"""
sys.exit(0)
#############################
##### Logging subsystem #####
#############################
class Scapy_Exception(Exception):
pass
import logging,traceback,time
class ScapyFreqFilter(logging.Filter):
def __init__(self):
logging.Filter.__init__(self)
self.warning_table = {}
def filter(self, record):
wt = conf.warning_threshold
if wt > 0:
stk = traceback.extract_stack()
caller=None
for f,l,n,c in stk:
if n == 'warning':
break
caller = l
tm,nb = self.warning_table.get(caller, (0,0))
ltm = time.time()
if ltm-tm > wt:
tm = ltm
nb = 0
else:
if nb < 2:
nb += 1
if nb == 2:
record.msg = "more "+record.msg
else:
return 0
self.warning_table[caller] = (tm,nb)
return 1
log_scapy = logging.getLogger("scapy")
console_handler = logging.StreamHandler()
console_handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
log_scapy.addHandler(console_handler)
log_runtime = logging.getLogger("scapy.runtime") # logs at runtime
log_runtime.addFilter(ScapyFreqFilter())
log_interactive = logging.getLogger("scapy.interactive") # logs in interactive functions
log_loading = logging.getLogger("scapy.loading") # logs when loading scapy
if __name__ == "__main__":
log_scapy.setLevel(1)
##################
##### Module #####
##################
import socket, sys, getopt, string, struct, random, code
import cPickle, copy, types, gzip, base64, re, zlib, array
from sets import Set
from select import select
from glob import glob
from fcntl import ioctl
import fcntl
import warnings
warnings.filterwarnings("ignore","tempnam",RuntimeWarning, __name__)
try:
import Gnuplot
GNUPLOT=1
except ImportError:
log_loading.info("did not find python gnuplot wrapper . Won't be able to plot")
GNUPLOT=0
try:
import pyx
PYX=1
except ImportError:
log_loading.info("Can't import PyX. Won't be able to use psdump() or pdfdump()")
PYX=0
LINUX=sys.platform.startswith("linux")
OPENBSD=sys.platform.startswith("openbsd")
FREEBSD=sys.platform.startswith("freebsd")
DARWIN=sys.platform.startswith("darwin")
BIG_ENDIAN= struct.pack("H",1) == "\x00\x01"
X86_64 = (os.uname()[4] == 'x86_64')
SOLARIS=sys.platform.startswith("sunos")
if LINUX:
DNET=PCAP=0
else:
DNET=PCAP=1
if PCAP:
try:
import pcap
PCAP = 1
except ImportError:
if LINUX:
log_loading.warning("did not find pcap module. Fallback to linux primitives")
PCAP = 0
else:
if __name__ == "__main__":
log_loading.error("did not find pcap module")
raise SystemExit
else:
raise
if DNET:
try:
import dnet
DNET = 1
except ImportError:
if LINUX:
log_loading.warning("did not find dnet module. Fallback to linux primitives")
DNET = 0
else:
if __name__ == "__main__":
log_loading.error("did not find dnet module")
raise SystemExit
else:
raise
if not PCAP:
f = os.popen("tcpdump -V 2> /dev/null")
if f.close() >> 8 == 0x7f:
log_loading.warning("Failed to execute tcpdump. Check it is installed and in the PATH")
TCPDUMP=0
else:
TCPDUMP=1
try:
from Crypto.Cipher import ARC4
except ImportError:
log_loading.info("Can't find Crypto python lib. Won't be able to decrypt WEP")
# Workarround bug 643005 : https://sourceforge.net/tracker/?func=detail&atid=105470&aid=643005&group_id=5470
try:
socket.inet_aton("255.255.255.255")
except socket.error:
def inet_aton(x):
if x == "255.255.255.255":
return "\xff"*4
else:
return socket.inet_aton(x)
else:
inet_aton = socket.inet_aton
inet_ntoa = socket.inet_ntoa
try:
inet_ntop = socket.inet_ntop
inet_pton = socket.inet_pton
except AttributeError:
log_loading.info("inet_ntop/pton functions not found. Python IPv6 support not present")
if SOLARIS:
# GRE is missing on Solaris
socket.IPPROTO_GRE = 47
###############################
## Direct Access dictionnary ##
###############################
def fixname(x):
if x and x[0] in "0123456789":
x = "n_"+x
return x.translate("________________________________________________0123456789_______ABCDEFGHIJKLMNOPQRSTUVWXYZ______abcdefghijklmnopqrstuvwxyz_____________________________________________________________________________________________________________________________________")
class DADict_Exception(Scapy_Exception):
pass
class DADict:
def __init__(self, _name="DADict", **kargs):
self._name=_name
self.__dict__.update(kargs)
def fixname(self,val):
return fixname(val)
def __contains__(self, val):
return val in self.__dict__
def __getitem__(self, attr):
return getattr(self, attr)
def __setitem__(self, attr, val):
return setattr(self, self.fixname(attr), val)
def __iter__(self):
return iter(map(lambda (x,y):y,filter(lambda (x,y):x[0]!="_", self.__dict__.items())))
def _show(self):
for k in self.__dict__.keys():
if k[0] != "_":
print "%10s = %r" % (k,getattr(self,k))
def __repr__(self):
return "<%s/ %s>" % (self._name," ".join(filter(lambda x:x[0]!="_",self.__dict__.keys())))
def _branch(self, br, uniq=0):
if uniq and br._name in self:
raise DADict_Exception("DADict: [%s] already branched in [%s]" % (br._name, self._name))
self[br._name] = br
def _my_find(self, *args, **kargs):
if args and self._name not in args:
return False
for k in kargs:
if k not in self or self[k] != kargs[k]:
return False
return True
def _find(self, *args, **kargs):
return self._recurs_find((), *args, **kargs)
def _recurs_find(self, path, *args, **kargs):
if self in path:
return None
if self._my_find(*args, **kargs):
return self
for o in self:
if isinstance(o, DADict):
p = o._recurs_find(path+(self,), *args, **kargs)
if p is not None:
return p
return None
def _find_all(self, *args, **kargs):
return self._recurs_find_all((), *args, **kargs)
def _recurs_find_all(self, path, *args, **kargs):
r = []
if self in path:
return r
if self._my_find(*args, **kargs):
r.append(self)
for o in self:
if isinstance(o, DADict):
p = o._recurs_find_all(path+(self,), *args, **kargs)
r += p
return r
def keys(self):
return filter(lambda x:x[0]!="_", self.__dict__.keys())
############
## Consts ##
############
ETHER_ANY = "\x00"*6
ETHER_BROADCAST = "\xff"*6
ETH_P_ALL = 3
ETH_P_IP = 0x800
ETH_P_ARP = 0x806
# From net/if_arp.h
ARPHDR_ETHER = 1
ARPHDR_METRICOM = 23
ARPHDR_PPP = 512
ARPHDR_LOOPBACK = 772
ARPHDR_TUN = 65534
# From bits/ioctls.h
SIOCGIFHWADDR = 0x8927 # Get hardware address
SIOCGIFADDR = 0x8915 # get PA address
SIOCGIFNETMASK = 0x891b # get network PA mask
SIOCGIFNAME = 0x8910 # get iface name
SIOCSIFLINK = 0x8911 # set iface channel
SIOCGIFCONF = 0x8912 # get iface list
SIOCGIFFLAGS = 0x8913 # get flags
SIOCSIFFLAGS = 0x8914 # set flags
SIOCGIFINDEX = 0x8933 # name -> if_index mapping
SIOCGIFCOUNT = 0x8938 # get number of devices
# From if.h
IFF_UP = 0x1 # Interface is up.
IFF_BROADCAST = 0x2 # Broadcast address valid.
IFF_DEBUG = 0x4 # Turn on debugging.
IFF_LOOPBACK = 0x8 # Is a loopback net.
IFF_POINTOPOINT = 0x10 # Interface is point-to-point link.
IFF_NOTRAILERS = 0x20 # Avoid use of trailers.
IFF_RUNNING = 0x40 # Resources allocated.
IFF_NOARP = 0x80 # No address resolution protocol.
IFF_PROMISC = 0x100 # Receive all packets.
# From netpacket/packet.h
PACKET_ADD_MEMBERSHIP = 1
PACKET_DROP_MEMBERSHIP = 2
PACKET_RECV_OUTPUT = 3
PACKET_RX_RING = 5
PACKET_STATISTICS = 6
PACKET_MR_MULTICAST = 0
PACKET_MR_PROMISC = 1
PACKET_MR_ALLMULTI = 2
# From bits/socket.h
SOL_PACKET = 263
# From asm/socket.h
SO_ATTACH_FILTER = 26
SOL_SOCKET = 1
# From net/route.h
RTF_UP = 0x0001 # Route usable
RTF_REJECT = 0x0200
# From BSD net/bpf.h
#BIOCIMMEDIATE=0x80044270
BIOCIMMEDIATE=-2147204496
MTU = 1600
# file parsing to get some values :
def load_protocols(filename):
spaces = re.compile("[ \t]+|\n")
dct = DADict(_name=filename)
try:
for l in open(filename):
try:
if l[0] in ["#","\n"]:
continue
lt = tuple(re.split(spaces, l))
if len(lt) < 3:
continue
dct[lt[2]] = int(lt[1])
except Exception,e:
log_loading.info("Couldn't parse file [%s]: line [%r] (%s)" % (filename,l,e))
f.close()
except IOError:
log_loading.info("Can't open /etc/protocols file")
return dct
IP_PROTOS=load_protocols("/etc/protocols")
def load_ethertypes(filename):
spaces = re.compile("[ \t]+|\n")
dct = DADict(_name=filename)
try:
f=open(filename)
for l in f:
try:
if l[0] in ["#","\n"]:
continue
lt = tuple(re.split(spaces, l))
if len(lt) < 2:
continue
dct[lt[0]] = int(lt[1], 16)
except Exception,e:
log_loading.info("Couldn't parse file [%s]: line [%r] (%s)" % (filename,l,e))
f.close()
except IOError,msg:
pass
return dct
ETHER_TYPES=load_ethertypes("/etc/ethertypes")
def load_services(filename):
spaces = re.compile("[ \t]+|\n")
tdct=DADict(_name="%s-tcp"%filename)
udct=DADict(_name="%s-udp"%filename)
try:
f=open(filename)
for l in f:
try:
if l[0] in ["#","\n"]:
continue
lt = tuple(re.split(spaces, l))
if len(lt) < 2:
continue
if lt[1].endswith("/tcp"):
tdct[lt[0]] = int(lt[1].split('/')[0])
elif lt[1].endswith("/udp"):
udct[lt[0]] = int(lt[1].split('/')[0])
except Exception,e:
log_loading.warning("Couldn't file [%s]: line [%r] (%s)" % (filename,l,e))
f.close()
except IOError:
log_loading.info("Can't open /etc/services file")
return tdct,udct
TCP_SERVICES,UDP_SERVICES=load_services("/etc/services")
class ManufDA(DADict):
def fixname(self, val):
return val
def _get_manuf_couple(self, mac):
oui = ":".join(mac.split(":")[:3]).upper()
return self.__dict__.get(oui,(mac,mac))
def _get_manuf(self, mac):
return self._get_manuf_couple(mac)[1]
def _get_short_manuf(self, mac):
return self._get_manuf_couple(mac)[0]
def _resolve_MAC(self, mac):
oui = ":".join(mac.split(":")[:3]).upper()
if oui in self:
return ":".join([self[oui][0]]+ mac.split(":")[3:])
return mac
def load_manuf(filename):
try:
manufdb=ManufDA(_name=filename)
for l in open(filename):
try:
l = l.strip()
if not l or l.startswith("#"):
continue
oui,shrt=l.split()[:2]
i = l.find("#")
if i < 0:
lng=shrt
else:
lng = l[i+2:]
manufdb[oui] = shrt,lng
except Exception,e:
log_loadding.warning("Couldn't parse one line from [%s] [%r] (%s)" % (filename, l, e))
except IOError:
#log_loading.warning("Couldn't open [%s] file" % filename)
pass
return manufdb
MANUFDB = load_manuf("/usr/share/wireshark/wireshark/manuf")
###########
## Tools ##
###########
def sane_color(x):
r=""
for i in x:
j = ord(i)
if (j < 32) or (j >= 127):
r=r+conf.color_theme.not_printable(".")
else:
r=r+i
return r
def sane(x):
r=""
for i in x:
j = ord(i)
if (j < 32) or (j >= 127):
r=r+"."
else:
r=r+i
return r
def lhex(x):
if type(x) is int:
return hex(x)
elif type(x) is tuple:
return "(%s)" % ", ".join(map(lhex, x))
elif type(x) is list:
return "[%s]" % ", ".join(map(lhex, x))
else:
return x
def hexdump(x):
x=str(x)
l = len(x)
i = 0
while i < l:
print "%04x " % i,
for j in range(16):
if i+j < l:
print "%02X" % ord(x[i+j]),
else:
print " ",
if j%16 == 7:
print "",
print " ",
print sane_color(x[i:i+16])
i += 16
def linehexdump(x, onlyasc=0, onlyhex=0):
x = str(x)
l = len(x)
if not onlyasc:
for i in range(l):
print "%02X" % ord(x[i]),
print "",
if not onlyhex:
print sane_color(x)
def chexdump(x):
x=str(x)
print ", ".join(map(lambda x: "%#04x"%ord(x), x))
def hexstr(x, onlyasc=0, onlyhex=0):
s = []
if not onlyasc:
s.append(" ".join(map(lambda x:"%02x"%ord(x), x)))
if not onlyhex:
s.append(sane(x))
return " ".join(s)
def hexdiff(x,y, gran=5):
"""hexdiff(before, after, gran=5)
gran: granularity in bytes for similarity matching. Must be >= 1"""
x=str(x)
y=str(y)
if gran <= 0:
gran = 1
i=j=0
ii=jj=-1
diff = []
cdiff = ""
while i < len(x) and j < len(y):
if x[i] == y[j] and ii == jj == -1:
cdiff += x[i]
i+=1; j+=1
continue
if ii == jj == -1:
if cdiff:
diff.append((0,cdiff))
cdiff = ""
ii = i; jj = j
i += 1; j+= 1
continue
k = l = -1
if i+gran < len(x) or j+gran >= len(y):
k = y[jj:j+gran].find(x[i:i+gran])
if k != -1:
j = jj+k
if j+gran < len(y) or i+gran >= len(x):
l = x[ii:i+gran].find(y[j:j+gran])
if l != -1:
i = ii+l
if k != -1 or l != -1:
if i != ii:
diff.append((-1, x[ii:i]))
if j != jj:
diff.append((+1, y[jj:j]))
ii = jj = -1
else:
i += 1
j += 1
if cdiff:
diff.append((0,cdiff))
if ii>=0:
i=ii
if i < len(x):
diff.append((-1,x[i:]))
if jj>=0:
j=jj
if j < len(y):
diff.append((+1,y[j:]))
colorize = { 0: lambda x:x,
-1: conf.color_theme.left,
1: conf.color_theme.right }
i = j = 0
for s,h in diff:
l = len(h)
u = -(j%16)
while u < l:
line = ""
if s <= 0:
line += "%04x " % (i+u)
else:
line += " "
if s >= 0:
line += "%04x " % (j+u)
else:
line += " "
ch = ""
for v in range(16):
if 0 <= u+v < l:
c = h[u+v]
line += "%02X " % ord(c)
if 32 <= ord(c) < 127:
ch += colorize[s](c)
else:
ch += conf.color_theme.not_printable(".")
else:
line += " "
ch += " "
if v%16 == 7:
line += " "
line += " "
line = colorize[s](line)
line += ch
u += 16
print line
if s <= 0:
i += l
if s >= 0:
j += l
if BIG_ENDIAN:
CRCPOLY=0x04c11db7L
else:
CRCPOLY=0xedb88320L
crc32 = zlib.crc32
def checksum(pkt):
pkt=str(pkt)
s=0
if len(pkt) % 2 == 1:
pkt += "\0"
for i in range(len(pkt)/2):
s = s + (struct.unpack("!H",pkt[2*i:2*i+2])[0])
s = (s >> 16) + (s & 0xffff)
s += s >> 16
return ~s & 0xffff
def warning(x):
log_runtime.warning(x)
def mac2str(mac):
return "".join(map(lambda x: chr(int(x,16)), mac.split(":")))
def str2mac(s):
return ("%02x:"*6)[:-1] % tuple(map(ord, s))
def strxor(x,y):
return "".join(map(lambda x,y:chr(ord(x)^ord(y)),x,y))
def atol(x):
try:
ip = inet_aton(x)
except socket.error:
ip = inet_aton(socket.gethostbyname(x))
return struct.unpack("I", ip)[0]
def ltoa(x):
return inet_ntoa(struct.pack("I", x))
def itom(x):
return socket.ntohl((0xffffffff00000000L>>x)&0xffffffffL)&0xffffffffL
def do_graph(graph,prog=None,type="svg",target=None):
"""do_graph(graph, prog=conf.prog.dot, type="svg",target="| conf.prog.display"):
graph: GraphViz graph description
type: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option
target: filename or redirect. Defaults pipe to Imagemagick's display program
prog: which graphviz program to use"""
if prog is None:
prog = conf.prog.dot
if target is None:
target = "| %s" % conf.prog.display
w,r = os.popen2("%s -T %s %s" % (prog,type,target))
w.write(graph)
w.close()
_TEX_TR = {
"{":"{\\tt\\char123}",
"}":"{\\tt\\char125}",
"\\":"{\\tt\\char92}",
"^":"\\^{}",
"$":"\\$",
"#":"\\#",
"~":"\\~",
"_":"\\_",
"&":"\\&",
"%":"\\%",
"|":"{\\tt\\char124}",
"~":"{\\tt\\char126}",
"<":"{\\tt\\char60}",
">":"{\\tt\\char62}",
}
def tex_escape(x):
s = ""
for c in x:
s += _TEX_TR.get(c,c)
return s
def colgen(*lstcol,**kargs):
"""Returns a generator that mixes provided quantities forever
trans: a function to convert the three arguments into a color. lambda x,y,z:(x,y,z) by default"""
if len(lstcol) < 2:
lstcol *= 2
trans = kargs.get("trans", lambda x,y,z: (x,y,z))
while 1:
for i in range(len(lstcol)):
for j in range(len(lstcol)):
for k in range(len(lstcol)):
if i != j or j != k or k != i:
yield trans(lstcol[(i+j)%len(lstcol)],lstcol[(j+k)%len(lstcol)],lstcol[(k+i)%len(lstcol)])
def incremental_label(label="tag%05i", start=0):
while True:
yield label % start
start += 1
#########################
#### Enum management ####
#########################
class EnumElement:
def __init__(self, key, value):
self._key = key
self._value = value
def __repr__(self):
return "<%s %s[%r]>" % (self.__dict__.get("_name", self.__class__.__name__), self._key, self._value)
def __getattr__(self, attr):
return getattr(self._value, attr)
def __str__(self):
return self._key
def __eq__(self, other):
return self._value == int(other)
class Enum_metaclass(type):
element_class = EnumElement
def __new__(cls, name, bases, dct):
rdict={}
for k,v in dct.iteritems():
if type(v) is int:
v = cls.element_class(k,v)
dct[k] = v
rdict[v] = k
dct["__rdict__"] = rdict
return super(Enum_metaclass, cls).__new__(cls, name, bases, dct)
def __getitem__(self, attr):
return self.__rdict__[attr]
def __contains__(self, val):
return val in self.__rdict__
def get(self, attr, val=None):
return self._rdict__.get(attr, val)
def __repr__(self):
return "<%s>" % self.__dict__.get("name", self.__name__)
##############################
## Session saving/restoring ##
##############################
def save_session(fname, session=None, pickleProto=-1):
if session is None:
session = scapy_session
to_be_saved = session.copy()
if to_be_saved.has_key("__builtins__"):
del(to_be_saved["__builtins__"])
for k in to_be_saved.keys():
if type(to_be_saved[k]) in [types.TypeType, types.ClassType, types.ModuleType]:
log_interactive.error("[%s] (%s) can't be saved." % (k, type(to_be_saved[k])))
del(to_be_saved[k])
try:
os.rename(fname, fname+".bak")
except OSError:
pass
f=gzip.open(fname,"wb")
cPickle.dump(to_be_saved, f, pickleProto)
f.close()
def load_session(fname):
try:
s = cPickle.load(gzip.open(fname,"rb"))
except IOError:
s = cPickle.load(open(fname,"rb"))
scapy_session.clear()
scapy_session.update(s)
def update_session(fname):
try:
s = cPickle.load(gzip.open(fname,"rb"))
except IOError:
s = cPickle.load(open(fname,"rb"))
scapy_session.update(s)
def export_object(obj):
print base64.encodestring(gzip.zlib.compress(cPickle.dumps(obj,2),9))
def import_object(obj=None):
if obj is None:
obj = sys.stdin.read()
return cPickle.loads(gzip.zlib.decompress(base64.decodestring(obj.strip())))
def save_object(fname, obj):
cPickle.dump(obj,gzip.open(fname,"wb"))
def load_object(fname):
return cPickle.load(gzip.open(fname,"rb"))
#################
## Debug class ##
#################
class debug:
recv=[]
sent=[]
match=[]
####################
## IP Tools class ##
####################
class IPTools:
"""Add more powers to a class that have a "src" attribute."""
def whois(self):
os.system("whois %s" % self.src)
def ottl(self):
t = [32,64,128,255]+[self.ttl]
t.sort()
return t[t.index(self.ttl)+1]
def hops(self):
return self.ottl()-self.ttl-1
##############################
## Routing/Interfaces stuff ##
##############################
class Route:
def __init__(self):
self.resync()
self.s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
def resync(self):
self.routes = read_routes()
def __repr__(self):
rt = "Network Netmask Gateway Iface Output IP\n"
for net,msk,gw,iface,addr in self.routes:
rt += "%-15s %-15s %-15s %-15s %-15s\n" % (ltoa(net),
ltoa(msk),
gw,
iface,
addr)
return rt
def make_route(self, host=None, net=None, gw=None, dev=None):
if host is not None:
thenet,msk = host,32
elif net is not None:
thenet,msk = net.split("/")
msk = int(msk)
else:
raise Scapy_Exception("make_route: Incorrect parameters. You should specify a host or a net")
if gw is None:
gw="0.0.0.0"
if dev is None:
if gw:
nhop = gw
else:
nhop = thenet
dev,ifaddr,x = self.route(nhop)
else:
ifaddr = get_if_addr(dev)
return (atol(thenet), itom(msk), gw, dev, ifaddr)
def add(self, *args, **kargs):
"""Ex:
add(net="192.168.1.0/24",gw="1.2.3.4")
"""
self.routes.append(self.make_route(*args,**kargs))
def delt(self, *args, **kargs):
"""delt(host|net, gw|dev)"""
route = self.make_route(*args,**kargs)
try:
i=self.routes.index(route)
del(self.routes[i])
except ValueError:
warning("no matching route found")
def ifchange(self, iff, addr):
the_addr,the_msk = (addr.split("/")+["32"])[:2]
the_msk = itom(int(the_msk))
the_rawaddr, = struct.unpack("I",inet_aton(the_addr))
the_net = the_rawaddr & the_msk
for i in range(len(self.routes)):
net,msk,gw,iface,addr = self.routes[i]
if iface != iff:
continue
if gw == '0.0.0.0':
self.routes[i] = (the_net,the_msk,gw,iface,the_addr)
else:
self.routes[i] = (net,msk,gw,iface,the_addr)
for i in arp_cache.keys():
del(arp_cache[i])
def ifdel(self, iff):
new_routes=[]
for rt in self.routes:
if rt[3] != iff:
new_routes.append(rt)
self.routes=new_routes
def ifadd(self, iff, addr):
the_addr,the_msk = (addr.split("/")+["32"])[:2]
the_msk = itom(int(the_msk))
the_rawaddr, = struct.unpack("I",inet_aton(the_addr))
the_net = the_rawaddr & the_msk
self.routes.append((the_net,the_msk,'0.0.0.0',iff,the_addr))
def route(self,dst):
# Transform "192.168.*.1-5" to one IP of the set
dst = dst.split("/")[0]
dst = dst.replace("*","0")
while 1:
l = dst.find("-")
if l < 0:
break
m = (dst[l:]+".").find(".")
dst = dst[:l]+dst[l+m:]
try:
dst=inet_aton(dst)
except socket.error:
dst=inet_aton(socket.gethostbyname(dst))
dst,=struct.unpack("I",dst)
pathes=[]
for d,m,gw,i,a in self.routes:
aa, = struct.unpack("I",inet_aton(a))
if aa == dst:
pathes.append((0xffffffffL,("lo",a,"0.0.0.0")))
if (dst & m) == (d & m):
pathes.append((m,(i,a,gw)))
if not pathes:
warning("No route found (no default route?)")
return "lo","0.0.0.0","0.0.0.0" #XXX linux specific!
# Choose the more specific route (greatest netmask).
# XXX: we don't care about metrics
pathes.sort()
return pathes[-1][1]
def get_if_bcast(self, iff):
for net, msk, gw, iface, addr in self.routes:
if (iff == iface and net != 0L):
bcast = atol(addr)|(~msk&0xffffffffL); # FIXME: check error in atol()
return ltoa(bcast);
warning("No broadcast address found for iface %s\n" % iff);
if DNET:
def get_if_raw_hwaddr(iff):
if iff[:2] == "lo":
return (772, '\x00'*6)
try:
l = dnet.intf().get(iff)
l = l["link_addr"]
except:
raise Scapy_Exception("Error in attempting to get hw address for interface [%s]" % iff)
return l.type,l.data
def get_if_raw_addr(ifname):
i = dnet.intf()
return i.get(ifname)["addr"].data
else:
def get_if_raw_hwaddr(iff):
return struct.unpack("16xh6s8x",get_if(iff,SIOCGIFHWADDR))
def get_if_raw_addr(iff):
try:
return get_if(iff, SIOCGIFADDR)[20:24]
except IOError:
return "\0\0\0\0"
if PCAP:
def get_if_list():
# remove 'any' interface
return map(lambda x:x[0],filter(lambda x:x[1] is None,pcap.findalldevs()))
def get_working_if():
try:
return pcap.lookupdev()
except pcap.pcapc.EXCEPTION:
return 'lo'
def attach_filter(s, filter):
warning("attach_filter() should not be called in PCAP mode")
def set_promisc(s,iff,val=1):
warning("set_promisc() should not be called in DNET/PCAP mode")
else:
def get_if_list():
f=open("/proc/net/dev","r")
lst = []
f.readline()
f.readline()
for l in f:
lst.append(l.split(":")[0].strip())
return lst
def get_working_if():
for i in get_if_list():
if i == 'lo':
continue
ifflags = struct.unpack("16xH14x",get_if(i,SIOCGIFFLAGS))[0]
if ifflags & IFF_UP:
return i
return "lo"
def attach_filter(s, filter):
# XXX We generate the filter on the interface conf.iface
# because tcpdump open the "any" interface and ppp interfaces
# in cooked mode. As we use them in raw mode, the filter will not
# work... one solution could be to use "any" interface and translate
# the filter from cooked mode to raw mode
# mode
if not TCPDUMP:
return
try:
f = os.popen("%s -i %s -ddd -s 1600 '%s'" % (conf.prog.tcpdump,conf.iface,filter))
except OSError,msg:
log_interactive.warning("Failed to execute tcpdump: (%s)")
return
lines = f.readlines()
if f.close():
raise Scapy_Exception("Filter parse error")
nb = int(lines[0])
bpf = ""
for l in lines[1:]:
bpf += struct.pack("HBBI",*map(long,l.split()))
# XXX. Argl! We need to give the kernel a pointer on the BPF,
# python object header seems to be 20 bytes. 36 bytes for x86 64bits arch.
if X86_64:
bpfh = struct.pack("HL", nb, id(bpf)+36)
else:
bpfh = struct.pack("HI", nb, id(bpf)+20)
s.setsockopt(SOL_SOCKET, SO_ATTACH_FILTER, bpfh)
def set_promisc(s,iff,val=1):
mreq = struct.pack("IHH8s", get_if_index(iff), PACKET_MR_PROMISC, 0, "")
if val:
cmd = PACKET_ADD_MEMBERSHIP
else:
cmd = PACKET_DROP_MEMBERSHIP
s.setsockopt(SOL_PACKET, cmd, mreq)
if not LINUX:
def new_read_routes():
rtlst = []
def addrt(rt,lst):
dst,gw = rt
lst.append(rt)
r = dnet.route()
print r.loop(addrt, rtlst)
return rtlst
def read_routes():
if SOLARIS:
f=os.popen("netstat -rvn") # -f inet
else:
f=os.popen("netstat -rn") # -f inet
ok = 0
mtu_present = False
routes = []
for l in f.readlines():
if not l:
break
l = l.strip()
if l.find("----") >= 0: # a separation line
continue
if l.find("Destination") >= 0:
ok = 1
if l.find("Mtu") >= 0:
mtu_present = True
continue
if ok == 0:
continue
if not l:
break
if SOLARIS:
dest,mask,gw,netif,mxfrg,rtt,ref,flg = l.split()[:8]
else:
if mtu_present:
dest,gw,flg,ref,use,mtu,netif = l.split()[:7]
else:
dest,gw,flg,ref,use,netif = l.split()[:6]
if flg.find("Lc") >= 0:
continue
if dest == "default":
dest = 0L
netmask = 0L
else:
if SOLARIS:
netmask, = struct.unpack("I",inet_aton(mask))
elif "/" in dest:
dest,netmask = dest.split("/")
netmask = itom(int(netmask))
else:
netmask = itom((dest.count(".") + 1) * 8)
dest += ".0"*(3-dest.count("."))
dest, = struct.unpack("I",inet_aton(dest))
if not "G" in flg:
gw = '0.0.0.0'
ifaddr = get_if_addr(netif)
routes.append((dest,netmask,gw,netif,ifaddr))
f.close()
return routes
def read_interfaces():
i = dnet.intf()
ifflist = {}
def addif(iff,lst):
if not iff.has_key("addr"):
return
if not iff.has_key("link_addr"):
return
rawip = iff["addr"].data
ip = inet_ntoa(rawip)
rawll = iff["link_addr"].data
ll = str2mac(rawll)
lst[iff["name"]] = (rawll,ll,rawip,ip)
i.loop(addif, ifflist)
return ifflist
else:
def read_routes():
f=open("/proc/net/route","r")
routes = []
s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x","lo"))
addrfamily = struct.unpack("h",ifreq[16:18])[0]
if addrfamily == socket.AF_INET:
ifreq2 = ioctl(s, SIOCGIFNETMASK,struct.pack("16s16x","lo"))
msk = struct.unpack("I",ifreq2[20:24])[0]
dst = struct.unpack("I",ifreq[20:24])[0] & msk
ifaddr = inet_ntoa(ifreq[20:24])
routes.append((dst, msk, "0.0.0.0", "lo", ifaddr))
else:
warning("Interface lo: unkownn address family (%i)"% addrfamily)
for l in f.readlines()[1:]:
iff,dst,gw,flags,x,x,x,msk,x,x,x = l.split()
flags = int(flags,16)
if flags & RTF_UP == 0:
continue
if flags & RTF_REJECT:
continue
ifreq = ioctl(s, SIOCGIFADDR,struct.pack("16s16x",iff))
addrfamily = struct.unpack("h",ifreq[16:18])[0]
if addrfamily == socket.AF_INET:
ifaddr = inet_ntoa(ifreq[20:24])
else:
warning("Interface %s: unkownn address family (%i)"%(iff, addrfamily))
continue
routes.append((long(dst,16),
long(msk,16),
inet_ntoa(struct.pack("I",long(gw,16))),
iff, ifaddr))
f.close()
return routes
def get_if(iff,cmd):
s=socket.socket()
ifreq = ioctl(s, cmd, struct.pack("16s16x",iff))
s.close()
return ifreq
def get_if_index(iff):
return int(struct.unpack("I",get_if(iff, SIOCGIFINDEX)[16:20])[0])
def get_if_addr(iff):
return inet_ntoa(get_if_raw_addr(iff))
def get_if_hwaddr(iff):
addrfamily, mac = get_if_raw_hwaddr(iff)
if addrfamily in [ARPHDR_ETHER,ARPHDR_LOOPBACK]:
return str2mac(mac)
else:
raise Scapy_Exception("Unsupported address family (%i) for interface [%s]" % (addrfamily,iff))
#####################
## ARP cache stuff ##
#####################
ARPTIMEOUT=120
# XXX Fill arp_cache with /etc/ether and arp cache
arp_cache={}
if 0 and DNET: ## XXX Can't use this because it does not resolve IPs not in cache
dnet_arp_object = dnet.arp()
def getmacbyip(ip):
tmp = map(ord, inet_aton(ip))
if (tmp[0] & 0xf0) == 0xe0: # mcast @
return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3])
iff,a,gw = conf.route.route(ip)
if iff == "lo":
return "ff:ff:ff:ff:ff:ff"
if gw != "0.0.0.0":
ip = gw
res = dnet_arp_object.get(dnet.addr(ip))
if res is None:
return None
else:
return res.ntoa()
else:
def getmacbyip(ip):
tmp = map(ord, inet_aton(ip))
if (tmp[0] & 0xf0) == 0xe0: # mcast @
return "01:00:5e:%.2x:%.2x:%.2x" % (tmp[1]&0x7f,tmp[2],tmp[3])
iff,a,gw = conf.route.route(ip)
if ( (iff == "lo") or (ip == conf.route.get_if_bcast(iff)) ):
return "ff:ff:ff:ff:ff:ff"
if gw != "0.0.0.0":
ip = gw
if arp_cache.has_key(ip):
mac, timeout = arp_cache[ip]
if not timeout or (time.time()-timeout < ARPTIMEOUT):
return mac
res = srp1(Ether(dst=ETHER_BROADCAST)/ARP(op="who-has", pdst=ip),
type=ETH_P_ARP,
iface = iff,
timeout=2,
verbose=0,
nofilter=1)
if res is not None:
mac = res.payload.hwsrc
arp_cache[ip] = (mac,time.time())
return mac
return None
####################
## Random numbers ##
####################
class VolatileValue:
def __repr__(self):
return "<%s>" % self.__class__.__name__
def __getattr__(self, attr):
return getattr(self._fix(),attr)
def _fix(self):
return None
class RandField(VolatileValue):
pass
class RandNum(RandField):
min = 0
max = 0
def __init__(self, min, max):
self.min = min
self.max = max
def _fix(self):
# XXX: replace with sth that guarantee unicity
return random.randrange(self.min, self.max)
class RandNumGamma(RandField):
def __init__(self, alpha, beta):
self.alpha = alpha
self.beta = beta
def _fix(self):
return int(round(random.gammavariate(self.alpha, self.beta)))
class RandNumGauss(RandField):
def __init__(self, mu, sigma):
self.mu = mu
self.sigma = sigma
def _fix(self):
return int(round(random.gauss(self.mu, self.sigma)))
class RandNumExpo(RandField):
def __init__(self, lambd):
self.lambd = lambd
def _fix(self):
return int(round(random.expovariate(self.lambd)))
class RandByte(RandNum):
def __init__(self):
RandNum.__init__(self, 0, 2L**8)
class RandShort(RandNum):
def __init__(self):
RandNum.__init__(self, 0, 2L**16)
class RandInt(RandNum):
def __init__(self):
RandNum.__init__(self, 0, 2L**32)
class RandSInt(RandNum):
def __init__(self):
RandNum.__init__(self, -2L**31, 2L**31)
class RandLong(RandNum):
def __init__(self):
RandNum.__init__(self, 0, 2L**64)
class RandSLong(RandNum):
def __init__(self):
RandNum.__init__(self, -2L**63, 2L**63)
class RandChoice(RandField):
def __init__(self, *args):
self._choice = args
def _fix(self):
return random.choice(self._choice)
class RandString(RandField):
def __init__(self, size, chars="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"):
self.chars = chars
self.size = size
def _fix(self):
s = ""
for i in range(self.size):
s += random.choice(self.chars)
return s
class RandBin(RandString):
def __init__(self, size):
RandString.__init__(self, size, "".join(map(chr,range(256))))
class RandTermString(RandString):
def __init__(self, size, term):
RandString.__init__(self, size, "".join(map(chr,range(1,256))))
self.term = term
def _fix(self):
return RandString._fix(self)+self.term
class RandIP(RandString):
def __init__(self, iptemplate="0.0.0.0/0"):
self.ip = Net(iptemplate)
def _fix(self):
return self.ip.choice()
class RandMAC(RandString):
def __init__(self, template="*"):
template += ":*:*:*:*:*"
template = template.split(":")
self.mac = ()
for i in range(6):
if template[i] == "*":
v = RandByte()
elif "-" in template[i]:
x,y = template[i].split("-")
v = RandNum(int(x,16), int(y,16))
else:
v = int(template[i],16)
self.mac += (v,)
def _fix(self):
return "%02x:%02x:%02x:%02x:%02x:%02x" % self.mac
class RandOID(RandString):
def __init__(self, fmt=None, depth=RandNumExpo(0.1), idnum=RandNumExpo(0.01)):
self.ori_fmt = fmt
if fmt is not None:
fmt = fmt.split(".")
for i in range(len(fmt)):
if "-" in fmt[i]:
fmt[i] = tuple(map(int, fmt[i].split("-")))
self.fmt = fmt
self.depth = depth
self.idnum = idnum
def __repr__(self):
if self.ori_fmt is None:
return "<%s>" % self.__class__.__name__
else:
return "<%s [%s]>" % (self.__class__.__name__, self.ori_fmt)
def _fix(self):
if self.fmt is None:
return ".".join(map(str, [self.idnum for i in xrange(1+self.depth)]))
else:
oid = []
for i in self.fmt:
if i == "*":
oid.append(str(self.idnum))
elif i == "**":
oid += map(str, [self.idnum for i in xrange(1+self.depth)])
elif type(i) is tuple:
oid.append(str(random.randrange(*i)))
else:
oid.append(i)
return ".".join(oid)
class RandASN1Object(RandField):
def __init__(self, objlist=None):
if objlist is None:
objlist = map(lambda x:x._asn1_obj,
filter(lambda x:hasattr(x,"_asn1_obj"), ASN1_Class_UNIVERSAL.__rdict__.values()))
self.objlist = objlist
self.chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
def _fix(self, n=0):
o = random.choice(self.objlist)
if issubclass(o, ASN1_INTEGER):
return o(int(random.gauss(0,1000)))
elif issubclass(o, ASN1_STRING):
z = int(random.expovariate(0.05)+1)
return o("".join([random.choice(self.chars) for i in range(z)]))
elif issubclass(o, ASN1_SEQUENCE) and (n < 10):
z = int(random.expovariate(0.08)+1)
return o(map(lambda x:x._fix(n+1), [self.__class__(objlist=self.objlist)]*z))
return ASN1_INTEGER(int(random.gauss(0,1000)))
# Automatic timestamp
class AutoTime(VolatileValue):
def __init__(self, base=None):
if base == None:
self.diff = 0
else:
self.diff = time.time()-base
def _fix(self):
return time.time()-self.diff
class IntAutoTime(AutoTime):
def _fix(self):
return int(time.time()-self.diff)
class DelayedEval(VolatileValue):
""" Exemple of usage: DelayedEval("time.time()") """
def __init__(self, expr):
self.expr = expr
def _fix(self):
return eval(self.expr)
class IncrementalValue(VolatileValue):
def __init__(self, start=0, step=1, restart=-1):
self.start = self.val = start
self.step = step
self.restart = restart
def _fix(self):
v = self.val
if self.val == self.restart :
self.val = self.start
else:
self.val += self.step
return v
def corrupt_bytes(s, p=0.01, n=None):
s = array.array("B",str(s))
l = len(s)
if n is None:
n = max(1,int(l*p))
for i in random.sample(xrange(l), n):
s[i] = random.randint(0,255)
return s.tostring()
def corrupt_bits(s, p=0.01, n=None):
s = array.array("B",str(s))
l = len(s)*8
if n is None:
n = max(1,int(l*p))
for i in random.sample(xrange(l), n):
s[i/8] ^= 1 << (i%8)
return s.tostring()
class CorruptedBytes(VolatileValue):
def __init__(self, s, p=0.01, n=None):
self.s = s
self.p = p
self.n = n
def _fix(self):
return corrupt_bytes(self.s, self.p, self.n)
class CorruptedBits(CorruptedBytes):
def _fix(self):
return corrupt_bits(self.s, self.p, self.n)
##############
#### ASN1 ####
##############
class ASN1_Error(Exception):
pass
class ASN1_Encoding_Error(ASN1_Error):
pass
class ASN1_Decoding_Error(ASN1_Error):
pass
class ASN1_BadTag_Decoding_Error(ASN1_Decoding_Error):
pass
class ASN1Codec(EnumElement):
def register_stem(cls, stem):
cls._stem = stem
def dec(cls, s, context=None):
return cls._stem.dec(s, context=context)
def safedec(cls, s, context=None):
return cls._stem.safedec(s, context=context)
def get_stem(cls):
return cls.stem
class ASN1_Codecs_metaclass(Enum_metaclass):
element_class = ASN1Codec
class ASN1_Codecs:
__metaclass__ = ASN1_Codecs_metaclass
BER = 1
DER = 2
PER = 3
CER = 4
LWER = 5
BACnet = 6
OER = 7
SER = 8
XER = 9
class ASN1Tag(EnumElement):
def __init__(self, key, value, context=None, codec=None):
EnumElement.__init__(self, key, value)
self._context = context
if codec == None:
codec = {}
self._codec = codec
def clone(self): # /!\ not a real deep copy. self.codec is shared
return self.__class__(self._key, self._value, self._context, self._codec)
def register_asn1_object(self, asn1obj):
self._asn1_obj = asn1obj
def asn1_object(self, val):
if hasattr(self,"_asn1_obj"):
return self._asn1_obj(val)
raise ASN1_Error("%r does not have any assigned ASN1 object" % self)
def register(self, codecnum, codec):
self._codec[codecnum] = codec
def get_codec(self, codec):
try:
c = self._codec[codec]
except KeyError,msg:
raise ASN1_Error("Codec %r not found for tag %r" % (codec, self))
return c
class ASN1_Class_metaclass(Enum_metaclass):
element_class = ASN1Tag
def __new__(cls, name, bases, dct): # XXX factorise a bit with Enum_metaclass.__new__()
for b in bases:
for k,v in b.__dict__.iteritems():
if k not in dct and isinstance(v,ASN1Tag):
dct[k] = v.clone()
rdict = {}
for k,v in dct.iteritems():
if type(v) is int:
v = ASN1Tag(k,v)
dct[k] = v
rdict[v] = v
elif isinstance(v, ASN1Tag):
rdict[v] = v
dct["__rdict__"] = rdict
cls = type.__new__(cls, name, bases, dct)
for v in cls.__dict__.values():
if isinstance(v, ASN1Tag):
v.context = cls # overwrite ASN1Tag contexts, even cloned ones
return cls
class ASN1_Class:
__metaclass__ = ASN1_Class_metaclass
class ASN1_Class_UNIVERSAL(ASN1_Class):
name = "UNIVERSAL"
ERROR = -3
RAW = -2
NONE = -1
ANY = 0
BOOLEAN = 1
INTEGER = 2
BIT_STRING = 3
STRING = 4
NULL = 5
OID = 6
OBJECT_DESCRIPTOR = 7
EXTERNAL = 8
REAL = 9
ENUMERATED = 10
EMBEDDED_PDF = 11
UTF8_STRING = 12
RELATIVE_OID = 13
SEQUENCE = 0x30#XXX 16 ??
SET = 17
NUMERIC_STRING = 18
PRINTABLE_STRING = 19
T61_STRING = 20
VIDEOTEX_STRING = 21
IA5_STRING = 22
UTC_TIME = 23
GENERALIZED_TIME = 24
GRAPHIC_STRING = 25
ISO646_STRING = 26
GENERAL_STRING = 27
UNIVERSAL_STRING = 28
CHAR_STRING = 29
BMP_STRING = 30
COUNTER32 = 0x41
TIME_TICKS = 0x43
class ASN1_Object_metaclass(type):
def __new__(cls, name, bases, dct):
c = super(ASN1_Object_metaclass, cls).__new__(cls, name, bases, dct)
try:
c.tag.register_asn1_object(c)
except:
warning("Error registering %r for %r" % (c.tag, c.codec))
return c
class ASN1_Object:
__metaclass__ = ASN1_Object_metaclass
tag = ASN1_Class_UNIVERSAL.ANY
def __init__(self, val):
self.val = val
def enc(self, codec):
return self.tag.get_codec(codec).enc(self.val)
def __repr__(self):
return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), self.val)
def __str__(self):
return self.enc(conf.ASN1_default_codec)
def strshow(self, lvl=0):
return (" "*lvl)+repr(self)+"\n"
def show(self, lvl=0):
print self.strshow(lvl)
def __eq__(self, other):
return self.val == other
def __cmp__(self, other):
return cmp(self.val, other)
class ASN1_DECODING_ERROR(ASN1_Object):
tag = ASN1_Class_UNIVERSAL.ERROR
def __init__(self, val, exc=None):
ASN1_Object.__init__(self, val)
self.exc = exc
def __repr__(self):
return "<%s[%r]{{%s}}>" % (self.__dict__.get("name", self.__class__.__name__),
self.val, self.exc.args[0])
def enc(self, codec):
if isinstance(self.val, ASN1_Object):
return self.val.enc(codec)
return self.val
class ASN1_force(ASN1_Object):
tag = ASN1_Class_UNIVERSAL.RAW
def enc(self, codec):
if isinstance(self.val, ASN1_Object):
return self.val.enc(codec)
return self.val
class ASN1_BADTAG(ASN1_force):
pass
class ASN1_INTEGER(ASN1_Object):
tag = ASN1_Class_UNIVERSAL.INTEGER
class ASN1_STRING(ASN1_Object):
tag = ASN1_Class_UNIVERSAL.STRING
class ASN1_BIT_STRING(ASN1_STRING):
tag = ASN1_Class_UNIVERSAL.BIT_STRING
class ASN1_PRINTABLE_STRING(ASN1_STRING):
tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING
class ASN1_T61_STRING(ASN1_STRING):
tag = ASN1_Class_UNIVERSAL.T61_STRING
class ASN1_IA5_STRING(ASN1_STRING):
tag = ASN1_Class_UNIVERSAL.IA5_STRING
class ASN1_NUMERIC_STRING(ASN1_STRING):
tag = ASN1_Class_UNIVERSAL.NUMERIC_STRING
class ASN1_VIDEOTEX_STRING(ASN1_STRING):
tag = ASN1_Class_UNIVERSAL.VIDEOTEX_STRING
class ASN1_UTC_TIME(ASN1_STRING):
tag = ASN1_Class_UNIVERSAL.UTC_TIME
class ASN1_TIME_TICKS(ASN1_INTEGER):
tag = ASN1_Class_UNIVERSAL.TIME_TICKS
class ASN1_BOOLEAN(ASN1_INTEGER):
tag = ASN1_Class_UNIVERSAL.BOOLEAN
class ASN1_NULL(ASN1_INTEGER):
tag = ASN1_Class_UNIVERSAL.NULL
class ASN1_COUNTER32(ASN1_INTEGER):
tag = ASN1_Class_UNIVERSAL.COUNTER32
class ASN1_SEQUENCE(ASN1_Object):
tag = ASN1_Class_UNIVERSAL.SEQUENCE
def strshow(self, lvl=0):
s = (" "*lvl)+("# %s:" % self.__class__.__name__)+"\n"
for o in self.val:
s += o.strshow(lvl=lvl+1)
return s
class ASN1_SET(ASN1_SEQUENCE):
tag = ASN1_Class_UNIVERSAL.SET
class ASN1_OID(ASN1_Object):
tag = ASN1_Class_UNIVERSAL.OID
def __init__(self, val):
val = conf.mib._oid(val)
ASN1_Object.__init__(self, val)
def __repr__(self):
return "<%s[%r]>" % (self.__dict__.get("name", self.__class__.__name__), conf.mib._oidname(self.val))
##################
## BER encoding ##
##################
#####[ BER tools ]#####
class BER_Exception(Exception):
pass
class BER_Decoding_Error(ASN1_Decoding_Error):
def __init__(self, msg, decoded=None, remaining=None):
Exception.__init__(self, msg)
self.remaining = remaining
self.decoded = decoded
def __str__(self):
s = Exception.__str__(self)
if isinstance(self.decoded, BERcodec_Object):
s+="\n### Already decoded ###\n%s" % self.decoded.strshow()
else:
s+="\n### Already decoded ###\n%r" % self.decoded
s+="\n### Remaining ###\n%r" % self.remaining
return s
class BER_BadTag_Decoding_Error(BER_Decoding_Error, ASN1_BadTag_Decoding_Error):
pass
def BER_len_enc(l, size=0):
if l <= 127 and size==0:
return chr(l)
s = ""
while l or size>0:
s = chr(l&0xff)+s
l >>= 8L
size -= 1
if len(s) > 127:
raise BER_Exception("BER_len_enc: Length too long (%i) to be encoded [%r]" % (len(s),s))
return chr(len(s)|0x80)+s
def BER_len_dec(s):
l = ord(s[0])
if not l & 0x80:
return l,s[1:]
l &= 0x7f
if len(s) <= l:
raise BER_Decoding_Error("BER_len_dec: Got %i bytes while expecting %i" % (len(s)-1, l),remaining=s)
ll = 0L
for c in s[1:l+1]:
ll <<= 8L
ll |= ord(c)
return ll,s[l+1:]
def BER_num_enc(l, size=1):
x=[]
while l or size>0:
x.insert(0, l & 0x7f)
if len(x) > 1:
x[0] |= 0x80
l >>= 7
size -= 1
return "".join([chr(k) for k in x])
def BER_num_dec(s):
x = 0
for i in range(len(s)):
c = ord(s[i])
x <<= 7
x |= c&0x7f
if not c&0x80:
break
if c&0x80:
raise BER_Decoding_Error("BER_num_dec: unfinished number description", remaining=s)
return x, s[i+1:]
#####[ BER classes ]#####
class BERcodec_metaclass(type):
def __new__(cls, name, bases, dct):
c = super(BERcodec_metaclass, cls).__new__(cls, name, bases, dct)
try:
c.tag.register(c.codec, c)
except:
warning("Error registering %r for %r" % (c.tag, c.codec))
return c
class BERcodec_Object:
__metaclass__ = BERcodec_metaclass
codec = ASN1_Codecs.BER
tag = ASN1_Class_UNIVERSAL.ANY
@classmethod
def asn1_object(cls, val):
return cls.tag.asn1_object(val)
@classmethod
def check_string(cls, s):
if not s:
raise BER_Decoding_Error("%s: Got empty object while expecting tag %r" %
(cls.__name__,cls.tag), remaining=s)
@classmethod
def check_type(cls, s):
cls.check_string(s)
if cls.tag != ord(s[0]):
raise BER_BadTag_Decoding_Error("%s: Got tag [%i/%#x] while expecting %r" %
(cls.__name__, ord(s[0]), ord(s[0]),cls.tag), remaining=s)
return s[1:]
@classmethod
def check_type_get_len(cls, s):
s2 = cls.check_type(s)
if not s2:
raise BER_Decoding_Error("%s: No bytes while expecting a length" %
cls.__name__, remaining=s)
return BER_len_dec(s2)
@classmethod
def check_type_check_len(cls, s):
l,s3 = cls.check_type_get_len(s)
if len(s3) < l:
raise BER_Decoding_Error("%s: Got %i bytes while expecting %i" %
(cls.__name__, len(s3), l), remaining=s)
return l,s3[:l],s3[l:]
@classmethod
def do_dec(cls, s, context=None, safe=False):
if context is None:
context = cls.tag.context
cls.check_string(s)
p = ord(s[0])
if p not in context:
t = s
if len(t) > 18:
t = t[:15]+"..."
raise BER_Decoding_Error("Unknown prefix [%02x] for [%r]" % (p,t), remaining=s)
codec = context[p].get_codec(ASN1_Codecs.BER)
return codec.dec(s,context,safe)
@classmethod
def dec(cls, s, context=None, safe=False):
if not safe:
return cls.do_dec(s, context, safe)
try:
return cls.do_dec(s, context, safe)
except BER_BadTag_Decoding_Error,e:
o,remain = BERcodec_Object.dec(e.remaining, context, safe)
return ASN1_BADTAG(o),remain
except BER_Decoding_Error, e:
return ASN1_DECODING_ERROR(s, exc=e),""
except ASN1_Error, e:
return ASN1_DECODING_ERROR(s, exc=e),""
@classmethod
def safedec(cls, s, context=None):
return cls.dec(s, context, safe=True)
@classmethod
def enc(cls, s):
if type(s) is str:
return BERcodec_STRING.enc(s)
else:
return BERcodec_INTEGER.enc(int(s))
ASN1_Codecs.BER.register_stem(BERcodec_Object)
class BERcodec_INTEGER(BERcodec_Object):
tag = ASN1_Class_UNIVERSAL.INTEGER
@classmethod
def enc(cls, i):
s = []
while 1:
s.append(i&0xff)
if -127 <= i < 0:
break
if 128 <= i <= 255:
s.append(0)
i >>= 8
if not i:
break
s.append(len(s))
s.append(cls.tag)
s.reverse()
return "".join(map(chr, s))
@classmethod
def do_dec(cls, s, context=None, safe=False):
l,s,t = cls.check_type_check_len(s)
x = 0L
if s:
if ord(s[0])&0x80: # negative int
x = -1L
for c in s:
x <<= 8
x |= ord(c)
return cls.asn1_object(x),t
class BERcodec_BOOLEAN(BERcodec_INTEGER):
tag = ASN1_Class_UNIVERSAL.BOOLEAN
class BERcodec_NULL(BERcodec_INTEGER):
tag = ASN1_Class_UNIVERSAL.NULL
@classmethod
def enc(cls, i):
if i == 0:
return chr(cls.tag)+"\0"
class BERcodec_STRING(BERcodec_Object):
tag = ASN1_Class_UNIVERSAL.STRING
@classmethod
def enc(cls,s):
return chr(cls.tag)+BER_len_enc(len(s))+s
@classmethod
def do_dec(cls, s, context=None, safe=False):
l,s,t = cls.check_type_check_len(s)
return cls.tag.asn1_object(s),t
class BERcodec_BIT_STRING(BERcodec_STRING):
tag = ASN1_Class_UNIVERSAL.BIT_STRING
class BERcodec_PRINTABLE_STRING(BERcodec_STRING):
tag = ASN1_Class_UNIVERSAL.PRINTABLE_STRING
class BERcodec_T61_STRING (BERcodec_STRING):
tag = ASN1_Class_UNIVERSAL.T61_STRING
class BERcodec_IA5_STRING(BERcodec_STRING):
tag = ASN1_Class_UNIVERSAL.IA5_STRING
class BERcodec_UTC_TIME(BERcodec_STRING):
tag = ASN1_Class_UNIVERSAL.UTC_TIME
class BERcodec_TIME_TICKS(BERcodec_INTEGER):
tag = ASN1_Class_UNIVERSAL.TIME_TICKS
class BERcodec_COUNTER32(BERcodec_INTEGER):
tag = ASN1_Class_UNIVERSAL.COUNTER32
class BERcodec_SEQUENCE(BERcodec_Object):
tag = ASN1_Class_UNIVERSAL.SEQUENCE
@classmethod
def enc(cls, l):
if type(l) is not str:
l = "".join(map(lambda x: x.enc(cls.codec), l))
return chr(cls.tag)+BER_len_enc(len(l))+l
@classmethod
def do_dec(cls, s, context=None, safe=False):
if context is None:
context = cls.tag.context
l,st = cls.check_type_get_len(s) # we may have len(s) < l
s,t = st[:l],st[l:]
obj = []
while s:
try:
o,s = BERcodec_Object.dec(s, context, safe)
except BER_Decoding_Error, err:
print "enrichi %r <- %r %r" % (err.remaining,t,s), obj
err.remaining += t
if err.decoded is not None:
obj.append(err.decoded)
err.decoded = obj
raise
obj.append(o)
if len(st) < l:
raise BER_Decoding_Error("Not enough bytes to decode sequence", decoded=obj)
return cls.asn1_object(obj),t
class BERcodec_SET(BERcodec_SEQUENCE):
tag = ASN1_Class_UNIVERSAL.SET
class BERcodec_OID(BERcodec_Object):
tag = ASN1_Class_UNIVERSAL.OID
@classmethod
def enc(cls, oid):
lst = [int(x) for x in oid.strip(".").split(".")]
if len(lst) >= 2:
lst[1] += 40*lst[0]
del(lst[0])
s = "".join([BER_num_enc(k) for k in lst])
return chr(cls.tag)+BER_len_enc(len(s))+s
@classmethod
def do_dec(cls, s, context=None, safe=False):
l,s,t = cls.check_type_check_len(s)
lst = []
while s:
l,s = BER_num_dec(s)
lst.append(l)
if (len(lst) > 0):
lst.insert(0,lst[0]/40)
lst[1] %= 40
return cls.asn1_object(".".join([str(k) for k in lst])), t
#################
## MIB parsing ##
#################
_mib_re_integer = re.compile("^[0-9]+$")
_mib_re_both = re.compile("^([a-zA-Z_][a-zA-Z0-9_-]*)\(([0-9]+)\)$")
_mib_re_oiddecl = re.compile("$\s*([a-zA-Z0-9_-]+)\s+OBJECT[^:]+::=\s*\{([^\}]+)\}",re.M)
_mib_re_strings = re.compile('"[^"]*"')
_mib_re_comments = re.compile('--.*(\r|\n)')
class MIBDict(DADict):
def _findroot(self, x):
if x.startswith("."):
x = x[1:]
if not x.endswith("."):
x += "."
max=0
root="."
for k in self.keys():
if x.startswith(self[k]+"."):
if max < len(self[k]):
max = len(self[k])
root = k
return root, x[max:-1]
def _oidname(self, x):
root,remainder = self._findroot(x)
return root+remainder
def _oid(self, x):
xl = x.strip(".").split(".")
p = len(xl)-1
while p >= 0 and _mib_re_integer.match(xl[p]):
p -= 1
if p != 0 or xl[p] not in self:
return x
xl[p] = self[xl[p]]
return ".".join(xl[p:])
def _make_graph(self, other_keys=[]):
nodes = [(k,self[k]) for k in self.keys()]
oids = [self[k] for k in self.keys()]
for k in other_keys:
if k not in oids:
nodes.append(self.oidname(k),k)
s = 'digraph "mib" {\n'
for k,o in nodes:
s += '\t"%s" [ label="%s" ];\n' % (o,k)
s += "\n"
for k,o in nodes:
parent,remainder = self._findroot(o[:-1])
remainder = remainder[1:]+o[-1]
if parent != ".":
parent = self[parent]
s += '\t"%s" -> "%s" [label="%s"];\n' % (parent, o,remainder)
s += "}\n"
return s
def mib_register(ident, value, the_mib, unresolved):
if ident in the_mib or ident in unresolved:
return ident in the_mib
resval = []
not_resolved = 0
for v in value:
if _mib_re_integer.match(v):
resval.append(v)
else:
v = fixname(v)
if v not in the_mib:
not_resolved = 1
if v in the_mib:
v = the_mib[v]
elif v in unresolved:
v = unresolved[v]
if type(v) is list:
resval += v
else:
resval.append(v)
if not_resolved:
unresolved[ident] = resval
return False
else:
the_mib[ident] = resval
keys = unresolved.keys()
i = 0
while i < len(keys):
k = keys[i]
if mib_register(k,unresolved[k], the_mib, {}):
del(unresolved[k])
del(keys[i])
i = 0
else:
i += 1
return True
def load_mib(filenames):
the_mib = {'iso': ['1']}
unresolved = {}
for k in conf.mib.keys():
mib_register(k, conf.mib[k].split("."), the_mib, unresolved)
if type(filenames) is str:
filenames = [filenames]
for fnames in filenames:
for fname in glob(fnames):
f = open(fname)
text = f.read()
cleantext = " ".join(_mib_re_strings.split(" ".join(_mib_re_comments.split(text))))
for m in _mib_re_oiddecl.finditer(cleantext):
ident,oid = m.groups()
ident=fixname(ident)
oid = oid.split()
for i in range(len(oid)):
m = _mib_re_both.match(oid[i])
if m:
oid[i] = m.groups()[1]
mib_register(ident, oid, the_mib, unresolved)
newmib = MIBDict(_name="MIB")
for k,o in the_mib.iteritems():
newmib[k]=".".join(o)
for k,o in unresolved.iteritems():
newmib[k]=".".join(o)
conf.mib=newmib
################
## Generators ##
################
class Gen(object):
def __iter__(self):
return iter([])
class SetGen(Gen):
def __init__(self, set, _iterpacket=1):
self._iterpacket=_iterpacket
if type(set) is list:
self.set = set
elif isinstance(set, PacketList):
self.set = list(set)
else:
self.set = [set]
def transf(self, element):
return element
def __iter__(self):
for i in self.set:
if (type(i) is tuple) and (len(i) == 2) and type(i[0]) is int and type(i[1]) is int:
if (i[0] <= i[1]):
j=i[0]
while j <= i[1]:
yield j
j += 1
elif isinstance(i, Gen) and (self._iterpacket or not isinstance(i,Packet)):
for j in i:
yield j
else:
yield i
def __repr__(self):
return "<SetGen %s>" % self.set.__repr__()
class Net(Gen):
"""Generate a list of IPs from a network address or a name"""
name = "ip"
ipaddress = re.compile(r"^(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)\.(\*|[0-2]?[0-9]?[0-9](-[0-2]?[0-9]?[0-9])?)(/[0-3]?[0-9])?$")
def __init__(self, net):
self.repr=net
tmp=net.split('/')+["32"]
if not self.ipaddress.match(net):
tmp[0]=socket.gethostbyname(tmp[0])
netmask = int(tmp[1])
def parse_digit(a,netmask):
netmask = min(8,max(netmask,0))
if a == "*":
a = (0,256)
elif a.find("-") >= 0:
x,y = map(int,a.split("-"))
if x > y:
y = x
a = (x & (0xffL<<netmask) , max(y, (x | (0xffL>>(8-netmask))))+1)
else:
a = (int(a) & (0xffL<<netmask),(int(a) | (0xffL>>(8-netmask)))+1)
return a
self.parsed = map(lambda x,y: parse_digit(x,y), tmp[0].split("."), map(lambda x,nm=netmask: x-nm, (8,16,24,32)))
def __iter__(self):
for d in xrange(*self.parsed[3]):
for c in xrange(*self.parsed[2]):
for b in xrange(*self.parsed[1]):
for a in xrange(*self.parsed[0]):
yield "%i.%i.%i.%i" % (a,b,c,d)
def choice(self):
ip = []
for v in self.parsed:
ip.append(str(random.randint(v[0],v[1]-1)))
return ".".join(ip)
def __repr__(self):
return "Net(%r)" % self.repr
class OID(Gen):
name = "OID"
def __init__(self, oid):
self.oid = oid
self.cmpt = []
fmt = []
for i in oid.split("."):
if "-" in i:
fmt.append("%i")
self.cmpt.append(tuple(map(int, i.split("-"))))
else:
fmt.append(i)
self.fmt = ".".join(fmt)
def __repr__(self):
return "OID(%r)" % self.oid
def __iter__(self):
ii = [k[0] for k in self.cmpt]
while 1:
yield self.fmt % tuple(ii)
i = 0
while 1:
if i >= len(ii):
raise StopIteration
if ii[i] < self.cmpt[i][1]:
ii[i]+=1
break
else:
ii[i] = self.cmpt[i][0]
i += 1
#############
## Results ##
#############
class PacketList:
res = []
def __init__(self, res=None, name="PacketList", stats=None):
"""create a packet list from a list of packets
res: the list of packets
stats: a list of classes that will appear in the stats (defaults to [TCP,UDP,ICMP])"""
if stats is None:
stats = [ TCP,UDP,ICMP ]
self.stats = stats
if res is None:
res = []
if isinstance(res, PacketList):
res = res.res
self.res = res
self.listname = name
def _elt2pkt(self, elt):
return elt
def _elt2sum(self, elt):
return elt.summary()
def _elt2show(self, elt):
return self._elt2sum(elt)
def __repr__(self):
# stats=dict.fromkeys(self.stats,0) ## needs python >= 2.3 :(
stats = dict(map(lambda x: (x,0), self.stats))
other = 0
for r in self.res:
f = 0
for p in stats:
if self._elt2pkt(r).haslayer(p):
stats[p] += 1
f = 1
break
if not f:
other += 1
s = ""
ct = conf.color_theme
for p in stats:
s += " %s%s%s" % (ct.packetlist_proto(p.name),
ct.punct(":"),
ct.packetlist_value(stats[p]))
s += " %s%s%s" % (ct.packetlist_proto("Other"),
ct.punct(":"),
ct.packetlist_value(other))
return "%s%s%s%s%s" % (ct.punct("<"),
ct.packetlist_name(self.listname),
ct.punct(":"),
s,
ct.punct(">"))
def __getattr__(self, attr):
return getattr(self.res, attr)
def __getitem__(self, item):
if isinstance(item,type) and issubclass(item,Packet):
return self.__class__(filter(lambda x: item in self._elt2pkt(x),self.res),
name="%s from %s"%(item.__name__,self.listname))
if type(item) is slice:
return self.__class__(self.res.__getitem__(item),
name = "mod %s" % self.listname)
return self.res.__getitem__(item)
def __getslice__(self, *args, **kargs):
return self.__class__(self.res.__getslice__(*args, **kargs),
name="mod %s"%self.listname)
def __add__(self, other):
return self.__class__(self.res+other.res,
name="%s+%s"%(self.listname,other.listname))
def summary(self, prn=None, lfilter=None):
"""prints a summary of each packet
prn: function to apply to each packet instead of lambda x:x.summary()
lfilter: truth function to apply to each packet to decide whether it will be displayed"""
for r in self.res:
if lfilter is not None:
if not lfilter(r):
continue
if prn is None:
print self._elt2sum(r)
else:
print prn(r)
def nsummary(self,prn=None, lfilter=None):
"""prints a summary of each packet with the packet's number
prn: function to apply to each packet instead of lambda x:x.summary()
lfilter: truth function to apply to each packet to decide whether it will be displayed"""
for i in range(len(self.res)):
if lfilter is not None:
if not lfilter(self.res[i]):
continue
print conf.color_theme.id(i,"%04i"),
if prn is None:
print self._elt2sum(self.res[i])
else:
print prn(self.res[i])
def display(self): # Deprecated. Use show()
"""deprecated. is show()"""
self.show()
def show(self, *args, **kargs):
"""Best way to display the packet list. Defaults to nsummary() method"""
return self.nsummary(*args, **kargs)
def filter(self, func):
"""Returns a packet list filtered by a truth function"""
return self.__class__(filter(func,self.res),
name="filtered %s"%self.listname)
def make_table(self, *args, **kargs):
"""Prints a table using a function that returs for each packet its head column value, head row value and displayed value
ex: p.make_table(lambda x:(x[IP].dst, x[TCP].dport, x[TCP].sprintf("%flags%")) """
return make_table(self.res, *args, **kargs)
def make_lined_table(self, *args, **kargs):
"""Same as make_table, but print a table with lines"""
return make_lined_table(self.res, *args, **kargs)
def make_tex_table(self, *args, **kargs):
"""Same as make_table, but print a table with LaTeX syntax"""
return make_tex_table(self.res, *args, **kargs)
def plot(self, f, lfilter=None,**kargs):
"""Applies a function to each packet to get a value that will be plotted with GnuPlot. A gnuplot object is returned
lfilter: a truth function that decides whether a packet must be ploted"""
g=Gnuplot.Gnuplot()
l = self.res
if lfilter is not None:
l = filter(lfilter, l)
l = map(f,l)
g.plot(Gnuplot.Data(l, **kargs))
return g
def diffplot(self, f, delay=1, lfilter=None, **kargs):
"""diffplot(f, delay=1, lfilter=None)
Applies a function to couples (l[i],l[i+delay])"""
g = Gnuplot.Gnuplot()
l = self.res
if lfilter is not None:
l = filter(lfilter, l)
l = map(f,l[:-delay],l[delay:])
g.plot(Gnuplot.Data(l, **kargs))
return g
def multiplot(self, f, lfilter=None, **kargs):
"""Uses a function that returns a label and a value for this label, then plots all the values label by label"""
g=Gnuplot.Gnuplot()
l = self.res
if lfilter is not None:
l = filter(lfilter, l)
d={}
for e in l:
k,v = f(e)
if k in d:
d[k].append(v)
else:
d[k] = [v]
data=[]
for k in d:
data.append(Gnuplot.Data(d[k], title=k, **kargs))
g.plot(*data)
return g
def rawhexdump(self):
"""Prints an hexadecimal dump of each packet in the list"""
for p in self:
hexdump(self._elt2pkt(p))
def hexraw(self, lfilter=None):
"""Same as nsummary(), except that if a packet has a Raw layer, it will be hexdumped
lfilter: a truth function that decides whether a packet must be displayed"""
for i in range(len(self.res)):
p = self._elt2pkt(self.res[i])
if lfilter is not None and not lfilter(p):
continue
print "%s %s %s" % (conf.color_theme.id(i,"%04i"),
p.sprintf("%.time%"),
self._elt2sum(self.res[i]))
if p.haslayer(Raw):
hexdump(p.getlayer(Raw).load)
def hexdump(self, lfilter=None):
"""Same as nsummary(), except that packets are also hexdumped
lfilter: a truth function that decides whether a packet must be displayed"""
for i in range(len(self.res)):
p = self._elt2pkt(self.res[i])
if lfilter is not None and not lfilter(p):
continue
print "%s %s %s" % (conf.color_theme.id(i,"%04i"),
p.sprintf("%.time%"),
self._elt2sum(self.res[i]))
hexdump(p)
def padding(self, lfilter=None):
"""Same as hexraw(), for Padding layer"""
for i in range(len(self.res)):
p = self._elt2pkt(self.res[i])
if p.haslayer(Padding):
if lfilter is None or lfilter(p):
print "%s %s %s" % (conf.color_theme.id(i,"%04i"),
p.sprintf("%.time%"),
self._elt2sum(self.res[i]))
hexdump(p.getlayer(Padding).load)
def nzpadding(self, lfilter=None):
"""Same as padding() but only non null padding"""
for i in range(len(self.res)):
p = self._elt2pkt(self.res[i])
if p.haslayer(Padding):
pad = p.getlayer(Padding).load
if pad == pad[0]*len(pad):
continue
if lfilter is None or lfilter(p):
print "%s %s %s" % (conf.color_theme.id(i,"%04i"),
p.sprintf("%.time%"),
self._elt2sum(self.res[i]))
hexdump(p.getlayer(Padding).load)
def conversations(self, getsrcdst=None,**kargs):
"""Graphes a conversations between sources and destinations and display it
(using graphviz and imagemagick)
getsrcdst: a function that takes an element of the list and return the source and dest
by defaults, return source and destination IP
type: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option
target: filename or redirect. Defaults pipe to Imagemagick's display program
prog: which graphviz program to use"""
if getsrcdst is None:
getsrcdst = lambda x:(x[IP].src, x[IP].dst)
conv = {}
for p in self.res:
p = self._elt2pkt(p)
try:
c = getsrcdst(p)
except:
#XXX warning()
continue
conv[c] = conv.get(c,0)+1
gr = 'digraph "conv" {\n'
for s,d in conv:
gr += '\t "%s" -> "%s"\n' % (s,d)
gr += "}\n"
do_graph(gr, **kargs)
def afterglow(self, src=None, event=None, dst=None, **kargs):
"""Experimental clone attempt of http://sourceforge.net/projects/afterglow
each datum is reduced as src -> event -> dst and the data are graphed.
by default we have IP.src -> IP.dport -> IP.dst"""
if src is None:
src = lambda x: x[IP].src
if event is None:
event = lambda x: x[IP].dport
if dst is None:
dst = lambda x: x[IP].dst
sl = {}
el = {}
dl = {}
for i in self.res:
try:
s,e,d = src(i),event(i),dst(i)
if s in sl:
n,l = sl[s]
n += 1
if e not in l:
l.append(e)
sl[s] = (n,l)
else:
sl[s] = (1,[e])
if e in el:
n,l = el[e]
n+=1
if d not in l:
l.append(d)
el[e] = (n,l)
else:
el[e] = (1,[d])
dl[d] = dl.get(d,0)+1
except:
continue
import math
def normalize(n):
return 2+math.log(n)/4.0
def minmax(x):
m,M = min(x),max(x)
if m == M:
m = 0
if M == 0:
M = 1
return m,M
mins,maxs = minmax(map(lambda (x,y): x, sl.values()))
mine,maxe = minmax(map(lambda (x,y): x, el.values()))
mind,maxd = minmax(dl.values())
gr = 'digraph "afterglow" {\n\tedge [len=2.5];\n'
gr += "# src nodes\n"
for s in sl:
n,l = sl[s]; n = 1+float(n-mins)/(maxs-mins)
gr += '"src.%s" [label = "%s", shape=box, fillcolor="#FF0000", style=filled, fixedsize=1, height=%.2f,width=%.2f];\n' % (`s`,`s`,n,n)
gr += "# event nodes\n"
for e in el:
n,l = el[e]; n = n = 1+float(n-mine)/(maxe-mine)
gr += '"evt.%s" [label = "%s", shape=circle, fillcolor="#00FFFF", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (`e`,`e`,n,n)
for d in dl:
n = dl[d]; n = n = 1+float(n-mind)/(maxd-mind)
gr += '"dst.%s" [label = "%s", shape=triangle, fillcolor="#0000ff", style=filled, fixedsize=1, height=%.2f, width=%.2f];\n' % (`d`,`d`,n,n)
gr += "###\n"
for s in sl:
n,l = sl[s]
for e in l:
gr += ' "src.%s" -> "evt.%s";\n' % (`s`,`e`)
for e in el:
n,l = el[e]
for d in l:
gr += ' "evt.%s" -> "dst.%s";\n' % (`e`,`d`)
gr += "}"
open("/tmp/aze","w").write(gr)
do_graph(gr, **kargs)
def timeskew_graph(self, ip, **kargs):
"""Tries to graph the timeskew between the timestamps and real time for a given ip"""
res = map(lambda x: self._elt2pkt(x), self.res)
b = filter(lambda x:x.haslayer(IP) and x.getlayer(IP).src == ip and x.haslayer(TCP), res)
c = []
for p in b:
opts = p.getlayer(TCP).options
for o in opts:
if o[0] == "Timestamp":
c.append((p.time,o[1][0]))
if not c:
warning("No timestamps found in packet list")
return
d = map(lambda (x,y): (x%2000,((x-c[0][0])-((y-c[0][1])/1000.0))),c)
g = Gnuplot.Gnuplot()
g.plot(Gnuplot.Data(d,**kargs))
return g
def _dump_document(self, **kargs):
d = pyx.document.document()
l = len(self.res)
for i in range(len(self.res)):
elt = self.res[i]
c = self._elt2pkt(elt).canvas_dump(**kargs)
cbb = c.bbox()
c.text(cbb.left(),cbb.top()+1,r"\font\cmssfont=cmss12\cmssfont{Frame %i/%i}" % (i,l),[pyx.text.size.LARGE])
if conf.verb >= 2:
os.write(1,".")
d.append(pyx.document.page(c, paperformat=pyx.document.paperformat.A4,
margin=1*pyx.unit.t_cm,
fittosize=1))
return d
def psdump(self, filename = None, **kargs):
"""Creates a multipage poscript file with a psdump of every packet
filename: name of the file to write to. If empty, a temporary file is used and
conf.prog.psreader is called"""
d = self._dump_document(**kargs)
if filename is None:
filename = "/tmp/scapy.psd.%i" % os.getpid()
d.writePSfile(filename)
os.system("%s %s.ps &" % (conf.prog.psreader,filename))
else:
d.writePSfile(filename)
print
def pdfdump(self, filename = None, **kargs):
"""Creates a PDF file with a psdump of every packet
filename: name of the file to write to. If empty, a temporary file is used and
conf.prog.pdfreader is called"""
d = self._dump_document(**kargs)
if filename is None:
filename = "/tmp/scapy.psd.%i" % os.getpid()
d.writePDFfile(filename)
os.system("%s %s.pdf &" % (conf.prog.pdfreader,filename))
else:
d.writePDFfile(filename)
print
def sr(self,multi=0):
"""sr([multi=1]) -> (SndRcvList, PacketList)
Matches packets in the list and return ( (matched couples), (unmatched packets) )"""
remain = self.res[:]
sr = []
i = 0
while i < len(remain):
s = remain[i]
j = i
while j < len(remain)-1:
j += 1
r = remain[j]
if r.answers(s):
sr.append((s,r))
if multi:
remain[i]._answered=1
remain[j]._answered=2
continue
del(remain[j])
del(remain[i])
i -= 1
break
i += 1
if multi:
remain = filter(lambda x:not hasattr(x,"_answered"), remain)
return SndRcvList(sr),PacketList(remain)
class Dot11PacketList(PacketList):
def __init__(self, res=None, name="Dot11List", stats=None):
if stats is None:
stats = [Dot11WEP, Dot11Beacon, UDP, ICMP, TCP]
PacketList.__init__(self, res, name, stats)
def toEthernet(self):
data = map(lambda x:x.getlayer(Dot11), filter(lambda x : x.haslayer(Dot11) and x.type == 2, self.res))
r2 = []
for p in data:
q = p.copy()
q.unwep()
r2.append(Ether()/q.payload.payload.payload) #Dot11/LLC/SNAP/IP
return PacketList(r2,name="Ether from %s"%self.listname)
class SndRcvList(PacketList):
def __init__(self, res=None, name="Results", stats=None):
PacketList.__init__(self, res, name, stats)
def _elt2pkt(self, elt):
return elt[1]
def _elt2sum(self, elt):
return "%s ==> %s" % (elt[0].summary(),elt[1].summary())
class ARPingResult(SndRcvList):
def __init__(self, res=None, name="ARPing", stats=None):
PacketList.__init__(self, res, name, stats)
def show(self):
for s,r in self.res:
print r.sprintf("%Ether.src% %ARP.psrc%")
class AS_resolver:
server = None
options = "-k"
def __init__(self, server=None, port=43, options=None):
if server is not None:
self.server = server
self.port = port
if options is not None:
self.options = options
def _start(self):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.connect((self.server,self.port))
if self.options:
self.s.send(self.options+"\n")
self.s.recv(8192)
def _stop(self):
self.s.close()
def _parse_whois(self, txt):
asn,desc = None,""
for l in txt.splitlines():
if not asn and l.startswith("origin:"):
asn = l[7:].strip()
if l.startswith("descr:"):
if desc:
desc += r"\n"
desc += l[6:].strip()
if asn is not None and desc:
break
return asn,desc.strip()
def _resolve_one(self, ip):
self.s.send("%s\n" % ip)
x = ""
while not ("%" in x or "source" in x):
x += self.s.recv(8192)
asn, desc = self._parse_whois(x)
return ip,asn,desc
def resolve(self, *ips):
self._start()
ret = []
for ip in ips:
ip,asn,desc = self._resolve_one(ip)
if asn is not None:
ret.append((ip,asn,desc))
self._stop()
return ret
class AS_resolver_riswhois(AS_resolver):
server = "riswhois.ripe.net"
options = "-k -M -1"
class AS_resolver_radb(AS_resolver):
server = "whois.ra.net"
options = "-k -M"
class AS_resolver_cymru(AS_resolver):
server = "whois.cymru.com"
options = None
def resolve(self, *ips):
ASNlist = []
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((self.server,self.port))
s.send("begin\r\n"+"\r\n".join(ips)+"\r\nend\r\n")
r = ""
while 1:
l = s.recv(8192)
if l == "":
break
r += l
s.close()
for l in r.splitlines()[1:]:
if "|" not in l:
continue
asn,ip,desc = map(str.strip, l.split("|"))
if asn == "NA":
continue
asn = int(asn)
ASNlist.append((ip,asn,desc))
return ASNlist
class AS_resolver_multi(AS_resolver):
resolvers_list = ( AS_resolver_cymru(),AS_resolver_riswhois(),AS_resolver_radb() )
def __init__(self, *reslist):
if reslist:
self.resolvers_list = reslist
def resolve(self, *ips):
todo = ips
ret = []
for ASres in self.resolvers_list:
res = ASres.resolve(*todo)
resolved = [ ip for ip,asn,desc in res ]
todo = [ ip for ip in todo if ip not in resolved ]
ret += res
return ret
class TracerouteResult(SndRcvList):
def __init__(self, res=None, name="Traceroute", stats=None):
PacketList.__init__(self, res, name, stats)
self.graphdef = None
self.graphASres = 0
self.padding = 0
self.hloc = None
self.nloc = None
def show(self):
return self.make_table(lambda (s,r): (s.sprintf("%IP.dst%:{TCP:tcp%ir,TCP.dport%}{UDP:udp%ir,UDP.dport%}{ICMP:ICMP}"),
s.ttl,
r.sprintf("%-15s,IP.src% {TCP:%TCP.flags%}{ICMP:%ir,ICMP.type%}")))
def get_trace(self):
trace = {}
for s,r in self.res:
if IP not in s:
continue
d = s[IP].dst
if d not in trace:
trace[d] = {}
trace[d][s[IP].ttl] = r[IP].src, ICMP not in r
for k in trace.values():
m = filter(lambda x:k[x][1], k.keys())
if not m:
continue
m = min(m)
for l in k.keys():
if l > m:
del(k[l])
return trace
def trace3D(self):
"""Give a 3D representation of the traceroute.
right button: rotate the scene
middle button: zoom
left button: move the scene
left button on a ball: toggle IP displaying
ctrl-left button on a ball: scan ports 21,22,23,25,80 and 443 and display the result"""
trace = self.get_trace()
import visual
class IPsphere(visual.sphere):
def __init__(self, ip, **kargs):
visual.sphere.__init__(self, **kargs)
self.ip=ip
self.label=None
self.setlabel(self.ip)
def setlabel(self, txt,visible=None):
if self.label is not None:
if visible is None:
visible = self.label.visible
self.label.visible = 0
elif visible is None:
visible=0
self.label=visual.label(text=txt, pos=self.pos, space=self.radius, xoffset=10, yoffset=20, visible=visible)
def action(self):
self.label.visible ^= 1
visual.scene = visual.display()
visual.scene.exit_on_close(0)
start = visual.box()
rings={}
tr3d = {}
for i in trace:
tr = trace[i]
tr3d[i] = []
ttl = tr.keys()
for t in range(1,max(ttl)+1):
if t not in rings:
rings[t] = []
if t in tr:
if tr[t] not in rings[t]:
rings[t].append(tr[t])
tr3d[i].append(rings[t].index(tr[t]))
else:
rings[t].append(("unk",-1))
tr3d[i].append(len(rings[t])-1)
for t in rings:
r = rings[t]
l = len(r)
for i in range(l):
if r[i][1] == -1:
col = (0.75,0.75,0.75)
elif r[i][1]:
col = visual.color.green
else:
col = visual.color.blue
s = IPsphere(pos=((l-1)*visual.cos(2*i*visual.pi/l),(l-1)*visual.sin(2*i*visual.pi/l),2*t),
ip = r[i][0],
color = col)
for trlst in tr3d.values():
if t <= len(trlst):
if trlst[t-1] == i:
trlst[t-1] = s
forecol = colgen(0.625, 0.4375, 0.25, 0.125)
for trlst in tr3d.values():
col = forecol.next()
start = (0,0,0)
for ip in trlst:
visual.cylinder(pos=start,axis=ip.pos-start,color=col,radius=0.2)
start = ip.pos
movcenter=None
while 1:
if visual.scene.kb.keys:
k = visual.scene.kb.getkey()
if k == "esc":
break
if visual.scene.mouse.events:
ev = visual.scene.mouse.getevent()
if ev.press == "left":
o = ev.pick
if o:
if ev.ctrl:
if o.ip == "unk":
continue
savcolor = o.color
o.color = (1,0,0)
a,b=sr(IP(dst=o.ip)/TCP(dport=[21,22,23,25,80,443]),timeout=2)
o.color = savcolor
if len(a) == 0:
txt = "%s:\nno results" % o.ip
else:
txt = "%s:\n" % o.ip
for s,r in a:
txt += r.sprintf("{TCP:%IP.src%:%TCP.sport% %TCP.flags%}{TCPerror:%IPerror.dst%:%TCPerror.dport% %IP.src% %ir,ICMP.type%}\n")
o.setlabel(txt, visible=1)
else:
if hasattr(o, "action"):
o.action()
elif ev.drag == "left":
movcenter = ev.pos
elif ev.drop == "left":
movcenter = None
if movcenter:
visual.scene.center -= visual.scene.mouse.pos-movcenter
movcenter = visual.scene.mouse.pos
def world_trace(self):
ips = {}
rt = {}
ports_done = {}
for s,r in self.res:
ips[r.src] = None
if s.haslayer(TCP) or s.haslayer(UDP):
trace_id = (s.src,s.dst,s.proto,s.dport)
elif s.haslayer(ICMP):
trace_id = (s.src,s.dst,s.proto,s.type)
else:
trace_id = (s.src,s.dst,s.proto,0)
trace = rt.get(trace_id,{})
if not r.haslayer(ICMP) or r.type != 11:
if ports_done.has_key(trace_id):
continue
ports_done[trace_id] = None
trace[s.ttl] = r.src
rt[trace_id] = trace
trt = {}
for trace_id in rt:
trace = rt[trace_id]
loctrace = []
for i in range(max(trace.keys())):
ip = trace.get(i,None)
if ip is None:
continue
loc = locate_ip(ip)
if loc is None:
continue
# loctrace.append((ip,loc)) # no labels yet
loctrace.append(loc)
if loctrace:
trt[trace_id] = loctrace
tr = map(lambda x: Gnuplot.Data(x,with="lines"), trt.values())
g = Gnuplot.Gnuplot()
world = Gnuplot.File(conf.gnuplot_world,with="lines")
g.plot(world,*tr)
return g
def make_graph(self,ASres=None,padding=0):
if ASres is None:
ASres = conf.AS_resolver
self.graphASres = ASres
self.graphpadding = padding
ips = {}
rt = {}
ports = {}
ports_done = {}
for s,r in self.res:
r = r[IP] or r[IPv6] or r
s = s[IP] or s[IPv6] or s
ips[r.src] = None
if TCP in s:
trace_id = (s.src,s.dst,6,s.dport)
elif UDP in s:
trace_id = (s.src,s.dst,17,s.dport)
elif ICMP in s:
trace_id = (s.src,s.dst,1,s.type)
else:
trace_id = (s.src,s.dst,s.proto,0)
trace = rt.get(trace_id,{})
ttl = IPv6 in s and s.hlim or s.ttl
if not (ICMP in r and r[ICMP].type == 11) and not (IPv6 in r and ICMPv6TimeExceeded in r):
if trace_id in ports_done:
continue
ports_done[trace_id] = None
p = ports.get(r.src,[])
if TCP in r:
p.append(r.sprintf("<T%ir,TCP.sport%> %TCP.sport% %TCP.flags%"))
trace[ttl] = r.sprintf('"%r,src%":T%ir,TCP.sport%')
elif UDP in r:
p.append(r.sprintf("<U%ir,UDP.sport%> %UDP.sport%"))
trace[ttl] = r.sprintf('"%r,src%":U%ir,UDP.sport%')
elif ICMP in r:
p.append(r.sprintf("<I%ir,ICMP.type%> ICMP %ICMP.type%"))
trace[ttl] = r.sprintf('"%r,src%":I%ir,ICMP.type%')
else:
p.append(r.sprintf("{IP:<P%ir,proto%> IP %proto%}{IPv6:<P%ir,nh%> IPv6 %nh%}"))
trace[ttl] = r.sprintf('"%r,src%":{IP:P%ir,proto%}{IPv6:P%ir,nh%}')
ports[r.src] = p
else:
trace[ttl] = r.sprintf('"%r,src%"')
rt[trace_id] = trace
# Fill holes with unk%i nodes
unknown_label = incremental_label("unk%i")
blackholes = []
bhip = {}
for rtk in rt:
trace = rt[rtk]
k = trace.keys()
for n in range(min(k), max(k)):
if not trace.has_key(n):
trace[n] = unknown_label.next()
if not ports_done.has_key(rtk):
if rtk[2] == 1: #ICMP
bh = "%s %i/icmp" % (rtk[1],rtk[3])
elif rtk[2] == 6: #TCP
bh = "%s %i/tcp" % (rtk[1],rtk[3])
elif rtk[2] == 17: #UDP
bh = '%s %i/udp' % (rtk[1],rtk[3])
else:
bh = '%s %i/proto' % (rtk[1],rtk[2])
ips[bh] = None
bhip[rtk[1]] = bh
bh = '"%s"' % bh
trace[max(k)+1] = bh
blackholes.append(bh)
# Find AS numbers
ASN_query_list = dict.fromkeys(map(lambda x:x.rsplit(" ",1)[0],ips)).keys()
if ASres is None:
ASNlist = []
else:
ASNlist = ASres.resolve(*ASN_query_list)
ASNs = {}
ASDs = {}
for ip,asn,desc, in ASNlist:
if asn is None:
continue
iplist = ASNs.get(asn,[])
if ip in bhip:
if ip in ports:
iplist.append(ip)
iplist.append(bhip[ip])
else:
iplist.append(ip)
ASNs[asn] = iplist
ASDs[asn] = desc
backcolorlist=colgen("60","86","ba","ff")
forecolorlist=colgen("a0","70","40","20")
s = "digraph trace {\n"
s += "\n\tnode [shape=ellipse,color=black,style=solid];\n\n"
s += "\n#ASN clustering\n"
for asn in ASNs:
s += '\tsubgraph cluster_%s {\n' % asn
col = backcolorlist.next()
s += '\t\tcolor="#%s%s%s";' % col
s += '\t\tnode [fillcolor="#%s%s%s",style=filled];' % col
s += '\t\tfontsize = 10;'
s += '\t\tlabel = "%s\\n[%s]"\n' % (asn,ASDs[asn])
for ip in ASNs[asn]:
s += '\t\t"%s";\n'%ip
s += "\t}\n"
s += "#endpoints\n"
for p in ports:
s += '\t"%s" [shape=record,color=black,fillcolor=green,style=filled,label="%s|%s"];\n' % (p,p,"|".join(ports[p]))
s += "\n#Blackholes\n"
for bh in blackholes:
s += '\t%s [shape=octagon,color=black,fillcolor=red,style=filled];\n' % bh
if padding:
s += "\n#Padding\n"
pad={}
for snd,rcv in self.res:
if rcv.src not in ports and rcv.haslayer(Padding):
p = rcv.getlayer(Padding).load
if p != "\x00"*len(p):
pad[rcv.src]=None
for rcv in pad:
s += '\t"%s" [shape=triangle,color=black,fillcolor=red,style=filled];\n' % rcv
s += "\n\tnode [shape=ellipse,color=black,style=solid];\n\n"
for rtk in rt:
s += "#---[%s\n" % `rtk`
s += '\t\tedge [color="#%s%s%s"];\n' % forecolorlist.next()
trace = rt[rtk]
k = trace.keys()
for n in range(min(k), max(k)):
s += '\t%s ->\n' % trace[n]
s += '\t%s;\n' % trace[max(k)]
s += "}\n";
self.graphdef = s
def graph(self, ASres=None, padding=0, **kargs):
"""x.graph(ASres=conf.AS_resolver, other args):
ASres=None : no AS resolver => no clustering
ASres=AS_resolver() : default whois AS resolver (riswhois.ripe.net)
ASres=AS_resolver_cymru(): use whois.cymru.com whois database
ASres=AS_resolver(server="whois.ra.net")
type: output type (svg, ps, gif, jpg, etc.), passed to dot's "-T" option
target: filename or redirect. Defaults pipe to Imagemagick's display program
prog: which graphviz program to use"""
if ASres is None:
ASres = conf.AS_resolver
if (self.graphdef is None or
self.graphASres != ASres or
self.graphpadding != padding):
self.make_graph(ASres,padding)
do_graph(self.graphdef, **kargs)
############
## Fields ##
############
class Field:
"""For more informations on how this work, please refer to
http://www.secdev.org/projects/scapy/files/scapydoc.pdf
chapter ``Adding a New Field''"""
islist=0
holds_packets=0
def __init__(self, name, default, fmt="H"):
self.name = name
if fmt[0] in "@=<>!":
self.fmt = fmt
else:
self.fmt = "!"+fmt
self.default = self.any2i(None,default)
self.sz = struct.calcsize(self.fmt)
self.owners = []
def register_owner(self, cls):
self.owners.append(cls)
def i2len(self, pkt, x):
"""Convert internal value to a length usable by a FieldLenField"""
return self.sz
def h2i(self, pkt, x):
"""Convert human value to internal value"""
return x
def i2h(self, pkt, x):
"""Convert internal value to human value"""
return x
def m2i(self, pkt, x):
"""Convert machine value to internal value"""
return x
def i2m(self, pkt, x):
"""Convert internal value to machine value"""
if x is None:
x = 0
return x
def any2i(self, pkt, x):
"""Try to understand the most input values possible and make an internal value from them"""
return self.h2i(pkt, x)
def i2repr(self, pkt, x):
"""Convert internal value to a nice representation"""
if x is None:
x = 0
return repr(self.i2h(pkt,x))
def addfield(self, pkt, s, val):
"""Add an internal value to a string"""
return s+struct.pack(self.fmt, self.i2m(pkt,val))
def getfield(self, pkt, s):
"""Extract an internal value from a string"""
return s[self.sz:], self.m2i(pkt, struct.unpack(self.fmt, s[:self.sz])[0])
def do_copy(self, x):
if hasattr(x, "copy"):
return x.copy()
if type(x) is list:
x = x[:]
for i in xrange(len(x)):
if isinstance(x[i], Packet):
x[i] = x[i].copy()
return x
def __repr__(self):
return "<Field (%s).%s>" % (",".join(x.__name__ for x in self.owners),self.name)
def copy(self):
return copy.deepcopy(self)
def randval(self):
"""Return a volatile object whose value is both random and suitable for this field"""
fmtt = self.fmt[-1]
if fmtt in "BHIQ":
return {"B":RandByte,"H":RandShort,"I":RandInt, "Q":RandLong}[fmtt]()
elif fmtt == "s":
if self.fmt[0] in "0123456789":
l = int(self.fmt[:-1])
else:
l = int(self.fmt[1:-1])
return RandBin(l)
else:
warning("no random class for [%s] (fmt=%s)." % (self.name, self.fmt))
class Emph:
fld = ""
def __init__(self, fld):
self.fld = fld
def __getattr__(self, attr):
return getattr(self.fld,attr)
class ActionField:
def __init__(self, fld, action_method, **kargs):
self._fld = fld
self._action_method = action_method
self._privdata = kargs
def any2i(self, pkt, val):
getattr(pkt, self._action_method)(val, self._fld, **self._privdata)
return getattr(self._fld, "any2i")(pkt, val)
def __getattr__(self, attr):
return getattr(self._fld,attr)
class ConditionalField:
def __init__(self, fld, fldlst, cond):
self.fld = fld
self.fldlst = fldlst
self.cond = cond
def _evalcond(self,pkt):
if type(self.fldlst) is list or type(self.fldlst) is tuple:
res = map(lambda x,pkt=pkt:getattr(pkt,x), self.fldlst)
else:
res = getattr(pkt, self.fldlst)
return self.cond(res)
def getfield(self, pkt, s):
if self._evalcond(pkt):
return self.fld.getfield(pkt,s)
else:
return s,None
def addfield(self, pkt, s, val):
if self._evalcond(pkt):
return self.fld.addfield(pkt,s,val)
else:
return s
def __getattr__(self, attr):
return getattr(self.fld,attr)
class MACField(Field):
def __init__(self, name, default):
Field.__init__(self, name, default, "6s")
def i2m(self, pkt, x):
if x is None:
return "\0\0\0\0\0\0"
return mac2str(x)
def m2i(self, pkt, x):
return str2mac(x)
def any2i(self, pkt, x):
if type(x) is str and len(x) is 6:
x = self.m2i(pkt, x)
return x
def i2repr(self, pkt, x):
x = self.i2h(pkt, x)
if self in conf.resolve:
x = conf.manufdb._resolve_MAC(x)
return x
def randval(self):
return RandMAC()
class DestMACField(MACField):
def __init__(self, name):
MACField.__init__(self, name, None)
def i2h(self, pkt, x):
if x is None:
dstip = None
if isinstance(pkt.payload, IPv6):
dstip = pkt.payload.dst
elif isinstance(pkt.payload, IP):
dstip = pkt.payload.dst
elif isinstance(pkt.payload, ARP):
dstip = pkt.payload.pdst
if isinstance(dstip, Gen):
dstip = dstip.__iter__().next()
if dstip is not None:
if isinstance(pkt.payload, IPv6):
x = getmacbyip6(dstip)
else:
x = getmacbyip(dstip)
if x is None:
x = "ff:ff:ff:ff:ff:ff"
warning("Mac address to reach %s not found\n"%dstip)
return MACField.i2h(self, pkt, x)
def i2m(self, pkt, x):
return MACField.i2m(self, pkt, self.i2h(pkt, x))
class SourceMACField(MACField):
def __init__(self, name):
MACField.__init__(self, name, None)
def i2h(self, pkt, x):
if x is None:
dstip = None
if isinstance(pkt.payload, IPv6):
dstip = pkt.payload.dst
elif isinstance(pkt.payload, IP):
dstip = pkt.payload.dst
elif isinstance(pkt.payload, ARP):
dstip = pkt.payload.pdst
if isinstance(dstip, Gen):
dstip = dstip.__iter__().next()
if dstip is not None:
if isinstance(pkt.payload, IPv6):
iff,a,nh = conf.route6.route(dstip)
else:
iff,a,gw = conf.route.route(dstip)
try:
x = get_if_hwaddr(iff)
except:
pass
if x is None:
x = "00:00:00:00:00:00"
return MACField.i2h(self, pkt, x)
def i2m(self, pkt, x):
return MACField.i2m(self, pkt, self.i2h(pkt, x))
class ARPSourceMACField(MACField):
def __init__(self, name):
MACField.__init__(self, name, None)
def i2h(self, pkt, x):
if x is None:
dstip = pkt.pdst
if isinstance(dstip, Gen):
dstip = dstip.__iter__().next()
if dstip is not None:
iff,a,gw = conf.route.route(dstip)
try:
x = get_if_hwaddr(iff)
except:
pass
if x is None:
x = "00:00:00:00:00:00"
return MACField.i2h(self, pkt, x)
def i2m(self, pkt, x):
return MACField.i2m(self, pkt, self.i2h(pkt, x))
class Dot11AddrMACField(MACField):
def is_applicable(self, pkt):
return 1
def addfield(self, pkt, s, val):
if self.is_applicable(pkt):
return MACField.addfield(self, pkt, s, val)
else:
return s
def getfield(self, pkt, s):
if self.is_applicable(pkt):
return MACField.getfield(self, pkt, s)
else:
return s,None
class Dot11Addr2MACField(Dot11AddrMACField):
def is_applicable(self, pkt):
if pkt.type == 1:
return pkt.subtype in [ 0xb, 0xa, 0xe, 0xf] # RTS, PS-Poll, CF-End, CF-End+CF-Ack
return 1
class Dot11Addr3MACField(Dot11AddrMACField):
def is_applicable(self, pkt):
if pkt.type in [0,2]:
return 1
return 0
class Dot11Addr4MACField(Dot11AddrMACField):
def is_applicable(self, pkt):
if pkt.type == 2:
if pkt.FCfield & 0x3 == 0x3: # To-DS and From-DS are set
return 1
return 0
class IPField(Field):
def __init__(self, name, default):
Field.__init__(self, name, default, "4s")
def h2i(self, pkt, x):
if type(x) is str:
try:
inet_aton(x)
except socket.error:
x = Net(x)
elif type(x) is list:
x = map(Net, x)
return x
def resolve(self, x):
if self in conf.resolve:
try:
ret = socket.gethostbyaddr(x)[0]
except socket.herror:
pass
else:
if ret:
return ret
return x
def i2m(self, pkt, x):
return inet_aton(x)
def m2i(self, pkt, x):
return inet_ntoa(x)
def any2i(self, pkt, x):
return self.h2i(pkt,x)
def i2repr(self, pkt, x):
return self.resolve(self.i2h(pkt, x))
def randval(self):
return RandIP()
class SourceIPField(IPField):
def __init__(self, name, dstname):
IPField.__init__(self, name, None)
self.dstname = dstname
def i2m(self, pkt, x):
if x is None:
iff,x,gw = conf.route.route(getattr(pkt,self.dstname))
return IPField.i2m(self, pkt, x)
def i2h(self, pkt, x):
if x is None:
dst=getattr(pkt,self.dstname)
if isinstance(dst,Gen):
r = map(conf.route.route, dst)
r.sort()
if r[0] == r[-1]:
x=r[0][1]
else:
warning("More than one possible route for %s"%repr(dst))
return None
else:
iff,x,gw = conf.route.route(dst)
return IPField.i2h(self, pkt, x)
class ByteField(Field):
def __init__(self, name, default):
Field.__init__(self, name, default, "B")
class XByteField(ByteField):
def i2repr(self, pkt, x):
if x is None:
x = 0
return lhex(self.i2h(pkt, x))
class X3BytesField(XByteField):
def __init__(self, name, default):
Field.__init__(self, name, default, "!I")
def addfield(self, pkt, s, val):
return s+struct.pack(self.fmt, self.i2m(pkt,val))[1:4]
def getfield(self, pkt, s):
return s[3:], self.m2i(pkt, struct.unpack(self.fmt, "\x00"+s[:3])[0])
class ShortField(Field):
def __init__(self, name, default):
Field.__init__(self, name, default, "H")
class LEShortField(Field):
def __init__(self, name, default):
Field.__init__(self, name, default, "<H")
class XShortField(ShortField):
def i2repr(self, pkt, x):
if x is None:
x = 0
return lhex(self.i2h(pkt, x))
class IntField(Field):
def __init__(self, name, default):
Field.__init__(self, name, default, "I")
class SignedIntField(Field):
def __init__(self, name, default):
Field.__init__(self, name, default, "i")
class LEIntField(Field):
def __init__(self, name, default):
Field.__init__(self, name, default, "<I")
class LESignedIntField(Field):
def __init__(self, name, default):
Field.__init__(self, name, default, "<i")
class XIntField(IntField):
def i2repr(self, pkt, x):
if x is None:
x = 0
return lhex(self.i2h(pkt, x))
class LongField(Field):
def __init__(self, name, default):
Field.__init__(self, name, default, "Q")
class XLongField(LongField):
def i2repr(self, pkt, x):
if x is None:
x = 0
return lhex(self.i2h(pkt, x))
class StrField(Field):
def __init__(self, name, default, fmt="H", remain=0, shift=0):
Field.__init__(self,name,default,fmt)
self.remain = remain
self.shift = shift
def i2len(self, pkt, i):
return len(i)+self.shift
def i2m(self, pkt, x):
if x is None:
x = ""
return x
def addfield(self, pkt, s, val):
return s+self.i2m(pkt, val)
def getfield(self, pkt, s):
if self.remain == 0:
return "",self.m2i(pkt, s)
else:
return s[-self.remain:],self.m2i(pkt, s[:-self.remain])
def randval(self):
return RandBin(RandNum(0,1200))
class PacketField(StrField):
holds_packets=1
def __init__(self, name, default, cls, remain=0, shift=0):
StrField.__init__(self, name, default, remain=remain, shift=shift)
self.cls = cls
def i2m(self, pkt, i):
return str(i)
def m2i(self, pkt, m):
return self.cls(m)
def getfield(self, pkt, s):
i = self.m2i(pkt, s)
remain = ""
if i.haslayer(Padding):
r = i.getlayer(Padding)
del(r.underlayer.payload)
remain = r.load
return remain,i
class PacketLenField(PacketField):
holds_packets=1
def __init__(self, name, default, cls, fld, shift=0):
PacketField.__init__(self, name, default, cls, shift=shift)
self.fld = fld
def getfield(self, pkt, s):
l = getattr(pkt, self.fld)
l -= self.shift
i = self.m2i(pkt, s[:l])
return s[l:],i
class PacketListField(PacketLenField):
islist = 1
holds_packets=1
def do_copy(self, x):
return map(lambda p:p.copy(), x)
def getfield(self, pkt, s):
l = getattr(pkt, self.fld)
l -= self.shift
lst = []
remain = s
while l>0 and len(remain)>0:
l -= 1
p = self.m2i(pkt,remain)
if Padding in p:
pad = p[Padding]
remain = pad.load
del(pad.underlayer.payload)
else:
remain = ""
lst.append(p)
return remain,lst
def addfield(self, pkt, s, val):
return s+"".join(map(str, val))
class StrFixedLenField(StrField):
def __init__(self, name, default, length, shift=0):
StrField.__init__(self, name, default, shift=shift)
self.length = length
def getfield(self, pkt, s):
return s[self.length:], self.m2i(pkt,s[:self.length])
def addfield(self, pkt, s, val):
return s+struct.pack("%is"%self.length,self.i2m(pkt, val))
def randval(self):
return RandBin(self.length)
class NetBIOSNameField(StrFixedLenField):
def __init__(self, name, default, length=31, shift=0):
StrFixedLenField.__init__(self, name, default, length, shift=shift)
def i2m(self, pkt, x):
if x is None:
x = ""
x += " "*(self.length/2)
x = x[:(self.length/2)]
x = "".join(map(lambda x: chr(0x41+(ord(x)>>4))+chr(0x41+(ord(x)&0xf)), x))
x = " "+x
return x
def m2i(self, pkt, x):
x = x.strip("\x00").strip(" ")
return "".join(map(lambda x,y: chr((((ord(x)-1)&0xf)<<4)+((ord(y)-1)&0xf)), x[::2],x[1::2]))
class StrLenField(StrField):
def __init__(self, name, default, fld, shift=0):
StrField.__init__(self, name, default, shift=shift)
self.fld = fld
def getfield(self, pkt, s):
l = getattr(pkt, self.fld)
l -= self.shift
return s[l:], self.m2i(pkt,s[:l])
class FieldListField(Field):
islist=1
def __init__(self, name, default, cls, fld, shift=0):
Field.__init__(self, name, default)
self.cls = cls
self.fld = fld
self.shift=shift
def i2len(self, pkt, val):
if val is None:
return self.shift
else:
return len(val)+self.shift
def i2m(self, pkt, val):
if val is None:
val = []
return val
def addfield(self, pkt, s, val):
val = self.i2m(pkt, val)
for v in val:
s = self.cls.addfield(pkt, s, v)
return s
def getfield(self, pkt, s):
l = getattr(pkt, self.fld)
# add the shift from the length field
f = pkt.get_field(self.fld)
l -= self.shift
val = []
for i in range(l):
s,v = self.cls.getfield(pkt, s)
val.append(v)
return s, val
class FieldLenField(Field):
def __init__(self, name, default, fld, fmt = "H"):
Field.__init__(self, name, default, fmt)
self.fld = fld
def i2m(self, pkt, x):
if x is None:
f = pkt.get_field(self.fld)
x = f.i2len(pkt,pkt.getfieldval(self.fld))
return x
# see http://www.iana.org/assignments/ipsec-registry for details
ISAKMPAttributeTypes= { "Encryption": (1, { "DES-CBC" : 1,
"IDEA-CBC" : 2,
"Blowfish-CBC" : 3,
"RC5-R16-B64-CBC" : 4,
"3DES-CBC" : 5,
"CAST-CBC" : 6,
"AES-CBC" : 7,
"CAMELLIA-CBC" : 8, }, 0),
"Hash": (2, { "MD5": 1,
"SHA": 2,
"Tiger": 3,
"SHA2-256": 4,
"SHA2-384": 5,
"SHA2-512": 6,}, 0),
"Authentication":(3, { "PSK": 1,
"DSS": 2,
"RSA Sig": 3,
"RSA Encryption": 4,
"RSA Encryption Revised": 5,
"ElGamal Encryption": 6,
"ElGamal Encryption Revised": 7,
"ECDSA Sig": 8,
"HybridInitRSA": 64221,
"HybridRespRSA": 64222,
"HybridInitDSS": 64223,
"HybridRespDSS": 64224,
"XAUTHInitPreShared": 65001,
"XAUTHRespPreShared": 65002,
"XAUTHInitDSS": 65003,
"XAUTHRespDSS": 65004,
"XAUTHInitRSA": 65005,
"XAUTHRespRSA": 65006,
"XAUTHInitRSAEncryption": 65007,
"XAUTHRespRSAEncryption": 65008,
"XAUTHInitRSARevisedEncryption": 65009,
"XAUTHRespRSARevisedEncryptio": 65010, }, 0),
"GroupDesc": (4, { "768MODPgr" : 1,
"1024MODPgr" : 2,
"EC2Ngr155" : 3,
"EC2Ngr185" : 4,
"1536MODPgr" : 5,
"2048MODPgr" : 14,
"3072MODPgr" : 15,
"4096MODPgr" : 16,
"6144MODPgr" : 17,
"8192MODPgr" : 18, }, 0),
"GroupType": (5, {"MODP": 1,
"ECP": 2,
"EC2N": 3}, 0),
"GroupPrime": (6, {}, 1),
"GroupGenerator1":(7, {}, 1),
"GroupGenerator2":(8, {}, 1),
"GroupCurveA": (9, {}, 1),
"GroupCurveB": (10, {}, 1),
"LifeType": (11, {"Seconds": 1,
"Kilobytes": 2, }, 0),
"LifeDuration": (12, {}, 1),
"PRF": (13, {}, 0),
"KeyLength": (14, {}, 0),
"FieldSize": (15, {}, 0),
"GroupOrder": (16, {}, 1),
}
# the name 'ISAKMPTransformTypes' is actually a misnomer (since the table
# holds info for all ISAKMP Attribute types, not just transforms, but we'll
# keep it for backwards compatibility... for now at least
ISAKMPTransformTypes = ISAKMPAttributeTypes
ISAKMPTransformNum = {}
for n in ISAKMPTransformTypes:
val = ISAKMPTransformTypes[n]
tmp = {}
for e in val[1]:
tmp[val[1][e]] = e
ISAKMPTransformNum[val[0]] = (n,tmp, val[2])
del(n)
del(e)
del(tmp)
del(val)
class ISAKMPTransformSetField(StrLenField):
islist=1
def type2num(self, (typ,val)):
type_val,enc_dict,tlv = ISAKMPTransformTypes.get(typ, (typ,{},0))
val = enc_dict.get(val, val)
s = ""
if (val & ~0xffff):
if not tlv:
warning("%r should not be TLV but is too big => using TLV encoding" % typ)
n = 0
while val:
s = chr(val&0xff)+s
val >>= 8
n += 1
val = n
else:
type_val |= 0x8000
return struct.pack("!HH",type_val, val)+s
def num2type(self, typ, enc):
val = ISAKMPTransformNum.get(typ,(typ,{}))
enc = val[1].get(enc,enc)
return (val[0],enc)
def i2m(self, pkt, i):
if i is None:
return ""
i = map(self.type2num, i)
return "".join(i)
def m2i(self, pkt, m):
# I try to ensure that we don't read off the end of our packet based
# on bad length fields we're provided in the packet. There are still
# conditions where struct.unpack() may not get enough packet data, but
# worst case that should result in broken attributes (which would
# be expected). (wam)
lst = []
while len(m) >= 4:
trans_type, = struct.unpack("!H", m[:2])
is_tlv = not (trans_type & 0x8000)
if is_tlv:
# We should probably check to make sure the attribute type we
# are looking at is allowed to have a TLV format and issue a
# warning if we're given an TLV on a basic attribute.
value_len, = struct.unpack("!H", m[2:4])
if value_len+4 > len(m):
warning("Bad length for ISAKMP tranform type=%#6x" % trans_type)
value = m[4:4+value_len]
value = reduce(lambda x,y: (x<<8L)|y, struct.unpack("!%s" % ("B"*len(value),), value),0)
else:
trans_type &= 0x7fff
value_len=0
value, = struct.unpack("!H", m[2:4])
m=m[4+value_len:]
lst.append(self.num2type(trans_type, value))
if len(m) > 0:
warning("Extra bytes after ISAKMP transform dissection [%r]" % m)
return lst
def getfield(self, pkt, s):
l = getattr(pkt, self.fld)
l -= self.shift
i = self.m2i(pkt, s[:l])
return s[l:],i
class StrNullField(StrField):
def addfield(self, pkt, s, val):
return s+self.i2m(pkt, val)+"\x00"
def getfield(self, pkt, s):
l = s.find("\x00")
if l < 0:
#XXX \x00 not found
return "",s
return s[l+1:],self.m2i(pkt, s[:l])
def randval(self):
return RandTermString(RandNum(0,1200),"\x00")
class StrStopField(StrField):
def __init__(self, name, default, stop, additionnal=0):
Field.__init__(self, name, default)
self.stop=stop
self.additionnal=additionnal
def getfield(self, pkt, s):
l = s.find(self.stop)
if l < 0:
return "",s
# raise Scapy_Exception,"StrStopField: stop value [%s] not found" %stop
l += len(self.stop)+self.additionnal
return s[l:],s[:l]
def randval(self):
return RandTermString(RandNum(0,1200),self.stop)
class LenField(Field):
def i2m(self, pkt, x):
if x is None:
x = len(pkt.payload)
return x
class BCDFloatField(Field):
def i2m(self, pkt, x):
return int(256*x)
def m2i(self, pkt, x):
return x/256.0
class BitField(Field):
def __init__(self, name, default, size):
Field.__init__(self, name, default)
self.size = size
def addfield(self, pkt, s, val):
if val is None:
val = 0
if type(s) is tuple:
s,bitsdone,v = s
else:
bitsdone = 0
v = 0
v <<= self.size
v |= val & ((1L<<self.size) - 1)
bitsdone += self.size
while bitsdone >= 8:
bitsdone -= 8
s = s+struct.pack("!B", v >> bitsdone)
v &= (1L<<bitsdone)-1
if bitsdone:
return s,bitsdone,v
else:
return s
def getfield(self, pkt, s):
if type(s) is tuple:
s,bn = s
else:
bn = 0
# we don't want to process all the string
nb_bytes = (self.size+bn-1)/8 + 1
w = s[:nb_bytes]
# split the substring byte by byte
bytes = struct.unpack('!%dB' % nb_bytes , w)
b = 0L
for c in range(nb_bytes):
b |= long(bytes[c]) << (nb_bytes-c-1)*8
# get rid of high order bits
b &= (1L << (nb_bytes*8-bn)) - 1
# remove low order bits
b = b >> (nb_bytes*8 - self.size - bn)
bn += self.size
s = s[bn/8:]
bn = bn%8
if bn:
return (s,bn),b
else:
return s,b
def randval(self):
return RandNum(0,2**self.size-1)
class XBitField(BitField):
def i2repr(self, pkt, x):
return lhex(self.i2h(pkt,x))
class EnumField(Field):
def __init__(self, name, default, enum, fmt = "H"):
i2s = self.i2s = {}
s2i = self.s2i = {}
if type(enum) is list:
keys = xrange(len(enum))
else:
keys = enum.keys()
if filter(lambda x: type(x) is str, keys):
i2s,s2i = s2i,i2s
for k in keys:
i2s[k] = enum[k]
s2i[enum[k]] = k
Field.__init__(self, name, default, fmt)
def any2i_one(self, pkt, x):
if type(x) is str:
x = self.s2i[x]
return x
def i2repr_one(self, pkt, x):
if self not in conf.noenum and x in self.i2s:
return self.i2s[x]
return repr(x)
def any2i(self, pkt, x):
if type(x) is list:
return map(lambda z,pkt=pkt:self.any2i_one(pkt,z), x)
else:
return self.any2i_one(pkt,x)
def i2repr(self, pkt, x):
if type(x) is list:
return map(lambda z,pkt=pkt:self.i2repr_one(pkt,z), x)
else:
return self.i2repr_one(pkt,x)
class CharEnumField(EnumField):
def __init__(self, name, default, enum, fmt = "1s"):
EnumField.__init__(self, name, default, enum, fmt)
k = self.i2s.keys()
if k and len(k[0]) != 1:
self.i2s,self.s2i = self.s2i,self.i2s
def any2i_one(self, pkt, x):
if len(x) != 1:
x = self.s2i[x]
return x
class BitEnumField(BitField,EnumField):
def __init__(self, name, default, size, enum):
EnumField.__init__(self, name, default, enum)
self.size = size
def any2i(self, pkt, x):
return EnumField.any2i(self, pkt, x)
def i2repr(self, pkt, x):
return EnumField.i2repr(self, pkt, x)
class ShortEnumField(EnumField):
def __init__(self, name, default, enum):
EnumField.__init__(self, name, default, enum, "H")
class LEShortEnumField(EnumField):
def __init__(self, name, default, enum):
EnumField.__init__(self, name, default, enum, "<H")
class ByteEnumField(EnumField):
def __init__(self, name, default, enum):
EnumField.__init__(self, name, default, enum, "B")
class IntEnumField(EnumField):
def __init__(self, name, default, enum):
EnumField.__init__(self, name, default, enum, "I")
class LEIntEnumField(EnumField):
def __init__(self, name, default, enum):
EnumField.__init__(self, name, default, enum, "<I")
class XShortEnumField(ShortEnumField):
def i2repr_one(self, pkt, x):
if self not in conf.noenum and x in self.i2s:
return self.i2s[x]
return lhex(x)
# Little endian long field
class LELongField(Field):
def __init__(self, name, default):
Field.__init__(self, name, default, "<Q")
# Little endian fixed length field
class LEFieldLenField(FieldLenField):
def __init__(self, name, default, fld, fmt = "<H"):
FieldLenField.__init__(self, name, default, fld=fld, fmt=fmt)
class FlagsField(BitField):
def __init__(self, name, default, size, names):
BitField.__init__(self, name, default, size)
self.multi = type(names) is list
if self.multi:
self.names = map(lambda x:[x], names)
else:
self.names = names
def any2i(self, pkt, x):
if type(x) is str:
if self.multi:
x = map(lambda y:[y], x.split("+"))
y = 0
for i in x:
y |= 1 << self.names.index(i)
x = y
return x
def i2repr(self, pkt, x):
if self.multi:
r = []
else:
r = ""
i=0
while x:
if x & 1:
r += self.names[i]
i += 1
x >>= 1
if self.multi:
r = "+".join(r)
return r
class IPoptionsField(StrField):
def i2m(self, pkt, x):
return x+"\x00"*(3-((len(x)+3)%4))
def getfield(self, pkt, s):
opsz = (pkt.ihl-5)*4
if opsz < 0:
warning("bad ihl (%i). Assuming ihl=5"%pkt.ihl)
opsz = 0
return s[opsz:],s[:opsz]
def randval(self):
return RandBin(RandNum(0,39))
TCPOptions = (
{ 0 : ("EOL",None),
1 : ("NOP",None),
2 : ("MSS","!H"),
3 : ("WScale","!B"),
4 : ("SAckOK",None),
5 : ("SAck","!"),
8 : ("Timestamp","!II"),
14 : ("AltChkSum","!BH"),
15 : ("AltChkSumOpt",None)
},
{ "EOL":0,
"NOP":1,
"MSS":2,
"WScale":3,
"SAckOK":4,
"SAck":5,
"Timestamp":8,
"AltChkSum":14,
"AltChkSumOpt":15,
} )
class TCPOptionsField(StrField):
islist=1
def getfield(self, pkt, s):
opsz = (pkt.dataofs-5)*4
if opsz < 0:
warning("bad dataofs (%i). Assuming dataofs=5"%pkt.dataofs)
opsz = 0
return s[opsz:],self.m2i(pkt,s[:opsz])
def m2i(self, pkt, x):
opt = []
while x:
onum = ord(x[0])
if onum == 0:
opt.append(("EOL",None))
x=x[1:]
break
if onum == 1:
opt.append(("NOP",None))
x=x[1:]
continue
olen = ord(x[1])
if olen < 2:
warning("Malformed TCP option (announced length is %i)" % olen)
olen = 2
oval = x[2:olen]
if TCPOptions[0].has_key(onum):
oname, ofmt = TCPOptions[0][onum]
if onum == 5: #SAck
ofmt += "%iI" % (len(oval)/4)
if ofmt and struct.calcsize(ofmt) == len(oval):
oval = struct.unpack(ofmt, oval)
if len(oval) == 1:
oval = oval[0]
opt.append((oname, oval))
else:
opt.append((onum, oval))
x = x[olen:]
return opt
def i2m(self, pkt, x):
opt = ""
for oname,oval in x:
if type(oname) is str:
if oname == "NOP":
opt += "\x01"
continue
elif oname == "EOL":
opt += "\x00"
continue
elif TCPOptions[1].has_key(oname):
onum = TCPOptions[1][oname]
ofmt = TCPOptions[0][onum][1]
if onum == 5: #SAck
ofmt += "%iI" % len(oval)
if ofmt is not None:
if type(oval) is not tuple:
oval = (oval,)
oval = struct.pack(ofmt, *oval)
else:
warning("option [%s] unknown. Skipped."%oname)
continue
else:
onum = oname
if type(oval) is not str:
warning("option [%i] is not string."%onum)
continue
opt += chr(onum)+chr(2+len(oval))+oval
return opt+"\x00"*(3-((len(opt)+3)%4))
def randval(self):
return [] # XXX
class DNSStrField(StrField):
def i2m(self, pkt, x):
x = x.split(".")
x = map(lambda y: chr(len(y))+y, x)
x = "".join(x)
if x[-1] != "\x00":
x += "\x00"
return x
def getfield(self, pkt, s):
n = ""
while 1:
l = ord(s[0])
s = s[1:]
if not l:
break
if l & 0xc0:
raise Scapy_Exception("DNS message can't be compressed at this point!")
else:
n += s[:l]+"."
s = s[l:]
return s, n
class DNSRRCountField(ShortField):
holds_packets=1
def __init__(self, name, default, rr):
ShortField.__init__(self, name, default)
self.rr = rr
def _countRR(self, pkt):
x = getattr(pkt,self.rr)
i = 0
while isinstance(x, DNSRR) or isinstance(x, DNSQR):
x = x.payload
i += 1
return i
def i2m(self, pkt, x):
if x is None:
x = self._countRR(pkt)
return x
def i2h(self, pkt, x):
if x is None:
x = self._countRR(pkt)
return x
def DNSgetstr(s,p):
name = ""
q = 0
jpath = [p]
while 1:
if p >= len(s):
warning("DNS RR prematured end (ofs=%i, len=%i)"%(p,len(s)))
break
l = ord(s[p])
p += 1
if l & 0xc0:
if not q:
q = p+1
if p >= len(s):
warning("DNS incomplete jump token at (ofs=%i)" % p)
break
p = ((l & 0x3f) << 8) + ord(s[p]) - 12
if p in jpath:
warning("DNS decompression loop detected")
break
jpath.append(p)
continue
elif l > 0:
name += s[p:p+l]+"."
p += l
continue
break
if q:
p = q
return name,p
class DNSRRField(StrField):
holds_packets=1
def __init__(self, name, countfld, passon=1):
StrField.__init__(self, name, None)
self.countfld = countfld
self.passon = passon
def i2m(self, pkt, x):
if x is None:
return ""
return str(x)
def decodeRR(self, name, s, p):
ret = s[p:p+10]
type,cls,ttl,rdlen = struct.unpack("!HHIH", ret)
p += 10
rr = DNSRR("\x00"+ret+s[p:p+rdlen])
if rr.type in [2, 3, 4, 5]:
rr.rdata = DNSgetstr(s,p)[0]
del(rr.rdlen)
p += rdlen
rr.rrname = name
return rr,p
def getfield(self, pkt, s):
if type(s) is tuple :
s,p = s
else:
p = 0
ret = None
c = getattr(pkt, self.countfld)
if c > len(s):
warning("wrong value: DNS.%s=%i" % (self.countfld,c))
return s,""
while c:
c -= 1
name,p = DNSgetstr(s,p)
rr,p = self.decodeRR(name, s, p)
if ret is None:
ret = rr
else:
ret.add_payload(rr)
if self.passon:
return (s,p),ret
else:
return s[p:],ret
class DNSQRField(DNSRRField):
holds_packets=1
def decodeRR(self, name, s, p):
ret = s[p:p+4]
p += 4
rr = DNSQR("\x00"+ret)
rr.qname = name
return rr,p
class RDataField(StrLenField):
def m2i(self, pkt, s):
family = None
if pkt.type == 1:
family = socket.AF_INET
elif pkt.type == 28:
family = socket.AF_INET6
elif pkt.type == 12:
s = DNSgetstr(s, 0)[0]
if family is not None:
s = inet_ntop(family, s)
return s
def i2m(self, pkt, s):
if pkt.type == 1:
if s:
s = inet_aton(s)
elif pkt.type == 28:
if s:
s = inet_pton(socket.AF_INET6, s)
elif pkt.type in [2,3,4,5]:
s = "".join(map(lambda x: chr(len(x))+x, s.split(".")))
if ord(s[-1]):
s += "\x00"
return s
class RDLenField(Field):
def __init__(self, name):
Field.__init__(self, name, None, "H")
def i2m(self, pkt, x):
if x is None:
rdataf = pkt.get_field("rdata")
x = len(rdataf.i2m(pkt, pkt.rdata))
return x
def i2h(self, pkt, x):
if x is None:
rdataf = pkt.get_field("rdata")
x = len(rdataf.i2m(pkt, pkt.rdata))
return x
# seconds between 01-01-1900 and 01-01-1970
ntp_basetime = 2208988800
class TimeStampField(BitField):
def __init__(self, name, default, size):
BitField.__init__(self, name, default, size)
self.size = size
def getfield(self, pkt, s):
s,timestamp = BitField.getfield(self, pkt, s)
if timestamp:
# timestamp is a 64 bits field :
# + first 32 bits : number of seconds since 1900
# + last 32 bits : fraction part
timestamp >>= 32
timestamp -= ntp_basetime
from time import gmtime, strftime
b = strftime("%a, %d %b %Y %H:%M:%S +0000", gmtime(timestamp))
else:
b = 'None'
return s, b
def addfield(self, pkt, s, val):
t = -1
if type(val) is str:
from time import strptime, mktime
t = int(mktime(strptime(val))) + ntp_basetime + 3600
else:
if val == -1:
from time import time
t = int(time()) + ntp_basetime
else:
t = val
t <<= 32
return BitField.addfield(self,pkt,s, t)
class FloatField(BitField):
def getfield(self, pkt, s):
s,b = BitField.getfield(self, pkt, s)
# fraction point between bits 15 and 16.
sec = b >> 16
frac = b & (1L << (32+1)) - 1
frac /= 65536.0
b = sec+frac
return s,b
class Dot11SCField(LEShortField):
def is_applicable(self, pkt):
return pkt.type != 1 # control frame
def addfield(self, pkt, s, val):
if self.is_applicable(pkt):
return LEShortField.addfield(self, pkt, s, val)
else:
return s
def getfield(self, pkt, s):
if self.is_applicable(pkt):
return LEShortField.getfield(self, pkt, s)
else:
return s,None
#####################
#### ASN1 Fields ####
#####################
class ASN1F_badsequence(Exception):
pass
class ASN1F_element:
pass
class ASN1F_field(ASN1F_element):
holds_packets=0
islist=0
ASN1_tag = ASN1_Class_UNIVERSAL.ANY
def __init__(self, name, default):
self.name = name
self.default = default
def i2repr(self, pkt, x):
if x is None:
x = 0
return repr(x)
def i2h(self, pkt, x):
if x is None:
x = 0
return x
def any2i(self, pkt, x):
return x
def m2i(self, pkt, x):
return self.ASN1_tag.get_codec(pkt.ASN1_codec).safedec(x)
def i2m(self, pkt, x):
if x is None:
x = 0
if isinstance(x, ASN1_Object):
if ( self.ASN1_tag == ASN1_Class_UNIVERSAL.ANY
or x.tag == ASN1_Class_UNIVERSAL.RAW
or x.tag == ASN1_Class_UNIVERSAL.ERROR
or self.ASN1_tag == x.tag ):
return x.enc(pkt.ASN1_codec)
else:
raise ASN1_Error("Encoding Error: got %r instead of an %r for field [%s]" % (x, self.ASN1_tag, self.name))
return self.ASN1_tag.get_codec(pkt.ASN1_codec).enc(x)
def do_copy(self, x):
if hasattr(x, "copy"):
return x.copy()
if type(x) is list:
x = x[:]
for i in xrange(len(x)):
if isinstance(x[i], Packet):
x[i] = x[i].copy()
return x
def build(self, pkt):
return self.i2m(pkt, getattr(pkt, self.name))
def set_val(self, pkt, val):
setattr(pkt, self.name, val)
def dissect(self, pkt, s):
v,s = self.m2i(pkt, s)
self.set_val(pkt, v)
return s
def get_fields_list(self):
return [self]
def __hash__(self):
return hash(self.name)
def __str__(self):
return self.name
def __eq__(self, other):
return self.name == other
def __repr__(self):
return self.name
def randval(self):
return RandInt()
class ASN1F_INTEGER(ASN1F_field):
ASN1_tag= ASN1_Class_UNIVERSAL.INTEGER
def randval(self):
return RandNum(-2**64, 2**64)
class ASN1F_enum_INTEGER(ASN1F_INTEGER):
def __init__(self, name, default, enum):
ASN1F_INTEGER.__init__(self, name, default)
i2s = self.i2s = {}
s2i = self.s2i = {}
if type(enum) is list:
keys = xrange(len(enum))
else:
keys = enum.keys()
if filter(lambda x: type(x) is str, keys):
i2s,s2i = s2i,i2s
for k in keys:
i2s[k] = enum[k]
s2i[enum[k]] = k
def any2i_one(self, pkt, x):
if type(x) is str:
x = self.s2i[x]
return x
def i2repr_one(self, pkt, x):
return self.i2s.get(x, repr(x))
def any2i(self, pkt, x):
if type(x) is list:
return map(lambda z,pkt=pkt:self.any2i_one(pkt,z), x)
else:
return self.any2i_one(pkt,x)
def i2repr(self, pkt, x):
if type(x) is list:
return map(lambda z,pkt=pkt:self.i2repr_one(pkt,z), x)
else:
return self.i2repr_one(pkt,x)
class ASN1F_STRING(ASN1F_field):
ASN1_tag = ASN1_Class_UNIVERSAL.STRING
def randval(self):
return RandString(RandNum(0, 1000))
class ASN1F_OID(ASN1F_field):
ASN1_tag = ASN1_Class_UNIVERSAL.OID
def randval(self):
return RandOID()
class ASN1F_SEQUENCE(ASN1F_field):
ASN1_tag = ASN1_Class_UNIVERSAL.SEQUENCE
def __init__(self, *seq, **kargs):
if "ASN1_tag" in kargs:
self.ASN1_tag = kargs["ASN1_tag"]
self.seq = seq
def __repr__(self):
return "<%s%r>" % (self.__class__.__name__,self.seq,)
def get_fields_list(self):
return reduce(lambda x,y: x+y.get_fields_list(), self.seq, [])
def build(self, pkt):
s = reduce(lambda x,y: x+y.build(pkt), self.seq, "")
return self.i2m(pkt, s)
def dissect(self, pkt, s):
codec = self.ASN1_tag.get_codec(pkt.ASN1_codec)
try:
i,s,remain = codec.check_type_check_len(s)
for obj in self.seq:
s = obj.dissect(pkt,s)
if s:
warning("Too many bytes to decode sequence: [%r]" % s) # XXX not reversible!
return remain
except ASN1_Error,e:
raise ASN1F_badsequence(e)
class ASN1F_SEQUENCE_OF(ASN1F_SEQUENCE):
holds_packets = 1
islist = 1
def __init__(self, name, default, asn1pkt, ASN1_tag=0x30):
self.asn1pkt = asn1pkt
self.tag = chr(ASN1_tag)
self.name = name
self.default = default
def get_fields_list(self):
return [self]
def build(self, pkt):
val = getattr(pkt, self.name)
if isinstance(val, ASN1_Object) and val.tag == ASN1_Class_UNIVERSAL.RAW:
s = val
else:
s = "".join(map(str, val ))
return self.i2m(pkt, s)
def dissect(self, pkt, s):
codec = self.ASN1_tag.get_codec(pkt.ASN1_codec)
i,s1,remain = codec.check_type_check_len(s)
lst = []
while s1:
try:
p = self.asn1pkt(s1)
except ASN1F_badsequence:
lst.append(Raw(s1))
break
lst.append(p)
if Raw in p:
s1 = p[Raw].load
del(p[Raw].underlayer.payload)
else:
break
self.set_val(pkt, lst)
return remain
def randval(self):
return fuzz(self.asn1pkt())
class ASN1F_PACKET(ASN1F_field):
holds_packets = 1
def __init__(self, name, default, cls):
ASN1_field.__init__(self, name, default)
self.cls = cls
def i2m(self, pkt, x):
if x is None:
x = ""
return str(x)
def extract_packet(self, cls, x):
try:
c = cls(x)
except ASN1F_badsequence:
c = Raw(x)
cpad = c[Padding]
x = ""
if cpad is not None:
x = cpad.load
del(cpad.underlayer.payload)
return c,x
def m2i(self, pkt, x):
return self.extract_packet(self.cls, x)
class ASN1F_CHOICE(ASN1F_PACKET):
ASN1_tag = ASN1_Class_UNIVERSAL.NONE
def __init__(self, name, default, *args):
self.name=name
self.choice = {}
for p in args:
self.choice[p.ASN1_root.ASN1_tag] = p
# self.context=context
self.default=default
def m2i(self, pkt, x):
if len(x) == 0:
return Raw(),""
raise ASN1_Error("ASN1F_CHOICE: got empty string")
if ord(x[0]) not in self.choice:
return Raw(x),"" # XXX return RawASN1 packet ? Raise error
raise ASN1_Error("Decoding Error: choice [%i] not found in %r" % (ord(x[0]), self.choice.keys()))
z = ASN1F_PACKET.extract_packet(self, self.choice[ord(x[0])], x)
return z
def randval(self):
return RandChoice(*map(lambda x:fuzz(x()), self.choice.values()))
###########################
## Packet abstract class ##
###########################
class Packet_metaclass(type):
def __new__(cls, name, bases, dct):
newcls = super(Packet_metaclass, cls).__new__(cls, name, bases, dct)
for f in newcls.fields_desc:
f.register_owner(newcls)
return newcls
def __getattr__(self, attr):
for k in self.fields_desc:
if k.name == attr:
return k
raise AttributeError(attr)
class NewDefaultValues(Packet_metaclass):
"""NewDefaultValues metaclass. Example usage:
class MyPacket(Packet):
fields_desc = [ StrField("my_field", "my default value"), ]
class MyPacket_variant(MyPacket):
__metaclass__ = NewDefaultValues
my_field = "my new default value"
"""
def __new__(cls, name, bases, dct):
fields = None
for b in bases:
if hasattr(b,"fields_desc"):
fields = b.fields_desc
break
if fields is None:
raise Scapy_Exception("No fields_desc in superclasses")
new_fields = []
for f in fields:
if f.name in dct:
f = f.copy()
f.default = dct[f.name]
del(dct[f.name])
new_fields.append(f)
dct["fields_desc"] = new_fields
return super(NewDefaultValues, cls).__new__(cls, name, bases, dct)
class Packet(Gen):
__metaclass__ = Packet_metaclass
name=None
fields_desc = []
aliastypes = []
overload_fields = {}
underlayer = None
payload_guess = []
initialized = 0
show_indent=1
def from_hexcap(cls):
return cls(import_hexcap())
from_hexcap = classmethod(from_hexcap)
def __init__(self, _pkt="", post_transform=None, _internal=0, _underlayer=None, **fields):
self.time = time.time()
if self.name is None:
self.name = self.__class__.__name__
self.aliastypes = [ self.__class__ ] + self.aliastypes
self.default_fields = {}
self.overloaded_fields = {}
self.fields={}
self.fieldtype={}
self.packetfields=[]
self.__dict__["payload"] = NoPayload()
self.init_fields()
self.underlayer = _underlayer
self.initialized = 1
if _pkt:
self.dissect(_pkt)
if not _internal:
self.dissection_done(self)
for f in fields.keys():
self.fields[f] = self.get_field(f).any2i(self,fields[f])
if type(post_transform) is list:
self.post_transforms = post_transform
elif post_transform is None:
self.post_transforms = []
else:
self.post_transforms = [post_transform]
def init_fields(self):
self.do_init_fields(self.fields_desc)
def do_init_fields(self, flist):
for f in flist:
self.default_fields[f.name] = f.default
self.fieldtype[f.name] = f
if f.holds_packets:
self.packetfields.append(f)
def dissection_done(self,pkt):
"""DEV: will be called after a dissection is completed"""
self.post_dissection(pkt)
self.payload.dissection_done(pkt)
def post_dissection(self, pkt):
"""DEV: is called after the dissection of the whole packet"""
pass
def get_field(self, fld):
"""DEV: returns the field instance from the name of the field"""
return self.fieldtype[fld]
def add_payload(self, payload):
if payload is None:
return
elif not isinstance(self.payload, NoPayload):
self.payload.add_payload(payload)
else:
if isinstance(payload, Packet):
self.__dict__["payload"] = payload
payload.add_underlayer(self)
for t in self.aliastypes:
if payload.overload_fields.has_key(t):
self.overloaded_fields = payload.overload_fields[t]
break
elif type(payload) is str:
self.__dict__["payload"] = Raw(load=payload)
else:
raise TypeError("payload must be either 'Packet' or 'str', not [%s]" % repr(payload))
def remove_payload(self):
self.payload.remove_underlayer(self)
self.__dict__["payload"] = NoPayload()
self.overloaded_fields = {}
def add_underlayer(self, underlayer):
self.underlayer = underlayer
def remove_underlayer(self,other):
self.underlayer = None
def copy(self):
"""Returns a deep copy of the instance."""
clone = self.__class__()
clone.fields = self.fields.copy()
for k in clone.fields:
clone.fields[k]=self.get_field(k).do_copy(clone.fields[k])
clone.default_fields = self.default_fields.copy()
clone.overloaded_fields = self.overloaded_fields.copy()
clone.overload_fields = self.overload_fields.copy()
clone.underlayer=self.underlayer
clone.post_transforms=self.post_transforms[:]
clone.__dict__["payload"] = self.payload.copy()
clone.payload.add_underlayer(clone)
return clone
def getfieldval(self, attr):
for f in self.fields, self.overloaded_fields, self.default_fields:
if f.has_key(attr):
return f[attr]
return self.payload.getfieldval(attr)
def getfield_and_val(self, attr):
for f in self.fields, self.overloaded_fields, self.default_fields:
if f.has_key(attr):
return self.get_field(attr),f[attr]
return self.payload.getfield_and_val(attr)
def __getattr__(self, attr):
if self.initialized:
fld,v = self.getfield_and_val(attr)
if fld is not None:
return fld.i2h(self, v)
return v
raise AttributeError(attr)
def __setattr__(self, attr, val):
if self.initialized:
if self.default_fields.has_key(attr):
fld = self.get_field(attr)
if fld is None:
any2i = lambda x,y: y
else:
any2i = fld.any2i
self.fields[attr] = any2i(self, val)
elif attr == "payload":
self.remove_payload()
self.add_payload(val)
else:
self.__dict__[attr] = val
else:
self.__dict__[attr] = val
def __delattr__(self, attr):
if self.initialized:
if self.fields.has_key(attr):
del(self.fields[attr])
return
elif self.default_fields.has_key(attr):
return
elif attr == "payload":
self.remove_payload()
return
if self.__dict__.has_key(attr):
del(self.__dict__[attr])
else:
raise AttributeError(attr)
def __repr__(self):
s = ""
ct = conf.color_theme
for f in self.fields_desc:
if f.name in self.fields:
val = f.i2repr(self, self.fields[f.name])
elif f.name in self.overloaded_fields:
val = f.i2repr(self, self.overloaded_fields[f.name])
else:
continue
if isinstance(f, Emph):
ncol = ct.emph_field_name
vcol = ct.emph_field_value
else:
ncol = ct.field_name
vcol = ct.field_value
s += " %s%s%s" % (ncol(f.name),
ct.punct("="),
vcol(val))
return "%s%s %s %s%s%s"% (ct.punct("<"),
ct.layer_name(self.__class__.__name__),
s,
ct.punct("|"),
repr(self.payload),
ct.punct(">"))
def __str__(self):
return self.__iter__().next().build()
def __div__(self, other):
if isinstance(other, Packet):
cloneA = self.copy()
cloneB = other.copy()
cloneA.add_payload(cloneB)
return cloneA
elif type(other) is str:
return self/Raw(load=other)
else:
return other.__rdiv__(self)
def __rdiv__(self, other):
if type(other) is str:
return Raw(load=other)/self
else:
raise TypeError
def __mul__(self, other):
if type(other) is int:
return [self]*other
else:
raise TypeError
def __rmul__(self,other):
return self.__mul__(other)
def __nonzero__(self):
return True
def __len__(self):
return len(self.__str__())
def do_build(self):
p=""
for f in self.fields_desc:
p = f.addfield(self, p, self.getfieldval(f.name))
return p
def post_build(self, pkt, pay):
"""DEV: called right after the current layer is build."""
return pkt+pay
def build_payload(self):
return self.payload.build(internal=1)
def build(self,internal=0):
pkt = self.do_build()
for t in self.post_transforms:
pkt = t(pkt)
pay = self.build_payload()
try:
p = self.post_build(pkt,pay)
except TypeError:
log_runtime.error("API changed! post_build() now takes 2 arguments. Compatibility is only assured for a short transition time")
p = self.post_build(pkt+pay)
if not internal:
pad = self.payload.getlayer(Padding)
if pad:
p += pad.build()
return p
def do_build_ps(self):
p=""
pl = []
q=""
for f in self.fields_desc:
p = f.addfield(self, p, self.getfieldval(f.name) )
if type(p) is str:
r = p[len(q):]
q = p
else:
r = ""
pl.append( (f, f.i2repr(self,self.getfieldval(f.name)), r) )
pkt,lst = self.payload.build_ps(internal=1)
p += pkt
lst.append( (self, pl) )
return p,lst
def build_ps(self,internal=0):
p,lst = self.do_build_ps()
# if not internal:
# pkt = self
# while pkt.haslayer(Padding):
# pkt = pkt.getlayer(Padding)
# lst.append( (pkt, [ ("loakjkjd", pkt.load, pkt.load) ] ) )
# p += pkt.load
# pkt = pkt.payload
return p,lst
def psdump(self, filename=None, **kargs):
"""psdump(filename=None, layer_shift=0, rebuild=1)
Creates an EPS file describing a packet. If filename is not provided a temporary file is created and gs is called."""
canvas = self.canvas_dump(**kargs)
if filename is None:
fname = "/tmp/scapy.%i"%os.getpid()
canvas.writeEPSfile(fname)
os.system("%s '%s.eps' &" % (conf.prog.psreader,fname))
else:
canvas.writeEPSfile(filename)
def pdfdump(self, filename=None, **kargs):
"""pdfdump(filename=None, layer_shift=0, rebuild=1)
Creates a PDF file describing a packet. If filename is not provided a temporary file is created and xpdf is called."""
canvas = self.canvas_dump(**kargs)
if filename is None:
fname = "/tmp/scapy.%i"%os.getpid()
canvas.writePDFfile(fname)
os.system("%s '%s.pdf' &" % (conf.prog.pdfreader,fname))
else:
canvas.writePDFfile(filename)
def canvas_dump(self, layer_shift=0, rebuild=1):
canvas = pyx.canvas.canvas()
if rebuild:
p,t = self.__class__(str(self)).build_ps()
else:
p,t = self.build_ps()
YTXT=len(t)
for n,l in t:
YTXT += len(l)
YTXT = float(YTXT)
YDUMP=YTXT
XSTART = 1
XDSTART = 10
y = 0.0
yd = 0.0
xd = 0
XMUL= 0.55
YMUL = 0.4
backcolor=colgen(0.6, 0.8, 1.0, trans=pyx.color.rgb)
forecolor=colgen(0.2, 0.5, 0.8, trans=pyx.color.rgb)
# backcolor=makecol(0.376, 0.729, 0.525, 1.0)
def hexstr(x):
s = []
for c in x:
s.append("%02x" % ord(c))
return " ".join(s)
def make_dump_txt(x,y,txt):
return pyx.text.text(XDSTART+x*XMUL, (YDUMP-y)*YMUL, r"\tt{%s}"%hexstr(txt), [pyx.text.size.Large])
def make_box(o):
return pyx.box.rect(o.left(), o.bottom(), o.width(), o.height(), relcenter=(0.5,0.5))
def make_frame(lst):
if len(lst) == 1:
b = lst[0].bbox()
b.enlarge(pyx.unit.u_pt)
return b.path()
else:
fb = lst[0].bbox()
fb.enlarge(pyx.unit.u_pt)
lb = lst[-1].bbox()
lb.enlarge(pyx.unit.u_pt)
if len(lst) == 2 and fb.left() > lb.right():
return pyx.path.path(pyx.path.moveto(fb.right(), fb.top()),
pyx.path.lineto(fb.left(), fb.top()),
pyx.path.lineto(fb.left(), fb.bottom()),
pyx.path.lineto(fb.right(), fb.bottom()),
pyx.path.moveto(lb.left(), lb.top()),
pyx.path.lineto(lb.right(), lb.top()),
pyx.path.lineto(lb.right(), lb.bottom()),
pyx.path.lineto(lb.left(), lb.bottom()))
else:
# XXX
gb = lst[1].bbox()
if gb != lb:
gb.enlarge(pyx.unit.u_pt)
kb = lst[-2].bbox()
if kb != gb and kb != lb:
kb.enlarge(pyx.unit.u_pt)
return pyx.path.path(pyx.path.moveto(fb.left(), fb.top()),
pyx.path.lineto(fb.right(), fb.top()),
pyx.path.lineto(fb.right(), kb.bottom()),
pyx.path.lineto(lb.right(), kb.bottom()),
pyx.path.lineto(lb.right(), lb.bottom()),
pyx.path.lineto(lb.left(), lb.bottom()),
pyx.path.lineto(lb.left(), gb.top()),
pyx.path.lineto(fb.left(), gb.top()),
pyx.path.closepath(),)
def make_dump(s, shift=0, y=0, col=None, bkcol=None, larg=16):
c = pyx.canvas.canvas()
tlist = []
while s:
dmp,s = s[:larg-shift],s[larg-shift:]
txt = make_dump_txt(shift, y, dmp)
tlist.append(txt)
shift += len(dmp)
if shift >= 16:
shift = 0
y += 1
if col is None:
col = pyx.color.rgb.red
if bkcol is None:
col = pyx.color.rgb.white
c.stroke(make_frame(tlist),[col,pyx.deco.filled([bkcol]),pyx.style.linewidth.Thick])
for txt in tlist:
c.insert(txt)
return c, tlist[-1].bbox(), shift, y
last_shift,last_y=0,0.0
while t:
bkcol = backcolor.next()
proto,fields = t.pop()
y += 0.5
pt = pyx.text.text(XSTART, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % proto.name, [ pyx.text.size.Large])
y += 1
ptbb=pt.bbox()
ptbb.enlarge(pyx.unit.u_pt*2)
canvas.stroke(ptbb.path(),[pyx.color.rgb.black, pyx.deco.filled([bkcol])])
canvas.insert(pt)
for fname, fval, fdump in fields:
col = forecolor.next()
ft = pyx.text.text(XSTART, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % tex_escape(fname.name))
if fval is not None:
if len(fval) > 18:
fval = fval[:18]+"[...]"
else:
fval=""
vt = pyx.text.text(XSTART+3, (YTXT-y)*YMUL, r"\font\cmssfont=cmss10\cmssfont{%s}" % tex_escape(fval))
y += 1.0
if fdump:
dt,target,last_shift,last_y = make_dump(fdump, last_shift, last_y, col, bkcol)
dtb = dt.bbox()
dtb=target
vtb = vt.bbox()
bxvt = make_box(vtb)
bxdt = make_box(dtb)
dtb.enlarge(pyx.unit.u_pt)
try:
if yd < 0:
cnx = pyx.connector.curve(bxvt,bxdt,absangle1=0, absangle2=-90)
else:
cnx = pyx.connector.curve(bxvt,bxdt,absangle1=0, absangle2=90)
except:
pass
else:
canvas.stroke(cnx,[pyx.style.linewidth.thin,pyx.deco.earrow.small,col])
canvas.insert(dt)
canvas.insert(ft)
canvas.insert(vt)
last_y += layer_shift
return canvas
def extract_padding(self, s):
"""DEV: to be overloaded to extract current layer's padding. Return a couple of strings (actual layer, padding)"""
return s,None
def post_dissect(self, s):
"""DEV: is called right after the current layer has been dissected"""
return s
def pre_dissect(self, s):
"""DEV: is called right before the current layer is dissected"""
return s
def do_dissect(self, s):
flist = self.fields_desc[:]
flist.reverse()
while s and flist:
f = flist.pop()
s,fval = f.getfield(self, s)
self.fields[f.name] = fval
return s
def do_dissect_payload(self, s):
if s:
cls = self.guess_payload_class(s)
try:
p = cls(s, _internal=1, _underlayer=self)
except KeyboardInterrupt:
raise
except:
if conf.debug_dissector:
if isinstance(cls,type) and issubclass(cls,Packet):
log_runtime.error("%s dissector failed" % cls.name)
else:
log_runtime.error("%s.guess_payload_class() returned [%s]" % (self.__class__.__name__,repr(cls)))
if cls is not None:
raise
p = Raw(s, _internal=1, _underlayer=self)
self.add_payload(p)
def dissect(self, s):
s = self.pre_dissect(s)
s = self.do_dissect(s)
s = self.post_dissect(s)
payl,pad = self.extract_padding(s)
self.do_dissect_payload(payl)
if pad and conf.padding:
self.add_payload(Padding(pad))
def guess_payload_class(self, payload):
"""DEV: Guesses the next payload class from layer bonds. Can be overloaded to use a different mechanism."""
for t in self.aliastypes:
for fval, cls in t.payload_guess:
ok = 1
for k in fval.keys():
if not hasattr(self, k) or fval[k] != self.getfieldval(k):
ok = 0
break
if ok:
return cls
return self.default_payload_class(payload)
def default_payload_class(self, payload):
"""DEV: Returns the default payload class if nothing has been found by the guess_payload_class() method."""
return Raw
def hide_defaults(self):
"""Removes fields' values that are the same as default values."""
for k in self.fields.keys():
if self.default_fields.has_key(k):
if self.default_fields[k] == self.fields[k]:
del(self.fields[k])
self.payload.hide_defaults()
def __iter__(self):
def loop(todo, done, self=self):
if todo:
eltname = todo.pop()
elt = self.getfieldval(eltname)
if not isinstance(elt, Gen):
if self.get_field(eltname).islist:
elt = SetGen([elt])
else:
elt = SetGen(elt)
for e in elt:
done[eltname]=e
for x in loop(todo[:], done):
yield x
else:
if isinstance(self.payload,NoPayload):
payloads = [None]
else:
payloads = self.payload
for payl in payloads:
done2=done.copy()
for k in done2:
if isinstance(done2[k], VolatileValue):
done2[k] = done2[k]._fix()
pkt = self.__class__()
pkt.fields = done2
pkt.time = self.time
pkt.underlayer = self.underlayer
pkt.overload_fields = self.overload_fields.copy()
pkt.post_transforms = self.post_transforms
if payl is None:
yield pkt
else:
yield pkt/payl
todo = map(lambda (x,y):x, filter(lambda (x,y):isinstance(y,VolatileValue), self.default_fields.items()))
todo += map(lambda (x,y):x, filter(lambda (x,y):isinstance(y,VolatileValue), self.overloaded_fields.items()))
todo += self.fields.keys()
return loop(map(lambda x:str(x), todo), {})
def __gt__(self, other):
"""True if other is an answer from self (self ==> other)."""
if isinstance(other, Packet):
return other < self
elif type(other) is str:
return 1
else:
raise TypeError((self, other))
def __lt__(self, other):
"""True if self is an answer from other (other ==> self)."""
if isinstance(other, Packet):
return self.answers(other)
elif type(other) is str:
return 1
else:
raise TypeError((self, other))
def __eq__(self, other):
if not isinstance(other, self.__class__):
return False
for f in self.fields_desc:
if f not in other.fields_desc:
return False
if self.getfieldval(f.name) != other.getfieldval(f.name):
return False
return self.payload == other.payload
def __ne__(self, other):
return not self.__eq__(other)
def hashret(self):
"""DEV: returns a string that has the same value for a request and its answer."""
return self.payload.hashret()
def answers(self, other):
"""DEV: true if self is an answer from other"""
if other.__class__ == self.__class__:
return self.payload.answers(other.payload)
return 0
def haslayer(self, cls):
"""true if self has a layer that is an instance of cls. Superseded by "cls in self" syntax."""
if self.__class__ == cls or self.__class__.__name__ == cls:
return 1
for f in self.packetfields:
fvalue_gen = self.getfieldval(f.name)
if fvalue_gen is None:
continue
if not f.islist:
fvalue_gen = SetGen(fvalue_gen,_iterpacket=0)
for fvalue in fvalue_gen:
if isinstance(fvalue, Packet):
ret = fvalue.haslayer(cls)
if ret:
return ret
return self.payload.haslayer(cls)
def getlayer(self, cls, nb=1, _track=None):
"""Return the nb^th layer that is an instance of cls."""
if type(cls) is str and "." in cls:
ccls,fld = cls.split(".",1)
else:
ccls,fld = cls,None
if self.__class__ == cls or self.__class__.name == ccls:
if nb == 1:
if fld is None:
return self
else:
return self.getfieldval(fld)
else:
nb -=1
for f in self.packetfields:
fvalue_gen = self.getfieldval(f.name)
if fvalue_gen is None:
continue
if not f.islist:
fvalue_gen = SetGen(fvalue_gen,_iterpacket=0)
for fvalue in fvalue_gen:
if isinstance(fvalue, Packet):
track=[]
ret = fvalue.getlayer(cls, nb, _track=track)
if ret is not None:
return ret
nb = track[0]
return self.payload.getlayer(cls,nb,_track=_track)
def __getitem__(self, cls):
if type(cls) is slice:
if cls.stop:
ret = self.getlayer(cls.start, cls.stop)
else:
ret = self.getlayer(cls.start)
if ret is None and cls.step is not None:
ret = cls.step
return ret
else:
return self.getlayer(cls)
def __contains__(self, cls):
""""cls in self" returns true if self has a layer which is an instance of cls."""
return self.haslayer(cls)
def display(self,*args,**kargs): # Deprecated. Use show()
"""Deprecated. Use show() method."""
self.show(*args,**kargs)
def show(self, indent=3, lvl="", label_lvl=""):
"""Prints a hierarchical view of the packet. "indent" gives the size of indentation for each layer."""
ct = conf.color_theme
print "%s%s %s %s" % (label_lvl,
ct.punct("###["),
ct.layer_name(self.name),
ct.punct("]###"))
for f in self.fields_desc:
if isinstance(f, Emph):
ncol = ct.emph_field_name
vcol = ct.emph_field_value
else:
ncol = ct.field_name
vcol = ct.field_value
fvalue = self.getfieldval(f.name)
if isinstance(fvalue, Packet) or (f.islist and f.holds_packets and type(fvalue) is list):
print "%s \\%-10s\\" % (label_lvl+lvl, ncol(f.name))
fvalue_gen = SetGen(fvalue,_iterpacket=0)
for fvalue in fvalue_gen:
fvalue.show(indent=indent, label_lvl=label_lvl+lvl+" |")
else:
print "%s %-10s%s %s" % (label_lvl+lvl,
ncol(f.name),
ct.punct("="),
vcol(f.i2repr(self,fvalue)))
self.payload.show(indent=indent, lvl=lvl+(" "*indent*self.show_indent), label_lvl=label_lvl)
def show2(self):
"""Prints a hierarchical view of an assembled version of the packet, so that automatic fields are calculated (checksums, etc.)"""
self.__class__(str(self)).show()
def sprintf(self, fmt, relax=1):
"""sprintf(format, [relax=1]) -> str
where format is a string that can include directives. A directive begins and
ends by % and has the following format %[fmt[r],][cls[:nb].]field%.
fmt is a classic printf directive, "r" can be appended for raw substitution
(ex: IP.flags=0x18 instead of SA), nb is the number of the layer we want
(ex: for IP/IP packets, IP:2.src is the src of the upper IP layer).
Special case : "%.time%" is the creation time.
Ex : p.sprintf("%.time% %-15s,IP.src% -> %-15s,IP.dst% %IP.chksum% "
"%03xr,IP.proto% %r,TCP.flags%")
Moreover, the format string can include conditionnal statements. A conditionnal
statement looks like : {layer:string} where layer is a layer name, and string
is the string to insert in place of the condition if it is true, i.e. if layer
is present. If layer is preceded by a "!", the result si inverted. Conditions
can be imbricated. A valid statement can be :
p.sprintf("This is a{TCP: TCP}{UDP: UDP}{ICMP:n ICMP} packet")
p.sprintf("{IP:%IP.dst% {ICMP:%ICMP.type%}{TCP:%TCP.dport%}}")
A side effect is that, to obtain "{" and "}" characters, you must use
"%(" and "%)".
"""
escape = { "%": "%",
"(": "{",
")": "}" }
# Evaluate conditions
while "{" in fmt:
i = fmt.rindex("{")
j = fmt[i+1:].index("}")
cond = fmt[i+1:i+j+1]
k = cond.find(":")
if k < 0:
raise Scapy_Exception("Bad condition in format string: [%s] (read sprintf doc!)"%cond)
cond,format = cond[:k],cond[k+1:]
res = False
if cond[0] == "!":
res = True
cond = cond[1:]
if self.haslayer(cond):
res = not res
if not res:
format = ""
fmt = fmt[:i]+format+fmt[i+j+2:]
# Evaluate directives
s = ""
while "%" in fmt:
i = fmt.index("%")
s += fmt[:i]
fmt = fmt[i+1:]
if fmt[0] in escape:
s += escape[fmt[0]]
fmt = fmt[1:]
continue
try:
i = fmt.index("%")
sfclsfld = fmt[:i]
fclsfld = sfclsfld.split(",")
if len(fclsfld) == 1:
f = "s"
clsfld = fclsfld[0]
elif len(fclsfld) == 2:
f,clsfld = fclsfld
else:
raise Scapy_Exception
if "." in clsfld:
cls,fld = clsfld.split(".")
else:
cls = self.__class__.__name__
fld = clsfld
num = 1
if ":" in cls:
cls,num = cls.split(":")
num = int(num)
fmt = fmt[i+1:]
except:
raise Scapy_Exception("Bad format string [%%%s%s]" % (fmt[:25], fmt[25:] and "..."))
else:
if fld == "time":
val = time.strftime("%H:%M:%S.%%06i", time.localtime(self.time)) % int((self.time-int(self.time))*1000000)
elif cls == self.__class__.__name__ and hasattr(self, fld):
if num > 1:
val = self.payload.sprintf("%%%s,%s:%s.%s%%" % (f,cls,num-1,fld), relax)
f = "s"
elif f[-1] == "r": # Raw field value
val = getattr(self,fld)
f = f[:-1]
if not f:
f = "s"
else:
val = getattr(self,fld)
if fld in self.fieldtype:
val = self.fieldtype[fld].i2repr(self,val)
else:
val = self.payload.sprintf("%%%s%%" % sfclsfld, relax)
f = "s"
s += ("%"+f) % val
s += fmt
return s
def mysummary(self):
"""DEV: can be overloaded to return a string that summarizes the layer.
Only one mysummary() is used in a whole packet summary: the one of the upper layer,
except if a mysummary() also returns (as a couple) a list of layers whose
mysummary() must be called if they are present."""
return ""
def summary(self, intern=0):
"""Prints a one line summary of a packet."""
found,s,needed = self.payload.summary(intern=1)
if s:
s = " / "+s
ret = ""
if not found or self.__class__ in needed:
ret = self.mysummary()
if type(ret) is tuple:
ret,n = ret
needed += n
if ret or needed:
found = 1
if not ret:
ret = self.__class__.__name__
ret = "%s%s" % (ret,s)
if intern:
return found,ret,needed
else:
return ret
def lastlayer(self,layer=None):
"""Returns the uppest layer of the packet"""
return self.payload.lastlayer(self)
def decode_payload_as(self,cls):
"""Reassembles the payload and decode it using another packet class"""
s = str(self.payload)
self.payload = cls(s)
def libnet(self):
"""Not ready yet. Should give the necessary C code that interfaces with libnet to recreate the packet"""
print "libnet_build_%s(" % self.__class__.name.lower()
det = self.__class__(str(self))
for f in self.fields_desc:
val = det.getfieldval(f.name)
if val is None:
val = 0
elif type(val) is int:
val = str(val)
else:
val = '"%s"' % str(val)
print "\t%s, \t\t/* %s */" % (val,f.name)
print ");"
def command(self):
"""Returns a string representing the command you have to type to obtain the same packet"""
f = []
for fn,fv in self.fields.items():
if isinstance(fv, Packet):
fv = fv.command()
else:
fv = repr(fv)
f.append("%s=%s" % (fn, fv))
c = "%s(%s)" % (self.__class__.__name__, ", ".join(f))
pc = self.payload.command()
if pc:
c += "/"+pc
return c
class ASN1_Packet(Packet):
ASN1_root = None
ASN1_codec = None
def init_fields(self):
flist = self.ASN1_root.get_fields_list()
self.do_init_fields(flist)
self.fields_desc = flist
def do_build(self):
return self.ASN1_root.build(self)
def do_dissect(self, x):
return self.ASN1_root.dissect(self, x)
class NoPayload(Packet,object):
def __new__(cls, *args, **kargs):
singl = cls.__dict__.get("__singl__")
if singl is None:
cls.__singl__ = singl = object.__new__(cls)
Packet.__init__(singl, *args, **kargs)
return singl
def __init__(self, *args, **kargs):
pass
def dissection_done(self,pkt):
return
def add_payload(self, payload):
raise Scapy_Exception("Can't add payload to NoPayload instance")
def remove_payload(self):
pass
def add_underlayer(self,underlayer):
pass
def remove_underlayer(self,other):
pass
def copy(self):
return self
def __repr__(self):
return ""
def __str__(self):
return ""
def __nonzero__(self):
return False
def build(self, internal=0):
return ""
def build_ps(self, internal=0):
return "",[]
def getfieldval(self, attr):
raise AttributeError(attr)
def getfield_and_val(self, attr):
raise AttributeError(attr)
def __getattr__(self, attr):
if attr in self.__dict__:
return self.__dict__[attr]
elif attr in self.__class__.__dict__:
return self.__class__.__dict__[attr]
else:
raise AttributeError, attr
def hide_defaults(self):
pass
def __iter__(self):
return iter([])
def __eq__(self, other):
if isinstance(other, NoPayload):
return True
return False
def hashret(self):
return ""
def answers(self, other):
return isinstance(other, NoPayload) or isinstance(other, Padding)
def haslayer(self, cls):
return 0
def getlayer(self, cls, nb=1, _track=None):
if _track is not None:
_track.append(nb)
return None
def show(self, indent=3, lvl="", label_lvl=""):
pass
def sprintf(self, fmt, relax):
if relax:
return "??"
else:
raise Scapy_Exception("Format not found [%s]"%fmt)
def summary(self, intern=0):
return 0,"",[]
def lastlayer(self,layer):
return layer
def command(self):
return ""
####################
## packet classes ##
####################
class Raw(Packet):
name = "Raw"
fields_desc = [ StrField("load", "") ]
def answers(self, other):
return 1
# s = str(other)
# t = self.load
# l = min(len(s), len(t))
# return s[:l] == t[:l]
class Padding(Raw):
name = "Padding"
def build(self, internal=0):
if internal:
return ""
else:
return Raw.build(self)
class Ether(Packet):
name = "Ethernet"
fields_desc = [ DestMACField("dst"),
SourceMACField("src"),
XShortEnumField("type", 0x0000, ETHER_TYPES) ]
def hashret(self):
return struct.pack("H",self.type)+self.payload.hashret()
def answers(self, other):
if isinstance(other,Ether):
if self.type == other.type:
return self.payload.answers(other.payload)
return 0
def mysummary(self):
return self.sprintf("%src% > %dst% (%type%)")
class PPPoE(Packet):
name = "PPP over Ethernet"
fields_desc = [ BitField("version", 1, 4),
BitField("type", 1, 4),
ByteEnumField("code", 0, {0:"Session"}),
XShortField("sessionid", 0x0),
ShortField("len", None) ]
def post_build(self, p, pay):
p += pay
if self.len is None:
l = len(p)-6
p = p[:4]+struct.pack("!H", l)+p[6:]
return p
class PPPoED(PPPoE):
name = "PPP over Ethernet Discovery"
fields_desc = [ BitField("version", 1, 4),
BitField("type", 1, 4),
ByteEnumField("code", 0x09, {0x09:"PADI",0x07:"PADO",0x19:"PADR",0x65:"PADS",0xa7:"PADT"}),
XShortField("sessionid", 0x0),
ShortField("len", None) ]
class Dot3(Packet):
name = "802.3"
fields_desc = [ MACField("dst", ETHER_BROADCAST),
MACField("src", ETHER_ANY),
LenField("len", None, "H") ]
def extract_padding(self,s):
l = self.len
return s[:l],s[l:]
def answers(self, other):
if isinstance(other,Dot3):
return self.payload.answers(other.payload)
return 0
def mysummary(self):
return "802.3 %s > %s" % (self.src, self.dst)
class LLC(Packet):
name = "LLC"
fields_desc = [ XByteField("dsap", 0x00),
XByteField("ssap", 0x00),
ByteField("ctrl", 0) ]
class CookedLinux(Packet):
name = "cooked linux"
fields_desc = [ ShortEnumField("pkttype",0, {0: "unicast",
4:"sent-by-us"}), #XXX incomplete
XShortField("lladdrtype",512),
ShortField("lladdrlen",0),
StrFixedLenField("src","",8),
XShortEnumField("proto",0x800,ETHER_TYPES) ]
class SNAP(Packet):
name = "SNAP"
fields_desc = [ X3BytesField("OUI",0x000000),
XShortEnumField("code", 0x000, ETHER_TYPES) ]
class Dot1Q(Packet):
name = "802.1Q"
aliastypes = [ Ether ]
fields_desc = [ BitField("prio", 0, 3),
BitField("id", 0, 1),
BitField("vlan", 1, 12),
XShortEnumField("type", 0x0000, ETHER_TYPES) ]
def answers(self, other):
if isinstance(other,Dot1Q):
if ( (self.type == other.type) and
(self.vlan == other.vlan) ):
return self.payload.answers(other.payload)
else:
return self.payload.answers(other)
return 0
def default_payload_class(self, pay):
if self.type <= 1500:
return LLC
return Raw
def extract_padding(self,s):
if self.type <= 1500:
return s[:self.type],s[self.type:]
return s,None
def mysummary(self):
if isinstance(self.underlayer, Ether):
return self.underlayer.sprintf("802.1q %Ether.src% > %Ether.dst% (%Dot1Q.type%) vlan %Dot1Q.vlan%")
else:
return self.sprintf("802.1q (%Dot1Q.type%) vlan %Dot1Q.vlan%")
class STP(Packet):
name = "Spanning Tree Protocol"
fields_desc = [ ShortField("proto", 0),
ByteField("version", 0),
ByteField("bpdutype", 0),
ByteField("bpduflags", 0),
ShortField("rootid", 0),
MACField("rootmac", ETHER_ANY),
IntField("pathcost", 0),
ShortField("bridgeid", 0),
MACField("bridgemac", ETHER_ANY),
ShortField("portid", 0),
ShortField("age", 1),
BCDFloatField("maxage", 20),
BCDFloatField("hellotime", 2),
BCDFloatField("fwddelay", 15) ]
class EAPOL(Packet):
name = "EAPOL"
fields_desc = [ ByteField("version", 1),
ByteEnumField("type", 0, ["EAP_PACKET", "START", "LOGOFF", "KEY", "ASF"]),
LenField("len", None, "H") ]
EAP_PACKET= 0
START = 1
LOGOFF = 2
KEY = 3
ASF = 4
def extract_padding(self, s):
l = self.len
return s[:l],s[l:]
def hashret(self):
return chr(self.type)+self.payload.hashret()
def answers(self, other):
if isinstance(other,EAPOL):
if ( (self.type == self.EAP_PACKET) and
(other.type == self.EAP_PACKET) ):
return self.payload.answers(other.payload)
return 0
def mysummary(self):
return self.sprintf("EAPOL %EAPOL.type%")
class EAP(Packet):
name = "EAP"
fields_desc = [ ByteEnumField("code", 4, {1:"REQUEST",2:"RESPONSE",3:"SUCCESS",4:"FAILURE"}),
ByteField("id", 0),
ShortField("len",None),
ConditionalField(ByteEnumField("type",0, {1:"ID",4:"MD5"}), "code", lambda x:x not in [EAP.SUCCESS, EAP.FAILURE])
]
REQUEST = 1
RESPONSE = 2
SUCCESS = 3
FAILURE = 4
TYPE_ID = 1
TYPE_MD5 = 4
def answers(self, other):
if isinstance(other,EAP):
if self.code == self.REQUEST:
return 0
elif self.code == self.RESPONSE:
if ( (other.code == self.REQUEST) and
(other.type == self.type) ):
return 1
elif other.code == self.RESPONSE:
return 1
return 0
def post_build(self, p, pay):
if self.len is None:
l = len(p)+len(pay)
p = p[:2]+chr((l>>8)&0xff)+chr(l&0xff)+p[4:]
return p+pay
class ARP(Packet):
name = "ARP"
fields_desc = [ XShortField("hwtype", 0x0001),
XShortEnumField("ptype", 0x0800, ETHER_TYPES),
ByteField("hwlen", 6),
ByteField("plen", 4),
ShortEnumField("op", 1, {"who-has":1, "is-at":2, "RARP-req":3, "RARP-rep":4, "Dyn-RARP-req":5, "Dyn-RAR-rep":6, "Dyn-RARP-err":7, "InARP-req":8, "InARP-rep":9}),
ARPSourceMACField("hwsrc"),
SourceIPField("psrc","pdst"),
MACField("hwdst", ETHER_ANY),
IPField("pdst", "0.0.0.0") ]
who_has = 1
is_at = 2
def answers(self, other):
if isinstance(other,ARP):
if ( (self.op == self.is_at) and
(other.op == self.who_has) and
(self.psrc == other.pdst) ):
return 1
return 0
def extract_padding(self, s):
return "",s
def mysummary(self):
if self.op == self.is_at:
return "ARP is at %s says %s" % (self.hwsrc, self.psrc)
elif self.op == self.who_has:
return "ARP who has %s says %s" % (self.pdst, self.psrc)
else:
return "ARP %ARP.op% %ARP.psrc% > %ARP.pdst%"
class IP(Packet, IPTools):
name = "IP"
fields_desc = [ BitField("version" , 4 , 4),
BitField("ihl", None, 4),
XByteField("tos", 0),
ShortField("len", None),
ShortField("id", 1),
FlagsField("flags", 0, 3, ["MF","DF","evil"]),
BitField("frag", 0, 13),
ByteField("ttl", 64),
ByteEnumField("proto", 0, IP_PROTOS),
XShortField("chksum", None),
#IPField("src", "127.0.0.1"),
Emph(SourceIPField("src","dst")),
Emph(IPField("dst", "127.0.0.1")),
IPoptionsField("options", "") ]
def post_build(self, p, pay):
ihl = self.ihl
if ihl is None:
ihl = len(p)/4
p = chr(((self.version&0xf)<<4) | ihl&0x0f)+p[1:]
if self.len is None:
l = len(p)+len(pay)
p = p[:2]+struct.pack("!H", l)+p[4:]
if self.chksum is None:
ck = checksum(p)
p = p[:10]+chr(ck>>8)+chr(ck&0xff)+p[12:]
return p+pay
def extract_padding(self, s):
l = self.len - (self.ihl << 2)
return s[:l],s[l:]
def send(self, s, slp=0):
for p in self:
try:
s.sendto(str(p), (p.dst,0))
except socket.error, msg:
log_runtime.error(msg)
if slp:
time.sleep(slp)
def hashret(self):
if ( (self.proto == socket.IPPROTO_ICMP)
and (isinstance(self.payload, ICMP))
and (self.payload.type in [3,4,5,11,12]) ):
return self.payload.payload.hashret()
else:
if conf.checkIPsrc and conf.checkIPaddr:
return strxor(inet_aton(self.src),inet_aton(self.dst))+struct.pack("B",self.proto)+self.payload.hashret()
else:
return struct.pack("B", self.proto)+self.payload.hashret()
def answers(self, other):
if not isinstance(other,IP):
return 0
if conf.checkIPaddr and (self.dst != other.src):
return 0
if ( (self.proto == socket.IPPROTO_ICMP) and
(isinstance(self.payload, ICMP)) and
(self.payload.type in [3,4,5,11,12]) ):
# ICMP error message
return self.payload.payload.answers(other)
else:
if ( (conf.checkIPaddr and (self.src != other.dst)) or
(self.proto != other.proto) ):
return 0
return self.payload.answers(other.payload)
def mysummary(self):
s = self.sprintf("%IP.src% > %IP.dst% %IP.proto%")
if self.frag:
s += " frag:%i" % self.frag
return s
class TCP(Packet):
name = "TCP"
fields_desc = [ ShortEnumField("sport", 20, TCP_SERVICES),
ShortEnumField("dport", 80, TCP_SERVICES),
IntField("seq", 0),
IntField("ack", 0),
BitField("dataofs", None, 4),
BitField("reserved", 0, 4),
FlagsField("flags", 0x2, 8, "FSRPAUEC"),
ShortField("window", 8192),
XShortField("chksum", None),
ShortField("urgptr", 0),
TCPOptionsField("options", {}) ]
def post_build(self, p, pay):
p += pay
dataofs = self.dataofs
if dataofs is None:
dataofs = 5+((len(self.get_field("options").i2m(self,self.options))+3)/4)
p = p[:12]+chr((dataofs << 4) | ord(p[12])&0x0f)+p[13:]
if self.chksum is None:
if isinstance(self.underlayer, IP):
if self.underlayer.len is not None:
ln = self.underlayer.len-20
else:
ln = len(p)
psdhdr = struct.pack("!4s4sHH",
inet_aton(self.underlayer.src),
inet_aton(self.underlayer.dst),
self.underlayer.proto,
ln)
ck=checksum(psdhdr+p)
p = p[:16]+struct.pack("!H", ck)+p[18:]
elif isinstance(self.underlayer, IPv6) or isinstance(self.underlayer, _IPv6OptionHeader):
ck = in6_chksum(socket.IPPROTO_TCP, self.underlayer, p)
p = p[:16]+struct.pack("!H", ck)+p[18:]
else:
warning("No IP underlayer to compute checksum. Leaving null.")
return p
def hashret(self):
if conf.checkIPsrc:
return struct.pack("H",self.sport ^ self.dport)+self.payload.hashret()
else:
return self.payload.hashret()
def answers(self, other):
if not isinstance(other, TCP):
return 0
if conf.checkIPsrc:
if not ((self.sport == other.dport) and
(self.dport == other.sport)):
return 0
if (abs(other.seq-self.ack) > 2+len(other.payload)):
return 0
return 1
def mysummary(self):
if isinstance(self.underlayer, IP):
return self.underlayer.sprintf("TCP %IP.src%:%TCP.sport% > %IP.dst%:%TCP.dport% %TCP.flags%")
elif isinstance(self.underlayer, IPv6):
return self.underlayer.sprintf("TCP %IPv6.src%:%TCP.sport% > %IPv6.dst%:%TCP.dport% %TCP.flags%")
else:
return self.sprintf("TCP %TCP.sport% > %TCP.dport% %TCP.flags%")
class UDP(Packet):
name = "UDP"
fields_desc = [ ShortEnumField("sport", 53, UDP_SERVICES),
ShortEnumField("dport", 53, UDP_SERVICES),
ShortField("len", None),
XShortField("chksum", None), ]
def post_build(self, p, pay):
p += pay
l = self.len
if l is None:
l = len(p)
p = p[:4]+struct.pack("!H",l)+p[6:]
if self.chksum is None:
if isinstance(self.underlayer, IP):
if self.underlayer.len is not None:
ln = self.underlayer.len-20
else:
ln = len(p)
psdhdr = struct.pack("!4s4sHH",
inet_aton(self.underlayer.src),
inet_aton(self.underlayer.dst),
self.underlayer.proto,
ln)
ck=checksum(psdhdr+p)
p = p[:6]+struct.pack("!H", ck)+p[8:]
elif isinstance(self.underlayer, IPv6) or isinstance(self.underlayer, _IPv6OptionHeader):
ck = in6_chksum(socket.IPPROTO_UDP, self.underlayer, p)
p = p[:6]+struct.pack("!H", ck)+p[8:]
else:
warning("No IP underlayer to compute checksum. Leaving null.")
return p
def extract_padding(self, s):
l = self.len - 8
return s[:l],s[l:]
def hashret(self):
if conf.checkIPsrc:
return struct.pack("H",self.sport ^ self.dport)+self.payload.hashret()
else:
return self.payload.hashret()
def answers(self, other):
if not isinstance(other, UDP):
return 0
if conf.checkIPsrc:
if not ((self.sport == other.dport) and
(self.dport == other.sport)):
return 0
return self.payload.answers(other.payload)
def mysummary(self):
if isinstance(self.underlayer, IP):
return self.underlayer.sprintf("UDP %IP.src%:%UDP.sport% > %IP.dst%:%UDP.dport%")
elif isinstance(self.underlayer, IPv6):
return self.underlayer.sprintf("UDP %IPv6.src%:%UDP.sport% > %IPv6.dst%:%UDP.dport%")
else:
return self.sprintf("UDP %UDP.sport% > %UDP.dport%")
icmptypes = { 0 : "echo-reply",
3 : "dest-unreach",
4 : "source-quench",
5 : "redirect",
8 : "echo-request",
9 : "router-advertisement",
10 : "router-solicitation",
11 : "time-exceeded",
12 : "parameter-problem",
13 : "timestamp-request",
14 : "timestamp-reply",
15 : "information-request",
16 : "information-response",
17 : "address-mask-request",
18 : "address-mask-reply" }
class ICMP(Packet):
name = "ICMP"
fields_desc = [ ByteEnumField("type",8, icmptypes),
ByteField("code",0),
XShortField("chksum", None),
XShortField("id",0),
XShortField("seq",0) ]
def post_build(self, p, pay):
p += pay
if self.chksum is None:
ck = checksum(p)
p = p[:2]+chr(ck>>8)+chr(ck&0xff)+p[4:]
return p
def hashret(self):
return struct.pack("HH",self.id,self.seq)+self.payload.hashret()
def answers(self, other):
if not isinstance(other,ICMP):
return 0
if ( (other.type,self.type) in [(8,0),(13,14),(15,16),(17,18)] and
self.id == other.id and
self.seq == other.seq ):
return 1
return 0
def guess_payload_class(self, payload):
if self.type in [3,4,5,11,12]:
return IPerror
else:
return None
def mysummary(self):
if isinstance(self.underlayer, IP):
return self.underlayer.sprintf("ICMP %IP.src% > %IP.dst% %ICMP.type% %ICMP.code%")
else:
return self.sprintf("ICMP %ICMP.type% %ICMP.code%")
class IPerror(IP):
name = "IP in ICMP"
def answers(self, other):
if not isinstance(other, IP):
return 0
if not ( ((conf.checkIPsrc == 0) or (self.dst == other.dst)) and
(self.src == other.src) and
( ((conf.checkIPID == 0)
or (self.id == other.id)
or (conf.checkIPID == 1 and self.id == socket.htons(other.id)))) and
(self.proto == other.proto) ):
return 0
return self.payload.answers(other.payload)
def mysummary(self):
return Packet.mysummary(self)
class TCPerror(TCP):
name = "TCP in ICMP"
def answers(self, other):
if not isinstance(other, TCP):
return 0
if conf.checkIPsrc:
if not ((self.sport == other.sport) and
(self.dport == other.dport)):
return 0
if conf.check_TCPerror_seqack:
if self.seq is not None:
if self.seq != other.seq:
return 0
if self.ack is not None:
if self.ack != other.ack:
return 0
return 1
def mysummary(self):
return Packet.mysummary(self)
class UDPerror(UDP):
name = "UDP in ICMP"
def answers(self, other):
if not isinstance(other, UDP):
return 0
if conf.checkIPsrc:
if not ((self.sport == other.sport) and
(self.dport == other.dport)):
return 0
return 1
def mysummary(self):
return Packet.mysummary(self)
class ICMPerror(ICMP):
name = "ICMP in ICMP"
def answers(self, other):
if not isinstance(other,ICMP):
return 0
if not ((self.type == other.type) and
(self.code == other.code)):
return 0
if self.code in [0,8,13,14,17,18]:
if (self.id == other.id and
self.seq == other.seq):
return 1
else:
return 0
else:
return 1
def mysummary(self):
return Packet.mysummary(self)
class IPv6(Packet):
"""See http://namabiiru.hongo.wide.ad.jp/scapy6"""
name = "IPv6 not implemented here."
def __init__(self, *args, **kargs):
log_interactive.error(self.name)
def __repr__(self):
return "<IPv6: ERROR not implemented>"
class _IPv6OptionHeader(Packet):
"""See http://namabiiru.hongo.wide.ad.jp/scapy6"""
name = "IPv6 not implemented here."
def __init__(self, *args, **kargs):
log_interactive.error(self.name)
def __repr__(self):
return "<IPv6: ERROR not implemented>"
class PPP(Packet):
name = "PPP Link Layer"
fields_desc = [ ShortEnumField("proto", 0x0021, {0x0021: "IP",
0xc021: "LCP"} ) ]
class DNS(Packet):
name = "DNS"
fields_desc = [ ShortField("id",0),
BitField("qr",0, 1),
BitEnumField("opcode", 0, 4, {0:"QUERY",1:"IQUERY",2:"STATUS"}),
BitField("aa", 0, 1),
BitField("tc", 0, 1),
BitField("rd", 0, 1),
BitField("ra", 0 ,1),
BitField("z", 0, 3),
BitEnumField("rcode", 0, 4, {0:"ok", 1:"format-error", 2:"server-failure", 3:"name-error", 4:"not-implemented", 5:"refused"}),
DNSRRCountField("qdcount", None, "qd"),
DNSRRCountField("ancount", None, "an"),
DNSRRCountField("nscount", None, "ns"),
DNSRRCountField("arcount", None, "ar"),
DNSQRField("qd", "qdcount"),
DNSRRField("an", "ancount"),
DNSRRField("ns", "nscount"),
DNSRRField("ar", "arcount",0) ]
def answers(self, other):
return (isinstance(other, DNS)
and self.id == other.id
and self.qr == 1
and other.qr == 0)
def mysummary(self):
type = ["Qry","Ans"][self.qr]
name = ""
if self.qr:
type = "Ans"
if self.ancount > 0 and isinstance(self.an, DNSRR):
name = ' "%s"' % self.an.rdata
else:
type = "Qry"
if self.qdcount > 0 and isinstance(self.qd, DNSQR):
name = ' "%s"' % self.qd.qname
return 'DNS %s%s ' % (type, name)
dnstypes = { 0:"ANY", 255:"ALL",
1:"A", 2:"NS", 3:"MD", 4:"MD", 5:"CNAME", 6:"SOA", 7: "MB", 8:"MG",
9:"MR",10:"NULL",11:"WKS",12:"PTR",13:"HINFO",14:"MINFO",15:"MX",16:"TXT",
17:"RP",18:"AFSDB",28:"AAAA", 33:"SRV",38:"A6",39:"DNAME"}
dnsqtypes = {251:"IXFR",252:"AXFR",253:"MAILB",254:"MAILA",255:"ALL"}
dnsqtypes.update(dnstypes)
dnsclasses = {1: 'IN', 2: 'CS', 3: 'CH', 4: 'HS', 255: 'ANY'}
class DNSQR(Packet):
name = "DNS Question Record"
show_indent=0
fields_desc = [ DNSStrField("qname",""),
ShortEnumField("qtype", 1, dnsqtypes),
ShortEnumField("qclass", 1, dnsclasses) ]
class DNSRR(Packet):
name = "DNS Resource Record"
show_indent=0
fields_desc = [ DNSStrField("rrname",""),
ShortEnumField("type", 1, dnstypes),
ShortEnumField("rclass", 1, dnsclasses),
IntField("ttl", 0),
RDLenField("rdlen"),
RDataField("rdata", "", "rdlen") ]
dhcpmagic="c\x82Sc"
class BOOTP(Packet):
name = "BOOTP"
fields_desc = [ ByteEnumField("op",1, {1:"BOOTREQUEST", 2:"BOOTREPLY"}),
ByteField("htype",1),
ByteField("hlen",6),
ByteField("hops",0),
IntField("xid",0),
ShortField("secs",0),
FlagsField("flags", 0, 16, "???????????????B"),
IPField("ciaddr","0.0.0.0"),
IPField("yiaddr","0.0.0.0"),
IPField("siaddr","0.0.0.0"),
IPField("giaddr","0.0.0.0"),
Field("chaddr","", "16s"),
Field("sname","","64s"),
Field("file","","128s"),
StrField("options","") ]
def guess_payload_class(self, payload):
if self.options[:len(dhcpmagic)] == dhcpmagic:
return DHCP
else:
return Packet.guess_payload_class(self, payload)
def extract_padding(self,s):
if self.options[:len(dhcpmagic)] == dhcpmagic:
# set BOOTP options to DHCP magic cookie and make rest a payload of DHCP options
payload = self.options[len(dhcpmagic):]
self.options = self.options[:len(dhcpmagic)]
return payload, None
else:
return "", None
def hashret(self):
return struct.pack("L", self.xid)
def answers(self, other):
if not isinstance(other, BOOTP):
return 0
return self.xid == other.xid
#DHCP_UNKNOWN, DHCP_IP, DHCP_IPLIST, DHCP_TYPE \
#= range(4)
#
DHCPTypes = {
1: "discover",
2: "offer",
3: "request",
4: "decline",
5: "ack",
6: "nak",
7: "release",
8: "inform",
9: "force_renew",
10:"lease_query",
11:"lease_unassigned",
12:"lease_unknown",
13:"lease_active",
}
DHCPOptions = {
0: "pad",
1: IPField("subnet_mask", "0.0.0.0"),
2: "time_zone",
3: IPField("router","0.0.0.0"),
4: IPField("time_server","0.0.0.0"),
5: IPField("IEN_name_server","0.0.0.0"),
6: IPField("name_server","0.0.0.0"),
7: IPField("log_server","0.0.0.0"),
8: IPField("cookie_server","0.0.0.0"),
9: IPField("lpr_server","0.0.0.0"),
12: "hostname",
14: "dump_path",
15: "domain",
17: "root_disk_path",
22: "max_dgram_reass_size",
23: "default_ttl",
24: "pmtu_timeout",
28: IPField("broadcast_address","0.0.0.0"),
35: "arp_cache_timeout",
36: "ether_or_dot3",
37: "tcp_ttl",
38: "tcp_keepalive_interval",
39: "tcp_keepalive_garbage",
40: "NIS_domain",
41: IPField("NIS_server","0.0.0.0"),
42: IPField("NTP_server","0.0.0.0"),
43: "vendor_specific",
44: IPField("NetBIOS_server","0.0.0.0"),
45: IPField("NetBIOS_dist_server","0.0.0.0"),
50: IPField("requested_addr","0.0.0.0"),
51: IntField("lease_time", 43200),
54: IPField("server_id","0.0.0.0"),
55: "param_req_list",
57: ShortField("max_dhcp_size", 1500),
58: IntField("renewal_time", 21600),
59: IntField("rebinding_time", 37800),
60: "vendor_class_id",
61: "client_id",
64: "NISplus_domain",
65: IPField("NISplus_server","0.0.0.0"),
69: IPField("SMTP_server","0.0.0.0"),
70: IPField("POP3_server","0.0.0.0"),
71: IPField("NNTP_server","0.0.0.0"),
72: IPField("WWW_server","0.0.0.0"),
73: IPField("Finger_server","0.0.0.0"),
74: IPField("IRC_server","0.0.0.0"),
75: IPField("StreetTalk_server","0.0.0.0"),
76: "StreetTalk_Dir_Assistance",
82: "relay_agent_Information",
53: ByteEnumField("message-type", 1, DHCPTypes),
# 55: DHCPRequestListField("request-list"),
255: "end"
}
DHCPRevOptions = {}
for k,v in DHCPOptions.iteritems():
if type(v) is str:
n = v
v = None
else:
n = str(v)
DHCPRevOptions[n] = (k,v)
del(n)
del(v)
del(k)
class DHCPOptionsField(StrField):
islist=1
def i2repr(self,pkt,x):
s = []
for v in x:
if type(v) is tuple and len(v) == 2:
if DHCPRevOptions.has_key(v[0]) and isinstance(DHCPRevOptions[v[0]][1],Field):
f = DHCPRevOptions[v[0]][1]
vv = f.i2repr(pkt,v[1])
else:
vv = repr(v[1])
s.append("%s=%s" % (v[0],vv))
else:
s.append(str(v))
return "[%s]" % (" ".join(s))
def getfield(self, pkt, s):
return "", self.m2i(pkt, s)
def m2i(self, pkt, x):
opt = []
while x:
o = ord(x[0])
if o == 255:
opt.append("end")
x = x[1:]
continue
if o == 0:
opt.append("pad")
x = x[1:]
continue
if DHCPOptions.has_key(o):
f = DHCPOptions[o]
if isinstance(f, str):
olen = ord(x[1])
opt.append( (f,x[2:olen+2]) )
x = x[olen+2:]
else:
olen = ord(x[1])
left, val = f.getfield(pkt,x[2:olen+2])
# val = f.m2i(pkt,val)
# if left:
# print "m2i data left left=%s" % left
opt.append((f.name, val))
x = x[olen+2:]
else:
olen = ord(x[1])
opt.append((o, x[2:olen+2]))
x = x[olen+2:]
return opt
def i2m(self, pkt, x):
#print "i2m x=%s" % x
s = ""
for o in x:
if type(o) is tuple and len(o) == 2:
name, val = o
if isinstance(name, int):
onum, oval = name, val
elif DHCPRevOptions.has_key(name):
onum, f = DHCPRevOptions[name]
if f is None:
oval = val
else:
# oval = f.addfield(pkt,"",f.i2m(pkt,f.any2i(pkt,val)))
oval = f.addfield(pkt,"",f.any2i(pkt,val))
else:
warning("Unknown field option %s" % name)
continue
s += chr(onum)
s += chr(len(oval))
s += oval
elif (type(o) is str and DHCPRevOptions.has_key(o) and
DHCPRevOptions[o][1] == None):
s += chr(DHCPRevOptions[o][0])
elif type(o) is int:
s += chr(o)
else:
warning("Malformed option %s" % o)
return s
class DHCP(Packet):
name = "DHCP options"
fields_desc = [ DHCPOptionsField("options","") ]
class Dot11(Packet):
name = "802.11"
fields_desc = [
BitField("subtype", 0, 4),
BitEnumField("type", 0, 2, ["Management", "Control", "Data", "Reserved"]),
BitField("proto", 0, 2),
FlagsField("FCfield", 0, 8, ["to-DS", "from-DS", "MF", "retry", "pw-mgt", "MD", "wep", "order"]),
ShortField("ID",0),
MACField("addr1", ETHER_ANY),
Dot11Addr2MACField("addr2", ETHER_ANY),
Dot11Addr3MACField("addr3", ETHER_ANY),
Dot11SCField("SC", 0),
Dot11Addr4MACField("addr4", ETHER_ANY)
]
def mysummary(self):
return self.sprintf("802.11 %Dot11.type% %Dot11.subtype% %Dot11.addr2% > %Dot11.addr1%")
def guess_payload_class(self, payload):
if self.FCfield & 0x40:
return Dot11WEP
else:
return Packet.guess_payload_class(self, payload)
def answers(self, other):
if isinstance(other,Dot11):
if self.type == 0: # management
if self.addr1 != other.addr2: # check resp DA w/ req SA
return 0
if (other.subtype,self.subtype) in [(0,1),(2,3),(4,5)]:
return 1
if self.subtype == other.subtype == 11: # auth
return self.payload.answers(other.payload)
elif self.type == 1: # control
return 0
elif self.type == 2: # data
return self.payload.answers(other.payload)
elif self.type == 3: # reserved
return 0
return 0
def unwep(self, key=None, warn=1):
if self.FCfield & 0x40 == 0:
if warn:
warning("No WEP to remove")
return
if isinstance(self.payload.payload, NoPayload):
if key or conf.wepkey:
self.payload.decrypt(key)
if isinstance(self.payload.payload, NoPayload):
if warn:
warning("Dot11 can't be decrypted. Check conf.wepkey.")
return
self.FCfield &= ~0x40
self.payload=self.payload.payload
capability_list = [ "res8", "res9", "short-slot", "res11",
"res12", "DSSS-OFDM", "res14", "res15",
"ESS", "IBSS", "CFP", "CFP-req",
"privacy", "short-preamble", "PBCC", "agility"]
reason_code = {0:"reserved",1:"unspec", 2:"auth-expired",
3:"deauth-ST-leaving",
4:"inactivity", 5:"AP-full", 6:"class2-from-nonauth",
7:"class3-from-nonass", 8:"disas-ST-leaving",
9:"ST-not-auth"}
status_code = {0:"success", 1:"failure", 10:"cannot-support-all-cap",
11:"inexist-asso", 12:"asso-denied", 13:"algo-unsupported",
14:"bad-seq-num", 15:"challenge-failure",
16:"timeout", 17:"AP-full",18:"rate-unsupported" }
class Dot11Beacon(Packet):
name = "802.11 Beacon"
fields_desc = [ LELongField("timestamp", 0),
LEShortField("beacon_interval", 0x0064),
FlagsField("cap", 0, 16, capability_list) ]
class Dot11Elt(Packet):
name = "802.11 Information Element"
fields_desc = [ ByteEnumField("ID", 0, {0:"SSID", 1:"Rates", 2: "FHset", 3:"DSset", 4:"CFset", 5:"TIM", 6:"IBSSset", 16:"challenge",
42:"ERPinfo", 47:"ERPinfo", 48:"RSNinfo", 50:"ESRates",221:"vendor",68:"reserved"}),
FieldLenField("len", None, "info", "B"),
StrLenField("info", "", "len") ]
def mysummary(self):
if self.ID == 0:
return "SSID=%s"%repr(self.info),[Dot11]
else:
return ""
class Dot11ATIM(Packet):
name = "802.11 ATIM"
class Dot11Disas(Packet):
name = "802.11 Disassociation"
fields_desc = [ LEShortEnumField("reason", 1, reason_code) ]
class Dot11AssoReq(Packet):
name = "802.11 Association Request"
fields_desc = [ FlagsField("cap", 0, 16, capability_list),
LEShortField("listen_interval", 0x00c8) ]
class Dot11AssoResp(Packet):
name = "802.11 Association Response"
fields_desc = [ FlagsField("cap", 0, 16, capability_list),
LEShortField("status", 0),
LEShortField("AID", 0) ]
class Dot11ReassoReq(Packet):
name = "802.11 Reassociation Request"
fields_desc = [ FlagsField("cap", 0, 16, capability_list),
MACField("current_AP", ETHER_ANY),
LEShortField("listen_interval", 0x00c8) ]
class Dot11ReassoResp(Dot11AssoResp):
name = "802.11 Reassociation Response"
class Dot11ProbeReq(Packet):
name = "802.11 Probe Request"
class Dot11ProbeResp(Packet):
name = "802.11 Probe Response"
fields_desc = [ LELongField("timestamp", 0),
LEShortField("beacon_interval", 0x0064),
FlagsField("cap", 0, 16, capability_list) ]
class Dot11Auth(Packet):
name = "802.11 Authentication"
fields_desc = [ LEShortEnumField("algo", 0, ["open", "sharedkey"]),
LEShortField("seqnum", 0),
LEShortEnumField("status", 0, status_code) ]
def answers(self, other):
if self.seqnum == other.seqnum+1:
return 1
return 0
class Dot11Deauth(Packet):
name = "802.11 Deauthentication"
fields_desc = [ LEShortEnumField("reason", 1, reason_code) ]
class Dot11WEP(Packet):
name = "802.11 WEP packet"
fields_desc = [ StrFixedLenField("iv", "\0\0\0", 3),
ByteField("keyid", 0),
StrField("wepdata",None,remain=4),
IntField("icv",None) ]
def post_dissect(self, s):
# self.icv, = struct.unpack("!I",self.wepdata[-4:])
# self.wepdata = self.wepdata[:-4]
self.decrypt()
def build_payload(self):
if self.wepdata is None:
return Packet.build_payload(self)
return ""
def post_build(self, p, pay):
if self.wepdata is None:
key = conf.wepkey
if key:
if self.icv is None:
pay += struct.pack("<I",crc32(pay))
icv = ""
else:
icv = p[4:8]
c = ARC4.new(self.iv+key)
p = p[:4]+c.encrypt(pay)+icv
else:
warning("No WEP key set (conf.wepkey).. strange results expected..")
return p
def decrypt(self,key=None):
if key is None:
key = conf.wepkey
if key:
c = ARC4.new(self.iv+key)
self.add_payload(LLC(c.decrypt(self.wepdata)))
class PrismHeader(Packet):
""" iwpriv wlan0 monitor 3 """
name = "Prism header"
fields_desc = [ LEIntField("msgcode",68),
LEIntField("len",144),
StrFixedLenField("dev","",16),
LEIntField("hosttime_did",0),
LEShortField("hosttime_status",0),
LEShortField("hosttime_len",0),
LEIntField("hosttime",0),
LEIntField("mactime_did",0),
LEShortField("mactime_status",0),
LEShortField("mactime_len",0),
LEIntField("mactime",0),
LEIntField("channel_did",0),
LEShortField("channel_status",0),
LEShortField("channel_len",0),
LEIntField("channel",0),
LEIntField("rssi_did",0),
LEShortField("rssi_status",0),
LEShortField("rssi_len",0),
LEIntField("rssi",0),
LEIntField("sq_did",0),
LEShortField("sq_status",0),
LEShortField("sq_len",0),
LEIntField("sq",0),
LEIntField("signal_did",0),
LEShortField("signal_status",0),
LEShortField("signal_len",0),
LESignedIntField("signal",0),
LEIntField("noise_did",0),
LEShortField("noise_status",0),
LEShortField("noise_len",0),
LEIntField("noise",0),
LEIntField("rate_did",0),
LEShortField("rate_status",0),
LEShortField("rate_len",0),
LEIntField("rate",0),
LEIntField("istx_did",0),
LEShortField("istx_status",0),
LEShortField("istx_len",0),
LEIntField("istx",0),
LEIntField("frmlen_did",0),
LEShortField("frmlen_status",0),
LEShortField("frmlen_len",0),
LEIntField("frmlen",0),
]
class HSRP(Packet):
name = "HSRP"
fields_desc = [
ByteField("version", 0),
ByteEnumField("opcode", 0, { 0:"Hello"}),
ByteEnumField("state", 16, { 16:"Active"}),
ByteField("hellotime", 3),
ByteField("holdtime", 10),
ByteField("priority", 120),
ByteField("group", 1),
ByteField("reserved", 0),
StrFixedLenField("auth","cisco",8),
IPField("virtualIP","192.168.1.1") ]
class NTP(Packet):
# RFC 1769
name = "NTP"
fields_desc = [
BitEnumField('leap', 0, 2,
{ 0: 'nowarning',
1: 'longminute',
2: 'shortminute',
3: 'notsync'}),
BitField('version', 3, 3),
BitEnumField('mode', 3, 3,
{ 0: 'reserved',
1: 'sym_active',
2: 'sym_passive',
3: 'client',
4: 'server',
5: 'broadcast',
6: 'control',
7: 'private'}),
BitField('stratum', 2, 8),
BitField('poll', 0xa, 8), ### XXX : it's a signed int
BitField('precision', 0, 8), ### XXX : it's a signed int
FloatField('delay', 0, 32),
FloatField('dispersion', 0, 32),
IPField('id', "127.0.0.1"),
TimeStampField('ref', 0, 64),
TimeStampField('orig', -1, 64), # -1 means current time
TimeStampField('recv', 0, 64),
TimeStampField('sent', -1, 64)
]
def mysummary(self):
return self.sprintf("NTP v%ir,NTP.version%, %NTP.mode%")
class GRE(Packet):
name = "GRE"
fields_desc = [ BitField("chksumpresent",0,1),
BitField("reserved0",0,12),
BitField("version",0,3),
XShortEnumField("proto", 0x0000, ETHER_TYPES),
ConditionalField(XShortField("chksum",None),"chksumpresent",lambda x:x==1),
ConditionalField(XShortField("reserved1",None),"chksumpresent",lambda x:x==1),
]
def post_build(self, p, pay):
p += pay
if self.chksumpresent and self.chksum is None:
c = checksum(p)
p = p[:4]+chr((c>>8)&0xff)+chr(c&0xff)+p[6:]
return p
class Radius(Packet):
name = "Radius"
fields_desc = [ ByteEnumField("code", 1, {1: "Access-Request",
2: "Access-Accept",
3: "Access-Reject",
4: "Accounting-Request",
5: "Accounting-Accept",
6: "Accounting-Status",
7: "Password-Request",
8: "Password-Ack",
9: "Password-Reject",
10: "Accounting-Message",
11: "Access-Challenge",
12: "Status-Server",
13: "Status-Client",
21: "Resource-Free-Request",
22: "Resource-Free-Response",
23: "Resource-Query-Request",
24: "Resource-Query-Response",
25: "Alternate-Resource-Reclaim-Request",
26: "NAS-Reboot-Request",
27: "NAS-Reboot-Response",
29: "Next-Passcode",
30: "New-Pin",
31: "Terminate-Session",
32: "Password-Expired",
33: "Event-Request",
34: "Event-Response",
40: "Disconnect-Request",
41: "Disconnect-ACK",
42: "Disconnect-NAK",
43: "CoA-Request",
44: "CoA-ACK",
45: "CoA-NAK",
50: "IP-Address-Allocate",
51: "IP-Address-Release",
253: "Experimental-use",
254: "Reserved",
255: "Reserved"} ),
ByteField("id", 0),
ShortField("len", None),
StrFixedLenField("authenticator","",16) ]
def post_build(self, p, pay):
p += pay
l = self.len
if l is None:
l = len(p)
p = p[:2]+struct.pack("!H",l)+p[4:]
return p
class RIP(Packet):
name = "RIP header"
fields_desc = [
ByteEnumField("command",1,{1:"req",2:"resp",3:"traceOn",4:"traceOff",5:"sun",
6:"trigReq",7:"trigResp",8:"trigAck",9:"updateReq",
10:"updateResp",11:"updateAck"}),
ByteField("version",1),
ShortField("null",0),
]
class RIPEntry(Packet):
name = "RIP entry"
fields_desc = [
ShortEnumField("AF",2,{2:"IP"}),
ShortField("RouteTag",0),
IPField("addr","0.0.0.0"),
IPField("mask","0.0.0.0"),
IPField("nextHop","0.0.0.0"),
IntEnumField("metric",1,{16:"Unreach"}),
]
ISAKMP_payload_type = ["None","SA","Proposal","Transform","KE","ID","CERT","CR","Hash",
"SIG","Nonce","Notification","Delete","VendorID"]
ISAKMP_exchange_type = ["None","base","identity prot.",
"auth only", "aggressive", "info"]
class ISAKMP_class(Packet):
def guess_payload_class(self, payload):
np = self.next_payload
if np == 0:
return Raw
elif np < len(ISAKMP_payload_type):
pt = ISAKMP_payload_type[np]
return globals().get("ISAKMP_payload_%s" % pt, ISAKMP_payload)
else:
return ISAKMP_payload
class ISAKMP(ISAKMP_class): # rfc2408
name = "ISAKMP"
fields_desc = [
StrFixedLenField("init_cookie","",8),
StrFixedLenField("resp_cookie","",8),
ByteEnumField("next_payload",0,ISAKMP_payload_type),
XByteField("version",0x10),
ByteEnumField("exch_type",0,ISAKMP_exchange_type),
FlagsField("flags",0, 8, ["encryption","commit","auth_only","res3","res4","res5","res6","res7"]), # XXX use a Flag field
IntField("id",0),
IntField("length",None)
]
def guess_payload_class(self, payload):
if self.flags & 1:
return Raw
return ISAKMP_class.guess_payload_class(self, payload)
def answers(self, other):
if isinstance(other, ISAKMP):
if other.init_cookie == self.init_cookie:
return 1
return 0
def post_build(self, p, pay):
p += pay
if self.length is None:
p = p[:24]+struct.pack("!I",len(p))+p[28:]
return p
class ISAKMP_payload_Transform(ISAKMP_class):
name = "IKE Transform"
fields_desc = [
ByteEnumField("next_payload",None,ISAKMP_payload_type),
ByteField("res",0),
# ShortField("len",None),
ShortField("length",None),
ByteField("num",None),
ByteEnumField("id",1,{1:"KEY_IKE"}),
ShortField("res2",0),
ISAKMPTransformSetField("transforms",None,"length",shift=8)
# XIntField("enc",0x80010005L),
# XIntField("hash",0x80020002L),
# XIntField("auth",0x80030001L),
# XIntField("group",0x80040002L),
# XIntField("life_type",0x800b0001L),
# XIntField("durationh",0x000c0004L),
# XIntField("durationl",0x00007080L),
]
def post_build(self, p, pay):
if self.length is None:
l = len(p)
p = p[:2]+chr((l>>8)&0xff)+chr(l&0xff)+p[4:]
p += pay
return p
class ISAKMP_payload_Proposal(ISAKMP_class):
name = "IKE proposal"
# ISAKMP_payload_type = 0
fields_desc = [
ByteEnumField("next_payload",None,ISAKMP_payload_type),
ByteField("res",0),
FieldLenField("length",None,"trans","H"),
ByteField("proposal",1),
ByteEnumField("proto",1,{1:"ISAKMP"}),
FieldLenField("SPIsize",None,"SPI","B"),
ByteField("trans_nb",None),
StrLenField("SPI","","SPIsize"),
PacketLenField("trans",Raw(),ISAKMP_payload_Transform,"length",shift=8),
]
class ISAKMP_payload(ISAKMP_class):
name = "ISAKMP payload"
fields_desc = [
ByteEnumField("next_payload",None,ISAKMP_payload_type),
ByteField("res",0),
FieldLenField("length",None,"load","H"),
StrLenField("load","","length",shift=4),
]
class ISAKMP_payload_VendorID(ISAKMP_class):
name = "ISAKMP Vendor ID"
overload_fields = { ISAKMP: { "next_payload":13 }}
fields_desc = [
ByteEnumField("next_payload",None,ISAKMP_payload_type),
ByteField("res",0),
FieldLenField("length",None,"vendorID","H"),
StrLenField("vendorID","","length",shift=4),
]
class ISAKMP_payload_SA(ISAKMP_class):
name = "ISAKMP SA"
overload_fields = { ISAKMP: { "next_payload":1 }}
fields_desc = [
ByteEnumField("next_payload",None,ISAKMP_payload_type),
ByteField("res",0),
FieldLenField("length",None,"prop","H"),
IntEnumField("DOI",1,{1:"IPSEC"}),
IntEnumField("situation",1,{1:"identity"}),
PacketLenField("prop",Raw(),ISAKMP_payload_Proposal,"length",shift=12),
]
class ISAKMP_payload_Nonce(ISAKMP_class):
name = "ISAKMP Nonce"
overload_fields = { ISAKMP: { "next_payload":10 }}
fields_desc = [
ByteEnumField("next_payload",None,ISAKMP_payload_type),
ByteField("res",0),
FieldLenField("length",None,"load","H"),
StrLenField("load","","length",shift=4),
]
class ISAKMP_payload_KE(ISAKMP_class):
name = "ISAKMP Key Exchange"
overload_fields = { ISAKMP: { "next_payload":4 }}
fields_desc = [
ByteEnumField("next_payload",None,ISAKMP_payload_type),
ByteField("res",0),
FieldLenField("length",None,"load","H"),
StrLenField("load","","length",shift=4),
]
class ISAKMP_payload_ID(ISAKMP_class):
name = "ISAKMP Identification"
overload_fields = { ISAKMP: { "next_payload":5 }}
fields_desc = [
ByteEnumField("next_payload",None,ISAKMP_payload_type),
ByteField("res",0),
FieldLenField("length",None,"load","H"),
ByteEnumField("IDtype",1,{1:"IPv4_addr", 11:"Key"}),
ByteEnumField("ProtoID",0,{0:"Unused"}),
ShortEnumField("Port",0,{0:"Unused"}),
# IPField("IdentData","127.0.0.1"),
StrLenField("load","","length",shift=8),
]
class ISAKMP_payload_Hash(ISAKMP_class):
name = "ISAKMP Hash"
overload_fields = { ISAKMP: { "next_payload":8 }}
fields_desc = [
ByteEnumField("next_payload",None,ISAKMP_payload_type),
ByteField("res",0),
FieldLenField("length",None,"load","H"),
StrLenField("load","","length",shift=4),
]
ISAKMP_payload_type_overload = {}
for i in range(len(ISAKMP_payload_type)):
name = "ISAKMP_payload_%s" % ISAKMP_payload_type[i]
if name in globals():
ISAKMP_payload_type_overload[globals()[name]] = {"next_payload":i}
del(i)
del(name)
ISAKMP_class.overload_fields = ISAKMP_payload_type_overload.copy()
# Cisco Skinny protocol
# shamelessly ripped from Ethereal dissector
skinny_messages = {
# Station -> Callmanager
0x0000: "KeepAliveMessage",
0x0001: "RegisterMessage",
0x0002: "IpPortMessage",
0x0003: "KeypadButtonMessage",
0x0004: "EnblocCallMessage",
0x0005: "StimulusMessage",
0x0006: "OffHookMessage",
0x0007: "OnHookMessage",
0x0008: "HookFlashMessage",
0x0009: "ForwardStatReqMessage",
0x000A: "SpeedDialStatReqMessage",
0x000B: "LineStatReqMessage",
0x000C: "ConfigStatReqMessage",
0x000D: "TimeDateReqMessage",
0x000E: "ButtonTemplateReqMessage",
0x000F: "VersionReqMessage",
0x0010: "CapabilitiesResMessage",
0x0011: "MediaPortListMessage",
0x0012: "ServerReqMessage",
0x0020: "AlarmMessage",
0x0021: "MulticastMediaReceptionAck",
0x0022: "OpenReceiveChannelAck",
0x0023: "ConnectionStatisticsRes",
0x0024: "OffHookWithCgpnMessage",
0x0025: "SoftKeySetReqMessage",
0x0026: "SoftKeyEventMessage",
0x0027: "UnregisterMessage",
0x0028: "SoftKeyTemplateReqMessage",
0x0029: "RegisterTokenReq",
0x002A: "MediaTransmissionFailure",
0x002B: "HeadsetStatusMessage",
0x002C: "MediaResourceNotification",
0x002D: "RegisterAvailableLinesMessage",
0x002E: "DeviceToUserDataMessage",
0x002F: "DeviceToUserDataResponseMessage",
0x0030: "UpdateCapabilitiesMessage",
0x0031: "OpenMultiMediaReceiveChannelAckMessage",
0x0032: "ClearConferenceMessage",
0x0033: "ServiceURLStatReqMessage",
0x0034: "FeatureStatReqMessage",
0x0035: "CreateConferenceResMessage",
0x0036: "DeleteConferenceResMessage",
0x0037: "ModifyConferenceResMessage",
0x0038: "AddParticipantResMessage",
0x0039: "AuditConferenceResMessage",
0x0040: "AuditParticipantResMessage",
0x0041: "DeviceToUserDataVersion1Message",
# Callmanager -> Station */
0x0081: "RegisterAckMessage",
0x0082: "StartToneMessage",
0x0083: "StopToneMessage",
0x0085: "SetRingerMessage",
0x0086: "SetLampMessage",
0x0087: "SetHkFDetectMessage",
0x0088: "SetSpeakerModeMessage",
0x0089: "SetMicroModeMessage",
0x008A: "StartMediaTransmission",
0x008B: "StopMediaTransmission",
0x008C: "StartMediaReception",
0x008D: "StopMediaReception",
0x008F: "CallInfoMessage",
0x0090: "ForwardStatMessage",
0x0091: "SpeedDialStatMessage",
0x0092: "LineStatMessage",
0x0093: "ConfigStatMessage",
0x0094: "DefineTimeDate",
0x0095: "StartSessionTransmission",
0x0096: "StopSessionTransmission",
0x0097: "ButtonTemplateMessage",
0x0098: "VersionMessage",
0x0099: "DisplayTextMessage",
0x009A: "ClearDisplay",
0x009B: "CapabilitiesReqMessage",
0x009C: "EnunciatorCommandMessage",
0x009D: "RegisterRejectMessage",
0x009E: "ServerResMessage",
0x009F: "Reset",
0x0100: "KeepAliveAckMessage",
0x0101: "StartMulticastMediaReception",
0x0102: "StartMulticastMediaTransmission",
0x0103: "StopMulticastMediaReception",
0x0104: "StopMulticastMediaTransmission",
0x0105: "OpenReceiveChannel",
0x0106: "CloseReceiveChannel",
0x0107: "ConnectionStatisticsReq",
0x0108: "SoftKeyTemplateResMessage",
0x0109: "SoftKeySetResMessage",
0x0110: "SelectSoftKeysMessage",
0x0111: "CallStateMessage",
0x0112: "DisplayPromptStatusMessage",
0x0113: "ClearPromptStatusMessage",
0x0114: "DisplayNotifyMessage",
0x0115: "ClearNotifyMessage",
0x0116: "ActivateCallPlaneMessage",
0x0117: "DeactivateCallPlaneMessage",
0x0118: "UnregisterAckMessage",
0x0119: "BackSpaceReqMessage",
0x011A: "RegisterTokenAck",
0x011B: "RegisterTokenReject",
0x0042: "DeviceToUserDataResponseVersion1Message",
0x011C: "StartMediaFailureDetection",
0x011D: "DialedNumberMessage",
0x011E: "UserToDeviceDataMessage",
0x011F: "FeatureStatMessage",
0x0120: "DisplayPriNotifyMessage",
0x0121: "ClearPriNotifyMessage",
0x0122: "StartAnnouncementMessage",
0x0123: "StopAnnouncementMessage",
0x0124: "AnnouncementFinishMessage",
0x0127: "NotifyDtmfToneMessage",
0x0128: "SendDtmfToneMessage",
0x0129: "SubscribeDtmfPayloadReqMessage",
0x012A: "SubscribeDtmfPayloadResMessage",
0x012B: "SubscribeDtmfPayloadErrMessage",
0x012C: "UnSubscribeDtmfPayloadReqMessage",
0x012D: "UnSubscribeDtmfPayloadResMessage",
0x012E: "UnSubscribeDtmfPayloadErrMessage",
0x012F: "ServiceURLStatMessage",
0x0130: "CallSelectStatMessage",
0x0131: "OpenMultiMediaChannelMessage",
0x0132: "StartMultiMediaTransmission",
0x0133: "StopMultiMediaTransmission",
0x0134: "MiscellaneousCommandMessage",
0x0135: "FlowControlCommandMessage",
0x0136: "CloseMultiMediaReceiveChannel",
0x0137: "CreateConferenceReqMessage",
0x0138: "DeleteConferenceReqMessage",
0x0139: "ModifyConferenceReqMessage",
0x013A: "AddParticipantReqMessage",
0x013B: "DropParticipantReqMessage",
0x013C: "AuditConferenceReqMessage",
0x013D: "AuditParticipantReqMessage",
0x013F: "UserToDeviceDataVersion1Message",
}
class Skinny(Packet):
name="Skinny"
fields_desc = [ LEIntField("len",0),
LEIntField("res",0),
LEIntEnumField("msg",0,skinny_messages) ]
### SEBEK
class SebekHead(Packet):
name = "Sebek header"
fields_desc = [ XIntField("magic", 0xd0d0d0),
ShortField("version", 1),
ShortEnumField("type", 0, {"read":0, "write":1,
"socket":2, "open":3}),
IntField("counter", 0),
IntField("time_sec", 0),
IntField("time_usec", 0) ]
def mysummary(self):
return self.sprintf("Sebek Header v%SebekHead.version% %SebekHead.type%")
# we need this because Sebek headers differ between v1 and v3, and
# between v3 type socket and v3 others
class SebekV1(Packet):
name = "Sebek v1"
fields_desc = [ IntField("pid", 0),
IntField("uid", 0),
IntField("fd", 0),
StrFixedLenField("command", "", 12),
FieldLenField("data_length", None, "data",fmt="I"),
StrLenField("data", "", "data_length") ]
def mysummary(self):
if isinstance(self.underlayer, SebekHead):
return self.underlayer.sprintf("Sebek v1 %SebekHead.type% (%SebekV1.command%)")
else:
return self.sprintf("Sebek v1 (%SebekV1.command%)")
class SebekV3(Packet):
name = "Sebek v3"
fields_desc = [ IntField("parent_pid", 0),
IntField("pid", 0),
IntField("uid", 0),
IntField("fd", 0),
IntField("inode", 0),
StrFixedLenField("command", "", 12),
FieldLenField("data_length", None, "data",fmt="I"),
StrLenField("data", "", "data_length") ]
def mysummary(self):
if isinstance(self.underlayer, SebekHead):
return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV3.command%)")
else:
return self.sprintf("Sebek v3 (%SebekV3.command%)")
class SebekV2(SebekV3):
def mysummary(self):
if isinstance(self.underlayer, SebekHead):
return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV2.command%)")
else:
return self.sprintf("Sebek v2 (%SebekV2.command%)")
class SebekV3Sock(Packet):
name = "Sebek v2 socket"
fields_desc = [ IntField("parent_pid", 0),
IntField("pid", 0),
IntField("uid", 0),
IntField("fd", 0),
IntField("inode", 0),
StrFixedLenField("command", "", 12),
IntField("data_length", 15),
IPField("dip", "127.0.0.1"),
ShortField("dport", 0),
IPField("sip", "127.0.0.1"),
ShortField("sport", 0),
ShortEnumField("call", 0, { "bind":2,
"connect":3, "listen":4,
"accept":5, "sendmsg":16,
"recvmsg":17, "sendto":11,
"recvfrom":12}),
ByteEnumField("proto", 0, IP_PROTOS) ]
def mysummary(self):
if isinstance(self.underlayer, SebekHead):
return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV3Sock.command%)")
else:
return self.sprintf("Sebek v3 socket (%SebekV3Sock.command%)")
class SebekV2Sock(SebekV3Sock):
def mysummary(self):
if isinstance(self.underlayer, SebekHead):
return self.underlayer.sprintf("Sebek v%SebekHead.version% %SebekHead.type% (%SebekV2Sock.command%)")
else:
return self.sprintf("Sebek v2 socket (%SebekV2Sock.command%)")
class MGCP(Packet):
name = "MGCP"
longname = "Media Gateway Control Protocol"
fields_desc = [ StrStopField("verb","AUEP"," ", -1),
StrFixedLenField("sep1"," ",1),
StrStopField("transaction_id","1234567"," ", -1),
StrFixedLenField("sep2"," ",1),
StrStopField("endpoint","dummy@dummy.net"," ", -1),
StrFixedLenField("sep3"," ",1),
StrStopField("version","MGCP 1.0 NCS 1.0","\x0a", -1),
StrFixedLenField("sep4","\x0a",1),
]
#class MGCP(Packet):
# name = "MGCP"
# longname = "Media Gateway Control Protocol"
# fields_desc = [ ByteEnumField("type",0, ["request","response","others"]),
# ByteField("code0",0),
# ByteField("code1",0),
# ByteField("code2",0),
# ByteField("code3",0),
# ByteField("code4",0),
# IntField("trasid",0),
# IntField("req_time",0),
# ByteField("is_duplicate",0),
# ByteField("req_available",0) ]
#
class GPRS(Packet):
name = "GPRSdummy"
fields_desc = [
StrStopField("dummy","","\x65\x00\x00",1)
]
class HCI_Hdr(Packet):
name = "HCI header"
fields_desc = [ ByteEnumField("type",2,{1:"command",2:"ACLdata",3:"SCOdata",4:"event",5:"vendor"}),]
def mysummary(self):
return self.sprintf("HCI %type%")
class HCI_ACL_Hdr(Packet):
name = "HCI ACL header"
fields_desc = [ ByteField("handle",0), # Actually, handle is 12 bits and flags is 4.
ByteField("flags",0), # I wait to write a LEBitField
LEShortField("len",None), ]
def post_build(self, p, pay):
p += pay
if self.len is None:
l = len(p)-4
p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:]
return p
class L2CAP_Hdr(Packet):
name = "L2CAP header"
fields_desc = [ LEShortField("len",None),
LEShortEnumField("cid",0,{1:"control"}),]
def post_build(self, p, pay):
p += pay
if self.len is None:
l = len(p)-4
p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:]
return p
class L2CAP_CmdHdr(Packet):
name = "L2CAP command header"
fields_desc = [
ByteEnumField("code",8,{1:"rej",2:"conn_req",3:"conn_resp",
4:"conf_req",5:"conf_resp",6:"disconn_req",
7:"disconn_resp",8:"echo_req",9:"echo_resp",
10:"info_req",11:"info_resp"}),
ByteField("id",0),
LEShortField("len",None) ]
def post_build(self, p, pay):
p += pay
if self.len is None:
l = len(p)-4
p = p[:2]+chr(l&0xff)+chr((l>>8)&0xff)+p[4:]
return p
def answers(self, other):
if other.id == self.id:
if self.code == 1:
return 1
if other.code in [2,4,6,8,10] and self.code == other.code+1:
if other.code == 8:
return 1
return self.payload.answers(other.payload)
return 0
class L2CAP_ConnReq(Packet):
name = "L2CAP Conn Req"
fields_desc = [ LEShortEnumField("psm",0,{1:"SDP",3:"RFCOMM",5:"telephony control"}),
LEShortField("scid",0),
]
class L2CAP_ConnResp(Packet):
name = "L2CAP Conn Resp"
fields_desc = [ LEShortField("dcid",0),
LEShortField("scid",0),
LEShortEnumField("result",0,["no_info","authen_pend","author_pend"]),
LEShortEnumField("status",0,["success","pend","bad_psm",
"cr_sec_block","cr_no_mem"]),
]
def answers(self, other):
return self.scid == other.scid
class L2CAP_CmdRej(Packet):
name = "L2CAP Command Rej"
fields_desc = [ LEShortField("reason",0),
]
class L2CAP_ConfReq(Packet):
name = "L2CAP Conf Req"
fields_desc = [ LEShortField("dcid",0),
LEShortField("flags",0),
]
class L2CAP_ConfResp(Packet):
name = "L2CAP Conf Resp"
fields_desc = [ LEShortField("scid",0),
LEShortField("flags",0),
LEShortEnumField("result",0,["success","unaccept","reject","unknown"]),
]
def answers(self, other):
return self.scid == other.scid
class L2CAP_DisconnReq(Packet):
name = "L2CAP Disconn Req"
fields_desc = [ LEShortField("dcid",0),
LEShortField("scid",0), ]
class L2CAP_DisconnResp(Packet):
name = "L2CAP Disconn Resp"
fields_desc = [ LEShortField("dcid",0),
LEShortField("scid",0), ]
def answers(self, other):
return self.scid == other.scid
class L2CAP_InfoReq(Packet):
name = "L2CAP Info Req"
fields_desc = [ LEShortEnumField("type",0,{1:"CL_MTU",2:"FEAT_MASK"}),
StrField("data","")
]
class L2CAP_InfoResp(Packet):
name = "L2CAP Info Resp"
fields_desc = [ LEShortField("type",0),
LEShortEnumField("result",0,["success","not_supp"]),
StrField("data",""), ]
def answers(self, other):
return self.type == other.type
class NetBIOS_DS(Packet):
name = "NetBIOS datagram service"
fields_desc = [
ByteEnumField("type",17, {17:"direct_group"}),
ByteField("flags",0),
XShortField("id",0),
IPField("src","127.0.0.1"),
ShortField("sport",138),
ShortField("len",None),
ShortField("ofs",0),
NetBIOSNameField("srcname",""),
NetBIOSNameField("dstname",""),
]
def post_build(self, p, pay):
p += pay
if self.len is None:
l = len(p)-14
p = p[:10]+struct.pack("!H", l)+p[12:]
return p
# ShortField("length",0),
# ShortField("Delimitor",0),
# ByteField("command",0),
# ByteField("data1",0),
# ShortField("data2",0),
# ShortField("XMIt",0),
# ShortField("RSPCor",0),
# StrFixedLenField("dest","",16),
# StrFixedLenField("source","",16),
#
# ]
#
# IR
class IrLAPHead(Packet):
name = "IrDA Link Access Protocol Header"
fields_desc = [ XBitField("Address", 0x7f, 7),
BitEnumField("Type", 1, 1, {"Response":0,
"Command":1})]
class IrLAPCommand(Packet):
name = "IrDA Link Access Protocol Command"
fields_desc = [ XByteField("Control", 0),
XByteField("Format identifier", 0),
XIntField("Source address", 0),
XIntField("Destination address", 0xffffffffL),
XByteField("Discovery flags", 0x1),
ByteEnumField("Slot number", 255, {"final":255}),
XByteField("Version", 0)]
class IrLMP(Packet):
name = "IrDA Link Management Protocol"
fields_desc = [ XShortField("Service hints", 0),
XByteField("Character set", 0),
StrField("Device name", "") ]
#NetBIOS
# Name Query Request
# Node Status Request
class NBNSQueryRequest(Packet):
name="NBNS query request"
fields_desc = [ShortField("NAME_TRN_ID",0),
ShortField("FLAGS", 0x0110),
ShortField("QDCOUNT",1),
ShortField("ANCOUNT",0),
ShortField("NSCOUNT",0),
ShortField("ARCOUNT",0),
NetBIOSNameField("QUESTION_NAME","windows"),
ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
ByteField("NULL",0),
ShortEnumField("QUESTION_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}),
ShortEnumField("QUESTION_CLASS",1,{1:"INTERNET"})]
# Name Registration Request
# Name Refresh Request
# Name Release Request or Demand
class NBNSRequest(Packet):
name="NBNS request"
fields_desc = [ShortField("NAME_TRN_ID",0),
ShortField("FLAGS", 0x2910),
ShortField("QDCOUNT",1),
ShortField("ANCOUNT",0),
ShortField("NSCOUNT",0),
ShortField("ARCOUNT",1),
NetBIOSNameField("QUESTION_NAME","windows"),
ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
ByteField("NULL",0),
ShortEnumField("QUESTION_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}),
ShortEnumField("QUESTION_CLASS",1,{1:"INTERNET"}),
ShortEnumField("RR_NAME",0xC00C,{0xC00C:"Label String Pointer to QUESTION_NAME"}),
ShortEnumField("RR_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}),
ShortEnumField("RR_CLASS",1,{1:"INTERNET"}),
IntField("TTL", 0),
ShortField("RDLENGTH", 6),
BitEnumField("G",0,1,{0:"Unique name",1:"Group name"}),
BitEnumField("OWNER NODE TYPE",00,2,{00:"B node",01:"P node",02:"M node",03:"H node"}),
BitEnumField("UNUSED",0,13,{0:"Unused"}),
IPField("NB_ADDRESS", "127.0.0.1")]
# Name Query Response
# Name Registration Response
class NBNSQueryResponse(Packet):
name="NBNS query response"
fields_desc = [ShortField("NAME_TRN_ID",0),
ShortField("FLAGS", 0x8500),
ShortField("QDCOUNT",0),
ShortField("ANCOUNT",1),
ShortField("NSCOUNT",0),
ShortField("ARCOUNT",0),
NetBIOSNameField("RR_NAME","windows"),
ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
ByteField("NULL",0),
ShortEnumField("QUESTION_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}),
ShortEnumField("QUESTION_CLASS",1,{1:"INTERNET"}),
IntField("TTL", 0x493e0),
ShortField("RDLENGTH", 6),
ShortField("NB_FLAGS", 0),
IPField("NB_ADDRESS", "127.0.0.1")]
# Name Query Response (negative)
# Name Release Response
class NBNSQueryResponseNegative(Packet):
name="NBNS query response (negative)"
fields_desc = [ShortField("NAME_TRN_ID",0),
ShortField("FLAGS", 0x8506),
ShortField("QDCOUNT",0),
ShortField("ANCOUNT",1),
ShortField("NSCOUNT",0),
ShortField("ARCOUNT",0),
NetBIOSNameField("RR_NAME","windows"),
ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
ByteField("NULL",0),
ShortEnumField("RR_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}),
ShortEnumField("RR_CLASS",1,{1:"INTERNET"}),
IntField("TTL",0),
ShortField("RDLENGTH",6),
BitEnumField("G",0,1,{0:"Unique name",1:"Group name"}),
BitEnumField("OWNER NODE TYPE",00,2,{00:"B node",01:"P node",02:"M node",03:"H node"}),
BitEnumField("UNUSED",0,13,{0:"Unused"}),
IPField("NB_ADDRESS", "127.0.0.1")]
# Node Status Response
class NBNSNodeStatusResponse(Packet):
name="NBNS Node Status Response"
fields_desc = [ShortField("NAME_TRN_ID",0),
ShortField("FLAGS", 0x8500),
ShortField("QDCOUNT",0),
ShortField("ANCOUNT",1),
ShortField("NSCOUNT",0),
ShortField("ARCOUNT",0),
NetBIOSNameField("RR_NAME","windows"),
ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
ByteField("NULL",0),
ShortEnumField("RR_TYPE",0x21, {0x20:"NB",0x21:"NBSTAT"}),
ShortEnumField("RR_CLASS",1,{1:"INTERNET"}),
IntField("TTL",0),
ShortField("RDLENGTH",83),
ByteField("NUM_NAMES",1)]
# Service for Node Status Response
class NBNSNodeStatusResponseService(Packet):
name="NBNS Node Status Response Service"
fields_desc = [StrFixedLenField("NETBIOS_NAME","WINDOWS ",15),
ByteEnumField("SUFFIX",0,{0:"workstation",0x03:"messenger service",0x20:"file server service",0x1b:"domain master browser",0x1c:"domain controller", 0x1e:"browser election service"}),
ByteField("NAME_FLAGS",0x4),
ByteEnumField("UNUSED",0,{0:"unused"})]
# End of Node Status Response packet
class NBNSNodeStatusResponseEnd(Packet):
name="NBNS Node Status Response"
fields_desc = [SourceMACField("MAC_ADDRESS"),
BitField("STATISTICS",0,57*8)]
# Wait for Acknowledgement Response
class NBNSWackResponse(Packet):
name="NBNS Wait for Acknowledgement Response"
fields_desc = [ShortField("NAME_TRN_ID",0),
ShortField("FLAGS", 0xBC07),
ShortField("QDCOUNT",0),
ShortField("ANCOUNT",1),
ShortField("NSCOUNT",0),
ShortField("ARCOUNT",0),
NetBIOSNameField("RR_NAME","windows"),
ShortEnumField("SUFFIX",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
ByteField("NULL",0),
ShortEnumField("RR_TYPE",0x20, {0x20:"NB",0x21:"NBSTAT"}),
ShortEnumField("RR_CLASS",1,{1:"INTERNET"}),
IntField("TTL", 2),
ShortField("RDLENGTH",2),
BitField("RDATA",10512,16)] #10512=0010100100010000
class NBTDatagram(Packet):
name="NBT Datagram Packet"
fields_desc= [ByteField("Type", 0x10),
ByteField("Flags", 0x02),
ShortField("ID", 0),
IPField("SourceIP", "127.0.0.1"),
ShortField("SourcePort", 138),
ShortField("Length", 272),
ShortField("Offset", 0),
NetBIOSNameField("SourceName","windows"),
ShortEnumField("SUFFIX1",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
ByteField("NULL",0),
NetBIOSNameField("DestinationName","windows"),
ShortEnumField("SUFFIX2",0x4141,{0x4141:"workstation",0x4141+0x03:"messenger service",0x4141+0x200:"file server service",0x4141+0x10b:"domain master browser",0x4141+0x10c:"domain controller", 0x4141+0x10e:"browser election service"}),
ByteField("NULL",0)]
class NBTSession(Packet):
name="NBT Session Packet"
fields_desc= [ByteEnumField("TYPE",0,{0x00:"Session Message",0x81:"Session Request",0x82:"Positive Session Response",0x83:"Negative Session Response",0x84:"Retarget Session Response",0x85:"Session Keepalive"}),
BitField("RESERVED",0x00,7),
BitField("LENGTH",0,17)]
# SMB NetLogon Response Header
class SMBNetlogon_Protocol_Response_Header(Packet):
name="SMBNetlogon Protocol Response Header"
fields_desc = [StrFixedLenField("Start","\xffSMB",4),
ByteEnumField("Command",0x25,{0x25:"Trans"}),
ByteField("Error_Class",0x02),
ByteField("Reserved",0),
LEShortField("Error_code",4),
ByteField("Flags",0),
LEShortField("Flags2",0x0000),
LEShortField("PIDHigh",0x0000),
LELongField("Signature",0x0),
LEShortField("Unused",0x0),
LEShortField("TID",0),
LEShortField("PID",0),
LEShortField("UID",0),
LEShortField("MID",0),
ByteField("WordCount",17),
LEShortField("TotalParamCount",0),
LEShortField("TotalDataCount",112),
LEShortField("MaxParamCount",0),
LEShortField("MaxDataCount",0),
ByteField("MaxSetupCount",0),
ByteField("unused2",0),
LEShortField("Flags3",0),
ByteField("TimeOut1",0xe8),
ByteField("TimeOut2",0x03),
LEShortField("unused3",0),
LEShortField("unused4",0),
LEShortField("ParamCount2",0),
LEShortField("ParamOffset",0),
LEShortField("DataCount",112),
LEShortField("DataOffset",92),
ByteField("SetupCount", 3),
ByteField("unused5", 0)]
# SMB MailSlot Protocol
class SMBMailSlot(Packet):
name = "SMB Mail Slot Protocol"
fields_desc = [LEShortField("opcode", 1),
LEShortField("priority", 1),
LEShortField("class", 2),
LEShortField("size", 135),
StrNullField("name","\MAILSLOT\NET\GETDC660")]
# SMB NetLogon Protocol Response Tail SAM
class SMBNetlogon_Protocol_Response_Tail_SAM(Packet):
name = "SMB Netlogon Protocol Response Tail SAM"
fields_desc = [ByteEnumField("Command", 0x17, {0x12:"SAM logon request", 0x17:"SAM Active directory Response"}),
ByteField("unused", 0),
ShortField("Data1", 0),
ShortField("Data2", 0xfd01),
ShortField("Data3", 0),
ShortField("Data4", 0xacde),
ShortField("Data5", 0x0fe5),
ShortField("Data6", 0xd10a),
ShortField("Data7", 0x374c),
ShortField("Data8", 0x83e2),
ShortField("Data9", 0x7dd9),
ShortField("Data10", 0x3a16),
ShortField("Data11", 0x73ff),
ByteField("Data12", 0x04),
StrFixedLenField("Data13", "rmff", 4),
ByteField("Data14", 0x0),
ShortField("Data16", 0xc018),
ByteField("Data18", 0x0a),
StrFixedLenField("Data20", "rmff-win2k", 10),
ByteField("Data21", 0xc0),
ShortField("Data22", 0x18c0),
ShortField("Data23", 0x180a),
StrFixedLenField("Data24", "RMFF-WIN2K", 10),
ShortField("Data25", 0),
ByteField("Data26", 0x17),
StrFixedLenField("Data27", "Default-First-Site-Name", 23),
ShortField("Data28", 0x00c0),
ShortField("Data29", 0x3c10),
ShortField("Data30", 0x00c0),
ShortField("Data31", 0x0200),
ShortField("Data32", 0x0),
ShortField("Data33", 0xac14),
ShortField("Data34", 0x0064),
ShortField("Data35", 0x0),
ShortField("Data36", 0x0),
ShortField("Data37", 0x0),
ShortField("Data38", 0x0),
ShortField("Data39", 0x0d00),
ShortField("Data40", 0x0),
ShortField("Data41", 0xffff)]
# SMB NetLogon Protocol Response Tail LM2.0
class SMBNetlogon_Protocol_Response_Tail_LM20(Packet):
name = "SMB Netlogon Protocol Response Tail LM20"
fields_desc = [ByteEnumField("Command",0x06,{0x06:"LM 2.0 Response to logon request"}),
ByteField("unused", 0),
StrFixedLenField("DblSlash", "\\\\", 2),
StrNullField("ServerName","WIN"),
LEShortField("LM20Token", 0xffff)]
# SMBNegociate Protocol Request Header
class SMBNegociate_Protocol_Request_Header(Packet):
name="SMBNegociate Protocol Request Header"
fields_desc = [StrFixedLenField("Start","\xffSMB",4),
ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}),
ByteField("Error_Class",0),
ByteField("Reserved",0),
LEShortField("Error_code",0),
ByteField("Flags",0x18),
LEShortField("Flags2",0x0000),
LEShortField("PIDHigh",0x0000),
LELongField("Signature",0x0),
LEShortField("Unused",0x0),
LEShortField("TID",0),
LEShortField("PID",1),
LEShortField("UID",0),
LEShortField("MID",2),
ByteField("WordCount",0),
LEShortField("ByteCount",12)]
# SMB Negociate Protocol Request Tail
class SMBNegociate_Protocol_Request_Tail(Packet):
name="SMB Negociate Protocol Request Tail"
fields_desc=[ByteField("BufferFormat",0x02),
StrNullField("BufferData","NT LM 0.12")]
# SMBNegociate Protocol Response Advanced Security
class SMBNegociate_Protocol_Response_Advanced_Security(Packet):
name="SMBNegociate Protocol Response Advanced Security"
fields_desc = [StrFixedLenField("Start","\xffSMB",4),
ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}),
ByteField("Error_Class",0),
ByteField("Reserved",0),
LEShortField("Error_Code",0),
ByteField("Flags",0x98),
LEShortField("Flags2",0x0000),
LEShortField("PIDHigh",0x0000),
LELongField("Signature",0x0),
LEShortField("Unused",0x0),
LEShortField("TID",0),
LEShortField("PID",1),
LEShortField("UID",0),
LEShortField("MID",2),
ByteField("WordCount",17),
LEShortField("DialectIndex",7),
ByteField("SecurityMode",0x03),
LEShortField("MaxMpxCount",50),
LEShortField("MaxNumberVC",1),
LEIntField("MaxBufferSize",16144),
LEIntField("MaxRawSize",65536),
LEIntField("SessionKey",0x0000),
LEShortField("ServerCapabilities",0xf3f9),
BitField("UnixExtensions",0,1),
BitField("Reserved2",0,7),
BitField("ExtendedSecurity",1,1),
BitField("CompBulk",0,2),
BitField("Reserved3",0,5),
# There have been 127490112000000000 tenths of micro-seconds between 1st january 1601 and 1st january 2005. 127490112000000000=0x1C4EF94D6228000, so ServerTimeHigh=0xD6228000 and ServerTimeLow=0x1C4EF94.
LEIntField("ServerTimeHigh",0xD6228000L),
LEIntField("ServerTimeLow",0x1C4EF94),
LEShortField("ServerTimeZone",0x3c),
ByteField("EncryptionKeyLength",0),
LEFieldLenField("ByteCount", None, "SecurityBlob"),
BitField("GUID",0,128),
StrLenField("SecurityBlob", "", "ByteCount",shift=-16)]
# SMBNegociate Protocol Response No Security
# When using no security, with EncryptionKeyLength=8, you must have an EncryptionKey before the DomainName
class SMBNegociate_Protocol_Response_No_Security(Packet):
name="SMBNegociate Protocol Response No Security"
fields_desc = [StrFixedLenField("Start","\xffSMB",4),
ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}),
ByteField("Error_Class",0),
ByteField("Reserved",0),
LEShortField("Error_Code",0),
ByteField("Flags",0x98),
LEShortField("Flags2",0x0000),
LEShortField("PIDHigh",0x0000),
LELongField("Signature",0x0),
LEShortField("Unused",0x0),
LEShortField("TID",0),
LEShortField("PID",1),
LEShortField("UID",0),
LEShortField("MID",2),
ByteField("WordCount",17),
LEShortField("DialectIndex",7),
ByteField("SecurityMode",0x03),
LEShortField("MaxMpxCount",50),
LEShortField("MaxNumberVC",1),
LEIntField("MaxBufferSize",16144),
LEIntField("MaxRawSize",65536),
LEIntField("SessionKey",0x0000),
LEShortField("ServerCapabilities",0xf3f9),
BitField("UnixExtensions",0,1),
BitField("Reserved2",0,7),
BitField("ExtendedSecurity",0,1),
FlagsField("CompBulk",0,2,"CB"),
BitField("Reserved3",0,5),
# There have been 127490112000000000 tenths of micro-seconds between 1st january 1601 and 1st january 2005. 127490112000000000=0x1C4EF94D6228000, so ServerTimeHigh=0xD6228000 and ServerTimeLow=0x1C4EF94.
LEIntField("ServerTimeHigh",0xD6228000L),
LEIntField("ServerTimeLow",0x1C4EF94),
LEShortField("ServerTimeZone",0x3c),
ByteField("EncryptionKeyLength",8),
LEShortField("ByteCount",24),
BitField("EncryptionKey",0,64),
StrNullField("DomainName","WORKGROUP"),
StrNullField("ServerName","RMFF1")]
# SMBNegociate Protocol Response No Security No Key
class SMBNegociate_Protocol_Response_No_Security_No_Key(Packet):
namez="SMBNegociate Protocol Response No Security No Key"
fields_desc = [StrFixedLenField("Start","\xffSMB",4),
ByteEnumField("Command",0x72,{0x72:"SMB_COM_NEGOTIATE"}),
ByteField("Error_Class",0),
ByteField("Reserved",0),
LEShortField("Error_Code",0),
ByteField("Flags",0x98),
LEShortField("Flags2",0x0000),
LEShortField("PIDHigh",0x0000),
LELongField("Signature",0x0),
LEShortField("Unused",0x0),
LEShortField("TID",0),
LEShortField("PID",1),
LEShortField("UID",0),
LEShortField("MID",2),
ByteField("WordCount",17),
LEShortField("DialectIndex",7),
ByteField("SecurityMode",0x03),
LEShortField("MaxMpxCount",50),
LEShortField("MaxNumberVC",1),
LEIntField("MaxBufferSize",16144),
LEIntField("MaxRawSize",65536),
LEIntField("SessionKey",0x0000),
LEShortField("ServerCapabilities",0xf3f9),
BitField("UnixExtensions",0,1),
BitField("Reserved2",0,7),
BitField("ExtendedSecurity",0,1),
FlagsField("CompBulk",0,2,"CB"),
BitField("Reserved3",0,5),
# There have been 127490112000000000 tenths of micro-seconds between 1st january 1601 and 1st january 2005. 127490112000000000=0x1C4EF94D6228000, so ServerTimeHigh=0xD6228000 and ServerTimeLow=0x1C4EF94.
LEIntField("ServerTimeHigh",0xD6228000L),
LEIntField("ServerTimeLow",0x1C4EF94),
LEShortField("ServerTimeZone",0x3c),
ByteField("EncryptionKeyLength",0),
LEShortField("ByteCount",16),
StrNullField("DomainName","WORKGROUP"),
StrNullField("ServerName","RMFF1")]
# Session Setup AndX Request
class SMBSession_Setup_AndX_Request(Packet):
name="Session Setup AndX Request"
fields_desc=[StrFixedLenField("Start","\xffSMB",4),
ByteEnumField("Command",0x73,{0x73:"SMB_COM_SESSION_SETUP_ANDX"}),
ByteField("Error_Class",0),
ByteField("Reserved",0),
LEShortField("Error_Code",0),
ByteField("Flags",0x18),
LEShortField("Flags2",0x0001),
LEShortField("PIDHigh",0x0000),
LELongField("Signature",0x0),
LEShortField("Unused",0x0),
LEShortField("TID",0),
LEShortField("PID",1),
LEShortField("UID",0),
LEShortField("MID",2),
ByteField("WordCount",13),
ByteEnumField("AndXCommand",0x75,{0x75:"SMB_COM_TREE_CONNECT_ANDX"}),
ByteField("Reserved2",0),
LEShortField("AndXOffset",96),
LEShortField("MaxBufferS",2920),
LEShortField("MaxMPXCount",50),
LEShortField("VCNumber",0),
LEIntField("SessionKey",0),
LEFieldLenField("ANSIPasswordLength",None,"ANSIPassword"),
LEShortField("UnicodePasswordLength",0),
LEIntField("Reserved3",0),
LEShortField("ServerCapabilities",0x05),
BitField("UnixExtensions",0,1),
BitField("Reserved4",0,7),
BitField("ExtendedSecurity",0,1),
BitField("CompBulk",0,2),
BitField("Reserved5",0,5),
LEShortField("ByteCount",35),
StrLenField("ANSIPassword", "Pass","ANSIPasswordLength"),
StrNullField("Account","GUEST"),
StrNullField("PrimaryDomain", ""),
StrNullField("NativeOS","Windows 4.0"),
StrNullField("NativeLanManager","Windows 4.0"),
ByteField("WordCount2",4),
ByteEnumField("AndXCommand2",0xFF,{0xFF:"SMB_COM_NONE"}),
ByteField("Reserved6",0),
LEShortField("AndXOffset2",0),
LEShortField("Flags3",0x2),
LEShortField("PasswordLength",0x1),
LEShortField("ByteCount2",18),
ByteField("Password",0),
StrNullField("Path","\\\\WIN2K\\IPC$"),
StrNullField("Service","IPC")]
# Session Setup AndX Response
class SMBSession_Setup_AndX_Response(Packet):
name="Session Setup AndX Response"
fields_desc=[StrFixedLenField("Start","\xffSMB",4),
ByteEnumField("Command",0x73,{0x73:"SMB_COM_SESSION_SETUP_ANDX"}),
ByteField("Error_Class",0),
ByteField("Reserved",0),
LEShortField("Error_Code",0),
ByteField("Flags",0x90),
LEShortField("Flags2",0x1001),
LEShortField("PIDHigh",0x0000),
LELongField("Signature",0x0),
LEShortField("Unused",0x0),
LEShortField("TID",0),
LEShortField("PID",1),
LEShortField("UID",0),
LEShortField("MID",2),
ByteField("WordCount",3),
ByteEnumField("AndXCommand",0x75,{0x75:"SMB_COM_TREE_CONNECT_ANDX"}),
ByteField("Reserved2",0),
LEShortField("AndXOffset",66),
LEShortField("Action",0),
LEShortField("ByteCount",25),
StrNullField("NativeOS","Windows 4.0"),
StrNullField("NativeLanManager","Windows 4.0"),
StrNullField("PrimaryDomain",""),
ByteField("WordCount2",3),
ByteEnumField("AndXCommand2",0xFF,{0xFF:"SMB_COM_NONE"}),
ByteField("Reserved3",0),
LEShortField("AndXOffset2",80),
LEShortField("OptionalSupport",0x01),
LEShortField("ByteCount2",5),
StrNullField("Service","IPC"),
StrNullField("NativeFileSystem","")]
class MobileIP(Packet):
name = "Mobile IP (RFC3344)"
fields_desc = [ ByteEnumField("type", 1, {1:"RRQ", 3:"RRP"}) ]
class MobileIPRRQ(Packet):
name = "Mobile IP Registration Request (RFC3344)"
fields_desc = [ XByteField("flags", 0),
ShortField("lifetime", 180),
IPField("homeaddr", "0.0.0.0"),
IPField("haaddr", "0.0.0.0"),
IPField("coaddr", "0.0.0.0"),
Field("id", "", "64s") ]
class MobileIPRRP(Packet):
name = "Mobile IP Registration Reply (RFC3344)"
fields_desc = [ ByteField("code", 0),
ShortField("lifetime", 180),
IPField("homeaddr", "0.0.0.0"),
IPField("haaddr", "0.0.0.0"),
Field("id", "", "64s") ]
class MobileIPTunnelData(Packet):
name = "Mobile IP Tunnel Data Message (RFC3519)"
fields_desc = [ ByteField("nexthdr", 4),
ShortField("res", 0) ]
# Cisco Netflow Protocol version 1
class NetflowHeader(Packet):
name = "Netflow Header"
fields_desc = [ ShortField("version", 1) ]
class NetflowHeaderV1(Packet):
name = "Netflow Header V1"
fields_desc = [ ShortField("count", 0),
IntField("sysUptime", 0),
IntField("unixSecs", 0),
IntField("unixNanoSeconds", 0) ]
class NetflowRecordV1(Packet):
name = "Netflow Record"
fields_desc = [ IPField("ipsrc", "0.0.0.0"),
IPField("ipdst", "0.0.0.0"),
IPField("nexthop", "0.0.0.0"),
ShortField("inputIfIndex", 0),
ShortField("outpuIfIndex", 0),
IntField("dpkts", 0),
IntField("dbytes", 0),
IntField("starttime", 0),
IntField("endtime", 0),
ShortField("srcport", 0),
ShortField("dstport", 0),
ShortField("padding", 0),
ByteField("proto", 0),
ByteField("tos", 0),
IntField("padding1", 0),
IntField("padding2", 0) ]
##########
## SNMP ##
##########
######[ ASN1 class ]######
class ASN1_Class_SNMP(ASN1_Class_UNIVERSAL):
name="SNMP"
PDU_GET = 0xa0
PDU_NEXT = 0xa1
PDU_RESPONSE = 0xa2
PDU_SET = 0xa3
PDU_TRAPv1 = 0xa4
PDU_BULK = 0xa5
PDU_INFORM = 0xa6
PDU_TRAPv2 = 0xa7
class ASN1_SNMP_PDU_GET(ASN1_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_GET
class ASN1_SNMP_PDU_NEXT(ASN1_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_NEXT
class ASN1_SNMP_PDU_RESPONSE(ASN1_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_RESPONSE
class ASN1_SNMP_PDU_SET(ASN1_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_SET
class ASN1_SNMP_PDU_TRAPv1(ASN1_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_TRAPv1
class ASN1_SNMP_PDU_BULK(ASN1_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_BULK
class ASN1_SNMP_PDU_INFORM(ASN1_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_INFORM
class ASN1_SNMP_PDU_TRAPv2(ASN1_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_TRAPv2
######[ BER codecs ]#######
class BERcodec_SNMP_PDU_GET(BERcodec_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_GET
class BERcodec_SNMP_PDU_NEXT(BERcodec_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_NEXT
class BERcodec_SNMP_PDU_RESPONSE(BERcodec_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_RESPONSE
class BERcodec_SNMP_PDU_SET(BERcodec_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_SET
class BERcodec_SNMP_PDU_TRAPv1(BERcodec_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_TRAPv1
class BERcodec_SNMP_PDU_BULK(BERcodec_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_BULK
class BERcodec_SNMP_PDU_INFORM(BERcodec_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_INFORM
class BERcodec_SNMP_PDU_TRAPv2(BERcodec_SEQUENCE):
tag = ASN1_Class_SNMP.PDU_TRAPv2
######[ ASN1 fields ]######
class ASN1F_SNMP_PDU_GET(ASN1F_SEQUENCE):
ASN1_tag = ASN1_Class_SNMP.PDU_GET
class ASN1F_SNMP_PDU_NEXT(ASN1F_SEQUENCE):
ASN1_tag = ASN1_Class_SNMP.PDU_NEXT
class ASN1F_SNMP_PDU_RESPONSE(ASN1F_SEQUENCE):
ASN1_tag = ASN1_Class_SNMP.PDU_RESPONSE
class ASN1F_SNMP_PDU_SET(ASN1F_SEQUENCE):
ASN1_tag = ASN1_Class_SNMP.PDU_SET
class ASN1F_SNMP_PDU_TRAPv1(ASN1F_SEQUENCE):
ASN1_tag = ASN1_Class_SNMP.PDU_TRAPv1
class ASN1F_SNMP_PDU_BULK(ASN1F_SEQUENCE):
ASN1_tag = ASN1_Class_SNMP.PDU_BULK
class ASN1F_SNMP_PDU_INFORM(ASN1F_SEQUENCE):
ASN1_tag = ASN1_Class_SNMP.PDU_INFORM
class ASN1F_SNMP_PDU_TRAPv2(ASN1F_SEQUENCE):
ASN1_tag = ASN1_Class_SNMP.PDU_TRAPv2
######[ SNMP Packet ]######
SNMP_error = { 0: "no_error",
1: "too_big",
2: "no_such_name",
3: "bad_value",
4: "read_only",
5: "generic_error",
6: "no_access",
7: "wrong_type",
8: "wrong_length",
9: "wrong_encoding",
10: "wrong_value",
11: "no_creation",
12: "inconsistent_value",
13: "ressource_unavailable",
14: "commit_failed",
15: "undo_failed",
16: "authorization_error",
17: "not_writable",
18: "inconsistent_name",
}
SNMP_trap_types = { 0: "cold_start",
1: "warm_start",
2: "link_down",
3: "link_up",
4: "auth_failure",
5: "egp_neigh_loss",
6: "enterprise_specific",
}
class SNMPvarbind(ASN1_Packet):
ASN1_codec = ASN1_Codecs.BER
ASN1_root = ASN1F_SEQUENCE( ASN1F_OID("oid","1.3"),
ASN1F_field("value",ASN1_NULL(0))
)
class SNMPget(ASN1_Packet):
ASN1_codec = ASN1_Codecs.BER
ASN1_root = ASN1F_SNMP_PDU_GET( ASN1F_INTEGER("id",0),
ASN1F_enum_INTEGER("error",0, SNMP_error),
ASN1F_INTEGER("error_index",0),
ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
)
class SNMPnext(ASN1_Packet):
ASN1_codec = ASN1_Codecs.BER
ASN1_root = ASN1F_SNMP_PDU_NEXT( ASN1F_INTEGER("id",0),
ASN1F_enum_INTEGER("error",0, SNMP_error),
ASN1F_INTEGER("error_index",0),
ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
)
class SNMPresponse(ASN1_Packet):
ASN1_codec = ASN1_Codecs.BER
ASN1_root = ASN1F_SNMP_PDU_RESPONSE( ASN1F_INTEGER("id",0),
ASN1F_enum_INTEGER("error",0, SNMP_error),
ASN1F_INTEGER("error_index",0),
ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
)
class SNMPset(ASN1_Packet):
ASN1_codec = ASN1_Codecs.BER
ASN1_root = ASN1F_SNMP_PDU_SET( ASN1F_INTEGER("id",0),
ASN1F_enum_INTEGER("error",0, SNMP_error),
ASN1F_INTEGER("error_index",0),
ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
)
class SNMPtrapv1(ASN1_Packet):
ASN1_codec = ASN1_Codecs.BER
ASN1_root = ASN1F_SNMP_PDU_TRAPv1( ASN1F_INTEGER("id",0),
ASN1F_OID("enterprise", "1.3"),
ASN1F_STRING("agent_addr",""),
ASN1F_enum_INTEGER("generic_trap", 0, SNMP_trap_types),
ASN1F_INTEGER("specific_trap", 0),
ASN1F_INTEGER("time_stamp", IntAutoTime()),
ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
)
class SNMPbulk(ASN1_Packet):
ASN1_codec = ASN1_Codecs.BER
ASN1_root = ASN1F_SNMP_PDU_BULK( ASN1F_INTEGER("id",0),
ASN1F_INTEGER("non_repeaters",0),
ASN1F_INTEGER("max_repetitions",0),
ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
)
class SNMPinform(ASN1_Packet):
ASN1_codec = ASN1_Codecs.BER
ASN1_root = ASN1F_SNMP_PDU_INFORM( ASN1F_INTEGER("id",0),
ASN1F_enum_INTEGER("error",0, SNMP_error),
ASN1F_INTEGER("error_index",0),
ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
)
class SNMPtrapv2(ASN1_Packet):
ASN1_codec = ASN1_Codecs.BER
ASN1_root = ASN1F_SNMP_PDU_TRAPv2( ASN1F_INTEGER("id",0),
ASN1F_enum_INTEGER("error",0, SNMP_error),
ASN1F_INTEGER("error_index",0),
ASN1F_SEQUENCE_OF("varbindlist", [], SNMPvarbind)
)
class SNMP(ASN1_Packet):
ASN1_codec = ASN1_Codecs.BER
ASN1_root = ASN1F_SEQUENCE(
ASN1F_enum_INTEGER("version", 1, {0:"v1", 1:"v2c", 2:"v2", 3:"v3"}),
ASN1F_STRING("community","public"),
ASN1F_CHOICE("PDU", SNMPget(),
SNMPget, SNMPnext, SNMPresponse, SNMPset,
SNMPtrapv1, SNMPbulk, SNMPinform, SNMPtrapv2)
)
def answers(self, other):
return ( isinstance(self.PDU, SNMPresponse) and
( isinstance(other.PDU, SNMPget) or
isinstance(other.PDU, SNMPnext) or
isinstance(other.PDU, SNMPset) ) and
self.PDU.id == other.PDU.id )
#################
## Bind layers ##
#################
def bind_bottom_up(lower, upper, __fval=None, **fval):
if __fval is not None:
fval.update(__fval)
lower.payload_guess = lower.payload_guess[:]
lower.payload_guess.append((fval, upper))
def bind_top_down(lower, upper, __fval=None, **fval):
if __fval is not None:
fval.update(__fval)
upper.overload_fields = upper.overload_fields.copy()
upper.overload_fields[lower] = fval
def bind_layers(lower, upper, __fval=None, **fval):
if __fval is not None:
fval.update(__fval)
bind_top_down(lower, upper, **fval)
bind_bottom_up(lower, upper, **fval)
def split_bottom_up(lower, upper, __fval=None, **fval):
if __fval is not None:
fval.update(__fval)
def do_filter((f,u),upper=upper,fval=fval):
if u != upper:
return True
for k in fval:
if k not in f or f[k] != fval[k]:
return True
return False
lower.payload_guess = filter(do_filter, lower.payload_guess)
def split_top_down(lower, upper, __fval=None, **fval):
if __fval is not None:
fval.update(__fval)
if lower in upper.overload_fields:
ofval = upper.overload_fields[lower]
for k in fval:
if k not in ofval or ofval[k] != fval[k]:
return
upper.overload_fields = upper.overload_fields.copy()
del(upper.overload_fields[lower])
def split_layers(lower, upper, __fval=None, **fval):
if __fval is not None:
fval.update(__fval)
split_bottom_up(lower, upper, **fval)
split_top_down(lower, upper, **fval)
layer_bonds = [ ( Dot3, LLC, { } ),
( GPRS, IP, { } ),
( PrismHeader, Dot11, { }),
( Dot11, LLC, { "type" : 2 } ),
( PPP, IP, { "proto" : 0x0021 } ),
( Ether, LLC, { "type" : 0x007a } ),
( Ether, Dot1Q, { "type" : 0x8100 } ),
( Ether, Ether, { "type" : 0x0001 } ),
( Ether, ARP, { "type" : 0x0806 } ),
( Ether, IP, { "type" : 0x0800 } ),
( Ether, EAPOL, { "type" : 0x888e } ),
( Ether, EAPOL, { "type" : 0x888e, "dst" : "01:80:c2:00:00:03" } ),
( Ether, PPPoED, { "type" : 0x8863 } ),
( Ether, PPPoE, { "type" : 0x8864 } ),
( CookedLinux, LLC, { "proto" : 0x007a } ),
( CookedLinux, Dot1Q, { "proto" : 0x8100 } ),
( CookedLinux, Ether, { "proto" : 0x0001 } ),
( CookedLinux, ARP, { "proto" : 0x0806 } ),
( CookedLinux, IP, { "proto" : 0x0800 } ),
( CookedLinux, EAPOL, { "proto" : 0x888e } ),
( CookedLinux, PPPoED, { "proto" : 0x8863 } ),
( CookedLinux, PPPoE, { "proto" : 0x8864 } ),
( GRE, LLC, { "proto" : 0x007a } ),
( GRE, Dot1Q, { "proto" : 0x8100 } ),
( GRE, Ether, { "proto" : 0x0001 } ),
( GRE, ARP, { "proto" : 0x0806 } ),
( GRE, IP, { "proto" : 0x0800 } ),
( GRE, EAPOL, { "proto" : 0x888e } ),
( PPPoE, PPP, { "code" : 0x00 } ),
( EAPOL, EAP, { "type" : EAPOL.EAP_PACKET } ),
( LLC, STP, { "dsap" : 0x42 , "ssap" : 0x42, "ctrl":3 } ),
( LLC, SNAP, { "dsap" : 0xAA , "ssap" : 0xAA, "ctrl":3 } ),
( SNAP, Dot1Q, { "code" : 0x8100 } ),
( SNAP, Ether, { "code" : 0x0001 } ),
( SNAP, ARP, { "code" : 0x0806 } ),
( SNAP, IP, { "code" : 0x0800 } ),
( SNAP, EAPOL, { "code" : 0x888e } ),
( SNAP, STP, { "code" : 0x010b } ),
( IPerror,IPerror, { "frag" : 0, "proto" : socket.IPPROTO_IPIP } ),
( IPerror,ICMPerror,{ "frag" : 0, "proto" : socket.IPPROTO_ICMP } ),
( IPerror,TCPerror, { "frag" : 0, "proto" : socket.IPPROTO_TCP } ),
( IPerror,UDPerror, { "frag" : 0, "proto" : socket.IPPROTO_UDP } ),
( IP, IP, { "frag" : 0, "proto" : socket.IPPROTO_IPIP } ),
( IP, ICMP, { "frag" : 0, "proto" : socket.IPPROTO_ICMP } ),
( IP, TCP, { "frag" : 0, "proto" : socket.IPPROTO_TCP } ),
( IP, UDP, { "frag" : 0, "proto" : socket.IPPROTO_UDP } ),
( IP, GRE, { "frag" : 0, "proto" : socket.IPPROTO_GRE } ),
( UDP, SNMP, { "sport" : 161 } ),
( UDP, SNMP, { "dport" : 161 } ),
( UDP, MGCP, { "dport" : 2727 } ),
( UDP, MGCP, { "sport" : 2727 } ),
( UDP, DNS, { "dport" : 53 } ),
( UDP, DNS, { "sport" : 53 } ),
( UDP, ISAKMP, { "sport" : 500, "dport" : 500 } ),
( UDP, HSRP, { "sport" : 1985, "dport" : 1985} ),
( UDP, NTP, { "sport" : 123, "dport" : 123 } ),
( UDP, BOOTP, { "sport" : 68, "dport" : 67 } ),
( UDP, BOOTP, { "sport" : 67, "dport" : 68 } ),
( BOOTP, DHCP, { "options" : dhcpmagic } ),
( UDP, RIP, { "sport" : 520 } ),
( UDP, RIP, { "dport" : 520 } ),
( RIP, RIPEntry, { } ),
( RIPEntry,RIPEntry,{ } ),
( Dot11, Dot11AssoReq, { "type" : 0, "subtype" : 0 } ),
( Dot11, Dot11AssoResp, { "type" : 0, "subtype" : 1 } ),
( Dot11, Dot11ReassoReq, { "type" : 0, "subtype" : 2 } ),
( Dot11, Dot11ReassoResp, { "type" : 0, "subtype" : 3 } ),
( Dot11, Dot11ProbeReq, { "type" : 0, "subtype" : 4 } ),
( Dot11, Dot11ProbeResp, { "type" : 0, "subtype" : 5 } ),
( Dot11, Dot11Beacon, { "type" : 0, "subtype" : 8 } ),
( Dot11, Dot11ATIM , { "type" : 0, "subtype" : 9 } ),
( Dot11, Dot11Disas , { "type" : 0, "subtype" : 10 } ),
( Dot11, Dot11Auth, { "type" : 0, "subtype" : 11 } ),
( Dot11, Dot11Deauth, { "type" : 0, "subtype" : 12 } ),
( Dot11Beacon, Dot11Elt, {} ),
( Dot11AssoReq, Dot11Elt, {} ),
( Dot11AssoResp, Dot11Elt, {} ),
( Dot11ReassoReq, Dot11Elt, {} ),
( Dot11ReassoResp, Dot11Elt, {} ),
( Dot11ProbeReq, Dot11Elt, {} ),
( Dot11ProbeResp, Dot11Elt, {} ),
( Dot11Auth, Dot11Elt, {} ),
( Dot11Elt, Dot11Elt, {} ),
( TCP, Skinny, { "dport": 2000 } ),
( TCP, Skinny, { "sport": 2000 } ),
( UDP, SebekHead, { "sport" : 1101 } ),
( UDP, SebekHead, { "dport" : 1101 } ),
( UDP, SebekHead, { "sport" : 1101,
"dport" : 1101 } ),
( SebekHead, SebekV1, { "version" : 1 } ),
( SebekHead, SebekV2Sock, { "version" : 2,
"type" : 2 } ),
( SebekHead, SebekV2, { "version" : 2 } ),
( SebekHead, SebekV3Sock, { "version" : 3,
"type" : 2 } ),
( SebekHead, SebekV3, { "version" : 3 } ),
( CookedLinux, IrLAPHead, { "proto" : 0x0017 } ),
( IrLAPHead, IrLAPCommand, { "Type" : 1} ),
( IrLAPCommand, IrLMP, {} ),
(UDP, NBNSQueryRequest, {"dport" : 137 }),
(UDP, NBNSRequest, {"dport" : 137 }),
(UDP, NBNSQueryResponse, {"sport" : 137}),
(UDP, NBNSQueryResponseNegative, {"sport" : 137}),
(UDP, NBNSNodeStatusResponse, {"sport" : 137}),
(NBNSNodeStatusResponse, NBNSNodeStatusResponseService, {}),
(NBNSNodeStatusResponse, NBNSNodeStatusResponseService, {}),
(NBNSNodeStatusResponseService, NBNSNodeStatusResponseService, {}),
(NBNSNodeStatusResponseService, NBNSNodeStatusResponseEnd, {}),
(UDP, NBNSWackResponse, {"sport" : 137}),
(UDP,NBTDatagram,{ "dport":138}),
(TCP,NBTSession,{"dport":139}),
(NBTSession, SMBNegociate_Protocol_Request_Header,{}),
(SMBNegociate_Protocol_Request_Header,SMBNegociate_Protocol_Request_Tail,{}),
(SMBNegociate_Protocol_Request_Tail,SMBNegociate_Protocol_Request_Tail,{}),
(NBTSession, SMBNegociate_Protocol_Response_Advanced_Security,{"ExtendedSecurity":1}),
(NBTSession, SMBNegociate_Protocol_Response_No_Security,{"ExtendedSecurity":0,"EncryptionKeyLength":8 }),
(NBTSession, SMBNegociate_Protocol_Response_No_Security_No_Key,{"ExtendedSecurity":0,"EncryptionKeyLength":0 }),
(NBTSession, SMBSession_Setup_AndX_Request,{}),
(NBTSession, SMBSession_Setup_AndX_Response,{}),
(HCI_Hdr, HCI_ACL_Hdr, {"type":2}),
(HCI_Hdr, Raw, {}),
(HCI_ACL_Hdr, L2CAP_Hdr, {}),
(L2CAP_Hdr, L2CAP_CmdHdr, {"cid":1}),
(L2CAP_CmdHdr, L2CAP_CmdRej, {"code":1}),
(L2CAP_CmdHdr, L2CAP_ConnReq, {"code":2}),
(L2CAP_CmdHdr, L2CAP_ConnResp, {"code":3}),
(L2CAP_CmdHdr, L2CAP_ConfReq, {"code":4}),
(L2CAP_CmdHdr, L2CAP_ConfResp, {"code":5}),
(L2CAP_CmdHdr, L2CAP_DisconnReq, {"code":6}),
(L2CAP_CmdHdr, L2CAP_DisconnResp, {"code":7}),
(L2CAP_CmdHdr, L2CAP_InfoReq, {"code":10}),
(L2CAP_CmdHdr, L2CAP_InfoResp, {"code":11}),
( UDP, MobileIP, { "sport" : 434 } ),
( UDP, MobileIP, { "dport" : 434 } ),
( MobileIP, MobileIPRRQ, { "type" : 1 } ),
( MobileIP, MobileIPRRP, { "type" : 3 } ),
( MobileIP, MobileIPTunnelData, { "type" : 4 } ),
( MobileIPTunnelData, IP, { "nexthdr" : 4 } ),
( NetflowHeader, NetflowHeaderV1, { "version" : 1 } ),
( NetflowHeaderV1, NetflowRecordV1, {} ),
]
for l in layer_bonds:
bind_layers(*l)
del(l)
###################
## Fragmentation ##
###################
def fragment(pkt, fragsize=1480):
fragsize = (fragsize+7)/8*8
lst = []
for p in pkt:
s = str(p[IP].payload)
nb = (len(s)+fragsize-1)/fragsize
for i in range(nb):
q = p.copy()
del(q[IP].payload)
del(q[IP].chksum)
del(q[IP].len)
if i == nb-1:
q[IP].flags &= ~1
else:
q[IP].flags |= 1
q[IP].frag = i*fragsize/8
r = Raw(load=s[i*fragsize:(i+1)*fragsize])
r.overload_fields = p[IP].payload.overload_fields.copy()
q.add_payload(r)
lst.append(q)
return lst
def overlap_frag(p, overlap, fragsize=8, overlap_fragsize=None):
if overlap_fragsize is None:
overlap_fragsize = fragsize
q = p.copy()
del(q[IP].payload)
q[IP].add_payload(overlap)
qfrag = fragment(q, overlap_fragsize)
qfrag[-1][IP].flags |= 1
return qfrag+fragment(p, fragsize)
def defrag(plist):
"""defrag(plist) -> ([not fragmented], [defragmented],
[ [bad fragments], [bad fragments], ... ])"""
frags = {}
nofrag = PacketList()
for p in plist:
ip = p[IP]
if IP not in p:
nofrag.append(p)
continue
if ip.frag == 0 and ip.flags & 1 == 0:
nofrag.append(p)
continue
uniq = (ip.id,ip.src,ip.dst,ip.proto)
if uniq in frags:
frags[uniq].append(p)
else:
frags[uniq] = PacketList([p])
defrag = []
missfrag = []
for lst in frags.itervalues():
lst.sort(lambda x,y:cmp(x.frag, y.frag))
p = lst[0]
if p.frag > 0:
missfrag.append(lst)
continue
p = p.copy()
if Padding in p:
del(p[Padding].underlayer.payload)
ip = p[IP]
if ip.len is None or ip.ihl is None:
clen = len(ip.payload)
else:
clen = ip.len - (ip.ihl<<2)
txt = Raw()
for q in lst[1:]:
if clen != q.frag<<3:
if clen > q.frag<<3:
warning("Fragment overlap (%i > %i) %r || %r || %r" % (clen, q.frag<<3, p,txt,q))
missfrag.append(lst)
txt = None
break
if q[IP].len is None or q[IP].ihl is None:
clen += len(q[IP].payload)
else:
clen += q[IP].len - (q[IP].ihl<<2)
if Padding in q:
del(q[Padding].underlayer.payload)
txt.add_payload(q[IP].payload.copy())
if txt is None:
continue
ip.flags &= ~1 # !MF
del(ip.chksum)
del(ip.len)
p = p/txt
defrag.append(p)
defrag2=PacketList()
for p in defrag:
defrag2.append(p.__class__(str(p)))
return nofrag,defrag2,missfrag
###################
## Super sockets ##
###################
def Ether_Dot3_Dispatcher(pkt=None, **kargs):
if type(pkt) is str and len(pkt) >= 14 and struct.unpack("!H", pkt[12:14])[0] <= 1500:
return Dot3(pkt, **kargs)
return Ether(pkt, **kargs)
# According to libdnet
LLTypes = { ARPHDR_ETHER : Ether_Dot3_Dispatcher,
ARPHDR_METRICOM : Ether_Dot3_Dispatcher,
ARPHDR_LOOPBACK : Ether_Dot3_Dispatcher,
12 : IP,
101 : IP,
801 : Dot11,
802 : PrismHeader,
105 : Dot11,
113 : CookedLinux,
119 : PrismHeader, # for atheros
144 : CookedLinux, # called LINUX_IRDA, similar to CookedLinux
783 : IrLAPHead,
0xB1E70073L : HCI_Hdr, # I invented this one
}
LLNumTypes = { Ether : ARPHDR_ETHER,
IP : 12,
IP : 101,
Dot11 : 801,
PrismHeader : 802,
Dot11 : 105,
CookedLinux : 113,
CookedLinux : 144,
IrLAPHead : 783
}
L3Types = { ETH_P_IP : IP,
ETH_P_ARP : ARP,
ETH_P_ALL : IP
}
class SuperSocket:
closed=0
def __init__(self, family=socket.AF_INET,type=socket.SOCK_STREAM, proto=0):
self.ins = socket.socket(family, type, proto)
self.outs = self.ins
self.promisc=None
def send(self, x):
return self.outs.send(str(x))
def recv(self, x):
return Raw(self.ins.recv(x))
def fileno(self):
return self.ins.fileno()
def close(self):
if self.closed:
return
self.closed=1
if self.ins != self.outs:
if self.outs and self.outs.fileno() != -1:
self.outs.close()
if self.ins and self.ins.fileno() != -1:
self.ins.close()
def bind_in(self, addr):
self.ins.bind(addr)
def bind_out(self, addr):
self.outs.bind(addr)
class L3RawSocket(SuperSocket):
def __init__(self, type = ETH_P_IP, filter=None, iface=None, promisc=None, nofilter=0):
self.outs = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
self.outs.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1)
self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))
def recv(self, x):
return Ether(self.ins.recv(x)).payload
def send(self, x):
try:
self.outs.sendto(str(x),(x.dst,0))
except socket.error,msg:
log_runtime.error(msg)
class L3PacketSocket(SuperSocket):
def __init__(self, type = ETH_P_ALL, filter=None, promisc=None, iface=None, nofilter=0):
self.type = type
self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))
self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0)
if not nofilter:
if conf.except_filter:
if filter:
filter = "(%s) and not (%s)" % (filter, conf.except_filter)
else:
filter = "not (%s)" % conf.except_filter
if filter is not None:
attach_filter(self.ins, filter)
self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30)
self.outs = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))
self.outs.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2**30)
if promisc is None:
promisc = conf.promisc
self.promisc = promisc
if self.promisc:
if iface is None:
self.iff = get_if_list()
else:
if iface.__class__ is list:
self.iff = iface
else:
self.iff = [iface]
for i in self.iff:
set_promisc(self.ins, i)
def close(self):
if self.closed:
return
self.closed=1
if self.promisc:
for i in self.iff:
set_promisc(self.ins, i, 0)
SuperSocket.close(self)
def recv(self, x):
pkt, sa_ll = self.ins.recvfrom(x)
if sa_ll[2] == socket.PACKET_OUTGOING:
return None
if LLTypes.has_key(sa_ll[3]):
cls = LLTypes[sa_ll[3]]
lvl = 2
elif L3Types.has_key(sa_ll[1]):
cls = L3Types[sa_ll[1]]
lvl = 3
else:
warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using Ethernet" % (sa_ll[0],sa_ll[1],sa_ll[3]))
cls = Ether
lvl = 2
try:
pkt = cls(pkt)
except KeyboardInterrupt:
raise
except:
if conf.debug_dissector:
raise
pkt = Raw(pkt)
if lvl == 2:
pkt = pkt.payload
return pkt
def send(self, x):
if isinstance(x, IPv6):
iff,a,gw = conf.route6.route(x.dst)
elif hasattr(x,"dst"):
iff,a,gw = conf.route.route(x.dst)
else:
iff = conf.iface
sdto = (iff, self.type)
self.outs.bind(sdto)
sn = self.outs.getsockname()
ll = lambda x:x
if sn[3] in (ARPHDR_PPP,ARPHDR_TUN):
sdto = (iff, ETH_P_IP)
if LLTypes.has_key(sn[3]):
ll = lambda x:LLTypes[sn[3]]()/x
try:
self.outs.sendto(str(ll(x)), sdto)
except socket.error,msg:
if conf.auto_fragment and msg[0] == 90:
for p in fragment(x):
self.outs.sendto(str(ll(p)), sdto)
else:
raise
class L2Socket(SuperSocket):
def __init__(self, iface = None, type = ETH_P_ALL, filter=None, nofilter=0):
if iface is None:
iface = conf.iface
self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))
self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0)
if not nofilter:
if conf.except_filter:
if filter:
filter = "(%s) and not (%s)" % (filter, conf.except_filter)
else:
filter = "not (%s)" % conf.except_filter
if filter is not None:
attach_filter(self.ins, filter)
self.ins.bind((iface, type))
self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30)
self.outs = self.ins
self.outs.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 2**30)
sa_ll = self.outs.getsockname()
if LLTypes.has_key(sa_ll[3]):
self.LL = LLTypes[sa_ll[3]]
elif L3Types.has_key(sa_ll[1]):
self.LL = L3Types[sa_ll[1]]
else:
warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using Ethernet" % (sa_ll[0],sa_ll[1],sa_ll[3]))
self.LL = Ether
def recv(self, x):
pkt, sa_ll = self.ins.recvfrom(x)
if sa_ll[2] == socket.PACKET_OUTGOING:
return None
try:
q = self.LL(pkt)
except KeyboardInterrupt:
raise
except:
if conf.debug_dissector:
raise
q = Raw(pkt)
return q
class L2ListenSocket(SuperSocket):
def __init__(self, iface = None, type = ETH_P_ALL, promisc=None, filter=None, nofilter=0):
self.type = type
self.outs = None
self.ins = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(type))
self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 0)
if iface is not None:
self.ins.bind((iface, type))
if not nofilter:
if conf.except_filter:
if filter:
filter = "(%s) and not (%s)" % (filter, conf.except_filter)
else:
filter = "not (%s)" % conf.except_filter
if filter is not None:
attach_filter(self.ins, filter)
if promisc is None:
promisc = conf.sniff_promisc
self.promisc = promisc
if iface is None:
self.iff = get_if_list()
else:
if iface.__class__ is list:
self.iff = iface
else:
self.iff = [iface]
if self.promisc:
for i in self.iff:
set_promisc(self.ins, i)
self.ins.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 2**30)
def close(self):
if self.promisc:
for i in self.iff:
set_promisc(self.ins, i, 0)
SuperSocket.close(self)
def recv(self, x):
pkt, sa_ll = self.ins.recvfrom(x)
if LLTypes.has_key(sa_ll[3]):
cls = LLTypes[sa_ll[3]]
elif L3Types.has_key(sa_ll[1]):
cls = L3Types[sa_ll[1]]
else:
warning("Unable to guess type (interface=%s protocol=%#x family=%i). Using Ethernet" % (sa_ll[0],sa_ll[1],sa_ll[3]))
cls = Ether
try:
pkt = cls(pkt)
except KeyboardInterrupt:
raise
except:
if conf.debug_dissector:
raise
pkt = Raw(pkt)
return pkt
def send(self, x):
raise Scapy_Exception("Can't send anything with L2ListenSocket")
class L3dnetSocket(SuperSocket):
def __init__(self, type = ETH_P_ALL, filter=None, promisc=None, iface=None, nofilter=0):
self.iflist = {}
self.ins = pcap.pcapObject()
if iface is None:
iface = conf.iface
self.iface = iface
self.ins.open_live(iface, 1600, 0, 100)
try:
ioctl(self.ins.fileno(),BIOCIMMEDIATE,struct.pack("I",1))
except:
pass
if nofilter:
if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap
filter = "ether proto %i" % type
else:
filter = None
else:
if conf.except_filter:
if filter:
filter = "(%s) and not (%s)" % (filter, conf.except_filter)
else:
filter = "not (%s)" % conf.except_filter
if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap
if filter:
filter = "(ether proto %i) and (%s)" % (type,filter)
else:
filter = "ether proto %i" % type
if filter:
self.ins.setfilter(filter, 0, 0)
def send(self, x):
if isinstance(x, IPv6):
iff,a,gw = conf.route6.route(x.dst)
elif hasattr(x,"dst"):
iff,a,gw = conf.route.route(x.dst)
else:
iff = conf.iface
ifs = self.iflist.get(iff)
if ifs is None:
self.iflist[iff] = ifs = dnet.eth(iff)
ifs.send(str(Ether()/x))
def recv(self,x=MTU):
ll = self.ins.datalink()
if LLTypes.has_key(ll):
cls = LLTypes[ll]
else:
warning("Unable to guess datalink type (interface=%s linktype=%i). Using Ethernet" % (self.iface, ll))
cls = Ether
pkt = self.ins.next()
if pkt is not None:
pkt = pkt[1]
if pkt is None:
return
try:
pkt = cls(pkt)
except KeyboardInterrupt:
raise
except:
if conf.debug_dissector:
raise
pkt = Raw(pkt)
return pkt.payload
def nonblock_recv(self):
self.ins.setnonblock(1)
p = self.recv()
self.ins.setnonblock(0)
return p
def close(self):
if hasattr(self, "ins"):
del(self.ins)
if hasattr(self, "outs"):
del(self.outs)
class L2dnetSocket(SuperSocket):
def __init__(self, iface = None, type = ETH_P_ALL, filter=None, nofilter=0):
if iface is None:
iface = conf.iface
self.iface = iface
self.ins = pcap.pcapObject()
self.ins.open_live(iface, 1600, 0, 100)
try:
ioctl(self.ins.fileno(),BIOCIMMEDIATE,struct.pack("I",1))
except:
pass
if nofilter:
if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap
filter = "ether proto %i" % type
else:
filter = None
else:
if conf.except_filter:
if filter:
filter = "(%s) and not (%s)" % (filter, conf.except_filter)
else:
filter = "not (%s)" % conf.except_filter
if type != ETH_P_ALL: # PF_PACKET stuff. Need to emulate this for pcap
if filter:
filter = "(ether proto %i) and (%s)" % (type,filter)
else:
filter = "ether proto %i" % type
if filter:
self.ins.setfilter(filter, 0, 0)
self.outs = dnet.eth(iface)
def recv(self,x):
ll = self.ins.datalink()
if LLTypes.has_key(ll):
cls = LLTypes[ll]
else:
warning("Unable to guess datalink type (interface=%s linktype=%i). Using Ethernet" % (self.iface, ll))
cls = Ether
pkt = self.ins.next()
if pkt is not None:
pkt = pkt[1]
if pkt is None:
return
try:
pkt = cls(pkt)
except KeyboardInterrupt:
raise
except:
if conf.debug_dissector:
raise
pkt = Raw(pkt)
return pkt
def nonblock_recv(self):
self.ins.setnonblock(1)
p = self.recv(MTU)
self.ins.setnonblock(0)
return p
def close(self):
if hasattr(self, "ins"):
del(self.ins)
if hasattr(self, "outs"):
del(self.outs)
class L2pcapListenSocket(SuperSocket):
def __init__(self, iface = None, type = ETH_P_ALL, promisc=None, filter=None):
self.type = type
self.outs = None
self.ins = pcap.pcapObject()
self.iface = iface
if iface is None:
iface = conf.iface
if promisc is None:
promisc = conf.sniff_promisc
self.promisc = promisc
self.ins.open_live(iface, 1600, self.promisc, 100)
try:
ioctl(self.ins.fileno(),BIOCIMMEDIATE,struct.pack("I",1))
except:
pass
if type == ETH_P_ALL: # Do not apply any filter if Ethernet type is given
if conf.except_filter:
if filter:
filter = "(%s) and not (%s)" % (filter, conf.except_filter)
else:
filter = "not (%s)" % conf.except_filter
if filter:
self.ins.setfilter(filter, 0, 0)
def close(self):
del(self.ins)
def recv(self, x):
ll = self.ins.datalink()
if LLTypes.has_key(ll):
cls = LLTypes[ll]
else:
warning("Unable to guess datalink type (interface=%s linktype=%i). Using Ethernet" % (self.iface, ll))
cls = Ether
pkt = None
while pkt is None:
pkt = self.ins.next()
if pkt is not None:
pkt = pkt[1]
try:
pkt = cls(pkt)
except KeyboardInterrupt:
raise
except:
if conf.debug_dissector:
raise
pkt = Raw(pkt)
return pkt
def send(self, x):
raise Scapy_Exception("Can't send anything with L2pcapListenSocket")
class SimpleSocket(SuperSocket):
def __init__(self, sock):
self.ins = sock
self.outs = sock
class StreamSocket(SimpleSocket):
def __init__(self, sock, basecls=Raw):
SimpleSocket.__init__(self, sock)
self.basecls = basecls
def recv(self, x=MTU):
pkt = self.ins.recv(x, socket.MSG_PEEK)
x = len(pkt)
pkt = self.basecls(pkt)
pad = pkt[Padding]
if pad is not None and pad.underlayer is not None:
del(pad.underlayer.payload)
while pad is not None and not isinstance(pad, NoPayload):
x -= len(pad.load)
pad = pad.payload
self.ins.recv(x)
return pkt
class BluetoothL2CAPSocket(SuperSocket):
def __init__(self, peer):
s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW,
socket.BTPROTO_L2CAP)
s.connect((peer,0))
self.ins = self.outs = s
def recv(self, x):
return L2CAP_HdrCmd(self.ins.recv(x))
class BluetoothHCISocket(SuperSocket):
def __init__(self, iface=0x10000, type=None):
s = socket.socket(socket.AF_BLUETOOTH, socket.SOCK_RAW, socket.BTPROTO_HCI)
s.setsockopt(socket.SOL_HCI, socket.HCI_DATA_DIR,1)
s.setsockopt(socket.SOL_HCI, socket.HCI_TIME_STAMP,1)
s.setsockopt(socket.SOL_HCI, socket.HCI_FILTER, struct.pack("IIIh2x", 0xffffffffL,0xffffffffL,0xffffffffL,0)) #type mask, event mask, event mask, opcode
s.bind((iface,))
self.ins = self.outs = s
# s.connect((peer,0))
def recv(self, x):
return HCI_Hdr(self.ins.recv(x))
####################
## Send / Receive ##
####################
def sndrcv(pks, pkt, timeout = 2, inter = 0, verbose=None, chainCC=0, retry=0, multi=0):
if not isinstance(pkt, Gen):
pkt = SetGen(pkt)
if verbose is None:
verbose = conf.verb
debug.recv = PacketList([],"Unanswered")
debug.sent = PacketList([],"Sent")
debug.match = SndRcvList([])
nbrecv=0
ans = []
# do it here to fix random fields, so that parent and child have the same
tobesent = [p for p in pkt]
notans = len(tobesent)
hsent={}
for i in tobesent:
h = i.hashret()
if h in hsent:
hsent[h].append(i)
else:
hsent[h] = [i]
if retry < 0:
retry = -retry
autostop=retry
else:
autostop=0
while retry >= 0:
found=0
if timeout < 0:
timeout = None
rdpipe,wrpipe = os.pipe()
rdpipe=os.fdopen(rdpipe)
wrpipe=os.fdopen(wrpipe,"w")
pid = os.fork()
if pid == 0:
sys.stdin.close()
rdpipe.close()
try:
i = 0
if verbose:
print "Begin emission:"
for p in tobesent:
pks.send(p)
i += 1
time.sleep(inter)
if verbose:
print "Finished to send %i packets." % i
except SystemExit:
pass
except KeyboardInterrupt:
pass
except:
log_runtime.exception("--- Error in child %i" % os.getpid())
log_runtime.info("--- Error in child %i" % os.getpid())
os._exit(0)
else:
cPickle.dump(arp_cache, wrpipe)
wrpipe.close()
os._exit(0)
elif pid < 0:
log_runtime.error("fork error")
else:
wrpipe.close()
stoptime = 0
remaintime = None
inmask = [rdpipe,pks]
try:
while 1:
if stoptime:
remaintime = stoptime-time.time()
if remaintime <= 0:
break
r = None
if FREEBSD or DARWIN:
inp, out, err = select(inmask,[],[], 0.05)
if len(inp) == 0 or pks in inp:
r = pks.nonblock_recv()
else:
inp, out, err = select(inmask,[],[], remaintime)
if len(inp) == 0:
break
if pks in inp:
r = pks.recv(MTU)
if rdpipe in inp:
if timeout:
stoptime = time.time()+timeout
del(inmask[inmask.index(rdpipe)])
if r is None:
continue
ok = 0
h = r.hashret()
if h in hsent:
hlst = hsent[h]
for i in range(len(hlst)):
if r.answers(hlst[i]):
ans.append((hlst[i],r))
if verbose > 1:
os.write(1, "*")
ok = 1
if not multi:
del(hlst[i])
notans -= 1;
else:
if not hasattr(hlst[i], '_answered'):
notans -= 1;
hlst[i]._answered = 1;
break
if notans == 0 and not multi:
break
if not ok:
if verbose > 1:
os.write(1, ".")
nbrecv += 1
if conf.debug_match:
debug.recv.append(r)
except KeyboardInterrupt:
if chainCC:
raise
try:
ac = cPickle.load(rdpipe)
except EOFError:
warning("Child died unexpectedly. Packets may have not been sent")
else:
arp_cache.update(ac)
os.waitpid(pid,0)
remain = reduce(list.__add__, hsent.values(), [])
if multi:
remain = filter(lambda p: not hasattr(p, '_answered'), remain);
if autostop and len(remain) > 0 and len(remain) != len(tobesent):
retry = autostop
tobesent = remain
if len(tobesent) == 0:
break
retry -= 1
if conf.debug_match:
debug.sent=PacketList(remain[:],"Sent")
debug.match=SndRcvList(ans[:])
#clean the ans list to delete the field _answered
if (multi):
for s,r in ans:
if hasattr(s, '_answered'):
del(s._answered)
if verbose:
print "\nReceived %i packets, got %i answers, remaining %i packets" % (nbrecv+len(ans), len(ans), notans)
return SndRcvList(ans),PacketList(remain,"Unanswered"),debug.recv
def __gen_send(s, x, inter=0, loop=0, count=None, verbose=None, *args, **kargs):
if not isinstance(x, Gen):
x = SetGen(x)
if verbose is None:
verbose = conf.verb
n = 0
if count is not None:
loop = -count
elif not loop:
loop=-1
try:
while loop:
for p in x:
s.send(p)
n += 1
if verbose:
os.write(1,".")
time.sleep(inter)
if loop < 0:
loop += 1
except KeyboardInterrupt:
pass
s.close()
if verbose:
print "\nSent %i packets." % n
def send(x, inter=0, loop=0, count=None, verbose=None, *args, **kargs):
"""Send packets at layer 3
send(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None"""
__gen_send(conf.L3socket(*args, **kargs), x, inter=inter, loop=loop, count=count,verbose=verbose)
def sendp(x, inter=0, loop=0, iface=None, iface_hint=None, count=None, verbose=None, *args, **kargs):
"""Send packets at layer 2
send(packets, [inter=0], [loop=0], [verbose=conf.verb]) -> None"""
if iface is None and iface_hint is not None:
iface = conf.route.route(iface_hint)[0]
__gen_send(conf.L2socket(iface=iface, *args, **kargs), x, inter=inter, loop=loop, count=count, verbose=verbose)
def sr(x,filter=None, iface=None, nofilter=0, *args,**kargs):
"""Send and receive packets at layer 3
nofilter: put 1 to avoid use of bpf filters
retry: if positive, how many times to resend unanswered packets
if negative, how many times to retry when no more packets are answered
timeout: how much time to wait after the last packet has been sent
verbose: set verbosity level
multi: whether to accept multiple answers for the same stimulus
filter: provide a BPF filter
iface: listen answers only on the given interface"""
if not kargs.has_key("timeout"):
kargs["timeout"] = -1
s = conf.L3socket(filter=filter, iface=iface, nofilter=nofilter)
a,b,c=sndrcv(s,x,*args,**kargs)
s.close()
return a,b
def sr1(x,filter=None,iface=None, nofilter=0, *args,**kargs):
"""Send packets at layer 3 and return only the first answer
nofilter: put 1 to avoid use of bpf filters
retry: if positive, how many times to resend unanswered packets
if negative, how many times to retry when no more packets are answered
timeout: how much time to wait after the last packet has been sent
verbose: set verbosity level
multi: whether to accept multiple answers for the same stimulus
filter: provide a BPF filter
iface: listen answers only on the given interface"""
if not kargs.has_key("timeout"):
kargs["timeout"] = -1
s=conf.L3socket(filter=filter, nofilter=nofilter, iface=iface)
a,b,c=sndrcv(s,x,*args,**kargs)
s.close()
if len(a) > 0:
return a[0][1]
else:
return None
def srp(x,iface=None, iface_hint=None, filter=None, nofilter=0, type=ETH_P_ALL, *args,**kargs):
"""Send and receive packets at layer 2
nofilter: put 1 to avoid use of bpf filters
retry: if positive, how many times to resend unanswered packets
if negative, how many times to retry when no more packets are answered
timeout: how much time to wait after the last packet has been sent
verbose: set verbosity level
multi: whether to accept multiple answers for the same stimulus
filter: provide a BPF filter
iface: work only on the given interface"""
if not kargs.has_key("timeout"):
kargs["timeout"] = -1
if iface is None and iface_hint is not None:
iface = conf.route.route(iface_hint)[0]
a,b,c=sndrcv(conf.L2socket(iface=iface, filter=filter, nofilter=nofilter, type=type),x,*args,**kargs)
return a,b
def srp1(*args,**kargs):
"""Send and receive packets at layer 2 and return only the first answer
nofilter: put 1 to avoid use of bpf filters
retry: if positive, how many times to resend unanswered packets
if negative, how many times to retry when no more packets are answered
timeout: how much time to wait after the last packet has been sent
verbose: set verbosity level
multi: whether to accept multiple answers for the same stimulus
filter: provide a BPF filter
iface: work only on the given interface"""
if not kargs.has_key("timeout"):
kargs["timeout"] = -1
a,b=srp(*args,**kargs)
if len(a) > 0:
return a[0][1]
else:
return None
def __sr_loop(srfunc, pkts, prn=lambda x:x[1].summary(), prnfail=lambda x:x.summary(), inter=1, timeout=None, count=None, verbose=0, store=1, *args, **kargs):
n = 0
r = 0
ct = conf.color_theme
parity = 0
ans=[]
unans=[]
if timeout is None:
timeout = min(2*inter, 5)
try:
while 1:
parity ^= 1
col = [ct.even,ct.odd][parity]
if count is not None:
if count == 0:
break
count -= 1
start = time.time()
print "\rsend...\r",
res = srfunc(pkts, timeout=timeout, verbose=0, chainCC=1, *args, **kargs)
n += len(res[0])+len(res[1])
r += len(res[0])
if prn and len(res[0]) > 0:
msg = "RECV %i:" % len(res[0])
print "\r"+ct.success(msg),
for p in res[0]:
print col(prn(p))
print " "*len(msg),
if prnfail and len(res[1]) > 0:
msg = "fail %i:" % len(res[1])
print "\r"+ct.fail(msg),
for p in res[1]:
print col(prnfail(p))
print " "*len(msg),
if not (prn or prnfail):
print "recv:%i fail:%i" % tuple(map(len, res[:2]))
if store:
ans += res[0]
unans += res[1]
end=time.time()
if end-start < inter:
time.sleep(inter+start-end)
except KeyboardInterrupt:
pass
if n>0:
print "%s\nSent %i packets, received %i packets. %3.1f%% hits." % (Color.normal,n,r,100.0*r/n)
return SndRcvList(ans),PacketList(unans)
def srloop(pkts, *args, **kargs):
"""Send a packet at layer 3 in loop and print the answer each time
srloop(pkts, [prn], [inter], [count], ...) --> None"""
return __sr_loop(sr, pkts, *args, **kargs)
def srploop(pkts, *args, **kargs):
"""Send a packet at layer 2 in loop and print the answer each time
srloop(pkts, [prn], [inter], [count], ...) --> None"""
return __sr_loop(srp, pkts, *args, **kargs)
def sndrcvflood(pks, pkt, prn=lambda (s,r):r.summary(), chainCC=0, store=1, unique=0):
if not isinstance(pkt, Gen):
pkt = SetGen(pkt)
tobesent = [p for p in pkt]
received = SndRcvList()
seen = {}
hsent={}
for i in tobesent:
h = i.hashret()
if h in hsent:
hsent[h].append(i)
else:
hsent[h] = [i]
def send_in_loop(tobesent):
while 1:
for p in tobesent:
yield p
packets_to_send = send_in_loop(tobesent)
ssock = rsock = pks.fileno()
try:
while 1:
readyr,readys,_ = select([rsock],[ssock],[])
if ssock in readys:
pks.send(packets_to_send.next())
if rsock in readyr:
p = pks.recv(MTU)
if p is None:
continue
h = p.hashret()
if h in hsent:
hlst = hsent[h]
for i in hlst:
if p.answers(i):
res = prn((i,p))
if unique:
if res in seen:
continue
seen[res] = None
if res is not None:
print res
if store:
received.append((i,p))
except KeyboardInterrupt:
if chainCC:
raise
return received
def srflood(x,filter=None, iface=None, nofilter=None, *args,**kargs):
"""Flood and receive packets at layer 3
prn: function applied to packets received. Ret val is printed if not None
store: if 1 (default), store answers and return them
unique: only consider packets whose print
nofilter: put 1 to avoid use of bpf filters
filter: provide a BPF filter
iface: listen answers only on the given interface"""
s = conf.L3socket(filter=filter, iface=iface, nofilter=nofilter)
r=sndrcvflood(s,x,*args,**kargs)
s.close()
return r
def srpflood(x,filter=None, iface=None, iface_hint=None, nofilter=None, *args,**kargs):
"""Flood and receive packets at layer 2
prn: function applied to packets received. Ret val is printed if not None
store: if 1 (default), store answers and return them
unique: only consider packets whose print
nofilter: put 1 to avoid use of bpf filters
filter: provide a BPF filter
iface: listen answers only on the given interface"""
if iface is None and iface_hint is not None:
iface = conf.route.route(iface_hint)[0]
s = conf.L2socket(filter=filter, iface=iface, nofilter=nofilter)
r=sndrcvflood(s,x,*args,**kargs)
s.close()
return r
## Bluetooth
def srbt(peer, pkts, inter=0.1, *args, **kargs):
s = conf.BTsocket(peer=peer)
a,b,c=sndrcv(s,pkts,inter=inter,*args,**kargs)
s.close()
return a,b
def srbt1(peer, pkts, *args, **kargs):
a,b = srbt(peer, pkts, *args, **kargs)
if len(a) > 0:
return a[0][1]
#############################
## pcap capture file stuff ##
#############################
def wrpcap(filename, pkt, *args, **kargs):
"""Write a list of packets to a pcap file
gz: set to 1 to save a gzipped capture
linktype: force linktype value
endianness: "<" or ">", force endianness"""
PcapWriter(filename, *args, **kargs).write(pkt)
def rdpcap(filename, count=-1):
"""Read a pcap file and return a packet list
count: read only <count> packets"""
return PcapReader(filename).read_all(count=count)
class PcapReader:
"""A stateful pcap reader
Based entirely on scapy.rdpcap(), this class allows for packets
to be dispatched without having to be loaded into memory all at
once
"""
def __init__(self, filename):
self.filename = filename
try:
self.f = gzip.open(filename,"rb")
magic = self.f.read(4)
except IOError:
self.f = open(filename,"rb")
magic = self.f.read(4)
if magic == "\xa1\xb2\xc3\xd4": #big endian
self.endian = ">"
elif magic == "\xd4\xc3\xb2\xa1": #little endian
self.endian = "<"
else:
raise RuntimeWarning, "Not a pcap capture file (bad magic)"
hdr = self.f.read(20)
if len(hdr)<20:
raise RuntimeWarning, "Invalid pcap file (too short)"
vermaj,vermin,tz,sig,snaplen,linktype = struct.unpack(self.endian+"HHIIII",hdr)
self.LLcls = LLTypes.get(linktype, Raw)
if self.LLcls == Raw:
warning("PcapReader: unkonwon LL type [%i]/[%#x]. Using Raw packets" % (linktype,linktype))
def __iter__(self):
return self
def next(self):
"""impliment the iterator protocol on a set of packets in a
pcap file
"""
pkt = self.read_packet()
if pkt == None:
raise StopIteration
return pkt
def read_packet(self):
"""return a single packet read from the file
returns None when no more packets are available
"""
hdr = self.f.read(16)
if len(hdr) < 16:
return None
sec,usec,caplen,olen = struct.unpack(self.endian+"IIII", hdr)
s = self.f.read(caplen)
try:
p = self.LLcls(s)
except KeyboardInterrupt:
raise
except:
if conf.debug_dissector:
raise
p = Raw(s)
p.time = sec+0.000001*usec
return p
def dispatch(self, callback):
"""call the specified callback routine for each packet read
This is just a convienience function for the main loop
that allows for easy launching of packet processing in a
thread.
"""
p = self.read_packet()
while p != None:
callback(p)
p = self.read_packet()
def read_all(self,count=-1):
"""return a list of all packets in the pcap file
"""
res=[]
while count != 0:
count -= 1
p = self.read_packet()
if p is None:
break
res.append(p)
return PacketList(res,name = os.path.basename(self.filename))
def recv(self, size):
""" Emulate a socket
"""
return self.read_packet()
def fileno(self):
return self.f.fileno()
class PcapWriter:
"""A pcap writer with more control than wrpcap()
This routine is based entirely on scapy.wrpcap(), but adds capability
of writing one packet at a time in a streaming manner.
"""
def __init__(self, filename, linktype=None, gz=0, endianness=""):
self.linktype = linktype
self.header_done = 0
if gz:
self.f = gzip.open(filename,"wb")
else:
self.f = open(filename,"wb")
self.endian = endianness
def fileno(self):
return self.f.fileno()
def write(self, pkt):
"""accepts a either a single packet or a list of packets
to be written to the dumpfile
"""
if self.header_done == 0:
if self.linktype == None:
if isinstance(pkt,Packet):
linktype = LLNumTypes.get(pkt.__class__,1)
else:
linktype = LLNumTypes.get(pkt[0].__class__,1)
self.f.write(struct.pack(self.endian+"IHHIIII", 0xa1b2c3d4L,
2, 4, 0, 0, MTU, linktype))
self.header_done = 1
for p in pkt:
self._write_packet(p)
def _write_packet(self, packet):
"""writes a single packet to the pcap file
"""
s = str(packet)
l = len(s)
sec = int(packet.time)
usec = int((packet.time-sec)*1000000)
self.f.write(struct.pack(self.endian+"IIII", sec, usec, l, l))
self.f.write(s)
re_extract_hexcap = re.compile("^(0x[0-9a-fA-F]{2,}[ :\t]|(0x)?[0-9a-fA-F]{2,}:|(0x)?[0-9a-fA-F]{3,}[: \t]|) *(([0-9a-fA-F]{2} {,2}){,16})")
def import_hexcap():
p = ""
try:
while 1:
l = raw_input().strip()
try:
p += re_extract_hexcap.match(l).groups()[3]
except:
warning("Parsing error during hexcap")
continue
except EOFError:
pass
p = p.replace(" ","")
p2=""
for i in range(len(p)/2):
p2 += chr(int(p[2*i:2*i+2],16))
return p2
def wireshark(pktlist):
f = os.tempnam("scapy")
wrpcap(f, pktlist)
os.spawnlp(os.P_NOWAIT, conf.prog.wireshark, conf.prog.wireshark, "-r", f)
def hexedit(x):
x = str(x)
f = os.tempnam("scapy")
open(f,"w").write(x)
os.spawnlp(os.P_WAIT, conf.prog.hexedit, conf.prog.hexedit, f)
x = open(f).read()
os.unlink(f)
return x
#####################
## knowledge bases ##
#####################
class KnowledgeBase:
def __init__(self, filename):
self.filename = filename
self.base = None
def lazy_init(self):
self.base = ""
def reload(self, filename = None):
if filename is not None:
self.filename = filename
oldbase = self.base
self.base = None
self.lazy_init()
if self.base is None:
self.base = oldbase
def get_base(self):
if self.base is None:
self.lazy_init()
return self.base
##########################
## IP location database ##
##########################
class IPCountryKnowledgeBase(KnowledgeBase):
"""
How to generate the base :
db = []
for l in open("GeoIPCountryWhois.csv").readlines():
s,e,c = l.split(",")[2:5]
db.append((int(s[1:-1]),int(e[1:-1]),c[1:-1]))
cPickle.dump(gzip.open("xxx","w"),db)
"""
def lazy_init(self):
self.base = load_object(self.filename)
class CountryLocKnowledgeBase(KnowledgeBase):
def lazy_init(self):
f=open(self.filename)
self.base = {}
while 1:
l = f.readline()
if not l:
break
l = l.strip().split(",")
if len(l) != 3:
continue
c,lat,long = l
self.base[c] = (float(long),float(lat))
f.close()
def locate_ip(ip):
ip=map(int,ip.split("."))
ip = ip[3]+(ip[2]<<8L)+(ip[1]<<16L)+(ip[0]<<24L)
cloc = country_loc_kdb.get_base()
db = IP_country_kdb.get_base()
d=0
f=len(db)-1
while (f-d) > 1:
guess = (d+f)/2
if ip > db[guess][0]:
d = guess
else:
f = guess
s,e,c = db[guess]
if s <= ip and ip <= e:
return cloc.get(c,None)
###############
## p0f stuff ##
###############
# File format (according to p0f.fp) :
#
# wwww:ttt:D:ss:OOO...:QQ:OS:Details
#
# wwww - window size
# ttt - initial TTL
# D - don't fragment bit (0=unset, 1=set)
# ss - overall SYN packet size
# OOO - option value and order specification
# QQ - quirks list
# OS - OS genre
# details - OS description
class p0fKnowledgeBase(KnowledgeBase):
def __init__(self, filename):
KnowledgeBase.__init__(self, filename)
#self.ttl_range=[255]
def lazy_init(self):
try:
f=open(self.filename)
except IOError:
warning("Can't open base %s" % self.filename)
return
try:
self.base = []
for l in f:
if l[0] in ["#","\n"]:
continue
l = tuple(l.split(":"))
if len(l) < 8:
continue
li = map(int,l[1:4])
#if li[0] not in self.ttl_range:
# self.ttl_range.append(li[0])
# self.ttl_range.sort()
self.base.append((l[0], li[0], li[1], li[2], l[4], l[5], l[6], l[7][:-1]))
except:
warning("Can't parse p0f database (new p0f version ?)")
self.base = None
f.close()
def packet2p0f(pkt):
while pkt.haslayer(IP) and pkt.haslayer(TCP):
pkt = pkt.getlayer(IP)
if isinstance(pkt.payload, TCP):
break
pkt = pkt.payload
if not isinstance(pkt, IP) or not isinstance(pkt.payload, TCP):
raise TypeError("Not a TCP/IP packet")
if pkt.payload.flags & 0x13 != 0x02: #S,!A,!F
raise TypeError("Not a syn packet")
#t = p0f_kdb.ttl_range[:]
#t += [pkt.ttl]
#t.sort()
#ttl=t[t.index(pkt.ttl)+1]
ttl = pkt.ttl
df = (pkt.flags & 2) / 2
ss = len(pkt)
# from p0f/config.h : PACKET_BIG = 100
if ss > 100:
ss = 0
ooo = ""
mss = -1
qqT = False
qqP = False
#qqBroken = False
ilen = (pkt[TCP].dataofs << 2) - 20 # from p0f.c
for option in pkt.payload.options:
ilen -= 1
if option[0] == "MSS":
ooo += "M" + str(option[1]) + ","
mss = option[1]
# FIXME: qqBroken
ilen -= 3
elif option[0] == "WScale":
ooo += "W" + str(option[1]) + ","
# FIXME: qqBroken
ilen -= 2
elif option[0] == "Timestamp":
if option[1][0] == 0:
ooo += "T0,"
else:
ooo += "T,"
if option[1][1] != 0:
qqT = True
ilen -= 9
elif option[0] == "SAckOK":
ooo += "S,"
ilen -= 1
elif option[0] == "NOP":
ooo += "N,"
elif option[0] == "EOL":
ooo += "E,"
if ilen > 0:
qqP = True
else:
ooo += "?,"
# FIXME: ilen
ooo = ooo[:-1]
if ooo == "": ooo = "."
win = pkt.payload.window
if mss != -1:
if win % mss == 0:
win = "S" + str(win/mss)
elif win % (mss + 40) == 0:
win = "T" + str(win/(mss+40))
win = str(win)
qq = ""
if qqP:
qq += "P"
if pkt[IP].id == 0:
qq += "Z"
if pkt[IP].options != '':
qq += "I"
if pkt[TCP].urgptr != 0:
qq += "U"
if pkt[TCP].reserved != 0:
qq += "X"
if pkt[TCP].ack != 0:
qq += "A"
if qqT:
qq += "T"
if pkt[TCP].flags & 40 != 0:
# U or P
qq += "F"
if not isinstance(pkt[TCP].payload, NoPayload):
qq += "D"
# FIXME : "!" - broken options segment
if qq == "":
qq = "."
return (win,
ttl,
df,
ss,
ooo,
qq)
def p0f_correl(x,y):
d = 0
# wwww can be "*" or "%nn"
d += (x[0] == y[0] or y[0] == "*" or (y[0][0] == "%" and x[0].isdigit() and (int(x[0]) % int(y[0][1:])) == 0))
# ttl
d += (y[1] >= x[1] and y[1] - x[1] < 32)
for i in [2, 3, 5]:
d += (x[i] == y[i])
xopt = x[4].split(",")
yopt = y[4].split(",")
if len(xopt) == len(yopt):
same = True
for i in range(len(xopt)):
if not (xopt[i] == yopt[i] or
(len(yopt[i]) == 2 and len(xopt[i]) > 1 and
yopt[i][1] == "*" and xopt[i][0] == yopt[i][0]) or
(len(yopt[i]) > 2 and len(xopt[i]) > 1 and
yopt[i][1] == "%" and xopt[i][0] == yopt[i][0] and
int(xopt[i][1:]) % int(yopt[i][2:]) == 0)):
same = False
break
if same:
d += len(xopt)
return d
def p0f(pkt):
"""Passive OS fingerprinting: which OS emitted this TCP SYN ?
p0f(packet) -> accuracy, [list of guesses]
"""
pb = p0f_kdb.get_base()
if not pb:
warning("p0f base empty.")
return []
s = len(pb[0][0])
r = []
sig = packet2p0f(pkt)
max = len(sig[4].split(",")) + 5
for b in pb:
d = p0f_correl(sig,b)
if d == max:
r.append((b[6], b[7], b[1] - pkt[IP].ttl))
return r
def prnp0f(pkt):
try:
r = p0f(pkt)
except:
return
if r == []:
r = ("UNKNOWN", "[" + ":".join(map(str, packet2p0f(pkt))) + ":?:?]", None)
else:
r = r[0]
uptime = None
try:
uptime = pkt2uptime(pkt)
except:
pass
if uptime == 0:
uptime = None
res = pkt.sprintf("%IP.src%:%TCP.sport% - " + r[0] + " " + r[1])
if uptime is not None:
res += pkt.sprintf(" (up: " + str(uptime/3600) + " hrs)\n -> %IP.dst%:%TCP.dport%")
else:
res += pkt.sprintf("\n -> %IP.dst%:%TCP.dport%")
if r[2] is not None:
res += " (distance " + str(r[2]) + ")"
print res
def pkt2uptime(pkt, HZ=100):
"""Calculate the date the machine which emitted the packet booted using TCP timestamp
pkt2uptime(pkt, [HZ=100])"""
if not isinstance(pkt, Packet):
raise TypeError("Not a TCP packet")
if isinstance(pkt,NoPayload):
raise TypeError("Not a TCP packet")
if not isinstance(pkt, TCP):
return pkt2uptime(pkt.payload)
for opt in pkt.options:
if opt[0] == "Timestamp":
#t = pkt.time - opt[1][0] * 1.0/HZ
#return time.ctime(t)
t = opt[1][0] / HZ
return t
raise TypeError("No timestamp option")
#################
## Queso stuff ##
#################
def quesoTCPflags(flags):
if flags == "-":
return "-"
flv = "FSRPAUXY"
v = 0
for i in flags:
v |= 2**flv.index(i)
return "%x" % v
class QuesoKnowledgeBase(KnowledgeBase):
def lazy_init(self):
try:
f = open(self.filename)
except IOError:
return
self.base = {}
p = None
try:
for l in f:
l = l.strip()
if not l or l[0] == ';':
continue
if l[0] == '*':
if p is not None:
p[""] = name
name = l[1:].strip()
p = self.base
continue
if l[0] not in list("0123456"):
continue
res = l[2:].split()
res[-1] = quesoTCPflags(res[-1])
res = " ".join(res)
if not p.has_key(res):
p[res] = {}
p = p[res]
if p is not None:
p[""] = name
except:
self.base = None
warning("Can't load queso base [%s]", self.filename)
f.close()
def queso_sig(target, dport=80, timeout=3):
p = queso_kdb.get_base()
ret = []
for flags in ["S", "SA", "F", "FA", "SF", "P", "SEC"]:
ans, unans = sr(IP(dst=target)/TCP(dport=dport,flags=flags,seq=RandInt()),
timeout=timeout, verbose=0)
if len(ans) == 0:
rs = "- - - -"
else:
s,r = ans[0]
rs = "%i" % (r.seq != 0)
if not r.ack:
r += " 0"
elif r.ack-s.seq > 666:
rs += " R" % 0
else:
rs += " +%i" % (r.ack-s.seq)
rs += " %X" % r.window
rs += " %x" % r.payload.flags
ret.append(rs)
return ret
def queso_search(sig):
p = queso_kdb.get_base()
sig.reverse()
ret = []
try:
while sig:
s = sig.pop()
p = p[s]
if p.has_key(""):
ret.append(p[""])
except KeyError:
pass
return ret
def queso(*args,**kargs):
"""Queso OS fingerprinting
queso(target, dport=80, timeout=3)"""
return queso_search(queso_sig(*args, **kargs))
######################
## nmap OS fp stuff ##
######################
class NmapKnowledgeBase(KnowledgeBase):
def lazy_init(self):
try:
f=open(self.filename)
except IOError:
return
self.base = []
name = None
try:
for l in f:
l = l.strip()
if not l or l[0] == "#":
continue
if l[:12] == "Fingerprint ":
if name is not None:
self.base.append((name,sig))
name = l[12:].strip()
sig={}
p = self.base
continue
elif l[:6] == "Class ":
continue
op = l.find("(")
cl = l.find(")")
if op < 0 or cl < 0:
warning("error reading nmap os fp base file")
continue
test = l[:op]
s = map(lambda x: x.split("="), l[op+1:cl].split("%"))
si = {}
for n,v in s:
si[n] = v
sig[test]=si
if name is not None:
self.base.append((name,sig))
except:
self.base = None
warning("Can't read nmap database [%s](new nmap version ?)" % self.filename)
f.close()
def TCPflags2str(f):
fl="FSRPAUEC"
s=""
for i in range(len(fl)):
if f & 1:
s = fl[i]+s
f >>= 1
return s
def nmap_tcppacket_sig(pkt):
r = {}
if pkt is not None:
# r["Resp"] = "Y"
r["DF"] = (pkt.flags & 2) and "Y" or "N"
r["W"] = "%X" % pkt.window
r["ACK"] = pkt.ack==2 and "S++" or pkt.ack==1 and "S" or "O"
r["Flags"] = TCPflags2str(pkt.payload.flags)
r["Ops"] = "".join(map(lambda x: x[0][0],pkt.payload.options))
else:
r["Resp"] = "N"
return r
def nmap_udppacket_sig(S,T):
r={}
if T is None:
r["Resp"] = "N"
else:
r["DF"] = (T.flags & 2) and "Y" or "N"
r["TOS"] = "%X" % T.tos
r["IPLEN"] = "%X" % T.len
r["RIPTL"] = "%X" % T.payload.payload.len
r["RID"] = S.id == T.payload.payload.id and "E" or "F"
r["RIPCK"] = S.chksum == T.getlayer(IPerror).chksum and "E" or T.getlayer(IPerror).chksum == 0 and "0" or "F"
r["UCK"] = S.payload.chksum == T.getlayer(UDPerror).chksum and "E" or T.getlayer(UDPerror).chksum ==0 and "0" or "F"
r["ULEN"] = "%X" % T.getlayer(UDPerror).len
r["DAT"] = T.getlayer(Raw) is None and "E" or S.getlayer(Raw).load == T.getlayer(Raw).load and "E" or "F"
return r
def nmap_match_one_sig(seen, ref):
c = 0
for k in seen.keys():
if ref.has_key(k):
if seen[k] in ref[k].split("|"):
c += 1
if c == 0 and seen.get("Resp") == "N":
return 0.7
else:
return 1.0*c/len(seen.keys())
def nmap_sig(target, oport=80, cport=81, ucport=1):
res = {}
tcpopt = [ ("WScale", 10),
("NOP",None),
("MSS", 256),
("Timestamp",(123,0)) ]
tests = [ IP(dst=target, id=1)/TCP(seq=1, sport=5001, dport=oport, options=tcpopt, flags="CS"),
IP(dst=target, id=1)/TCP(seq=1, sport=5002, dport=oport, options=tcpopt, flags=0),
IP(dst=target, id=1)/TCP(seq=1, sport=5003, dport=oport, options=tcpopt, flags="SFUP"),
IP(dst=target, id=1)/TCP(seq=1, sport=5004, dport=oport, options=tcpopt, flags="A"),
IP(dst=target, id=1)/TCP(seq=1, sport=5005, dport=cport, options=tcpopt, flags="S"),
IP(dst=target, id=1)/TCP(seq=1, sport=5006, dport=cport, options=tcpopt, flags="A"),
IP(dst=target, id=1)/TCP(seq=1, sport=5007, dport=cport, options=tcpopt, flags="FPU"),
IP(str(IP(dst=target)/UDP(sport=5008,dport=ucport)/(300*"i"))) ]
ans, unans = sr(tests, timeout=2)
ans += map(lambda x: (x,None), unans)
for S,T in ans:
if S.sport == 5008:
res["PU"] = nmap_udppacket_sig(S,T)
else:
t = "T%i" % (S.sport-5000)
if T is not None and T.haslayer(ICMP):
warning("Test %s answered by an ICMP" % t)
T=None
res[t] = nmap_tcppacket_sig(T)
return res
def nmap_probes2sig(tests):
tests=tests.copy()
res = {}
if "PU" in tests:
res["PU"] = nmap_udppacket_sig(*tests["PU"])
del(tests["PU"])
for k in tests:
res[k] = nmap_tcppacket_sig(tests[k])
return res
def nmap_search(sigs):
guess = 0,[]
for os,fp in nmap_kdb.get_base():
c = 0.0
for t in sigs.keys():
if t in fp:
c += nmap_match_one_sig(sigs[t], fp[t])
c /= len(sigs.keys())
if c > guess[0]:
guess = c,[ os ]
elif c == guess[0]:
guess[1].append(os)
return guess
def nmap_fp(target, oport=80, cport=81):
"""nmap fingerprinting
nmap_fp(target, [oport=80,] [cport=81,]) -> list of best guesses with accuracy
"""
sigs = nmap_sig(target, oport, cport)
return nmap_search(sigs)
def nmap_sig2txt(sig):
torder = ["TSeq","T1","T2","T3","T4","T5","T6","T7","PU"]
korder = ["Class", "gcd", "SI", "IPID", "TS",
"Resp", "DF", "W", "ACK", "Flags", "Ops",
"TOS", "IPLEN", "RIPTL", "RID", "RIPCK", "UCK", "ULEN", "DAT" ]
txt=[]
for i in sig.keys():
if i not in torder:
torder.append(i)
for t in torder:
sl = sig.get(t)
if sl is None:
continue
s = []
for k in korder:
v = sl.get(k)
if v is None:
continue
s.append("%s=%s"%(k,v))
txt.append("%s(%s)" % (t, "%".join(s)))
return "\n".join(txt)
###################
## User commands ##
###################
def sniff(count=0, store=1, offline=None, prn = None, lfilter=None, L2socket=None, timeout=None, *arg, **karg):
"""Sniff packets
sniff([count=0,] [prn=None,] [store=1,] [offline=None,] [lfilter=None,] + L2ListenSocket args) -> list of packets
count: number of packets to capture. 0 means infinity
store: wether to store sniffed packets or discard them
prn: function to apply to each packet. If something is returned,
it is displayed. Ex:
ex: prn = lambda x: x.summary()
lfilter: python function applied to each packet to determine
if further action may be done
ex: lfilter = lambda x: x.haslayer(Padding)
offline: pcap file to read packets from, instead of sniffing them
timeout: stop sniffing after a given time (default: None)
L2socket: use the provided L2socket
"""
c = 0
if offline is None:
if L2socket is None:
L2socket = conf.L2listen
s = L2socket(type=ETH_P_ALL, *arg, **karg)
else:
s = PcapReader(offline)
lst = []
if timeout is not None:
stoptime = time.time()+timeout
remain = None
while 1:
try:
if timeout is not None:
remain = stoptime-time.time()
if remain <= 0:
break
sel = select([s],[],[],remain)
if s in sel[0]:
p = s.recv(MTU)
if p is None:
break
if lfilter and not lfilter(p):
continue
if store:
lst.append(p)
c += 1
if prn:
r = prn(p)
if r is not None:
print r
if count > 0 and c >= count:
break
except KeyboardInterrupt:
break
return PacketList(lst,"Sniffed")
def arpcachepoison(target, victim, interval=60):
"""Poison target's cache with (your MAC,victim's IP) couple
arpcachepoison(target, victim, [interval=60]) -> None
"""
tmac = getmacbyip(target)
p = Ether(dst=tmac)/ARP(op="who-has", psrc=victim, pdst=target)
try:
while 1:
sendp(p, iface_hint=target)
if conf.verb > 1:
os.write(1,".")
time.sleep(interval)
except KeyboardInterrupt:
pass
def traceroute(target, dport=80, minttl=1, maxttl=30, sport=RandShort(), l4 = None, filter=None, timeout=2, **kargs):
"""Instant TCP traceroute
traceroute(target, [maxttl=30], [dport=80], [sport=80]) -> None
"""
if filter is None:
filter="(icmp and icmp[0]=11) or (tcp and (tcp[13] & 0x16 > 0x10))"
if l4 is None:
a,b = sr(IP(dst=target, id=RandShort(), ttl=(minttl,maxttl))/TCP(seq=RandInt(),sport=sport, dport=dport),
timeout=timeout, filter=filter, **kargs)
else:
a,b = sr(IP(dst=target, id=RandShort(), ttl=(minttl,maxttl))/l4,
timeout=timeout, **kargs)
a = TracerouteResult(a.res)
a.display()
return a,b
def arping(net, timeout=2, cache=0, **kargs):
"""Send ARP who-has requests to determine which hosts are up
arping(net, cache=0, iface=conf.iface) -> None
Set cache=True if you want arping to modify internal ARP-Cache"""
ans,unans = srp(Ether(dst="ff:ff:ff:ff:ff:ff")/ARP(pdst=net),
filter="arp and arp[7] = 2", timeout=timeout, iface_hint=net, **kargs)
ans = ARPingResult(ans.res)
if cache and ans is not None:
for pair in ans:
arp_cache[pair[1].psrc] = (pair[1].hwsrc, time.time())
ans.display()
return ans,unans
def dyndns_add(nameserver, name, rdata, type="A", ttl=10):
"""Send a DNS add message to a nameserver for "name" to have a new "rdata"
dyndns_add(nameserver, name, rdata, type="A", ttl=10) -> result code (0=ok)
example: dyndns_add("ns1.toto.com", "dyn.toto.com", "127.0.0.1")
RFC2136
"""
zone = name[name.find(".")+1:]
r=sr1(IP(dst=nameserver)/UDP()/DNS(opcode=5,
qd=[DNSQR(qname=zone, qtype="SOA")],
ns=[DNSRR(rrname=name, type="A",
ttl=ttl, rdata=rdata)]),
verbose=0, timeout=5)
if r and r.haslayer(DNS):
return r.getlayer(DNS).rcode
else:
return -1
def dyndns_del(nameserver, name, type="ALL", ttl=10):
"""Send a DNS delete message to a nameserver for "name"
dyndns_del(nameserver, name, type="ANY", ttl=10) -> result code (0=ok)
example: dyndns_del("ns1.toto.com", "dyn.toto.com")
RFC2136
"""
zone = name[name.find(".")+1:]
r=sr1(IP(dst=nameserver)/UDP()/DNS(opcode=5,
qd=[DNSQR(qname=zone, qtype="SOA")],
ns=[DNSRR(rrname=name, type=type,
rclass="ANY", ttl=0, rdata="")]),
verbose=0, timeout=5)
if r and r.haslayer(DNS):
return r.getlayer(DNS).rcode
else:
return -1
def is_promisc(ip, fake_bcast="ff:ff:00:00:00:00",**kargs):
"""Try to guess if target is in Promisc mode. The target is provided by its ip."""
responses = srp1(Ether(dst=fake_bcast) / ARP(op="who-has", pdst=ip),type=ETH_P_ARP, iface_hint=ip, timeout=1, verbose=0,**kargs)
return responses is not None
def promiscping(net, timeout=2, fake_bcast="ff:ff:ff:ff:ff:fe", **kargs):
"""Send ARP who-has requests to determine which hosts are in promiscuous mode
promiscping(net, iface=conf.iface)"""
ans,unans = srp(Ether(dst=fake_bcast)/ARP(pdst=net),
filter="arp and arp[7] = 2", timeout=timeout, iface_hint=net, **kargs)
ans = ARPingResult(ans.res, name="PROMISCPing")
ans.display()
return ans,unans
def ikescan(ip):
return sr(IP(dst=ip)/UDP()/ISAKMP(init_cookie=RandString(8),
exch_type=2)/ISAKMP_payload_SA(prop=ISAKMP_payload_Proposal()))
def dhcp_request(iface=None,**kargs):
if conf.checkIPaddr != 0:
warning("conf.checkIPaddr is not 0, I may not be able to match the answer")
if iface is None:
iface = conf.iface
fam,hw = get_if_raw_hwaddr(iface)
return srp1(Ether(dst="ff:ff:ff:ff:ff:ff")/IP(src="0.0.0.0",dst="255.255.255.255")/UDP(sport=68,dport=67)
/BOOTP(chaddr=hw)/DHCP(options=[("message-type","discover"),"end"]),iface=iface,**kargs)
def snmpwalk(dst, oid="1", community="public"):
try:
while 1:
r = sr1(IP(dst=dst)/UDP(sport=RandShort())/SNMP(community=community, PDU=SNMPnext(varbindlist=[SNMPvarbind(oid=oid)])),timeout=2, chainCC=1, verbose=0, retry=2)
if ICMP in r:
print repr(r)
break
if r is None:
print "No answers"
break
print "%-40s: %r" % (r[SNMPvarbind].oid.val,r[SNMPvarbind].value)
oid = r[SNMPvarbind].oid
except KeyboardInterrupt:
pass
#####################
## Reporting stuff ##
#####################
def report_ports(target, ports):
"""portscan a target and output a LaTeX table
report_ports(target, ports) -> string"""
ans,unans = sr(IP(dst=target)/TCP(dport=ports),timeout=5)
rep = "\\begin{tabular}{|r|l|l|}\n\\hline\n"
for s,r in ans:
if not r.haslayer(ICMP):
if r.payload.flags == 0x12:
rep += r.sprintf("%TCP.sport% & open & SA \\\\\n")
rep += "\\hline\n"
for s,r in ans:
if r.haslayer(ICMP):
rep += r.sprintf("%TCPerror.dport% & closed & ICMP type %ICMP.type%/%ICMP.code% from %IP.src% \\\\\n")
elif r.payload.flags != 0x12:
rep += r.sprintf("%TCP.sport% & closed & TCP %TCP.flags% \\\\\n")
rep += "\\hline\n"
for i in unans:
rep += i.sprintf("%TCP.dport% & ? & unanswered \\\\\n")
rep += "\\hline\n\\end{tabular}\n"
return rep
def __make_table(yfmtfunc, fmtfunc, endline, list, fxyz, sortx=None, sorty=None, seplinefunc=None):
vx = {}
vy = {}
vz = {}
vxf = {}
vyf = {}
l = 0
for e in list:
xx,yy,zz = map(str, fxyz(e))
l = max(len(yy),l)
vx[xx] = max(vx.get(xx,0), len(xx), len(zz))
vy[yy] = None
vz[(xx,yy)] = zz
vxk = vx.keys()
vyk = vy.keys()
if sortx:
vxk.sort(sortx)
else:
try:
vxk.sort(lambda x,y:int(x)-int(y))
except:
try:
vxk.sort(lambda x,y: cmp(struct.unpack("I", inet_aton(x))[0],struct.unpack("I", inet_aton(y))[0]))
except:
vxk.sort()
if sorty:
vyk.sort(sorty)
else:
try:
vyk.sort(lambda x,y:int(x)-int(y))
except:
try:
vyk.sort(lambda x,y: cmp(struct.unpack("I", inet_aton(x))[0],struct.unpack("I", inet_aton(y))[0]))
except:
vyk.sort()
if seplinefunc:
sepline = seplinefunc(l, map(lambda x:vx[x],vxk))
print sepline
fmt = yfmtfunc(l)
print fmt % "",
for x in vxk:
vxf[x] = fmtfunc(vx[x])
print vxf[x] % x,
print endline
if seplinefunc:
print sepline
for y in vyk:
print fmt % y,
for x in vxk:
print vxf[x] % vz.get((x,y), "-"),
print endline
if seplinefunc:
print sepline
def make_table(*args, **kargs):
__make_table(lambda l:"%%-%is" % l, lambda l:"%%-%is" % l, "", *args, **kargs)
def make_lined_table(*args, **kargs):
__make_table(lambda l:"%%-%is |" % l, lambda l:"%%-%is |" % l, "",
seplinefunc=lambda a,x:"+".join(map(lambda y:"-"*(y+2), [a-1]+x+[-2])),
*args, **kargs)
def make_tex_table(*args, **kargs):
__make_table(lambda l: "%s", lambda l: "& %s", "\\\\", seplinefunc=lambda a,x:"\\hline", *args, **kargs)
######################
## Online doc stuff ##
######################
def lsc(cmd=None):
"""List user commands"""
if cmd is None:
for c in user_commands:
doc = "No doc. available"
if c.__doc__:
doc = c.__doc__.split("\n")[0]
print "%-16s : %s" % (c.__name__, doc)
else:
print cmd.__doc__
def ls(obj=None):
"""List available layers, or infos on a given layer"""
if obj is None:
import __builtin__
all = __builtin__.__dict__.copy()
all.update(globals())
objlst = filter(lambda (n,o): isinstance(o,type) and issubclass(o,Packet), all.items())
objlst.sort(lambda x,y:cmp(x[0],y[0]))
for n,o in objlst:
print "%-10s : %s" %(n,o.name)
else:
if isinstance(obj, type) and issubclass(obj, Packet):
for f in obj.fields_desc:
print "%-10s : %-20s = (%s)" % (f.name, f.__class__.__name__, repr(f.default))
elif isinstance(obj, Packet):
for f in obj.fields_desc:
print "%-10s : %-20s = %-15s (%s)" % (f.name, f.__class__.__name__, repr(getattr(obj,f.name)), repr(f.default))
if not isinstance(obj.payload, NoPayload):
print "--"
ls(obj.payload)
else:
print "Not a packet class. Type 'ls()' to list packet classes."
user_commands = [ sr, sr1, srp, srp1, srloop, srploop, sniff, p0f, arpcachepoison, send, sendp, traceroute, arping, ls, lsc, queso, nmap_fp, report_ports, dyndns_add, dyndns_del, is_promisc, promiscping ]
########################
## Answering machines ##
########################
class ReferenceAM(type):
def __new__(cls, name, bases, dct):
o = super(ReferenceAM, cls).__new__(cls, name, bases, dct)
if o.function_name:
globals()[o.function_name] = lambda o=o,*args,**kargs: o(*args,**kargs)()
return o
class AnsweringMachine(object):
__metaclass__ = ReferenceAM
function_name = ""
filter = None
sniff_options = { "store":0 }
sniff_options_list = [ "store", "iface", "count", "promisc", "filter", "type", "prn" ]
send_options = { "verbose":0 }
send_options_list = ["iface", "inter", "loop", "verbose"]
send_function = staticmethod(send)
def __init__(self, **kargs):
self.mode = 0
if self.filter:
kargs.setdefault("filter",self.filter)
kargs.setdefault("prn", self.reply)
self.optam1 = {}
self.optam2 = {}
self.optam0 = {}
doptsend,doptsniff = self.parse_all_options(1, kargs)
self.defoptsend = self.send_options.copy()
self.defoptsend.update(doptsend)
self.defoptsniff = self.sniff_options.copy()
self.defoptsniff.update(doptsniff)
self.optsend,self.optsniff = [{},{}]
def __getattr__(self, attr):
for d in [self.optam2, self.optam1]:
if attr in d:
return d[attr]
raise AttributeError,attr
def __setattr__(self, attr, val):
mode = self.__dict__.get("mode",0)
if mode == 0:
self.__dict__[attr] = val
else:
[self.optam1, self.optam2][mode-1][attr] = val
def parse_options(self):
pass
def parse_all_options(self, mode, kargs):
sniffopt = {}
sendopt = {}
for k in kargs.keys():
if k in self.sniff_options_list:
sniffopt[k] = kargs[k]
if k in self.send_options_list:
sendopt[k] = kargs[k]
if k in self.sniff_options_list+self.send_options_list:
del(kargs[k])
if mode != 2 or kargs:
if mode == 1:
self.optam0 = kargs
elif mode == 2 and kargs:
k = self.optam0.copy()
k.update(kargs)
self.parse_options(**k)
kargs = k
omode = self.__dict__.get("mode",0)
self.__dict__["mode"] = mode
self.parse_options(**kargs)
self.__dict__["mode"] = omode
return sendopt,sniffopt
def is_request(self, req):
return 1
def make_reply(self, req):
return req
def send_reply(self, reply):
self.send_function(reply, **self.optsend)
def print_reply(self, req, reply):
print "%s ==> %s" % (req.summary(),reply.summary())
def reply(self, pkt):
if not self.is_request(pkt):
return
reply = self.make_reply(pkt)
self.send_reply(reply)
if conf.verb >= 0:
self.print_reply(pkt, reply)
def run(self, *args, **kargs):
log_interactive.warning("run() method deprecated. The intance is now callable")
self(*args,**kargs)
def __call__(self, *args, **kargs):
optsend,optsniff = self.parse_all_options(2,kargs)
self.optsend=self.defoptsend.copy()
self.optsend.update(optsend)
self.optsniff=self.defoptsniff.copy()
self.optsniff.update(optsniff)
try:
self.sniff()
except KeyboardInterrupt:
print "Interrupted by user"
def sniff(self):
sniff(**self.optsniff)
class BOOTP_am(AnsweringMachine):
function_name = "bootpd"
filter = "udp and port 68 and port 67"
send_function = staticmethod(sendp)
def parse_options(self, ipset=Net("192.168.1.128/25"),gw="192.168.1.1"):
if type(ipset) is str:
ipset = Net(ipset)
if isinstance(ipset,Gen):
ipset = [k for k in ipset]
ipset.reverse()
if len(ipset) == 1:
ipset, = ipset
self.ipset = ipset
self.gw = gw
self.leases = {}
def is_request(self, req):
if not req.haslayer(BOOTP):
return 0
reqb = req.getlayer(BOOTP)
if reqb.op != 1:
return 0
return 1
def print_reply(self, req, reply):
print "Reply %s to %s" % (reply.getlayer(IP).dst,reply.dst)
def make_reply(self, req):
mac = req.src
if type(self.ipset) is list:
if not self.leases.has_key(mac):
self.leases[mac] = self.ipset.pop()
ip = self.leases[mac]
else:
ip = self.ipset
repb = req.getlayer(BOOTP).copy()
repb.options = ""
repb.op="BOOTREPLY"
repb.yiaddr = ip
repb.siaddr = self.gw
repb.ciaddr = self.gw
repb.giaddr = self.gw
rep=Ether(dst=mac)/IP(dst=ip)/UDP(sport=req.dport,dport=req.sport)/repb
return rep
class DHCP_am(BOOTP_am):
function_name="dhcpd"
def is_request(self, req):
if not BOOTP_am.is_request(self, req):
return 0
if req.getlayer(BOOTP).options[:4] != "'c\x82Sc":
return 0
return 1
def make_reply(self, req):
dhcprespmap={"\x01":"\x02","\x03":"\x05"}
resp = BOOTP_am.make_reply(self, req)
opt = req.getlayer(BOOTP).options
o = opt[:6]
if len(opt) > 6:
o += dhcprespmap.get(opt[6],opt[6])
if len(opt) > 7:
o += opt[7:]
resp.getlayer(BOOTP).options = o
class DNS_am(AnsweringMachine):
function_name="dns_spoof"
filter = "udp port 53"
def parse_options(self, joker="192.168.1.1", match=None):
if match is None:
self.match = {}
else:
self.match = match
self.joker=joker
def is_request(self, req):
return req.haslayer(DNS) and req.getlayer(DNS).qr == 0
def make_reply(self, req):
ip = req.getlayer(IP)
dns = req.getlayer(DNS)
resp = IP(dst=ip.src, src=ip.dst)/UDP(dport=ip.sport,sport=ip.dport)
rdata = self.match.get(dns.qd.qname, self.joker)
resp /= DNS(id=dns.id, qr=1, qd=dns.qd,
an=DNSRR(rrname=dns.qd.qname, ttl=10, rdata=rdata))
return resp
class WiFi_am(AnsweringMachine):
"""Before using this, initialize "iffrom" and "ifto" interfaces:
iwconfig iffrom mode monitor
iwpriv orig_ifto hostapd 1
ifconfig ifto up
note: if ifto=wlan0ap then orig_ifto=wlan0
note: ifto and iffrom must be set on the same channel
ex:
ifconfig eth1 up
iwconfig eth1 mode monitor
iwconfig eth1 channel 11
iwpriv wlan0 hostapd 1
ifconfig wlan0ap up
iwconfig wlan0 channel 11
iwconfig wlan0 essid dontexist
iwconfig wlan0 mode managed
"""
function_name = "airpwn"
filter = None
def parse_options(iffrom, ifto, replace, pattern="", ignorepattern=""):
self.iffrom = iffrom
self.ifto = ifto
ptrn = re.compile(pattern)
iptrn = re.compile(ignorepattern)
def is_request(self, pkt):
if not isinstance(pkt,Dot11):
return 0
if not pkt.FCfield & 1:
return 0
if not pkt.haslayer(TCP):
return 0
ip = pkt.getlayer(IP)
tcp = pkt.getlayer(TCP)
pay = str(tcp.payload)
if not self.ptrn.match(pay):
return 0
if self.iptrn.match(pay):
return 0
def make_reply(self, p):
ip = p.getlayer(IP)
tcp = p.getlayer(TCP)
pay = str(tcp.payload)
del(p.payload.payload.payload)
p.FCfield="from-DS"
p.addr1,p.addr2 = p.addr2,p.addr1
p /= IP(src=ip.dst,dst=ip.src)
p /= TCP(sport=tcp.dport, dport=tcp.sport,
seq=tcp.ack, ack=tcp.seq+len(pay),
flags="PA")
q = p.copy()
p /= self.replace
q.ID += 1
q.getlayer(TCP).flags="RA"
q.getlayer(TCP).seq+=len(replace)
return [p,q]
def print_reply(self):
print p.sprintf("Sent %IP.src%:%IP.sport% > %IP.dst%:%TCP.dport%")
def send_reply(self, reply):
sendp(reply, iface=self.ifto, **self.optsend)
def sniff(self):
sniff(iface=self.iffrom, **self.optsniff)
class ARP_am(AnsweringMachine):
function_name="farpd"
filter = "arp"
send_function = staticmethod(sendp)
def parse_options(self, IP_addr=None, iface=None, ARP_addr=None):
self.IP_addr=IP_addr
self.iface=iface
self.ARP_addr=ARP_addr
def is_request(self, req):
return (req.haslayer(ARP) and
req.getlayer(ARP).op == 1 and
(self.IP_addr == None or self.IP_addr == req.getlayer(ARP).pdst))
def make_reply(self, req):
ether = req.getlayer(Ether)
arp = req.getlayer(ARP)
iff,a,gw = conf.route.route(arp.psrc)
if self.iface != None:
iff = iface
ARP_addr = self.ARP_addr
IP_addr = arp.pdst
resp = Ether(dst=ether.src,
src=ARP_addr)/ARP(op="is-at",
hwsrc=ARP_addr,
psrc=IP_addr,
hwdst=arp.hwsrc,
pdst=arp.pdst)
return resp
def sniff(self):
sniff(iface=self.iface, **self.optsniff)
#############
## Fuzzing ##
#############
def fuzz(p, _inplace=0):
if not _inplace:
p = p.copy()
q = p
while not isinstance(q, NoPayload):
for f in q.fields_desc:
if isinstance(f, PacketListField):
for r in getattr(q, f.name):
print "fuzzing", repr(r)
fuzz(r, _inplace=1)
elif f.default is not None:
rnd = f.randval()
if rnd is not None:
q.default_fields[f.name] = rnd
q = q.payload
return p
###################
## Testing stuff ##
###################
def merge(x,y):
if len(x) > len(y):
y += "\x00"*(len(x)-len(y))
elif len(x) < len(y):
x += "\x00"*(len(y)-len(x))
m = ""
for i in range(len(x)/ss):
m += x[ss*i:ss*(i+1)]+y[ss*i:ss*(i+1)]
return m
# return "".join(map(str.__add__, x, y))
def voip_play(s1,list=None,**kargs):
FIFO="/tmp/conv1.%i.%%i" % os.getpid()
FIFO1=FIFO % 1
FIFO2=FIFO % 2
os.mkfifo(FIFO1)
os.mkfifo(FIFO2)
try:
os.system("soxmix -t .ul %s -t .ul %s -t ossdsp /dev/dsp &" % (FIFO1,FIFO2))
c1=open(FIFO1,"w", 4096)
c2=open(FIFO2,"w", 4096)
fcntl.fcntl(c1.fileno(),fcntl.F_SETFL, os.O_NONBLOCK)
fcntl.fcntl(c2.fileno(),fcntl.F_SETFL, os.O_NONBLOCK)
# dsp,rd = os.popen2("sox -t .ul -c 2 - -t ossdsp /dev/dsp")
def play(pkt,last=[]):
if not pkt:
return
if not pkt.haslayer(UDP):
return
ip=pkt.getlayer(IP)
if s1 in [ip.src, ip.dst]:
if not last:
last.append(pkt)
return
load=last.pop()
# x1 = load.load[12:]
c1.write(load.load[12:])
if load.getlayer(IP).src == ip.src:
# x2 = ""
c2.write("\x00"*len(load.load[12:]))
last.append(pkt)
else:
# x2 = pkt.load[:12]
c2.write(pkt.load[12:])
# dsp.write(merge(x1,x2))
if list is None:
sniff(store=0, prn=play, **kargs)
else:
for p in list:
play(p)
finally:
os.unlink(FIFO1)
os.unlink(FIFO2)
def voip_play1(s1,list=None,**kargs):
dsp,rd = os.popen2("sox -t .ul - -t ossdsp /dev/dsp")
def play(pkt):
if not pkt:
return
if not pkt.haslayer(UDP):
return
ip=pkt.getlayer(IP)
if s1 in [ip.src, ip.dst]:
dsp.write(pkt.getlayer(Raw).load[12:])
try:
if list is None:
sniff(store=0, prn=play, **kargs)
else:
for p in list:
play(p)
finally:
dsp.close()
rd.close()
def voip_play2(s1,**kargs):
dsp,rd = os.popen2("sox -t .ul -c 2 - -t ossdsp /dev/dsp")
def play(pkt,last=[]):
if not pkt:
return
if not pkt.haslayer(UDP):
return
ip=pkt.getlayer(IP)
if s1 in [ip.src, ip.dst]:
if not last:
last.append(pkt)
return
load=last.pop()
x1 = load.load[12:]
# c1.write(load.load[12:])
if load.getlayer(IP).src == ip.src:
x2 = ""
# c2.write("\x00"*len(load.load[12:]))
last.append(pkt)
else:
x2 = pkt.load[:12]
# c2.write(pkt.load[12:])
dsp.write(merge(x1,x2))
sniff(store=0, prn=play, **kargs)
def voip_play3(lst=None,**kargs):
dsp,rd = os.popen2("sox -t .ul - -t ossdsp /dev/dsp")
try:
def play(pkt, dsp=dsp):
if pkt and pkt.haslayer(UDP) and pkt.haslayer(Raw):
dsp.write(pkt.getlayer(Raw).load[12:])
if lst is None:
sniff(store=0, prn=play, **kargs)
else:
for p in lst:
play(p)
finally:
try:
dsp.close()
rd.close()
except:
pass
def IPID_count(lst, funcID=lambda x:x[1].id, funcpres=lambda x:x[1].summary()):
idlst = map(funcID, lst)
idlst.sort()
classes = [idlst[0]]+map(lambda x:x[1],filter(lambda (x,y): abs(x-y)>50, map(lambda x,y: (x,y),idlst[:-1], idlst[1:])))
lst = map(lambda x:(funcID(x), funcpres(x)), lst)
lst.sort()
print "Probably %i classes:" % len(classes), classes
for id,pr in lst:
print "%5i" % id, pr
last=None
def tethereal(*args,**kargs):
sniff(prn=lambda x: x.display(),*args,**kargs)
def etherleak(target, **kargs):
return srpflood(Ether()/ARP(pdst=target), prn=lambda (s,r): Padding in r and hexstr(r[Padding].load),
filter="arp", **kargs)
def fragleak(target,sport=123, dport=123, timeout=0.2, onlyasc=0):
load = "XXXXYYYYYYYYYY"
# getmacbyip(target)
# pkt = IP(dst=target, id=RandShort(), options="\x22"*40)/UDP()/load
pkt = IP(dst=target, id=RandShort(), options="\x00"*40, flags=1)/UDP(sport=sport, dport=sport)/load
s=conf.L3socket()
intr=0
found={}
try:
while 1:
try:
if not intr:
s.send(pkt)
sin,sout,serr = select([s],[],[],timeout)
if not sin:
continue
ans=s.recv(1600)
if not isinstance(ans, IP): #TODO: IPv6
continue
if not isinstance(ans.payload, ICMP):
continue
if not isinstance(ans.payload.payload, IPerror):
continue
if ans.payload.payload.dst != target:
continue
if ans.src != target:
print "leak from", ans.src,
# print repr(ans)
if not ans.haslayer(Padding):
continue
# print repr(ans.payload.payload.payload.payload)
# if not isinstance(ans.payload.payload.payload.payload, Raw):
# continue
# leak = ans.payload.payload.payload.payload.load[len(load):]
leak = ans.getlayer(Padding).load
if leak not in found:
found[leak]=None
linehexdump(leak, onlyasc=onlyasc)
except KeyboardInterrupt:
if intr:
raise
intr=1
except KeyboardInterrupt:
pass
def fragleak2(target, timeout=0.4, onlyasc=0):
found={}
try:
while 1:
p = sr1(IP(dst=target, options="\x00"*40, proto=200)/"XXXXYYYYYYYYYYYY",timeout=timeout,verbose=0)
if not p:
continue
if Padding in p:
leak = p[Padding].load
if leak not in found:
found[leak]=None
linehexdump(leak,onlyasc=onlyasc)
except:
pass
plst=[]
def get_toDS():
global plst
while 1:
p,=sniff(iface="eth1",count=1)
if not isinstance(p,Dot11):
continue
if p.FCfield & 1:
plst.append(p)
print "."
# if not ifto.endswith("ap"):
# print "iwpriv %s hostapd 1" % ifto
# os.system("iwpriv %s hostapd 1" % ifto)
# ifto += "ap"
#
# os.system("iwconfig %s mode monitor" % iffrom)
#
def airpwn(iffrom, ifto, replace, pattern="", ignorepattern=""):
"""Before using this, initialize "iffrom" and "ifto" interfaces:
iwconfig iffrom mode monitor
iwpriv orig_ifto hostapd 1
ifconfig ifto up
note: if ifto=wlan0ap then orig_ifto=wlan0
note: ifto and iffrom must be set on the same channel
ex:
ifconfig eth1 up
iwconfig eth1 mode monitor
iwconfig eth1 channel 11
iwpriv wlan0 hostapd 1
ifconfig wlan0ap up
iwconfig wlan0 channel 11
iwconfig wlan0 essid dontexist
iwconfig wlan0 mode managed
"""
ptrn = re.compile(pattern)
iptrn = re.compile(ignorepattern)
def do_airpwn(p, ifto=ifto, replace=replace, ptrn=ptrn, iptrn=iptrn):
if not isinstance(p,Dot11):
return
if not p.FCfield & 1:
return
if not p.haslayer(TCP):
return
ip = p.getlayer(IP)
tcp = p.getlayer(TCP)
pay = str(tcp.payload)
# print "got tcp"
if not ptrn.match(pay):
return
# print "match 1"
if iptrn.match(pay):
return
# print "match 2"
del(p.payload.payload.payload)
p.FCfield="from-DS"
p.addr1,p.addr2 = p.addr2,p.addr1
q = p.copy()
p /= IP(src=ip.dst,dst=ip.src)
p /= TCP(sport=tcp.dport, dport=tcp.sport,
seq=tcp.ack, ack=tcp.seq+len(pay),
flags="PA")
q = p.copy()
p /= replace
q.ID += 1
q.getlayer(TCP).flags="RA"
q.getlayer(TCP).seq+=len(replace)
sendp([p,q], iface=ifto, verbose=0)
# print "send",repr(p)
# print "send",repr(q)
print p.sprintf("Sent %IP.src%:%IP.sport% > %IP.dst%:%TCP.dport%")
sniff(iface=iffrom,prn=do_airpwn)
##################
## Color themes ##
##################
class Color:
normal = "\033[0m"
black = "\033[30m"
red = "\033[31m"
green = "\033[32m"
yellow = "\033[33m"
blue = "\033[34m"
purple = "\033[35m"
cyan = "\033[36m"
grey = "\033[37m"
bold = "\033[1m"
uline = "\033[4m"
blink = "\033[5m"
invert = "\033[7m"
class ColorTheme:
def __repr__(self):
return "<%s>" % self.__class__.__name__
def __getattr__(self, attr):
return lambda x:x
class NoTheme(ColorTheme):
pass
class AnsiColorTheme(ColorTheme):
def __getattr__(self, attr):
if attr.startswith("__"):
raise AttributeError(attr)
s = "style_%s" % attr
if s in self.__class__.__dict__:
before = getattr(self, s)
after = self.style_normal
else:
before = after = ""
def do_style(val, fmt=None, before=before, after=after):
if fmt is None:
if type(val) is not str:
val = str(val)
else:
val = fmt % val
return before+val+after
return do_style
style_normal = ""
style_prompt = ""
style_punct = ""
style_id = ""
style_not_printable = ""
style_layer_name = ""
style_field_name = ""
style_field_value = ""
style_emph_field_name = ""
style_emph_field_value = ""
style_packetlist_name = ""
style_packetlist_proto = ""
style_packetlist_value = ""
style_fail = ""
style_success = ""
style_odd = ""
style_even = ""
style_opening = ""
style_active = ""
style_closed = ""
style_left = ""
style_right = ""
class BlackAndWhite(AnsiColorTheme):
pass
class DefaultTheme(AnsiColorTheme):
style_normal = Color.normal
style_prompt = Color.blue+Color.bold
style_punct = Color.normal
style_id = Color.blue+Color.bold
style_not_printable = Color.grey
style_layer_name = Color.red+Color.bold
style_field_name = Color.blue
style_field_value = Color.purple
style_emph_field_name = Color.blue+Color.uline+Color.bold
style_emph_field_value = Color.purple+Color.uline+Color.bold
style_packetlist_name = Color.red+Color.bold
style_packetlist_proto = Color.blue
style_packetlist_value = Color.purple
style_fail = Color.red+Color.bold
style_success = Color.blue+Color.bold
style_even = Color.black+Color.bold
style_odd = Color.black
style_opening = Color.yellow
style_active = Color.black
style_closed = Color.grey
style_left = Color.blue
style_right = Color.red
class BrightTheme(AnsiColorTheme):
style_normal = Color.normal
style_punct = Color.normal
style_id = Color.yellow+Color.bold
style_layer_name = Color.red+Color.bold
style_field_name = Color.yellow+Color.bold
style_field_value = Color.purple+Color.bold
style_emph_field_name = Color.yellow+Color.bold
style_emph_field_value = Color.green+Color.bold
style_packetlist_name = Color.red+Color.bold
style_packetlist_proto = Color.yellow+Color.bold
style_packetlist_value = Color.purple+Color.bold
style_fail = Color.red+Color.bold
style_success = Color.blue+Color.bold
style_even = Color.black+Color.bold
style_odd = Color.black
style_left = Color.cyan
style_right = Color.purple
class RastaTheme(AnsiColorTheme):
style_normal = Color.green+Color.bold
style_prompt = Color.yellow+Color.bold
style_punct = Color.red
style_id = Color.green+Color.bold
style_not_printable = Color.green
style_layer_name = Color.red+Color.bold
style_field_name = Color.yellow+Color.bold
style_field_value = Color.green+Color.bold
style_emph_field_name = Color.green
style_emph_field_value = Color.green
style_packetlist_name = Color.red+Color.bold
style_packetlist_proto = Color.yellow+Color.bold
style_packetlist_value = Color.green+Color.bold
style_fail = Color.red
style_success = Color.red+Color.bold
style_even = Color.yellow
style_odd = Color.green
style_left = Color.red
style_right = Color.yellow
class FormatTheme(ColorTheme):
def __getattr__(self, attr):
if attr.startswith("__"):
raise AttributeError(attr)
col = self.__class__.__dict__.get("style_%s" % attr, "%s")
def do_style(val, fmt=None, col=col):
if fmt is None:
if type(val) is not str:
val = str(val)
else:
val = fmt % val
return col % val
return do_style
class LatexTheme(FormatTheme):
style_prompt = r"\textcolor{blue}{%s}"
style_not_printable = r"\textcolor{gray}{%s}"
style_layer_name = r"\textcolor{red}{\bf %s}"
style_field_name = r"\textcolor{blue}{%s}"
style_field_value = r"\textcolor{purple}{%s}"
style_emph_field_name = r"\textcolor{blue}{\underline{%s}}" #ul
style_emph_field_value = r"\textcolor{purple}{\underline{%s}}" #ul
style_packetlist_name = r"\textcolor{red}{\bf %s}"
style_packetlist_proto = r"\textcolor{blue}{%s}"
style_packetlist_value = r"\textcolor{purple}{%s}"
style_fail = r"\textcolor{red}{\bf %s}"
style_success = r"\textcolor{blue}{\bf %s}"
style_left = r"\textcolor{blue}{%s}"
style_right = r"\textcolor{red}{%s}"
# style_even = r"}{\bf "
# style_odd = ""
class LatexTheme2(FormatTheme):
style_prompt = r"@`@textcolor@[@blue@]@@[@%s@]@"
style_not_printable = r"@`@textcolor@[@gray@]@@[@%s@]@"
style_layer_name = r"@`@textcolor@[@red@]@@[@@`@bfseries@[@@]@%s@]@"
style_field_name = r"@`@textcolor@[@blue@]@@[@%s@]@"
style_field_value = r"@`@textcolor@[@purple@]@@[@%s@]@"
style_emph_field_name = r"@`@textcolor@[@blue@]@@[@@`@underline@[@%s@]@@]@"
style_emph_field_value = r"@`@textcolor@[@purple@]@@[@@`@underline@[@%s@]@@]@"
style_packetlist_name = r"@`@textcolor@[@red@]@@[@@`@bfseries@[@@]@%s@]@"
style_packetlist_proto = r"@`@textcolor@[@blue@]@@[@%s@]@"
style_packetlist_value = r"@`@textcolor@[@purple@]@@[@%s@]@"
style_fail = r"@`@textcolor@[@red@]@@[@@`@bfseries@[@@]@%s@]@"
style_success = r"@`@textcolor@[@blue@]@@[@@`@bfserices@[@@]@%s@]@"
style_even = r"@`@textcolor@[@gray@]@@[@@`@bfseries@[@@]@%s@]@"
# style_odd = r"@`@textcolor@[@black@]@@[@@`@bfseries@[@@]@%s@]@"
style_left = r"@`@textcolor@[@blue@]@@[@%s@]@"
style_right = r"@`@textcolor@[@red@]@@[@%s@]@"
class HTMLTheme(FormatTheme):
style_prompt = "<span class=prompt>%s</span>"
style_not_printable = "<span class=not_printable>%s</span>"
style_layer_name = "<span class=layer_name>%s</span>"
style_field_name = "<span class=field_name>%s</span>"
style_field_value = "<span class=field_value>%s</span>"
style_emph_field_name = "<span class=emph_field_name>%s</span>"
style_emph_field_value = "<span class=emph_field_value>%s</span>"
style_packetlist_name = "<span class=packetlist_name>%s</span>"
style_packetlist_proto = "<span class=packetlist_proto>%s</span>"
style_packetlist_value = "<span class=packetlist_value>%s</span>"
style_fail = "<span class=fail>%s</span>"
style_success = "<span class=success>%s</span>"
style_even = "<span class=even>%s</span>"
style_odd = "<span class=odd>%s</span>"
style_left = "<span class=left>%s</span>"
style_right = "<span class=right>%s</span>"
class HTMLTheme2(HTMLTheme):
style_prompt = "#[#span class=prompt#]#%s#[#/span#]#"
style_not_printable = "#[#span class=not_printable#]#%s#[#/span#]#"
style_layer_name = "#[#span class=layer_name#]#%s#[#/span#]#"
style_field_name = "#[#span class=field_name#]#%s#[#/span#]#"
style_field_value = "#[#span class=field_value#]#%s#[#/span#]#"
style_emph_field_name = "#[#span class=emph_field_name#]#%s#[#/span#]#"
style_emph_field_value = "#[#span class=emph_field_value#]#%s#[#/span#]#"
style_packetlist_name = "#[#span class=packetlist_name#]#%s#[#/span#]#"
style_packetlist_proto = "#[#span class=packetlist_proto#]#%s#[#/span#]#"
style_packetlist_value = "#[#span class=packetlist_value#]#%s#[#/span#]#"
style_fail = "#[#span class=fail#]#%s#[#/span#]#"
style_success = "#[#span class=success#]#%s#[#/span#]#"
style_even = "#[#span class=even#]#%s#[#/span#]#"
style_odd = "#[#span class=odd#]#%s#[#/span#]#"
style_left = "#[#span class=left#]#%s#[#/span#]#"
style_right = "#[#span class=right#]#%s#[#/span#]#"
class ColorPrompt:
__prompt = ">>> "
def __str__(self):
try:
ct = conf.color_theme
if isinstance(ct, AnsiColorTheme):
## ^A and ^B delimit invisible caracters for readline to count right
return "\001%s\002" % ct.prompt("\002"+conf.prompt+"\001")
else:
return ct.prompt(conf.prompt)
except:
return self.__prompt
############
## Config ##
############
class ConfClass:
def configure(self, cnf):
self.__dict__ = cnf.__dict__.copy()
def __repr__(self):
return str(self)
def __str__(self):
s="Version = %s\n" % VERSION
keys = self.__class__.__dict__.copy()
keys.update(self.__dict__)
keys = keys.keys()
keys.sort()
for i in keys:
if i[0] != "_":
s += "%-10s = %s\n" % (i, repr(getattr(self, i)))
return s[:-1]
class ProgPath(ConfClass):
pdfreader = "acroread"
psreader = "gv"
dot = "dot"
display = "display"
tcpdump = "tcpdump"
hexedit = "hexer"
wireshark = "wireshark"
class Resolve:
def __init__(self):
self.fields = {}
def add(self, *flds):
for fld in flds:
self.fields[fld]=None
def remove(self, *flds):
for fld in flds:
if fld in self.fields:
del(self.fields[fld])
def __contains__(self, elt):
return elt in self.fields
def __repr__(self):
return "<Resolve [%s]>" % " ".join(str(x) for x in self.fields)
class Conf(ConfClass):
"""This object contains the configuration of scapy.
session : filename where the session will be saved
stealth : if 1, prevents any unwanted packet to go out (ARP, DNS, ...)
checkIPID: if 0, doesn't check that IPID matches between IP sent and ICMP IP citation received
if 1, checks that they either are equal or byte swapped equals (bug in some IP stacks)
if 2, strictly checks that they are equals
checkIPsrc: if 1, checks IP src in IP and ICMP IP citation match (bug in some NAT stacks)
check_TCPerror_seqack: if 1, also check that TCP seq and ack match the ones in ICMP citation
iff : selects the default output interface for srp() and sendp(). default:"eth0")
verb : level of verbosity, from 0 (almost mute) to 3 (verbose)
promisc : default mode for listening socket (to get answers if you spoof on a lan)
sniff_promisc : default mode for sniff()
filter : bpf filter added to every sniffing socket to exclude traffic from analysis
histfile : history file
padding : includes padding in desassembled packets
except_filter : BPF filter for packets to ignore
debug_match : when 1, store received packet that are not matched into debug.recv
route : holds the Scapy routing table and provides methods to manipulate it
warning_threshold : how much time between warnings from the same place
ASN1_default_codec: Codec used by default for ASN1 objects
mib : holds MIB direct access dictionnary
resolve : holds list of fields for which resolution should be done
noenum : holds list of enum fields for which conversion to string should NOT be done
AS_resolver: choose the AS resolver class to use
"""
session = ""
stealth = "not implemented"
iface = get_working_if()
checkIPID = 0
checkIPsrc = 1
checkIPaddr = 1
check_TCPerror_seqack = 0
verb = 2
prompt = ">>> "
promisc = 1
sniff_promisc = 1
L3socket = L3PacketSocket
L2socket = L2Socket
L2listen = L2ListenSocket
BTsocket = BluetoothL2CAPSocket
histfile = os.path.join(os.environ["HOME"], ".scapy_history")
padding = 1
p0f_base ="/etc/p0f/p0f.fp"
queso_base ="/etc/queso.conf"
nmap_base ="/usr/share/nmap/nmap-os-fingerprints"
IPCountry_base = "GeoIPCountry4Scapy.gz"
countryLoc_base = "countryLoc.csv"
gnuplot_world = "world.dat"
except_filter = ""
debug_match = 0
route = Route()
wepkey = ""
auto_fragment = 1
debug_dissector = 0
color_theme = DefaultTheme()
warning_threshold = 5
ASN1_default_codec = ASN1_Codecs.BER
mib = MIBDict(_name="MIB")
prog = ProgPath()
resolve = Resolve()
noenum = Resolve()
ethertypes = ETHER_TYPES
protocols = IP_PROTOS
services_tcp = TCP_SERVICES
services_udp = UDP_SERVICES
manufdb = MANUFDB
AS_resolver = AS_resolver_multi()
conf=Conf()
if PCAP:
conf.L2listen=L2pcapListenSocket
if DNET:
conf.L3socket=L3dnetSocket
conf.L2socket=L2dnetSocket
p0f_kdb = p0fKnowledgeBase(conf.p0f_base)
queso_kdb = QuesoKnowledgeBase(conf.queso_base)
nmap_kdb = NmapKnowledgeBase(conf.nmap_base)
IP_country_kdb = IPCountryKnowledgeBase(conf.IPCountry_base)
country_loc_kdb = CountryLocKnowledgeBase(conf.countryLoc_base)
#########################
##### Autorun stuff #####
#########################
class ScapyAutorunInterpreter(code.InteractiveInterpreter):
def __init__(self, *args, **kargs):
code.InteractiveInterpreter.__init__(self, *args, **kargs)
self.error = 0
def showsyntaxerror(self, *args, **kargs):
self.error = 1
return code.InteractiveInterpreter.showsyntaxerror(self, *args, **kargs)
def showtraceback(self, *args, **kargs):
self.error = 1
return code.InteractiveInterpreter.showtraceback(self, *args, **kargs)
def autorun_commands(cmds,my_globals=None,verb=0):
sv = conf.verb
import __builtin__
try:
if my_globals is None:
my_globals = globals()
conf.verb = verb
interp = ScapyAutorunInterpreter(my_globals)
cmd = ""
cmds = cmds.splitlines()
cmds.append("") # ensure we finish multiline commands
cmds.reverse()
__builtin__.__dict__["_"] = None
while 1:
if cmd:
sys.stderr.write(sys.__dict__.get("ps2","... "))
else:
sys.stderr.write(str(sys.__dict__.get("ps1",ColorPrompt())))
l = cmds.pop()
print l
cmd += "\n"+l
if interp.runsource(cmd):
continue
if interp.error:
return 0
cmd = ""
if len(cmds) <= 1:
break
finally:
conf.verb = sv
return _
def autorun_get_interactive_session(cmds, **kargs):
class StringWriter:
def __init__(self):
self.s = ""
def write(self, x):
self.s += x
sw = StringWriter()
sstdout,sstderr = sys.stdout,sys.stderr
try:
sys.stdout = sys.stderr = sw
res = autorun_commands(cmds, **kargs)
finally:
sys.stdout,sys.stderr = sstdout,sstderr
return sw.s,res
def autorun_get_text_interactive_session(cmds, **kargs):
ct = conf.color_theme
try:
conf.color_theme = NoTheme()
s,res = autorun_get_interactive_session(cmds, **kargs)
finally:
conf.color_theme = ct
return s,res
def autorun_get_ansi_interactive_session(cmds, **kargs):
ct = conf.color_theme
try:
conf.color_theme = DefaultTheme()
s,res = autorun_get_interactive_session(cmds, **kargs)
finally:
conf.color_theme = ct
return s,res
def autorun_get_html_interactive_session(cmds, **kargs):
ct = conf.color_theme
try:
conf.color_theme = HTMLTheme2()
s,res = autorun_get_interactive_session(cmds, **kargs)
finally:
conf.color_theme = ct
s = s.replace("<","&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:
read_config_file(DEFAULT_CONFIG_FILE)